Zastąp flagi kompilacji dla pojedynczych plików

110

Chciałbym użyć globalnego zestawu flag do kompilacji projektu, co oznacza, że ​​w moim pliku CMakeLists.txt najwyższego poziomu określiłem:

ADD_DEFINITIONS ( -Wall -Weffc++ -pedantic -std=c++0x )

Jednak dla określonego pliku (powiedzmy "foo.cpp") w podkatalogu, chcę przełączyć flagi kompilacji, aby nie stosować -Weffc ++ (dołączona biblioteka komercyjna, której nie mogę zmienić). Aby uprościć sytuację, aby użyć tylko -Wall, próbowałem:

 SET_SOURCE_FILES_PROPERTIES( foo.cpp PROPERTIES COMPILE_FLAGS -Wall )
 ADD_EXECUTABLE( foo foo.cpp )

, który nie zadziałał. Ja też próbowałem

SET_PROPERTY( SOURCE foo.cpp PROPERTY COMPILE_FLAGS -Wall )
ADD_EXECUTABLE( foo foo.cpp )

i

ADD_EXECUTABLE( foo foo.cpp )
SET_TARGET_PROPERTIES( foo PROPERTIES COMPILE_FLAGS -Wall )

, w którym żaden nie działał.

Wreszcie spróbowałem usunąć tę definicję:

REMOVE_DEFINITIONS( -Weffc++ )
ADD_EXECUTABLE( foo foo.cpp )
ADD_DEFINITIONS( -Weffc++ )

, co również nie zadziałało (co oznacza, że ​​dostaję wiele ostrzeżeń dotyczących stylu komercyjnej biblioteki). (** Uwaga: ostrzeżenia są pomijane, jeśli NIE dołączę ponownie dyrektywy -Weffc ++ po zbudowaniu pliku wykonywalnego).

Próbowałem też tymczasowo usunąć flagi kompilacji: http://www.cmake.org/pipermail/cmake/2007-June/014614.html , ale to nie pomogło.

Czy nie ma na to eleganckiego rozwiązania?

JB Brown
źródło
1
Czekaj, jeśli ostatnia próba zadziała, ale dopiero po jej zbudowaniu, czy nie może to być problem z pamięcią podręczną? Spróbuj usunąć CMakeCache po wprowadzeniu zmian.
Cameron
Powiązane, zobacz Jak zmienić flagę kompilatora tylko dla jednego pliku wykonywalnego w CMake? Odpowiedź Andre pokazuje, co wydaje się być sposobem na zastąpienie istniejących opcji nowymi opcjami.
jww

Odpowiedzi:

126

Twoje próby powyżej dodają dalsze flagi do twojego pliku / celu, zamiast nadpisywać, jak się wydajesz. Na przykład z dokumentacji dotyczącej właściwości w plikach źródłowych - COMPILE_FLAGS :

Te flagi zostaną dodane do listy flag kompilacji podczas budowania tego pliku źródłowego.

Powinieneś być w stanie usunąć -Weffc++flagę dla foo.cpp, wykonując

set_source_files_properties(foo.cpp PROPERTIES COMPILE_FLAGS -Wno-effc++)

Powinno to skutkować dodaniem -Wno-effc++po -Weffc++w poleceniu kompilatora, a to drugie ustawienie wygrywa. Aby zobaczyć pełne polecenie i sprawdzić, czy tak jest, możesz to zrobić

make VERBOSE=1

Nawiasem mówiąc, jeden z opiekunów Biblioteki standardowej GNU C ++ przedstawia -Weffc++w tej odpowiedzi dość negatywną opinię .

Inną kwestią jest to, że nadużywasz add_definitionsw tym sensie, że używasz tego do flag kompilatora, a nie do zamierzonych definicji preprocesorów.

Byłoby lepiej użyć add_compile_options

add_compile_options(-Wall -Weffc++ -pedantic -std=c++0x)

lub dla wersji CMake <3.0, aby zrobić coś więcej jak:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Weffc++ -pedantic -std=c++0x")

W odpowiedzi na dalsze pytania w komentarzach poniżej uważam, że niemożliwe jest wiarygodne usunięcie flagi z pojedynczego pliku. Powodem jest to, że do dowolnego pliku źródłowego zastosowano cel COMPILE_OPTIONSi 1 , ale nie pojawiają się one w żadnej z właściwości tego pliku źródłowego.COMPILE_FLAGS

Możesz spojrzeć na usunięcie flagi problemu z elementu docelowego COMPILE_OPTIONS, a następnie zastosowanie go do każdego źródła celu indywidualnie, pomijając go w określonym pliku źródłowym zgodnie z wymaganiami.

Jednak, chociaż może to działać w wielu scenariuszach, wiąże się to z kilkoma problemami.

