In my project I have defined some general compile options using CMAKE_CXX_FLAGS globally. Some other options, that in common case should be applied to all targets, are specified using add_compile_options() in my main CMakeLists file.
For example I want the flag -Wconversion be applied to all targets.
But I have one external library that produces to many warnings with this option enabled. So I want to disable option only for this particular lib:
get_target_property(EXTLIB_COMPILE_FLAGS ext_lib COMPILE_OPTIONS )
list(REMOVE_ITEM EXTLIB_COMPILE_FLAGS -Wconversion)
set_target_properties(ext_lib PROPERTIES COMPILE_OPTIONS ${EXTLIB_COMPILE_FLAGS } )
But right now only -Wconversion was setted using add_compile_options().
And target does not have any own additional flags. So, after removing the only entry from the list I will get an empty list. Call to set_target_properties() fails with error:
set_target_properties called with incorrect number of arguments.
Is any way to clear some of target properties completly?
I'm using CMake 3.11
Turning my comment into an answer
Just add quotes:
set_target_properties(ext_lib PROPERTIES COMPILE_OPTIONS "${EXTLIB_COMPILE_FLAGS}")
Now - if EXTLIB_COMPILE_FLAGS variable is empty - you end-up having an empty string and just not an "missing argument".
Related
I've been told it's bad practice to do things like seting CFLAGS directly in CMake, and that, instead, I should use the target_compile_definitions() command.
Ok, but - what if I want to use similar/identical definitions for multiple (independent) targets? I don't want to repeat myself over and over again.
I see three possible ways:
The preferred one using target_compile_definitions(... INTERFACE/PUBLIC ...) which would self-propagate the compiler definitions to targets depending on it via target_link_libraries() command.
Using the set_property(TARGET target1 target2 ... APPEND PROPERTY COMPILE_DEFINITIONS ...) to set the same definitions to multiple targets.
You may still use the "old commands" of add_definitions() and remove_definitions() to modify COMPILE_DEFINITIONS directory property (which would pre-set all COMPILE_DEFINITIONS target properties in this directories scope).
References
Is Cmake set variable recursive?
CMake: Is there a difference between set_property(TARGET ...) and set_target_properties?
tl;dr: You can iterate the targets in a loop.
If you have a bunch of targets with some common/similar features, you may want to simply manipulate them all in a loop! Remember - CMake is not like GNU Make, it's a full-fledged scripting language (well, sort of). So you could write:
set(my_targets
foo
bar
baz)
foreach(TARGET ${my_targets})
add_executable(${TARGET} "${TARGET}.cu")
target_compile_options(${TARGET} PRIVATE "--some_option=some_value")
target_link_libraries(${TARGET} PRIVATE some_lib)
# and so on
set_target_properties(
${TARGET}
PROPERTIES
C_STANDARD 99
C_STANDARD_REQUIRED YES
C_EXTENSIONS NO )
endforeach(TARGET)
And you could also initialize an empty list of targets, then add to it here-and-there, and only finally apply your common options and settings to all of them, centrally.
Note: In this example I added PRIVATE compile options, but if you need some of them to propagate to targets using your targets, you can make them PUBLIC).
another neat solution is to define an interface library target (a fake target that does not produce any binaries) with all required properties and compiler definitions, then link the other existing targets against it
example:
add_library(myfakelib INTERFACE)
target_compile_definitions(myfakelib INTERFACE MY_NEEDED_DEFINITION)
add_executable(actualtarget1 main1.cpp)
add_executable(actualtarget2 main2.cpp)
set_property(
TARGET actualtarget1 actualtarget2
APPEND PROPERTY LINK_LIBRARIES myfakelib
)
refs:
https://cmake.org/cmake/help/latest/command/add_library.html#interface-libraries
I am including this external library https://github.com/S-Dafarra/alglib-cmake when compiling one of my projects.
In my CMakeLists.txt, I add link this library as PRIVATE:
find_package(ALGLIB REQUIRED)
target_link_libraries(<target> PRIVATE ALGLIB)
When I compile my project in debug mode with make VERBOSE=1, I find an -O3 flag added to my (g++) compiler flags, that I would prefer to avoid.
Is someone aware of a way to 'remove it' with some specific command in the CMakeLists?
I tried printing COMPILE_OPTIONS or CMAKE_CXX_FLAGS*, but they do not contain this flag. In the original ALGLIB.cmake file, they are defined as:
INTERFACE_COMPILE_OPTIONS "-O3;-DAE_OS=AE_POSIX;-pthread;-DAE_CPU=AE_INTEL"
Could I edit this property in my CMakeLists somehow? (I do not want to edit the original library). Thanks in advance.
If I remove the library from my project, or set it to INTERFACE instead of PRIVATE, then the O3 flag is gone.
Thanks for your inputs.
I followed your suggestion and came up with this solution:
find_package(ALGLIB REQUIRED)
if (CMAKE_BUILD_TYPE STREQUAL Debug)
get_target_property(ICO ALGLIB INTERFACE_COMPILE_OPTIONS)
string(REPLACE "-O3" "" ICO ${ICO})
string(REPLACE "-" " -" ICO ${ICO})
separate_arguments(ICO)
set_target_properties(ALGLIB PROPERTIES INTERFACE_COMPILE_OPTIONS "${ICO}")
endif()
Follow-up: https://github.com/S-Dafarra/alglib-cmake/issues/4
This answer describes how to create a custom configuration type from scratch. How can I make a configuration type that exactly matches the builtin Release, only with some added flags? I'm using this right now:
set(CMAKE_CONFIGURATION_TYPES "Debug;Release;ReleaseWithAssertions" CACHE STRING
"Available build-types: Debug, Release and ReleaseWithAssertions")
set(CMAKE_CXX_FLAGS_RELEASEWITHASSERTIONS "${CMAKE_CXX_FLAGS_RELEASE}
-DENABLE_ASSERTIONS=1")
This seems to do what I want, but I'm only copying the value of CMAKE_CXX_FLAGS_RELEASE, so I'm wondering if there is anything I'm missing that users might expect?
No, not in respect of adding a custom "configuration type that exactly matches the builtin Release". That's more like a feature request for CMake.
Edit: Just have seen that there actually is a "Creating new configurations for MSVC" feature request you could give support.
Here is some background information what's possible and what's not:
There are potentially many configuration specific variables. You could copy those with a script:
get_directory_property(_vars VARIABLES)
foreach(_var IN LISTS _vars)
if (_var MATCHES "_RELEASE$")
string(REPLACE "_RELEASE" "_RELEASEWITHASSERTIONS" _var_new "${_var}")
set(${_var_new} "${${_var}}")
endif()
endforeach()
You need to map imported targets to for your new configuration with setting CMAKE_MAP_IMPORTED_CONFIG_<CONFIG>:
list(APPEND CMAKE_MAP_IMPORTED_CONFIG_RELEASEWITHASSERTIONS "Release" "")
You can't do anything about $<CONFIG:cfg> type generator expressions checking for specific configuration names
You have to check directory/target/source file and configuration specific changes in properties
References
Is Cmake set variable recursive?
What's the CMake syntax to set and use variables?
The only other one you might want would be CMAKE_C_FLAGS_RELEASE in case you're compiling any C files.
See cmake's documentation:
None (CMAKE_C_FLAGS or CMAKE_CXX_FLAGS used)
Debug (CMAKE_C_FLAGS_DEBUG or CMAKE_CXX_FLAGS_DEBUG)
Release (CMAKE_C_FLAGS_RELEASE or CMAKE_CXX_FLAGS_RELEASE)
RelWithDebInfo (CMAKE_C_FLAGS_RELWITHDEBINFO or CMAKE_CXX_FLAGS_RELWITHDEBINFO
MinSizeRel (CMAKE_C_FLAGS_MINSIZEREL or CMAKE_CXX_FLAGS_MINSIZEREL)
From https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#how-can-i-extend-the-build-modes-with-a-custom-made-one-
It seems you would want to do the same for all of these.
CMAKE_CXX_FLAGS_RELEASEWITHASSERTIONS
CMAKE_C_FLAGS_RELEASEWITHASSERTIONS
CMAKE_EXE_LINKER_FLAGS_RELEASEWITHASSERTIONS
CMAKE_SHARED_LINKER_FLAGS_RELEASEWITHASSERTIONS
Does exist a variable which contains the compiler flags used in some call to CMake's ADD_LIBRARY function, for example the ones used when we add a module:
ADD_LIBRARY(mylib MODULE mysrc.cpp)
Or, is there a way of getting such flags?
Turning my comments into an answer
There is not a single CMake variable to get the all compiler flags. The problem is that the CMake generator will finally put together the compiler flags (from various CMake variables and properties incl. from depending targets). So you don't have all the flags during configuration step.
I see the following possible problem/solution pairs:
CMake is a cross-platform wrapper around your compiler (that's actually what the C stands for), so no need to extract the compiler flags into an external script
If you just want to add sort of a filter to what is called by CMake you can user set "launcher" variables/properties accordingly e.g. CMAKE_CXX_COMPILER_LAUNCHER or RULE_LAUNCH_LINK
If you want the compiler calls in a machine readable JSON format you could export those by setting CMAKE_EXPORT_COMPILE_COMMANDS
If you just want to see the compiler calls incl. all the flags you could set CMAKE_VERBOSE_MAKEFILE
If you really just need the compiler flags on the output and you don't want CMake to actually compile anything, you could - at least for CMake's Makefile generators - modify CMAKE_CXX_COMPILE_OBJECT and CMAKE_CXX_CREATE_SHARED_MODULE like this:
set(CMAKE_DEPFILE_FLAGS_CXX "")
set(
CMAKE_CXX_COMPILE_OBJECT
"<CMAKE_COMMAND> -E echo <FLAGS>"
)
set(
CMAKE_CXX_CREATE_SHARED_MODULE
"<CMAKE_COMMAND> -E echo <CMAKE_SHARED_MODULE_CXX_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS>"
)
file(WRITE mysrc.cpp "")
add_library(mylib MODULE mysrc.cpp)
References
Is Cmake set variable recursive?
What does the "c" in cmake stand for?
How to use CMAKE_EXPORT_COMPILE_COMMANDS?
Using CMake with GNU Make: How can I see the exact commands?
Retrieve all link flags in CMake
I have a problem using option together with if-else statement in cmake.
project(test)
option(TESTE "isso é um teste" OFF)
if(TESTE)
message("true")
else()
message("false")
endif()
add_executable(test main.cpp)
It always displays true even if I put OFF in the options, what am I doing wrong?
That's because the value of the option is stored in the cache (CMakeCache.txt).
If you change the default value in the CMakeLists but the actual value is already stored in the cache, it will just load the value from the cache.
So to test the logic in your CMakeLists, delete the cache each time before re-running CMake.
I had a similar problem and was able to solve it using a slightly different approach.
I needed some compilation flags to be added in case cmake was invoked with an option from the command line (i.e cmake -DUSE_MY_LIB=ON).
If the option was missing in the cmake invocation I wanted to go back to default case which was turning the option off.
I ran into the same issues, where the value for this option was being cached between invocations:
cmake -DUSE_MY_LIB=ON .. #invokes cmake and puts USE_MY_LIB=ON in CMake's cache.
cmake .. #invokes cmake with the cached option ON, instead of OFF
The solution I found was clearing the option from within CMakeLists.txt after the option was used:
option(USE_MY_LIB "Use MY_LIB instead of THEIR_LIB" OFF) #OFF by default
if(USE_MY_LIB)
#add some compilation flags
else()
#add some other compilation flags
endif(USE_MY_LIB)
unset(USE_MY_LIB CACHE) # <---- this is the important!!
Note:
The unset option is available since cmake v3.0.2
Try this, it works for me
unset(USE_MY_LIB CACHE)