Compiling library with different flags than main code - c++

My project includes an external library (HPTT) that needs to be compiled and linked with the main part of the code. At the moment, I compile both HPTT and my own source code together with the same compiler flags, using the following CMake file:
cmake_minimum_required(VERSION 2.6)
project(custom_tthresh)
# Default settings
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unknown-pragmas") # -Wno-unknown-pragmas ignores unknown OpenMP pragma's without warnings.
set(CMAKE_CXX_FLAGS_DEBUG "-g")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
file(GLOB SRC "src/*.cpp")
file(GLOB HPTT "src/hptt/*.cpp")
add_executable(experiments ${SRC} ${HPTT})
target_include_directories(experiments PRIVATE /usr/include/eigen3/ src/include/)
add_definitions(-std=c++14)
However, I have two issues with this setup:
HPTT takes a long time to compile, so whenever I change any flags for my own code, I have to wait a lot for it to recompile.
HPTT gives me a bunch of warnings, especially with the -Wall -Wextra -Wno-unknown-pragmas flags, which I'd like to keep for my own code.
How can I set up my CMake file so that it compiles both the library and my own code separately, using different compiler flags, and then links them together? I'd like to stick to some static settings for HPTT (always in release mode, less/no warnings, ...). For full information, these are the current locations of the relevant files:
My own header and source files are in src/
HPTT headers are in src/include/ (this directory needs to be included for the HPTT source files to compile)
HPTT source files are in src/hptt/
Update: Thanks for all the advice. I updated my CMake file now:
cmake_minimum_required(VERSION 3.7)
project(custom_tthresh)
# Always compile external dependencies in Release mode
# We use the custom flag CUSTOM_TTHRESH_BUILD_TYPE to determine the build type for our own library and its related executables
set(CUSTOM_TTHRESH_BUILD_TYPE Release FORCE)
# HPTT
set(HPTT_SRCS src/hptt/hptt.cpp src/hptt/plan.cpp src/hptt/transpose.cpp src/hptt/utils.cpp)
add_library(hptt STATIC ${HPTT_SRCS})
target_include_directories(hptt PRIVATE src/include)
target_compile_options(hptt PRIVATE -w)
# Custom TTHRESH
set(CUSTOM_TTHRESH_SRCS
src/compress.cpp
src/CompressedIO.cpp
src/Compressor.cpp
src/DataBuffer.cpp
src/decompress.cpp
src/quantize.cpp
src/Sizes.cpp
src/Slice.cpp
src/st_hosvd.cpp
)
add_library(custom_tthresh STATIC ${CUSTOM_TTHRESH_SRCS})
target_include_directories(custom_tthresh PRIVATE /usr/include/eigen3/)
target_link_libraries(custom_tthresh hptt)
target_compile_options(custom_tthresh PRIVATE -Wall -Wextra -Wno-unknown-pragmas)
if(CUSTOM_TTHRESH_BUILD_TYPE EQUAL Release)
target_compile_options(custom_tthresh PRIVATE -O3 -DNDEBUG)
else()
target_compile_options(custom_tthresh PRIVATE -g)
endif()
set_target_properties(custom_tthresh PROPERTIES
CXX_STANDARD 14
CXX_STANDARD_REQUIRED ON
)
# Experiments
add_executable(experiments src/experiments.cpp)
target_link_libraries(experiments custom_tthresh)
target_compile_options(experiments PRIVATE -Wall -Wextra -Wno-unknown-pragmas)
if(CUSTOM_TTHRESH_BUILD_TYPE EQUAL Release)
target_compile_options(custom_tthresh PRIVATE -O3 -DNDEBUG)
else()
target_compile_options(custom_tthresh PRIVATE -g)
endif()
This seems to address my problems, avoids some of the bad practices pointed out below and actually reflects the structure of the project. I'm still not proud of the use of CUSTOM_TTHRESH_BUILD_TYPE (based on this question), however I couldn't find a better solution.