Po pierwsze - właściwości plików źródłowych nie obejmują COMPILE_OPTIONStylko COMPILE_FLAGS. Jest to problem, ponieważ COMPILE_OPTIONSelement docelowy może zawierać wyrażenia generatora , ale COMPILE_FLAGSich nie obsługuje. Więc musiałbyś uwzględniać wyrażenia generatora podczas wyszukiwania swojej flagi, a nawet być może musiałbyś nawet "przeanalizować" wyrażenia generatora, jeśli twoja flaga była zawarta w jednym lub więcej, aby zobaczyć, czy powinna zostać ponownie zastosowana do pozostałych pliki źródłowe.

Po drugie - od CMake v3.0 cele mogą określać INTERFACE_COMPILE_OPTIONS. Oznacza to, że zależność twojego celu może dodać lub nadpisać twój cel COMPILE_OPTIONSpoprzez jego INTERFACE_COMPILE_OPTIONS. Więc dalej musiałbyś rekurencyjnie iterować przez wszystkie zależności twojego celu (nie jest to szczególnie łatwe zadanie, ponieważ lista LINK_LIBRARIESdla celu może również zawierać wyrażenia generatora), aby znaleźć te, które stosują flagę problemu, i spróbować usunąć je z tych cele ” INTERFACE_COMPILE_OPTIONS.

Na tym etapie złożoności chciałbym przesłać poprawkę do CMake, aby zapewnić funkcję bezwarunkowego usuwania określonej flagi z pliku źródłowego.


1: Zwróć uwagę, że w przeciwieństwie do COMPILE_FLAGSwłaściwości w plikach źródłowych COMPILE_FLAGSwłaściwość obiektów docelowych jest przestarzała.

Fraser
źródło
6
Ale jak właściwie ustawić flagi kompilacji dla plików osobno bez ich dołączania. Na przykład chcę użyć innych flag kompilacji dla wynikowego celu niż dla plików, ale ponieważ są one dołączone, musiałbym je usunąć ręcznie. Czy nie ma właściwości, które nie są dołączane, ale faktycznie ustawiają je tylko dla określonego pliku / celu?
Baradé
2
Co możemy zrobić, gdy flaga -fno-nie jest dostępna (a opcja -fflag jest ustawiona)?
gnzlbg
@ Baradé Nie możesz - nie w przypadku pliku źródłowego.
Fraser
@gnzlbg Ponownie utknęliśmy. Zaktualizowałem moją odpowiedź, aby podać trochę więcej informacji (i możliwe obejście, które prawdopodobnie zadziała w niektórych scenariuszach).
Fraser
Czy naprawdę nie ma obejścia dla ustawienia opcji kompilacji pojedynczego pliku? Muszę wyłączyć generowanie pokrycia gcc dla niektórych plików, które powodują awarię gcov.
Lothar
5

Po prostu dodam poprawną odpowiedź @ Fraser.

W przypadku, gdy chcesz dodać specjalną flagę do określonych folderów, możesz zrobić:

file(GLOB SPECIAL_SRC_FILES
        "path/one/src/*.cpp"
        "path/two/src/*.cpp")
set_property(SOURCE ${SPECIAL_SRC_FILES} PROPERTY COMPILE_FLAGS -Wno-effc++)

lub

file(GLOB SPECIAL_SRC_FILES
        "path/one/src/*.cpp"
        "path/two/src/*.cpp")
set_source_files_properties(${SPECIAL_SRC_FILES} PROPERTIES COMPILE_FLAGS -Wno-effc++)

Zauważ, że nie zaleca się używania GLOB, jak omówiono tutaj

Levon
źródło
0

Korzystając z odpowiedzi @Fraser, utworzyłem poniższy kod, aby obsłużyć dołączenia Qt, ponieważ zmienna zawiera wiele ścieżek oddzielonych średnikami. Oznacza to, że musiałem najpierw dodać foreach()pętlę i ręcznie utworzyć flagi dołączania . Ale to pozwala mi mieć jeden wyjątek: foo.cpp (ten jeden plik używa Qt na razie, ale na dłuższą metę chcę usunąć tę zależność i chcę się upewnić, że Qt nie wkradnie się nigdzie indziej).

find_package(Qt5Core REQUIRED)
set(QT_INCLUDE_PROPERTIES "")
foreach(DIR ${Qt5Core_INCLUDE_DIRS})
    set(QT_INCLUDE_PROPERTIES "${QT_INCLUDE_PROPERTIES} -isystem ${DIR}")
endforeach()
set_source_files_properties(foo.cpp PROPERTIES
    COMPILE_FLAGS
        ${QT_INCLUDE_PROPERTIES}
)

Zauważ również, że używam -isystemzamiast tego, -Iaby uniknąć niektórych ostrzeżeń, które w przeciwnym razie generują nagłówki Qt (mam włączonych mnóstwo ostrzeżeń).

Alexis Wilke
źródło