2011-01-25 18 views
10

Używam google cpplint.py do sprawdzenia kodu źródłowego w moim projekcie spełniającego standardy określone w Google C++ Style Guide. Używamy SConów do zbudowania, więc chciałbym zautomatyzować proces, ponieważ SCons najpierw przeczytał wszystkie nasze pliki .h i .cc, a następnie uruchom na nich cpplint.py, budując tylko plik, jeśli przejdzie. Kwestie są następujące:Konfigurowanie SCons na Autolint

  1. W SCons, jak mogę wstępnie podłączyć proces kompilacji? Żaden plik nie powinien być kompilowany, dopóki nie przejdzie lintingu.
  2. cpplint nie zwraca kodu zakończenia. Jak uruchomić polecenie w SCons i sprawdzić, czy wynik pasuje do wyrażenia regularnego? I.E., w jaki sposób mogę uzyskać tekst wyjściowy?
  3. Projekt jest duży, niezależnie od rozwiązania dla # 1 i # 2 powinien działać jednocześnie, gdy opcja -j jest przekazywana do SCons.
  4. Potrzebuję białej listy, która pozwala niektórym plikom pominąć sprawdzanie kłaczków.

Odpowiedz

2

Jednym ze sposobów, aby to zrobić, jest monkey patch funkcja emiterów obiektów, która zamienia kod C++ na pliki obiektów, które można linkować. Istnieją 2 takie funkcje emitera; jeden dla obiektów statycznych i jeden dla obiektów współużytkowanych. Oto przykład, który można skopiować wkleić do 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")) 

Nic zbyt skomplikowane o nim naprawdę. Ustawiłeś LINT na ścieżce do swojej kopii cpplint.py i ustawiłeś LINT_OPTIONS dla swojego projektu. Jedynym bitem wartym uwagi jest tworzenie pliku TARGET, jeśli test przechodzi z wykorzystaniem wiersza poleceń date. Jeśli chcesz być platformą crossową, to musiałaby się zmienić.

Dodanie białej listy jest teraz po prostu regularne kod Python, coś jak:

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) 

Wydaje cpplint.py robi wyjście prawidłowy stan błędu. Gdy występują błędy, zwraca 1, w przeciwnym razie zwraca 0. Nie ma więc dodatkowej pracy. Jeśli sprawdzanie kłaczków nie powiedzie się, nie powiedzie się kompilacja.

To rozwiązanie działa z opcją -j, ale pliki C++ mogą się kompilować, ponieważ nie istnieją żadne niejawne zależności między fałszem danych wyjściowych a celem pliku obiektu. Możesz dodać tam wyraźne env.Depends, aby wymusić, że wynik ".lint" zależy od celu obiektu. Jak to jest prawdopodobnie wystarczające, ponieważ sama kompilacja się nie powiedzie (scons daje niezerowy kod powrotu), jeśli istnieją jakiekolwiek pozostałe problemy związane z lintem, nawet po wszystkich kompilacjach C++. Aby wszystko było jasne zależy kod byłoby coś takiego w funkcji 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 wydaje się być to, czego szukasz, z podręcznika:

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

zobaczyć również http://benno.id.au/blog/2006/08/27/filtergensplint dla przykładu.

+0

Aby to działało muszę znać cel wyprzedzeniem. Jak mogę uzyskać listę wszystkich plików .cc/cpp/c oraz .h/hpp w moim projekcie? Muszę również wykluczyć nagłówki, takie jak nagłówki systemowe i doładowania. – Jonathan

+0

@ Jonathan, możesz to zrobić za pomocą dwuwierszowego skryptu. – ismail

+0

@ İsmail, Najlepiej byłoby użyć węzłów już zebranych przez mój skrypt SCONS. Patrzę na moduły SCons.Action, SCons.Job i SCons.Node, ale nie jest oczywiste, gdzie oczekujące kompilacje są w kolejce. – Jonathan

1

Zobacz moją GitHub dla pary SCons skryptów kompletnych z drzewa przykładem źródłowego. Korzysta z Google cpplint.py.

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

+0

Witamy w StackOverflow! Właśnie zredagowałem twój wpis i usunąłem twoje wprowadzenie. Choć z pewnością jest to dobre, ludzie trzymają zasady, aby pisać tylko rzeczy związane z pytaniem. – Thilo