Use target_compile_options() to set flags per target:
target_compile_options(experiments PRIVATE "-Wall -Wextra -Wno-unknown-pragmas")
Additionally, don't set flags globally because it sets the flag for everything in the source tree. Don't do this:
set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unknown-pragmas") # don' do this
set(CMAKE_CXX_FLAGS_DEBUG "-g") # especially this
set(CMAKE_CXX_FLAGS_RELEASE "-O3") # and this
Another bad practice is using file globbing. Read Why is cmake file GLOB evil?
file(GLOB SRC "src/*.cpp")
file(GLOB HPTT "src/hptt/*.cpp") #avoid this
And from the cmake docs:
Note: We do not recommend using GLOB to collect a list of source files from your source tree. If no CMakeLists.txt file changes when a source is added or removed then the generated build system cannot know when to ask CMake to regenerate. The CONFIGURE_DEPENDS flag may not work reliably on all generators, or if a new generator is added in the future that cannot support it, projects using it will be stuck. Even if CONFIGURE_DEPENDS works reliably, there is still a cost to perform the check on every rebuild.
This doesn't do what you think it does. It's certainly not setting the C++ standard:
add_definitions(-std=c++14)
To set the C++ standard, use set_target_properties:
set_target_properties(experiments PROPERTIES
CXX_STANDARD 14 # standard version
CXX_STANDARD_REQUIRED ON # required yes
)
You can set the standard globally using set(CMAKE_CXX_STANDARD 14) if you want to, but it may not work with MSVC.

How can I set up my CMake file so that it compiles both the library and my own code separately, using different compiler flags, and then links them together?
Use target_compile_options and target_link_options separately on targets to specific flags for a specific target.
Your add_definitions(-std=c++14) is doing nothing (because there are no targets after it) and prefer using set_target_properties(target PROPERTIES CXX_STANDARD 14 CXX_STANDARD_REQUIRED YES CXX_EXTENSIONS NO) to portably set C++14.

Related

What's the proper way to enable AddressSanitizer in CMake that works in Xcode

I've added AddressSanitizer flag as follow:
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
Everything builds and runs fine when using Unix Makefiles.
The problem comes when generating the Xcode project, it just doesn't want to link because it cannot find the ASan library.
I already found two solutions, but decided not to use them because they cannot be automated using just CMake:
Adding -Wl,-undefined,dynamic_lookup to the linked flags, so it skips linking to dynamic libraries.
Link with libclang_rt.asan_osx_dynamic.dylib directly.
So what's the problem with these two solutions?
When using solution #1, I have to manually open the target scheme in Xcode and add DYLD_INSERT_LIBRARIES environment variable pointing to libclang_rt.asan_osx_dynamic.dylib.
When using solution #2, the path for the ASan library varies between computers.
Additionally as another solution, I tried enabling Address Sanitizer flag from the Xcode target scheme but interestingly it didn't detect the issues I added, so I didn't list this as a solution because it failed my test.
Any help will be much appreciated.
Since the top-voted answer is the wrong way to do it these days and I did not get the proper cmake solution for this reading this thread, I thought I would mention the correct way at the time of writing this so that the next reader does not need to spend much time with this.
The idea of this solution is to pass -fsanitize=address to the compiler and linker flags.
If you would like to enable this for all your targets at the same time, you can use add_compile_options and add_link_options. This makes sense if you have multiple, potentially a large of, targets.
add_compile_options(-fsanitize=address)
add_link_options(-fsanitize=address)
Alternatively, you can also use target_compile_options and target_link_options to set these for a particular target. This might make more sense if you do not want this to apply to all the targets.
target_compile_options(asan-target PRIVATE -fsanitize=address)
target_link_options(asan-target PRIVATE -fsanitize=address)
You need to provide the flag(s) to the linker too. I'm doing it like this:
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
set (CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
I propose create your own Asan profile.
get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(isMultiConfig)
if(NOT "Asan" IN_LIST CMAKE_CONFIGURATION_TYPES)
list(APPEND CMAKE_CONFIGURATION_TYPES Asan)
endif()
else()
set(allowedBuildTypes Asan Debug Release RelWithDebInfo MinSizeRel)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "${allowedBuildTypes}")
if(CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE IN_LIST allowedBuildTypes)
message(FATAL_ERROR "Invalid build type: ${CMAKE_BUILD_TYPE}")
endif()
endif()
set(CMAKE_C_FLAGS_ASAN
"${CMAKE_C_FLAGS_DEBUG} -fsanitize=address -fno-omit-frame-pointer" CACHE STRING
"Flags used by the C compiler for Asan build type or configuration." FORCE)
set(CMAKE_CXX_FLAGS_ASAN
"${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address -fno-omit-frame-pointer" CACHE STRING
"Flags used by the C++ compiler for Asan build type or configuration." FORCE)
set(CMAKE_EXE_LINKER_FLAGS_ASAN
"${CMAKE_EXE_LINKER_FLAGS_DEBUG} -fsanitize=address" CACHE STRING
"Linker flags to be used to create executables for Asan build type." FORCE)
set(CMAKE_SHARED_LINKER_FLAGS_ASAN
"${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fsanitize=address" CACHE STRING
"Linker lags to be used to create shared libraries for Asan build type." FORCE)
Notes:
AddressSanitizer (ASan) for Windows with MSVC is under experimental stage thus I didn't provided the MSVC way here.
CMAKE_BUILD_TYPE isn't used by multi-configuration generators (Xcode, Visual Studio, etc), thus I provided an example to check this first.
The default value for CMAKE_BUILD_TYPE is an empty string. And user can set CMAKE_BUILD_TYPE to any value at the cmake command line. Therefore, we check both cases, and make sure that we are dealing with a known build type (if provided).
There is also CMAKE_MODULE_LINKER_FLAGS you may want to configure.
Usage:
$ cmake \
-DCMAKE_BUILD_TYPE=Asan \
...
...
cmake 3.13
introduce configuration for xcode schema
in CMake
cmake_minimum_required(VERSION 3.13)
set(CMAKE_XCODE_GENERATE_SCHEME ON)
set(CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER ON)
set(CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN ON)
When Build
xcodebuild -enableAddressSanitizer YES
First ensure with debug info, such as setting CMAKE_BUILD_TYPE to Debug passing -g flag for GCC/Clang.
Then, if your target is an executable or an shared library, then you may set those cmake variables:
CMAKE_EXE_LINKER_FLAGS
CMAKE_EXE_LINKER_FLAGS_DEBUG
CMAKE_SHARED_LINKER_FLAGS
CMAKE_SHARED_LINKER_FLAGS_DEBUG
i.e. When your target is an executable:
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
When your target is an shared library:
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
However, when your executable relies on an static library and you'd like to use asan to check your static library, then you have to set like this:
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
The simplest solution that I currently found is
cmake -DCMAKE_BUILD_TYPE=ASAN .
I prefer this option since it expresses the intent (run sanitizers) rather than modifies a number of flags.
I do not know when this option was added. I also cannot find any documentation to it.
I found that the other answers didn't work, you need to set the init variables in your toolchain file:
set(CMAKE_EXE_LINKER_FLAGS_INIT "-fsanitize=address -fno-omit-frame-pointer")

