Reputation:
I am using cmake 2.8.12.
I am using multiple targets with the same definitions by calling add_definitions(). I want to find out how to remove those definitions for single target and replace them by some other definitions or by default definitions like I have not called add_definitions().
Upvotes: 10
Views: 11007
Reputation: 769
This is a very important thing to be able to do when building large projects and using other 3rd party (e.g. from Github) projects in your own, as they often screw up the compile definitions and end up creating build-breaking problems that require you to selectively remove a definition, without editing the original project itself.
I haven't found a modern, per target way to do this sadly.
However, remove_definitiions is an old way to do it. It works in the sloppy old style of applying to the current subdirectory and below. This causes leakages to your other targets in the same directory frustratingly enough. But sometimes that might be exactly what you want.
One ugly solution is to break out part of your CMakeLists.txt into a separate CMakeLists.txt for the offending targets, and place remove_definitions only in that secondary CMakelists.txt in a subdirectory that quarantines those targets.
Hopefully CMake will add a target_remove_definitions() function.
Here is an example of where I needed this and how I solved it:
# main_directory/CMakeLists.txt
# Add subdir of the offending targets
add_subdirectory(evil_dependencies)
....
# main_directory/evil_dependencies/CMakeLists.txt
# This is required or else, there are headers in the repo
# that #define NOMINMAX which then causes a warning:
# macro redefinition, and warnings as errors = stop the build.
if(MSVC)
remove_definitions(/DNOMINMAX)
endif()
add_subdirectory(some_evil_dependency1)
add_subdirectory(some_evil_dependency2)
For GCC style problems it will look more like remove_definitions(-DSOMEDEFINE). Note, for this old style call, the /D or -D are required, unfortunately. This sadly requires you to write a bunch of extra if-then branches to see if you're in MSVC et. al. or GCC/Clang.
EDIT: See Remi's answer below. It's probably? better than mine, and how I think I'd do it now, mainly. My answer is still useful potentially for some situations where you actually want to remove definitions from a bunch of children folders as well, but Remi's answer is likely to be more elegant most of the time, esp. because of the regex that can make it easier to scan for -D and /D options.
As this is an open issue for CMake, it will likely be fixed any time, obsoleting these answers for newer versions of CMake. That hasn't happened yet (as of 2020-07-16). https://gitlab.kitware.com/cmake/cmake/-/issues/19796
Upvotes: 1
Reputation: 3745
I found a solution there:
https://gitlab.kitware.com/cmake/cmake/issues/19796
This is a way to remove the NOMINMAX define:
get_target_property(defs someTarget COMPILE_DEFINITIONS)
list(FILTER defs EXCLUDE REGEX [[^NOMINMAX$]])
set_property(TARGET someTarget PROPERTY COMPILE_DEFINITIONS ${defs})
Upvotes: 9
Reputation: 5547
The better approach here is to add the definitions for single targets rather than globally.
To do so, you should use target_compile_definitions
instead of add_definitions
For instance, instead of
add_definitions(-DSOMEMACRO)
add_executable(myExecutable main.cpp)
you would use
add_executable(myExecutable main.cpp)
target_compile_definitions(myExecutable PUBLIC -DSOMEMACRO)
This allows you for a fine-grain control of the definitions, and is usually the preferred way of setting them. I would argue that adding definitions for every target is easier than removing definitions from some of the targets.
Upvotes: 4