9

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().

3 Answers3

7

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})
Rémi
  • 3,705
  • 1
  • 28
  • 39
  • 3
    This does not work for me with add_compile_definitions. When I try to print out defs, it would not say not found. – László Papp Apr 15 '22 at 03:47
  • 1
    If you use add_compile_definitions() then the properties go to the directory (not the target). Use the following code: `get_directory_property(dirprop_ COMPILE_DEFINITIONS) list(FILTER dirprop_ EXCLUDE REGEX [[^MY_DEFINITION=.*$]]) set_directory_properties(PROPERTIES COMPILE_DEFINITIONS ${dirprop_})` – Daniel Mar 16 '23 at 02:36
3

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.

oLen
  • 5,177
  • 1
  • 32
  • 48
  • 3
    But is there an elegant way to remove built-in definitions per target? For example, for testing purposes I need to remove NDEBUG definition in Release configuration. How can I do that? – Fedorov7890 Jun 09 '18 at 08:17
  • @Fedorov7890 Maybe you should look at this: https://stackoverflow.com/questions/22140520/how-to-enable-assert-in-cmake-release-mode –  Jun 09 '18 at 20:51
  • This is not scalable though when you have many targets in a big project. – László Papp Apr 14 '22 at 22:52
1

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

Daniel Russell
  • 578
  • 4
  • 9
  • The problem with this is that it is platform and setup specific, so it is undesirable. We would really need remove_compile_definitions in that feature request. – László Papp Apr 15 '22 at 03:48