cmake - Global linker flag setting (for all targets in directory)

I want to pass linker flags to all sub-projects (sub-directory CMakeList) in my project.
Before switching to new cmake 3.3, I was using the following code (cmake 3.2) which was working well, adding flags for both compilation and linking :
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -stdlibc++")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -stdlibc++")
With cmake 3.3 this no longer works and set the flags only for compilation step. I updated the CMakeList to use a more "modern" cmake syntax :
set(MY_DEBUG_OPTIONS -g -stdlib=libstdc++ -Wfatal-errors)
set(MY_RELEASE_OPTIONS -O3 -stdlib=libstdc++ -Wfatal-errors)
add_compile_options(
"$<$<CONFIG:DEBUG>:${MY_DEBUG_OPTIONS}>"
"$<$<CONFIG:RELEASE>:${MY_RELEASE_OPTIONS}>")
This set compilation flags for all sub-projects, is there a similar way of doing this for linker flags ? I know one can add linker flags on a target basis with target_link_librariescommand but can't find anything else.
I tried using CMAKE_SHARED_LINKER_FLAGS (and corresponding var for exe, module,..) variable with no success.
Update :
It turns out that this has nothing to do with cmake version, things work correctly with CMAKE_CXX_FLAGS_XXXvariables, except on first make command. If one run make a second time (with a modification in CmakeList), flags are presents.
I think I found a solution while testing with a simple CMakeList : if flags are declared after the project command it just work as expected. I don't know if it's a requirement from cmake itself or just a weird behavior.
cmake_minimum_required (VERSION 3.2)
set(PROJECT Test_Project)
# Not working (on first run)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -stdlib=libstdc++ -Wfatal-errors")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -stdlib=libstdc++ -Wfatal-errors")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -stdlib=libstdc++ -Wfatal-errors")
project(${PROJECT})
# Declare here instead...
add_executable(Test test.cpp)
MESSAGE( STATUS "Config flags : " ${CMAKE_CXX_FLAGS_RELEASE})
Using :
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release .
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 the project() command
generally use the set(... CACHE ... FORCE) to force/overwrite
move the set() after the project() 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.

