cmake - Global linker flag setting (for all targets in directory)
Your problems are/were not related to a specific CMake version.
It's the same for all linker/compiler flag variables in CMake. Because those variables are cached variables and set with the project()
/enable_language()
command (details see here), you either have to
- prefill the cache with
set(... CACHE ...)
before theproject()
command - generally use the
set(... CACHE ... FORCE)
to force/overwrite - move the
set()
after theproject()
command to hide or append to the cached variables
Here is an example for CMAKE_EXE_LINKER_FLAGS
showing all three variants:
CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
# 1. prefill
#set(CMAKE_EXE_LINKER_FLAGS "-Wl,-Map=output.map" CACHE INTERNAL "")
project(Test_Project CXX)
# 2. force
set(CMAKE_EXE_LINKER_FLAGS "-Wl,-Map=output.map" CACHE INTERNAL "" FORCE)
# 3. hide
#set(CMAKE_EXE_LINKER_FLAGS "-Wl,-Map=output.map")
# 3. or append
#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-Map=output.map")
# TODO: Remove, this is just for testing
file(WRITE "foo.cpp" "int main() {}")
add_executable(${PROJECT_NAME} foo.cpp)
Whatever the values of those variables are at the end of your any given CMakeLists.txt
file will be applied to all corresponding targets in the same CMakeLists.txt
file as defaults (see CMAKE - setting compile flags for libraries and What's the CMake syntax to set and use variables?).
The first variant has the disadvantage that it's really only the initial value. The second and third variant would most likely need an if (CMAKE_COMPILER_IS_GNUCXX)
around it, so I prefer the second variant with moving those settings to its own initial-cache file:
MyGNUSettings.cmake
set(CMAKE_CXX_FLAGS "-stdlib=libstdc++ -Wfatal-errors" CACHE INTERNAL "" FORCE)
set(CMAKE_CXX_FLAGS_DEBUG "-g" CACHE INTERNAL "" FORCE)
set(CMAKE_CXX_FLAGS_RELEASE "-O3" CACHE INTERNAL "" FORCE)
set(CMAKE_EXE_LINKER_FLAGS "-Wl,-Map=output.map" CACHE INTERNAL "" FORCE)
Using e.g.
cmake -G "Unix Makefiles" -C MyGNUSettings.cmake -DCMAKE_BUILD_TYPE=Release .
And yes - for the global and per compiler settings - I prefer the global cached variables over the add_compile_options()
command. I think add_compile_options()
haven't replaced the global variables, it was mainly introduced to prevent people putting compiler options in add_definitions()
commands.
Problem setting up linker options for different configs using generator expressions
set_target_properties
expects one argument after each property.
set_target_properties(common_target PROPERTIES
INTERFACE_LINK_OPTIONS
"$<${isWindows}:${win32DynLinkerFlagsAllConfigs}>"
"$<${isWindows}:$<$<CONFIG:Debug>:${win32DynLinkerFlagsDebug}>>"
"$<${isWindows}:$<$<CONFIG:Release>:${win32DynLinkerFlagsRelease}>>"
)
Here, though, you have supplied three and since "$<${isWindows}:$<$<CONFIG:Debug>:${win32DynLinkerFlagsDebug}>>"
is not a property name, you get an error.
Write this instead:
set(link_options
"$<${isWindows}:${win32DynLinkerFlagsAllConfigs}>"
"$<${isWindows}:$<$<CONFIG:Debug>:${win32DynLinkerFlagsDebug}>>"
"$<${isWindows}:$<$<CONFIG:Release>:${win32DynLinkerFlagsRelease}>>"
)
set_target_properties(common_target PROPERTIES "${link_options}")
How can I apply target-specific compiler and linker flags to subdirectories in CMake?
I'm hesitant to put the microcontroller-specific flags in that toolchain file as well since this project could expand to where I'd want to run my project on a different microcontroller.
So don't be hesitant and do that. And when you will move to a different microcontroller, you will have a different toolchain file for it. Have one toolchain for every unique set of compiler flags. -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard
flags definitely belong to a toolchain file.
When you want to support many many many toolchain files combinations and want to go a bit advanced, you might want to use the default behavior of sourcing Platform/${CMAKE_SYSTEM_NAME}-GNU-C-${CMAKE_SYSTEM_PROCESSOR}.cmake
file from CMake module search path. That, combined with some custom variables -DUSE_FLOAT=hard/soft
and -DMFPU=fpv4-sp-d16
makes a nice structure view.
How to make CMake append linker flags instead of prepending them?
In general you can't (I think), but in the specific case that you want to link against a particular library, you should be using the syntax
target_link_libraries(helloapp rt)
instead. CMake knows that this corresponds to passing -lrt
on the linker command line.
Adding global compile flags in CMake
Conclusion: add_compile_options
and add_definitions
work on the current directory and all included directories that are included after the command. Setting CMAKE_CXX_FLAGS
, however, seems to only work on the current directory. Not sure why however, because as commenter Tsyvarev says, it should have the same scope as the first two methods.
Basically, shifting the lines around like this:
[...]
# Custom commands
add_compile_options ( -Wno-reorder )
add_definitions ( -Wno-unknown-pragmas )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-sign-compare")
add_subdirectory(0_dummy)
add_subdirectory(1_cannonball)
add_subdirectory(2_spring)
add_subdirectory(3_spinning)
add_subdirectory(4_gyro)
I no longer get -Wreorder
and -Wunknown-pragmas
warnings, but I still get -Wsign-compare
warnings.
How can I add linker flag for libraries with CMake?
Note: modern CMake has a better solution than mentioned below (see updates for details).
You can use CMAKE_SHARED_LINKER_FLAGS like:
set (CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed")
This question looks like related.
UPD
Thanks to @Bruce Adams who points out that since v3.13 CMake has special command for such purpose: add_link_options
.
UPD 2
Thanks to @Alex Reinking who points out that modern CMake doesn't recommend using global settings. It is suggested to give the preference to the property settings before the global ones, so instead of add_link_options
that has a global scope, the target_link_options
should be used. See Alex's answer for details.
How do I add a linker or compile flag in a CMake file?
Note: Given CMake evolution since this was answer was written in 2012, most of the suggestions here are now outdated/deprecated and have better alternatives.
Suppose you want to add those flags (better to declare them in a constant):
SET(GCC_COVERAGE_COMPILE_FLAGS "-fprofile-arcs -ftest-coverage")
SET(GCC_COVERAGE_LINK_FLAGS "-lgcov")
There are several ways to add them:
The easiest one (not clean, but easy and convenient, and works only for compile flags, C & C++ at once):
add_definitions(${GCC_COVERAGE_COMPILE_FLAGS})
Appending to corresponding CMake variables:
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")Using target properties, cf. doc CMake compile flag target property and need to know the target name.
get_target_property(TEMP ${THE_TARGET} COMPILE_FLAGS)
if(TEMP STREQUAL "TEMP-NOTFOUND")
SET(TEMP "") # Set to empty string
else()
SET(TEMP "${TEMP} ") # A space to cleanly separate from existing content
endif()
# Append our values
SET(TEMP "${TEMP}${GCC_COVERAGE_COMPILE_FLAGS}" )
set_target_properties(${THE_TARGET} PROPERTIES COMPILE_FLAGS ${TEMP} )
Right now I use method 2.
Related Topics
How to Load a Bmp on Glut to Use It as a Texture
Is Casting Std::Pair<T1, T2> Const& to Std::Pair<T1 Const, T2> Const& Safe
Why Can't We Declare Object of a Class Inside the Same Class
How to Avoid Errors While Using Crtp
Why Is Iterating 2D Array Row Major Faster Than Column Major
Incomplete Class Usage in Template
Forward Declaration with Vector of Class Type - Pointer to Incomplete Class Type Not Allowed
Open File with Fopen, Given Absolute Path on Windows
Building Boost with Visual Studio 2013 (Express)
How to Program for Windows Phone 7 in Standard C++ Only
Conversion from Void* to the Pointer of the Base Class
How to Call a Pointer-To-Member-Function
How to Implement a Map with Different Data Types as Values
Borderless Window with Drop Shadow
Variable or Field Declared Void
Erasing Vector::End from Vector
Using an Iterator to Divide an Array into Parts with Unequal Size