Настройка SCons to Autolint

Я использую google cpplint.py, чтобы проверить исходный код в моем проекте, соответствует стандартам, изложенным в Руководство по стилю Google С++. Мы используем SCons для сборки, поэтому я хотел бы автоматизировать процесс, сначала прочитав SCons во всех наших файлах .h и .cc, а затем запустим cpplint.py, только создав файл, если он пройдет. Проблемы заключаются в следующем:

  • В SCons как мне предварительно подхватить процесс сборки? Файл не должен компилироваться до тех пор, пока он не пройдет листинг.
  • cpplint не возвращает код выхода. Как запустить команду в SCons и проверить, соответствует ли результат регулярному выражению? I.E., как я могу получить вывод текста?
  • Проект большой, независимо от решения # 1 и # 2 он должен запускаться одновременно, когда опция -j передается в SCons.
  • Мне нужен белый список, который позволяет некоторым файлам пропустить проверку ворса.

Ответ 1

Один из способов сделать это - патч обезьяны функция эмиттера объекта, которая превращает код С++ в связываемые объектные файлы. Есть две такие функции эмиттера; один для статических объектов и один для общих объектов. Вот пример, который вы можете скопировать в 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 для вашего проекта. Единственный бородавчатый бит создает файл TARGET, если проверка проходит с помощью командной строки 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. Поэтому нет никакой дополнительной работы. Если проверка линта не удалась, это приведет к сбою сборки.

Это решение работает с -j, но файлы С++ могут компилироваться, поскольку не существует неявных зависимостей между выводом фальшивки fint и целевым файлом объектного файла. Вы можете добавить явный env.Depends туда, чтобы заставить вывод ".lint" зависеть от цели объекта. Как это, вероятно, достаточно, поскольку сама сборка не сработает (scons дает ненулевой код возврата), если есть какие-либо проблемы с lint даже после всех компиляций на С++. Для полноты кода в коде 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 похоже на то, что вы ищете, из 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 для примера.

Ответ 3

См. мой github для пары скриптов scons в комплекте с примером исходного дерева. Он использует Google cpplint.py.

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