2011-01-25 12 views
10

Estoy usando el cpplint.py de Google para verificar que el código fuente en mi proyecto cumple con los estándares establecidos en el Google C++ Style Guide. Usamos SCons para compilar, por lo que me gustaría automatizar el proceso haciendo que SCons lea por primera vez en todos nuestros archivos .h y .cc y luego ejecute cpplint.py en ellos, creando solo un archivo si pasa. Los problemas son los siguientes:Configuración de SCons a Autolint

  1. En SCons, ¿cómo puedo anclar previamente el proceso de compilación? No se debe compilar ningún archivo hasta que pase la pelusa.
  2. cpplint no devuelve un código de salida. ¿Cómo ejecuto un comando en SCons y verifico si el resultado coincide con una expresión regular? I.E., ¿cómo obtengo el texto?
  3. El proyecto es grande, cualquiera que sea la solución para los n. ° 1 y n. ° 2, debe ejecutarse al mismo tiempo cuando la opción -j se pasa a SCons.
  4. Necesito una lista blanca que permita que algunos archivos omitan la verificación de pelusas.

Respuesta

2

Una forma de hacerlo es monkey patch la función de emisor de objetos, que convierte el código de C++ en archivos de objetos enlazables. Hay 2 funciones de emisor de este tipo; uno para objetos estáticos y uno para objetos compartidos. Aquí está un ejemplo que se puede copiar y pegar en un SConstruct:

import sys 
import SCons.Defaults 
import SCons.Builder 
OriginalShared = SCons.Defaults.SharedObjectEmitter 
OriginalStatic = SCons.Defaults.StaticObjectEmitter 

def DoLint(env, source): 
    for s in source: 
     env.Lint(s.srcnode().path + ".lint", s) 

def SharedObjectEmitter(target, source, env): 
    DoLint(env, source) 
    return OriginalShared(target, source, env) 

def StaticObjectEmitter(target, source, env): 
    DoLint(env, source) 
    return OriginalStatic(target, source, env) 

SCons.Defaults.SharedObjectEmitter = SharedObjectEmitter 
SCons.Defaults.StaticObjectEmitter = StaticObjectEmitter 
linter = SCons.Builder.Builder(
    action=['$PYTHON $LINT $LINT_OPTIONS $SOURCE','date > $TARGET'], 
    suffix='.lint', 
    src_suffix='.cpp') 

# actual build 
env = Environment() 
env.Append(BUILDERS={'Lint': linter}) 
env["PYTHON"] = sys.executable 
env["LINT"] = "cpplint.py" 
env["LINT_OPTIONS"] = ["--filter=-whitespace,+whitespace/tab", "--verbose=3"] 
env.Program("test", Glob("*.cpp")) 

No hay nada demasiado complicado de lo que realmente. Debería establecer LINT en la ruta a su copia de cpplint.py y establecer LINT_OPTIONS apropiadas para su proyecto. El único bit vergonzoso es crear un archivo TARGET si la verificación se realiza utilizando el programa de línea de comando date. Si quieres ser una plataforma cruzada, eso debería cambiar.

Adición de una lista blanca es ahora el código Python simplemente regular, algo así como:

whitelist = """" 
src/legacy_code.cpp 
src/by_the_PHB.cpp 
"""".split() 

def DoLint(env, source): 
    for s in source: 
     src = s.srcnode().path 
     if src not in whitelist: 
      env.Lint(+ ".lint", s) 

Parece cpplint.py hace el estado de error de salida correcta. Cuando hay errores, devuelve 1; de lo contrario, devuelve 0. Por lo tanto, no hay trabajo adicional que hacer allí. Si la prueba de pelusa falla, fallará la construcción.

Esta solución funciona con -j, pero los archivos C++ pueden compilarse ya que no existen dependencias implícitas entre la salida falsa de pelusa y el objetivo del archivo de objeto. Puede agregar un env.Depends explícito para forzar que la salida ".int" dependa del objetivo del objeto. Como probablemente sea suficiente, dado que la compilación fallará (scons da un código de retorno distinto de cero) si quedan problemas de pelusa, incluso después de todas las compilaciones de C++. Para completar el depende código sería algo como esto en la función DoLint:

def DoLint(env, source, target): 
    for i in range(len(source)): 
     s = source[i] 
     out = env.Lint(s.srcnode().path + ".lint", s) 
     env.Depends(target[i], out) 
2

AddPreAction parece ser lo que busca, desde la página de manual:

AddPreAction(target, action) 
env.AddPreAction(target, action) 
Arranges for the specified action to be performed before the specified target is built. T 

Véase también http://benno.id.au/blog/2006/08/27/filtergensplint para un ejemplo.

+0

para que esto funcione necesito saber el objetivo antes de tiempo. Entonces, ¿cómo obtengo una lista de todos los archivos .cc/cpp/c y .h/hpp en mi proyecto? También necesito excluir encabezados como el sistema y aumentar los encabezados. – Jonathan

+0

@Jonathan, puedes hacer eso con un shellscript de dos líneas. – ismail

+0

@ İsmail, Lo mejor sería utilizar los nodos ya recopilados por mi script SCons. Estoy mirando los módulos SCons.Action, SCons.Job y SCons.Node, pero no es obvio dónde están pendientes las compilaciones pendientes. – Jonathan

1

Ver mi github para un par de SCons escrituras completas con un árbol fuente de ejemplo. Utiliza el cpplint.py de Google.

https://github.com/xyzisinus/scons-tidbits

+0

¡Bienvenido a StackOverflow! Acabo de editar tu publicación y eliminé tu introducción. Aunque ciertamente significó algo bueno, las personas aquí mantienen la política de escribir solo cosas relacionadas con la pregunta. – Thilo

Cuestiones relacionadas