142

I would like to use a global set of flags for compiling a project, meaning that at my top-level CMakeLists.txt file I have specified:

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

However, for a specific file (let's say "foo.cpp") in a subdirectory, I want to switch the compile flags to not apply -Weffc++ (included commercial library I cannot change). To simplify the situation to use only -Wall, I tried:

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

, which did not work. I also tried

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

and

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

, in which neither worked.

Finally, I tried removing this defintion:

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

, which also did not work (meaning, I get a lot of style warnings about the commercial library). (**Note: The warnings ARE suppressed if I DO NOT re-include the -Weffc++ directive after the executable is built.)

I also tried temporarily removing the compile flags: http://www.cmake.org/pipermail/cmake/2007-June/014614.html , but that didn't help.

Is there not an elegant solution to this?

jww
  • 97,681
  • 90
  • 411
  • 885
J.B. Brown
  • 1,753
  • 2
  • 13
  • 14
  • 1
    Wait, if your last attempt works, but only after it's built, might this not be a caching issue? Try deleting CMakeCache after making your change(s). – Cameron Nov 30 '12 at 04:44
  • Related, see [How to change a compiler flag for just one executable in CMake?](https://stackoverflow.com/q/24238937/608639) Andre's answer shows what appears to be a way to replace existing options with new options. – jww Aug 23 '17 at 09:12

4 Answers4

153

Your attempts above are adding further flags to your file/target rather than overwriting as you seem to expect. For example, from the docs for Properties on Source Files - COMPILE_FLAGS:

These flags will be added to the list of compile flags when this source file builds.

You should be able to countermand the -Weffc++ flag for foo.cpp by doing

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

This should have the effect of adding -Wno-effc++ after -Weffc++ in the compiler command, and the latter setting wins. To see the full command and check that this is indeed the case, you can do

make VERBOSE=1

As an aside, one of the maintainers of the GNU C++ Standard Library presents a pretty negative opinion on -Weffc++ in this answer.

Another point is that you're misusing add_definitions in the sense that you're using this for compiler flags rather than the intended preprocessor definitions.

It would be preferable to use add_compile_options

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

or for CMake versions < 3.0 to do something more like:

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

In response to further questions in the comments below, I believe it's impossible to reliably remove a flag on a single file. The reason is that for any given source file, it has the COMPILE_OPTIONS and COMPILE_FLAGS1 of its target applied, but these don't show up in any of the properties for that source file.

You could look at stripping the problem flag from the target's COMPILE_OPTIONS, then applying it to each of the target's sources individually, omitting it from the specific source file as required.

However, while this could work in many scenarios, it has a couple of problems.

First - source files' properties don't include COMPILE_OPTIONS, only COMPILE_FLAGS. This is a problem because the COMPILE_OPTIONS of a target can include generator expressions, but COMPILE_FLAGS doesn't support them. So you'd have to accommodate generator expressions while searching for your flag, and indeed you'd maybe even have to "parse" generator expressions if your flag was contained in one or more to see whether it should be re-applied to the remaining source files.

Second - since CMake v3.0, targets can specify INTERFACE_COMPILE_OPTIONS. This means that a dependency of your target can add or override your target's COMPILE_OPTIONS via its INTERFACE_COMPILE_OPTIONS. So you'd further have to recursively iterate through all your target's dependencies (not a particularly easy task since the list of LINK_LIBRARIES for the target can also contain generator expressions) to find any which are applying the problem flag, and try and remove it from those targets' INTERFACE_COMPILE_OPTIONS too.

At this stage of complexity, I'd be looking to submit a patch to CMake to provide the functionality to remove a specific flag unconditionally from a source file.


1: Note that unlike the COMPILE_FLAGS property on source files, the COMPILE_FLAGS property on targets is deprecated.

starball
  • 20,030
  • 7
  • 43
  • 238
Fraser
  • 74,704
  • 20
  • 238
  • 215
  • 6
    But how do you actually set the compile flags for files separately without appending them. For example I want to use different compile flags for the resulting target than for the files but since they are appended I would have to remove them manually. Is there no property which does not append but actually set them only for the specified file/target? – Baradé Nov 27 '14 at 15:54
  • 2
    What can we do when -fno-flag is not available (and the -fflag is set)? – gnzlbg Feb 05 '15 at 12:51
  • @Baradé You can't - not for a source file. – Fraser Sep 16 '15 at 04:57
  • @gnzlbg Again, we're pretty much stuck. I've updated my answer to give a bit more info (and a possible workaround that would probably work in *some* scenarios). – Fraser Sep 16 '15 at 04:59
  • 1
    Is there really no workaround to the single file compile options setting? I have to disable gcc coverage generation for some files which are crashing gcov. – Lothar Jan 04 '17 at 01:20
  • @Fraser, How can I see the list of compiler options that will be used? – Royi Feb 20 '18 at 16:39
  • Note, as of 3.11, source files' properties *does* include COMPILE_OPTIONS. See https://cmake.org/cmake/help/v3.11/prop_sf/COMPILE_OPTIONS.html which has the note "This property should be preferred over the COMPILE_FLAGS property." – ronen May 18 '18 at 21:34
  • How can we config this in command line but not to change the CMakeLists.txt file, this would be very useful when we need to compile a certain file with debug mode while the whole project is build with release mode – BruceSun May 09 '23 at 08:48
7

Just adding to @Fraser's correct answer.

In case if you want to add the special flag to specific folders you could do:

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

or

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

Note that its not recommended to use GLOB as discussed here

Levon
  • 10,408
  • 4
  • 47
  • 42
0

Using @Fraser answer, I created the following to handle the Qt includes because the variable includes multiple paths separated by semicolons. This means I had to first add a foreach() loop and create the include flags by hand. But that allows me to have one exception: foo.cpp (that one file uses Qt for now but long term I want to remove that dependency and I want to make sure not Qt creeps in anywhere else).

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

Notice also that I use the -isystem instead of -I to avoid some warnings that Qt headers otherwise generate (I have a ton of warnings turned on).

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
0

While not exactly an answer to OPs question, the following tip solved a problem for me. Some compilers allow to set or unset an option in the source file itself:

#pragma option -Xinteger-divide-fast=0

This would disable the integer-divide-fast option on a diab compiler, which in my case caused it to crash on that particular file.

Karsten Becker
  • 502
  • 5
  • 11