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)
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
@Jonathan, puedes hacer eso con un shellscript de dos líneas. – ismail
@ İ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