【问题标题】:Setting up SCons to Autolint将 SCons 设置为 Autolint
【发布时间】:2023-03-09 15:37:01
【问题描述】:

我正在使用 google 的 cpplint.py 来验证我的项目中的源代码是否符合 Google C++ Style Guide 中规定的标准。我们使用 SCons 来构建,所以我想通过让 SCons 首先读取我们所有的 .h 和 .cc 文件,然后在它们上运行 cpplint.py 来自动化这个过程,只有在它通过时才构建一个文件。问题如下:

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

【问题讨论】:

    标签: c++ python scons lint


    【解决方案1】:

    AddPreAction 似乎是您正在寻找的,来自联机帮助页:

    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 文件的列表呢?我还需要排除诸如 system 和 boost 标头之类的标头。
    • @Jonathan,你可以用两行 shellscript 做到这一点。
    • @İsmail,最好使用我的 SCons 脚本已经收集的节点。我正在查看 SCons.Action、SCons.Job 和 SCons.Node 模块,但待处理的构建在哪里排队并不明显。
    【解决方案2】:

    执行此操作的一种方法是monkey patch 对象发射器函数,它将 C++ 代码转换为可链接的对象文件。有 2 个这样的发射器功能;一种用于静态对象,一种用于共享对象。这是一个可以将粘贴复制到 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 程序,唯一的缺点是创建一个目标文件。如果您想成为跨平台,那么就必须改变。

    现在添加白名单只是普通的 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)
    

    【讨论】:

      【解决方案3】:

      查看我的 github 以获取一对带有示例源代码树的 scons 脚本。它使用 Google 的 cpplint.py。

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

      【讨论】:

      • 欢迎来到 StackOverflow!我刚刚编辑了您的帖子并删除了您的介绍。虽然这当然意味着好,但这里的人们坚持只写与问题相关的内容的政策。
      猜你喜欢
      • 2022-10-30
      • 2013-03-26
      • 1970-01-01
      • 2011-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多