How to set compiler flags for groups of files in CMake?

In my CMake project I set up compiler flags like this:
if (MSVC)
# Build cpp files on all cores
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /W4")
# can't use the "secure" versions as they're Windows specific
add_definitions("/D\"_CRT_SECURE_NO_WARNINGS\"")
add_definitions("/D\"_SCL_SECURE_NO_WARNINGS\"")
add_definitions("/wd4290")
else()
# Enable C++11, you may need to use -std=c++0x if using an older gcc compiler
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
else()
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-unused-parameter -fPIC -Wall -Weffc++ -pedantic")
endif()
endif()
To set the flags for MSVC, Clang and GCC. However in my source files var I have my source code and 3rd party things like gtest and gmock.
How can I set these flags such that they only apply to some subset of my source code?
E.g
# This should use the flags set above
SET(source
mycode/mysrc.cpp)
# This should not use the flags from above
SET(not_my_source
3rdparty/3rdparty.cpp)
# But both end up being part of the same executable
add_executable(Test ${source} ${not_my_source})
You may want to refer to here. You should be able to pass a list of files that you want to change the compiler flags for.

Compiler Flags from CMakeLists.txt don't appear in CMake-Gui or CMakeCache.txt

I just started to learn CMake and thought I would have understood the basic process of first writing the CMakeLists.txt, then configuring to generate the CMakeCache.txtand at the end generating the Makefiles.
However, when I try to apply it to the following CMakeLists.txt, I'm not getting the expected results and I'm not sure what is going wrong. Part of the CMakeLists.txt looks like this:
# compiler flags
if (CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fpermissive -Wall -Wformat-security")
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.8)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-local-typedefs")
endif()
endif()
Since I'm using gcc/g++ 4.7.3, the compiler flags from the first if-statement should be set. But if I configure this with CMake-Gui, there are no compiler flags pre-defined whatsoever. The same happens when I out-comment the if-statements and just keep the set(CMAKE_CXX_FLAGS ...).
When searching the CMakeCache.txt for any -std=c++11 flags, I don't get any results, too.
Why does this happen? What's the point of specifying compiler flags inside the CMakeLists.txt when they aren't used? Or am I getting something completely wrong and they are used, but then I don't know why and how I could check.
When generating the actual (Eclipse CDT) project with make and importing it to Eclipse, I'm getting error messages that C++11 features can't be resolved, the __cplusplus macro contains the value 199711 so the -std=c++11 flag is obviously not used.
The flags you specified in the CMakeLists.txt file are probably correctly used by the compiler. You can't see them directly in CMakeCache.txt but:
You can see command lines by running make VERBOSE=1 instead of standard make
Also, you can set CMAKE_VERBOSE_MAKEFILE to 1 to enable printing of commands (this can be found by checking "Advanced" in CMake GUI)
As #Angew said, if you really want to see the updated flags in the CMake GUI, set your variables with CACHE FORCE
As an example, i use this kind of configuration in a project for some month, and never had problem:
if(MSVC) # MSVC compiler (Win32 only)
# Display more warnings
set(CMAKE_CXX_FLAGS "/W3")
elseif(UNIX OR CMAKE_COMPILER_IS_GNUCXX) # Clang OR Gcc (Linux, Mac OS or Win32 with MingW)
# Enable C++11 and displays all warnings
set(CMAKE_CXX_FLAGS "-Wall -std=c++11")
if(APPLE) # Clang / Mac OS only
# Required on OSX to compile c++11
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -mmacosx-version-min=10.7")
endif(APPLE)
endif()
Update:
Starting with CMake 3.0, you can replace set(CMAKE_CXX_FLAGS "...") by add_compile_options(-std=c++11)
CMake 3.1 introduced a new syntax to configure the compiler with specific C++ version:
set(CMAKE_CXX_STANDARD 11)
You can first, set the variable to a value only if it is not in cache already. The last parameter is the description which we don't need since we'll override it anyway.
set(VARIABLE "Hello World!" CACHE STRING "")
Then force the value into cache using its existing value from the line above. Since that is cached, users can still change the variable and it won't be set back every time.
set(VARIABLE ${VARIABLE} CACHE STRING "Description." FORCE)
This is a bit hacky in CMake as you can see, but it works reliably.

Does set_target_properties in CMake override CMAKE_CXX_FLAGS?

