Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a robust way to set a compiler flag in CMake, overriding/replacing another if it exists?

I have a global CMakeLists.txt that sets a bunch of global compile options (examples will use MSVC, but it's not exclusive to it, just that cl.exe generates warnings when it encounters flags override), like add_compile_options(... /W3 ...). When, for some target in a subdirectory of that project I want to set target_compile_options(targetA PRIVATE /W4). However, this produces annoying warning D9025: overriding '/W3' with '/W4'. Same with other options that are either set by default, or in a top-level CMake file.

Is there some robust way to add a compile option replacing another (if it exists)? I can only thing of a very verbose and ugly get_target_property, followed by string(REGEX REPLACE... (which might be tricky to get the right regex and not match anything extra and I'm also not sure that this would include all sources that compile options might come from, like CMAKE_CXX_FLAGS and co) and the target_compile_options again. I want something that would be easy to add to each target that'd want to override "global" options (whether they come from the top-level cmake, default flags or some other source).

like image 827
Dan M. Avatar asked Dec 06 '25 07:12

Dan M.


1 Answers

While it is possible to replace some compiler options, it is not recommended in CMake.

If you know that in your project all targets require the same kind of option (e.g. /W) but with different values (e.g. 3, 4), then you could express the differences via (custom) target property, and add the option as generator expression which depends on given property.

You may even provide a default value for a target property, so set_target_properties will need to be called only for those targets, which requires non-default compile option.

Top-level CMakeLists.txt:

...
# Define a target property which will contain desired warning level
# for a target (library or executable)
define_property(TARGET PROPERTY MY_VS_WARNING_LEVEL
  BRIEF_DOCS "Warning level"
  FULL_DOCS "Warning level for Visual Studio compiler: 1, 2, ..."
  INHERITED # The property will be initialized from the directory property.
)
# Define a **directory** property with the same name
# It will be used via inheritance and provide default value for the target property.
define_property(TARGET DIRECTORY MY_VS_WARNING_LEVEL
  BRIEF_DOCS "Warning level"
  FULL_DOCS "Warning level for Visual Studio compiler: 1, 2, ..."
  INHERITED # The property will be initialized from the parent property.
)

# Set default value of the target property
set_directory_properties(PROPERTIES MY_VS_WARNING_LEVEL 3)

# Add compiler options which depends on the target property
add_compile_options(/W$<TARGET_PROPERTY:MY_VS_WARNING_LEVEL>)

Any CMakeLists.txt:

# This library will use /W3 option
add_library(foo ...)

# This library will use /W4 option
add_library(bar ...)
set_target_properties(bar PROPERTIES MY_VS_WARNING_LEVEL 4)

# Change default to /W2 for all targets defined below
# (including the ones in subdirectories).
set_directory_properties(PROPERTIES MY_VS_WARNING_LEVEL 2)

# This library will use /W2 option
add_library(baz ...)

The approach when a directory property is created with the same name as the target property is massively used by CMake itself. E.g. the command add_compile_options affects on COMPILE_OPTIONS directory property, from which the target property COMPILE_OPTIONS gets its default value.

like image 109
Tsyvarev Avatar answered Dec 08 '25 20:12

Tsyvarev