How do I replace the compiler options for one target?

I have a multi-directory project with a lot of CMakeLists.txt files. At the root file I have this:

set(CMAKE_CXX_FLAGS "-Wall -Wimplicit-fallthrough -Werror=return-type")

I’d like to completely replace that in a subdirectory, for a certain target. I tried lines 1 or 2 here:

add_executable(foo foo.cc)
set_target_properties(foo PROPERTIES COMPILE_OPTIONS "-g")  # 1
target_compile_options(foo PRIVATE "-g")                    # 2

Both of those led to a build where the clang++ command has the -g appended to the previous flags. How to I replace, not append, to the flags? Am I not setting them in the right way to begin with?

thanks,
Rob

Don’t modify CMAKE_CXX_FLAGS in your project. Leave variables like those for the user to manipulate. If the project needs to add flags project-wide, it can use add_compile_options() from the top level CMakeLists.txt instead. If you need to leave out some of those options for a specific target, then that suggests those flags shouldn’t have been applied project-wide to begin with. That said, there may be scenarios where that is justified (and I have had to do this before myself). If you’ve set a common set of options at the top level, you could search for those specific options in the COMPILE_OPTIONS directory property in a particular target’s CMakeLists.txt and remove them from that property. This assumes you want to remove those options for all targets in that CMakeLists.txt file’s directory scope. That’s the tradeoff to using this approach. It’s also quite fragile, because you’re assuming contents of those directory properties. It gets much worse if you start mixing in generator expressions, etc. Consider very carefully if this is really what you want to do before you commit to this approach.

1 Like

I should point out that the COMPILE_OPTIONS directory property is only used to initialise the COMPILE_OPTIONS property of targets created in that directory scope or below. Rather than modifying the directory property, you could just modify the target property instead if you only wanted to adjust the flags for that one target.

Thanks!

Is that rule about vars starting with CMAKE_, or just that one? My top level file has some others as well.

Some of these seem like they should be in a “toolchain” file, but I’m using vcpkg and last I checked I’m supposed to point -DCMAKE_TOOLCHAIN_FILE at their vcpkg.cmake file.

set(CMAKE_C_COMPILER ${MY_CLANG_DIR}/bin/clang)
set(CMAKE_CXX_COMPILER ${MY_CLANG_DIR}/bin/clang++)
set(CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS ${MY_CLANG_DIR}/bin/clang-scan-deps)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_EXE_LINKER_FLAGS "-L ${MY_CLANG_DIR}/lib -rpath ${MY_CLANG_DIR}/lib")

Avoid setting CMAKE_<LANG>_FLAGS, CMAKE_<LANG>_FLAGS_<CONFIG>, CMAKE_<TYPE>_LINKER_FLAGS or CMAKE_<TYPE>_LINKER_FLAGS_<CONFIG> variables in the project. These are for the user to manipulate. For those things, use either the directory or target property manipulation commands like add_compile_options(), add_link_options(), target_compile_options() or target_link_options().

The CMAKE_<LANG>_STANDARD flag is more contentious. Personally, I see that as something the project should set, but some people hold strong views that it should be under the user’s control. I understand the arguments for and against. I think the project can and should set it, but that can be done in a way that the user can still override it if they need to build everything with a higher language standard.

Regarding the use vcpkg and wanting to use your own toolchain file, vcpkg provides the VCPKG_CHAINLOAD_TOOLCHAIN_FILE variable for that. Or you can just include their toolchain file at the bottom of yours. Both methods are supported by vcpkg.

1 Like