Überschreiben Sie Kompilierungsflags für einzelne Dateien

109

Ich möchte einen globalen Satz von Flags zum Kompilieren eines Projekts verwenden. Dies bedeutet, dass ich in meiner CMakeLists.txt-Datei der obersten Ebene Folgendes angegeben habe:

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

Für eine bestimmte Datei (sagen wir "foo.cpp") in einem Unterverzeichnis möchte ich jedoch die Kompilierungsflags so ändern, dass sie nicht -Weffc ++ anwenden (enthaltene kommerzielle Bibliothek, die ich nicht ändern kann). Um die Situation zu vereinfachen, nur -Wall zu verwenden, habe ich versucht:

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

, was nicht funktioniert hat. Ich habe es auch versucht

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

und

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

, in denen keiner funktionierte.

Schließlich habe ich versucht, diese Definition zu entfernen:

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

, was auch nicht funktioniert hat (was bedeutet, ich bekomme viele Stilwarnungen über die kommerzielle Bibliothek). (** Hinweis: Die Warnungen werden unterdrückt, wenn ich die Direktive -Weffc ++ nach dem Erstellen der ausführbaren Datei NICHT wieder einbinde.)

Ich habe auch versucht, die Kompilierungsflags vorübergehend zu entfernen: http://www.cmake.org/pipermail/cmake/2007-June/014614.html , aber das hat nicht geholfen.

Gibt es dafür keine elegante Lösung?

JB Brown
quelle
1
Warten Sie, wenn Ihr letzter Versuch funktioniert, aber erst nachdem er erstellt wurde, ist dies möglicherweise kein Caching-Problem? Versuchen Sie, CMakeCache zu löschen, nachdem Sie Ihre Änderungen vorgenommen haben.
Cameron
Siehe auch So ändern Sie ein Compiler-Flag für nur eine ausführbare Datei in CMake. Andres Antwort zeigt, wie man bestehende Optionen durch neue Optionen ersetzen kann.
JWW

Antworten:

126

Bei den oben genannten Versuchen werden Ihrer Datei / Ihrem Ziel weitere Flags hinzugefügt, anstatt wie erwartet zu überschreiben. Zum Beispiel aus den Dokumenten für Eigenschaften in Quelldateien - COMPILE_FLAGS :

Diese Flags werden der Liste der Kompilierungsflags hinzugefügt, wenn diese Quelldatei erstellt wird.

Sie sollten in der Lage sein, das -Weffc++Flag für foo.cpp zu kontern, indem Sie dies tun

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

Dies sollte dazu führen, dass im Compiler-Befehl -Wno-effc++nachher hinzugefügt wird -Weffc++, und die letztere Einstellung gewinnt. Sie können den vollständigen Befehl anzeigen und überprüfen, ob dies tatsächlich der Fall ist

make VERBOSE=1

Abgesehen davon äußert sich einer der Betreuer der GNU C ++ Standard Library -Weffc++in dieser Antwort ziemlich negativ .

Ein weiterer Punkt ist, dass Sie add_definitionsin dem Sinne missbrauchen, dass Sie dies eher für Compiler-Flags als für die beabsichtigten Präprozessor-Definitionen verwenden.

Es wäre vorzuziehen, zu verwenden add_compile_options

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

oder für CMake-Versionen <3.0, um etwas mehr zu tun wie:

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

Als Antwort auf weitere Fragen in den Kommentaren unten glaube ich, dass es unmöglich ist , ein Flag in einer einzelnen Datei zuverlässig zu entfernen . Der Grund ist, dass für jede gegebene Quelldatei das COMPILE_OPTIONSund 1 vorhanden istCOMPILE_FLAGS des Ziels angewendet wird, diese jedoch in keiner der Eigenschaften für diese Quelldatei angezeigt werden.

Sie können versuchen, das Problemflag vom Ziel zu COMPILE_OPTIONSentfernen und es dann einzeln auf jede Quelle des Ziels anzuwenden und es bei Bedarf aus der spezifischen Quelldatei zu entfernen.

Dies kann zwar in vielen Szenarien funktionieren, weist jedoch einige Probleme auf.

