配置SCons实现自动代码检查

10

我正在使用谷歌的cpplint.py来验证我的项目中的源代码是否符合Google C++样式指南中制定的标准。我们使用SCons进行构建,因此我希望通过让SCons首先读取所有.h和.cc文件,然后在这些文件上运行cpplint.py来自动化该过程,只有在文件通过检查后才进行构建。问题如下:

  1. 在SCons中如何预处理构建过程?除非文件通过了linting,否则不应编译任何文件。
  2. cpplint没有返回退出代码。在SCons中如何运行命令并检查结果是否与正则表达式匹配?即如何获取输出的文本?
  3. 该项目很大,无论#1和#2的解决方案如何,都应在通过SCons传递-j选项时同时运行。
  4. 我需要一个白名单,允许某些文件跳过lint检查。
3个回答

2

AddPreAction 似乎是您正在寻找的内容,来自 manpage:

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

另请参见http://benno.id.au/blog/2006/08/27/filtergensplint,以了解一个示例。


为了使这个工作正常运行,我需要提前知道目标。那么,如何获取项目中所有 .cc/cpp/c 和 .h/hpp 文件的列表?我还需要排除诸如系统和 boost 头文件之类的头文件。 - Jonathan
@Jonathan,你可以用两行shell脚本来完成这个任务。 - ismail
@İsmail,最好使用我SCons脚本已经收集的节点。我正在查看SCons.Action、SCons.Job和SCons.Node模块,但是尚不清楚挂起的构建在哪里排队。 - Jonathan

2

一种方法是通过猴子补丁对象发射器函数,将C ++代码转换为可链接的对象文件。有两个这样的发射器函数:一个用于静态对象,另一个用于共享对象。以下是一个示例,您可以将其复制并粘贴到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"))

其实这并不太复杂。您需要将LINT设置为cpplint.py的路径,并为您的项目设置适当的LINT_OPTIONS。唯一棘手的部分是,如果检查通过,则使用命令行date程序创建TARGET文件。如果您想跨平台,则需要进行更改。

现在添加白名单只需要编写普通的Python代码,例如:

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)

看起来cpplint.py输出了正确的错误状态。当有错误时,它返回1,否则返回0。因此,在这方面没有额外的工作要做。如果lint检查失败,它将导致构建失败。

此解决方案适用于-j,但是C++文件可能会编译,因为lint虚假输出和目标对象文件之间没有隐式依赖关系。您可以在其中添加一个显式的env.Depends,以强制“.lint”输出依赖于对象目标。由于即使在所有C++编译之后仍然存在任何剩余的lint问题,构建本身也会失败(scons给出非零返回代码),因此现在可能已经足够了。对于完整性,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)

1

欢迎来到StackOverflow!我刚刚编辑了你的帖子并删除了你的介绍部分。虽然你的初衷是好的,但这里的人们遵循的规定是只写与问题相关的内容。 - Thilo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接