At the beginning of my CMake project, I'm setting general compilation flags in the variable CMAKE_CXX_FLAGS, like
set(CMAKE_CXX_FLAGS "-W -Wall ${CMAKE_CXX_FLAGS}")
Later on, I need to append additional configuration-specific compilation flags (stored in BUILD_FLAGS). Can I use the following command for this:
set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS ${BUILD_FLAGS})
or do I have to add the CMAKE_CXX_FLAGS manually:
set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${BUILD_FLAGS}")
to prevent CMAKE_CXX_FLAGS being overriden by BUILD_FLAGS?
The accepted answer is still working but outdated since 2013.
This answer is based and new functions from CMake v2.8.12, v3.3 and v3.13.
Since CMake-2.8.12 (2013)
Two new commands to set CMAKE_CXX_FLAGS:
target_compile_options() (for one single target)
add_compile_options() (for all targets)
The documentation of last version has not changed a lot since cmake-2.8.12:
target_compile_options()
add_compile_options()
In you case you can use:
target_compile_options(${TARGET} PRIVATE ${BUILD_FLAGS})
Or simply if you have a single target:
add_compile_options(${BUILD_FLAGS})
More examples
target_compile_options(mylib PRIVATE -O2) # only internal
target_compile_options(mylib INTERFACE -gl) # only external
target_compile_options(mylib PUBLIC -g) # same as PRIVATE + INTERFACE
# multiple targets and flags
target_compile_options(mylib1 mylib2 PRIVATE -Wall -Wextra)
target_compile_options( mylib PUBLIC -DUSEXX) # Bad
target_compile_definitions(mylib PUBLIC -DUSEXX) # OK
add_compile_options(-Wall -Wextra) # for all targets in current directory
add_compile_options(-DUSEXX) # Bad
add_definitions(-DUSEXX) # OK
Deprecated COMPILE_FLAGS
cmake-3.0 documentation flags COMPILE_FLAGS as deprecated:
COMPILE_FLAGS
Additional flags to use when compiling this target’s sources.
The COMPILE_FLAGS property sets additional compiler flags used to
build sources within the target. Use COMPILE_DEFINITIONS to pass
additional preprocessor definitions.
This property is deprecated. Use the COMPILE_OPTIONS property or the
target_compile_options command instead.
If you still want to use set_target_properties() you may use COMPILE_OPTIONS instead of COMPILE_FLAGS:
set_target_properties(${TARGET} PROPERTIES COMPILE_OPTIONS ${BUILD_FLAGS})
Since CMake-3.3 (2015)
Anton Petrov suggests to use generator expressions as presented in an answer of ar31.
The CMake generator expressions applies your ${BUILD_FLAGS} to:
C++ language using $<COMPILE_LANGUAGE:CXX> (can also be C, CUDA...)
Clang compiler using $<CXX_COMPILER_ID:Clang>
(can also be GNU for gcc, or MSVCfor Visual C++... see full list)
(use $<C_COMPILER_ID:Clang> instead if language is C)
and more as supported C++ feature or compiler version... (see documentation)
In you case you can use:
target_compile_options(${TARGET} PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:${BUILD_FLAGS_FOR_CXX}>
$<$<COMPILE_LANGUAGE:C>:${BUILD_FLAGS_FOR_C}>)
or about compilers:
target_compile_options(${TARGET} PRIVATE
$<$<CXX_COMPILER_ID:Clang>:${BUILD_FLAGS_FOR_CLANG}>
$<$<CXX_COMPILER_ID:GNU>:${BUILD_FLAGS_FOR_GCC}>
$<$<CXX_COMPILER_ID:MSVC>:${BUILD_FLAGS_FOR_VISUAL}>)
Since CMake-3.13 (2018)
A new function target_link_options() allow to pass options to the linker, as mentioned by Craig Scott.
Different options for C and C++ files
The best way is to distinguish C files and C++ files using two different targets.
Use the first one:
set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS ${BUILD_FLAGS})
The flags stored in BUILD_FLAGS are appended after CMAKE_CXX_FLAGS when compiling the sources of TARGET. The documentation hints at this, but I've just tried it to make sure.
COMPILE_FLAGS
Additional flags to use when compiling this target's sources.
The COMPILE_FLAGS property sets additional compiler flags used to
build sources within the target. Use COMPILE_DEFINITIONS to
pass additional preprocessor definitions.
The full command line will be the equivalent of:
${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} ${COMPILE_FLAGS} -o foo.o -c foo.cc
And as Ramon said, you can always check with make VERBOSE=1.