Die Eigenschaften der First- Source-Dateien enthalten nicht COMPILE_OPTIONSnur COMPILE_FLAGS. Dies ist ein Problem, da das COMPILE_OPTIONSeines Ziels Generatorausdrücke enthalten kann , diese COMPILE_FLAGSjedoch nicht unterstützt. Sie müssten also Generatorausdrücke berücksichtigen, während Sie nach Ihrem Flag suchen, und Sie müssten möglicherweise sogar Generatorausdrücke "analysieren", wenn Ihr Flag in einem oder mehreren enthalten wäre, um zu sehen, ob es erneut auf die verbleibenden angewendet werden sollte Quelldaten.

Zweitens: Seit CMake v3.0 können Ziele angeben INTERFACE_COMPILE_OPTIONS. Dies bedeutet, dass eine Abhängigkeit Ihres Ziels die Ihres Ziels COMPILE_OPTIONSüber seine hinzufügen oder überschreiben kann INTERFACE_COMPILE_OPTIONS. Sie müssten also alle Abhängigkeiten Ihres Ziels rekursiv durchlaufen (keine besonders einfache Aufgabe, da die Liste LINK_LIBRARIESfür das Ziel auch Generatorausdrücke enthalten kann), um diejenigen zu finden, die das Problemflag anwenden, und versuchen, es aus diesen zu entfernen Ziele ' INTERFACE_COMPILE_OPTIONSauch.

In dieser Phase der Komplexität möchte ich einen Patch an CMake senden, um die Funktionalität zum bedingungslosen Entfernen eines bestimmten Flags aus einer Quelldatei bereitzustellen.


1: Beachten Sie, dass im Gegensatz zur COMPILE_FLAGSEigenschaft für Quelldateien die COMPILE_FLAGSEigenschaft für Ziele veraltet ist.

Fraser
quelle
6
Aber wie setzen Sie die Kompilierungsflags für Dateien tatsächlich separat, ohne sie anzuhängen? Zum Beispiel möchte ich für das resultierende Ziel andere Kompilierungsflags verwenden als für die Dateien, aber da sie angehängt sind, müsste ich sie manuell entfernen. Gibt es keine Eigenschaft, die nicht angehängt, sondern nur für die angegebene Datei / das angegebene Ziel festgelegt wird?
Baradé
2
Was können wir tun, wenn -fno-flag nicht verfügbar ist (und das -fflag gesetzt ist)?
Gnzlbg
@ Baradé Sie können nicht - nicht für eine Quelldatei.
Fraser
@gnzlbg Wieder sind wir ziemlich fest. Ich habe meine Antwort aktualisiert, um ein bisschen mehr Informationen zu geben (und eine mögliche Problemumgehung, die in einigen Szenarien wahrscheinlich funktionieren würde ).
Fraser
Gibt es wirklich keine Problemumgehung für die Einstellung der Kompilierungsoptionen für einzelne Dateien? Ich muss die Generierung der gcc-Abdeckung für einige Dateien deaktivieren, die gcov zum Absturz bringen.
Lothar
5

Fügen Sie einfach @ Frasers richtige Antwort hinzu.

Wenn Sie bestimmten Ordnern das spezielle Flag hinzufügen möchten, haben Sie folgende Möglichkeiten:

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

oder

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++)

Beachten Sie, dass es nicht empfohlen wird, GLOB wie hier beschrieben zu verwenden

Levon
quelle
0

Mit der Antwort @Fraser habe ich Folgendes erstellt, um die Qt-Includes zu verarbeiten, da die Variable mehrere durch Semikolons getrennte Pfade enthält. Dies bedeutet, dass ich zuerst eine foreach()Schleife hinzufügen und die Include-Flags von Hand erstellen musste . Damit kann ich jedoch eine Ausnahme haben: foo.cpp (diese eine Datei verwendet derzeit Qt, aber langfristig möchte ich diese Abhängigkeit entfernen und sicherstellen, dass sich Qt nirgendwo anders einschleicht).

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}
)

Beachten Sie auch, dass ich das -isystemanstelle von verwende -I, um einige Warnungen zu vermeiden, die Qt-Header andernfalls generieren (ich habe eine Menge Warnungen aktiviert).

Alexis Wilke
quelle