In my particular CMake project, I have three CPP files:
a.cpp
b.cpp
c.cpp
I want 'a.cpp' to be compiled in all configurations (release & debug).
I only want 'b.cpp' to be compiled in DEBUG configuration.
I only want 'c.cpp' to be compiled in RELEASE configuration.
How can I do this? I need something similar to the debug and optimized keywords that are accepted by the target_link_libraries() CMake operation.
As far as I know cmake does not provide a way to exclude some files based on configuration. So you need a workaround to achieve this behavior.
For example, you can wrap the whole content of b.cpp and c.cpp with some guard macro:
#ifdef BUILD_ME
//original content of your file
#endif
and next set configuration-specific compiler definitions in cmake:
if (${CMAKE_GENERATOR} MATCHES "Make" AND "${CMAKE_BUILD_TYPE}" STREQUAL "")
# This block might be needed because CMAKE_BUILD_TYPE is usually
# undefined for makefiles.
# And COMPILE_DEFINITIONS_RELEASE are not chosen by default.
set(CMAKE_BUILD_TYPE RELEASE)
endif()
set_source_files_properties(b.cpp PROPERTIES COMPILE_DEFINITIONS_DEBUG BUILD_ME )
set_source_files_properties(c.cpp PROPERTIES COMPILE_DEFINITIONS_RELEASE BUILD_ME )
add_executable(target_name a.cpp b.cpp c.cpp)
This this issue has been fixed as of 3.17:
https://cmake.org/cmake/help/latest/release/3.17.html#generators
"Visual Studio Generators learned to support per-config sources. Previously only Command-Line Build Tool Generators supported them."
Related
I have embedded project using cross compiler. I would like to introduce Google test, compiled with native GCC compiler. Additionally build some unit test targets with CTC compiler.
Briefly:
I have 3 different targets and compile them with 3 different compilers. How to express it in CMakeLists.txt? I Tried SET_TARGET_PROPERTIES;
but it seems impossible to set CXX variable with this command!
I just had the same issue right now, but the other answer didn't help me. I'm also cross-compiling, and I need some utility programs to be compiled with GCC, but my core code to be compiled with avr-gcc.
Basically, if you have a CMakeLists.txt, and you want all targets in this file to be compiled with another compiler, you can just set the variables by hand.
Define these macros somewhere:
macro(use_host_compiler)
if (${CURRENT_COMPILER} STREQUAL "NATIVE")
# Save current native flags
set(NATIVE_C_FLAGS ${CMAKE_C_FLAGS} CACHE STRING "GCC flags for the native compiler." FORCE)
# Change compiler
set(CMAKE_SYSTEM_NAME ${CMAKE_HOST_SYSTEM_NAME})
set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_HOST_SYSTEM_PROCESSOR})
set(CMAKE_C_COMPILER ${HOST_C_COMPILER})
set(CMAKE_C_FLAGS ${HOST_C_FLAGS})
set(CURRENT_COMPILER "HOST" CACHE STRING "Which compiler we are using." FORCE)
endif()
endmacro()
macro(use_native_compiler)
if (CMAKE_CROSSCOMPILING AND ${CURRENT_COMPILER} STREQUAL "HOST")
# Save current host flags
set(HOST_C_FLAGS ${CMAKE_C_FLAGS} CACHE STRING "GCC flags for the host compiler." FORCE)
# Change compiler
set(CMAKE_SYSTEM_NAME ${NATIVE_SYSTEM_NAME})
set(CMAKE_SYSTEM_PROCESSOR ${NATIVE_SYSTEM_PROCESSOR})
set(CMAKE_C_COMPILER ${NATIVE_C_COMPILER})
set(CMAKE_C_FLAGS ${NATIVE_C_FLAGS})
set(CURRENT_COMPILER "NATIVE" CACHE STRING "Which compiler we are using." FORCE)
endif()
endmacro()
At the very beginning of your CMakeLists.txt script (or in a toolchain file), set the following variables according to what you need:
CURRENT_COMPILER
HOST_C_COMPILER
HOST_C_FLAGS
NATIVE_SYSTEM_NAME
NATIVE_C_COMPILER
NATIVE_C_FLAGS
The idea is that CMAKE_C_COMPILER (and company) is a variable like any other, so setting it inside a certain scope will only leave it changed within that scope.
Example usage:
use_host_compiler()
add_executable(foo foo.c) # Compiled with your host (computer)'s compiler.
use_native_compiler()
add_executable(bar bar.c) # Compiled with your native compiler (e.g. `avr-gcc`).
There is no proper way to change compiler for individual target.
According to cmake manual "Once set, you can not change this variable". This is about CMAKE_<LANG>_COMPILER.
The solution suggested by AnthonyD973 does not seem to work, which is sad of course. The ability to use several compilers in a project without custom_command things is very useful.
One solution (that I haven't tried yet) is to use
set_target_properties(your_target CXX_COMPILER_LAUNCHER foo_wrapper)
Then make foo_wrapper a script that just drops the first argument (which will be the default compiler, e.g. c++) and then calls the compiler you want.
There's also CXX_LINKER_LAUNCHER and the same for C_....
CMake is a make file generator. It generates a file that you can then use to build. If you want to more than one target platform, you need to run CMake multiple times with different generators.
So what you want to do is not possible in CMake, but with CMake: You can create a shell script that invokes CMake multiple times.
I am using the arm-linux-androideabi-g++ compiler. When I try to compile a simple "Hello, World!" program it compiles fine. When I test it by adding a simple exception handling in that code it works too (after adding -fexceptions .. I guess it is disabled by default).
This is for an Android device, and I only want to use CMake, not ndk-build.
For example - first.cpp
#include <iostream>
using namespace std;
int main()
{
try
{
}
catch (...)
{
}
return 0;
}
./arm-linux-androideadi-g++ -o first-test first.cpp -fexceptions
It works with no problem...
The problem ... I am trying to compile the file with a CMake file.
I want to add the -fexceptions as a flag. I tried with
set (CMAKE_EXE_LINKER_FLAGS -fexceptions ) or set (CMAKE_EXE_LINKER_FLAGS "fexceptions" )
and
set ( CMAKE_C_FLAGS "fexceptions")
It still displays an error.
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.
In newer versions of CMake you can set compiler and linker flags for a single target with target_compile_options and target_link_libraries respectively (yes, the latter sets linker options too):
target_compile_options(first-test PRIVATE -fexceptions)
The advantage of this method is that you can control propagation of options to other targets that depend on this one via PUBLIC and PRIVATE.
As of CMake 3.13 you can also use target_link_options to add linker options which makes the intent more clear.
Try setting the variable CMAKE_CXX_FLAGS instead of CMAKE_C_FLAGS:
set (CMAKE_CXX_FLAGS "-fexceptions")
The variable CMAKE_C_FLAGS only affects the C compiler, but you are compiling C++ code.
Adding the flag to CMAKE_EXE_LINKER_FLAGS is redundant.
The preferred way to specify toolchain-specific options is using CMake's toolchain facility. This ensures that there is a clean division between:
instructions on how to organise source files into targets -- expressed in CMakeLists.txt files, entirely toolchain-agnostic; and
details of how certain toolchains should be configured -- separated into CMake script files, extensible by future users of your project, scalable.
Ideally, there should be no compiler/linker flags in your CMakeLists.txt files -- even within if/endif blocks. And your program should build for the native platform with the default toolchain (e.g. GCC on GNU/Linux or MSVC on Windows) without any additional flags.
Steps to add a toolchain:
Create a file, e.g. arm-linux-androideadi-gcc.cmake with global toolchain settings:
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
set(CMAKE_CXX_FLAGS_INIT "-fexceptions")
(You can find an example Linux cross-compiling toolchain file here.)
When you want to generate a build system with this toolchain, specify the CMAKE_TOOLCHAIN_FILE parameter on the command line:
mkdir android-arm-build && cd android-arm-build
cmake -DCMAKE_TOOLCHAIN_FILE=$(pwd)/../arm-linux-androideadi-gcc.cmake ..
(Note: you cannot use a relative path.)
Build as normal:
cmake --build .
Toolchain files make cross-compilation easier, but they have other uses:
Hardened diagnostics for your unit tests.
set(CMAKE_CXX_FLAGS_INIT "-Werror -Wall -Wextra -Wpedantic")
Tricky-to-configure development tools.
# toolchain file for use with gcov
set(CMAKE_CXX_FLAGS_INIT "--coverage -fno-exceptions -g")
Enhanced safety checks.
# toolchain file for use with gdb
set(CMAKE_CXX_FLAGS_DEBUG_INIT "-fsanitize=address,undefined -fsanitize-undefined-trap-on-error")
set(CMAKE_EXE_LINKER_FLAGS_INIT "-fsanitize=address,undefined -static-libasan")
You can also add linker flags to a specific target using the LINK_FLAGS property:
set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS " ${flag}")
If you want to propagate this change to other targets, you can create a dummy target to link to.
This worked for me when I needed a precompile definition named "NO_DEBUG":
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -DNO_DEBUG")
Then from code
#ifdef NO_DEBUG
.....
With CMake 3.4+, APPEND can be used with the string command to add flags.
string(APPEND CMAKE_EXE_LINKER_FLAGS " -fexceptions")
The Cmake FAQ
and
other
places
recommend to check CMAKE_CONFIGURATION_TYPES to recognize a multi-configuration generator. I have found several questions where this did not work (for example this one). The issue seems to be that the variable is not set the first time cmake is called.
I tested with the following file
cmake_minimum_required(VERSION 2.6)
if(CMAKE_CONFIGURATION_TYPES)
message("Multi-configuration generator")
else()
message("Single-configuration generator")
endif()
project(foo)
and called it like this
mkdir build
cd build
cmake -G "Visual Studio 12 2013" ..
and got Single-configuration generator.
How should I distinguish whether the current generator supports multiple configurations?
EDITED: Added information on checking and changing CMAKE_CONFIGURATION_TYPES
Check and Changing CMAKE_CONFIGURATION_TYPES
Taking the suggestions from this question you could check and change CMAKE_CONFIGURATION_TYPES, but be aware that there was a bug 0015577: The 'project' command overwrites CMAKE_CONFIGURATION_TYPES in CMake 3.2.2 that did break this behaviour for the initial VS solution generation (fixed with CMake 3.3.0):
cmake_minimum_required(VERSION 3.3)
project(foo NONE)
if(CMAKE_CONFIGURATION_TYPES)
message("Multi-configuration generator")
set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "My multi config types" FORCE)
else()
message("Single-configuration generator")
endif()
enable_language(C CXX)
Preset CMAKE_CONFIGURATION_TYPES
If you just need a certain set of configurations for multi-configuration environments you can do (thanks to #Tsyvarev for the suggestion):
cmake_minimum_required(VERSION 2.8)
# NOTE: Only used in multi-configuration environments
set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "My multi config types" FORCE)
project(foo)
None multi-configuration environments will just ignore it. But be aware that other CMake modules like findBoost.cmake, findCUDA.cmake may rely on CMAKE_CONFIGURATION_TYPES being empty for single-configuration environments (thanks again #Tsyvarev for the hint).
So a better solution would be adding toolchain files for all your supported generators. They are generally useful, because there you can handle all the toolchain/generator specific parts.
Here is an extract of my VSToolchain.txt:
# Reduce the config types to only Debug and Release
SET(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE)
# Standard is a console app. If you need a windows app, use WIN32 define in add_executable
set(CMAKE_WIN32_EXECUTABLE 0 CACHE INTERNAL "")
CMAKE_WIN32_EXECUTABLE is just there to show what kind of settings I have put in my Visual Studio toolchain file.
Another CMake command line solution is suggested here: How to create cmake build configuration without debug symbols and without optimizations?
Only Checking CMAKE_CONFIGURATION_TYPES
If you only want do check what CMake does set in CMAKE_CONFIGURATION_TYPES:
I just tested your above code with Visual Studio 2013 and MinGW/GCC (both with empty build directories). You just need one small change and move the check after the project() command:
project(foo)
message("CMAKE_CONFIGURATION_TYPES ${CMAKE_CONFIGURATION_TYPES}")
if(CMAKE_CONFIGURATION_TYPES)
message("Multi-configuration generator")
else()
message("Single-configuration generator")
endif()
And I get for VS2013:
CMAKE_CONFIGURATION_TYPES Debug;Release;MinSizeRel;RelWithDebInfo
Multi-configuration generator
And for GCC:
CMAKE_CONFIGURATION_TYPES
Single-configuration generator
For more details about what CMake does see:
CMAKE_CONFIGURATION_TYPES set by EnableLanguage() in cmGlobalVisualStudio7Generator.cxx
CMake: In which Order are Files parsed (Cache, Toolchain, …)?
I see you are on CMake v2.6, but for anyone who is on v3.9+, v3.9 introduced the global property called GENERATOR_IS_MULTI_CONFIG:
Read-only property that is true on multi-configuration generators.
You can load the value into a CMake variable like so:
get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
This very approach is recommended in "Professional CMake" by Craig Scott, along with explanations of the shortcomings of other approaches- especially those involving CMAKE_CONFIGURATION_TYPES. The book is $30 but the section I'm referring to is in the sample chapters.
I have embedded project using cross compiler. I would like to introduce Google test, compiled with native GCC compiler. Additionally build some unit test targets with CTC compiler.
Briefly:
I have 3 different targets and compile them with 3 different compilers. How to express it in CMakeLists.txt? I Tried SET_TARGET_PROPERTIES;
but it seems impossible to set CXX variable with this command!
I just had the same issue right now, but the other answer didn't help me. I'm also cross-compiling, and I need some utility programs to be compiled with GCC, but my core code to be compiled with avr-gcc.
Basically, if you have a CMakeLists.txt, and you want all targets in this file to be compiled with another compiler, you can just set the variables by hand.
Define these macros somewhere:
macro(use_host_compiler)
if (${CURRENT_COMPILER} STREQUAL "NATIVE")
# Save current native flags
set(NATIVE_C_FLAGS ${CMAKE_C_FLAGS} CACHE STRING "GCC flags for the native compiler." FORCE)
# Change compiler
set(CMAKE_SYSTEM_NAME ${CMAKE_HOST_SYSTEM_NAME})
set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_HOST_SYSTEM_PROCESSOR})
set(CMAKE_C_COMPILER ${HOST_C_COMPILER})
set(CMAKE_C_FLAGS ${HOST_C_FLAGS})
set(CURRENT_COMPILER "HOST" CACHE STRING "Which compiler we are using." FORCE)
endif()
endmacro()
macro(use_native_compiler)
if (CMAKE_CROSSCOMPILING AND ${CURRENT_COMPILER} STREQUAL "HOST")
# Save current host flags
set(HOST_C_FLAGS ${CMAKE_C_FLAGS} CACHE STRING "GCC flags for the host compiler." FORCE)
# Change compiler
set(CMAKE_SYSTEM_NAME ${NATIVE_SYSTEM_NAME})
set(CMAKE_SYSTEM_PROCESSOR ${NATIVE_SYSTEM_PROCESSOR})
set(CMAKE_C_COMPILER ${NATIVE_C_COMPILER})
set(CMAKE_C_FLAGS ${NATIVE_C_FLAGS})
set(CURRENT_COMPILER "NATIVE" CACHE STRING "Which compiler we are using." FORCE)
endif()
endmacro()
At the very beginning of your CMakeLists.txt script (or in a toolchain file), set the following variables according to what you need:
CURRENT_COMPILER
HOST_C_COMPILER
HOST_C_FLAGS
NATIVE_SYSTEM_NAME
NATIVE_C_COMPILER
NATIVE_C_FLAGS
The idea is that CMAKE_C_COMPILER (and company) is a variable like any other, so setting it inside a certain scope will only leave it changed within that scope.
Example usage:
use_host_compiler()
add_executable(foo foo.c) # Compiled with your host (computer)'s compiler.
use_native_compiler()
add_executable(bar bar.c) # Compiled with your native compiler (e.g. `avr-gcc`).
There is no proper way to change compiler for individual target.
According to cmake manual "Once set, you can not change this variable". This is about CMAKE_<LANG>_COMPILER.
The solution suggested by AnthonyD973 does not seem to work, which is sad of course. The ability to use several compilers in a project without custom_command things is very useful.
One solution (that I haven't tried yet) is to use
set_target_properties(your_target CXX_COMPILER_LAUNCHER foo_wrapper)
Then make foo_wrapper a script that just drops the first argument (which will be the default compiler, e.g. c++) and then calls the compiler you want.
There's also CXX_LINKER_LAUNCHER and the same for C_....
CMake is a make file generator. It generates a file that you can then use to build. If you want to more than one target platform, you need to run CMake multiple times with different generators.
So what you want to do is not possible in CMake, but with CMake: You can create a shell script that invokes CMake multiple times.
Visual Studio C++ 2008 / GCC 4.4.2
I have written a program to run on Linux and now I have to port my code to run on Windows. I have decided to use CMake as I want to keep the same build system for both platforms.
However, I need to link with some libraries for both platforms. In my CMakeLists.txt I have the following:
# Compile with gcc c89 standard
IF(CMAKE_COMPILER_IS_GNUCXX)
MESSAGE(STATUS "GCC detected - Adding compiler flags")
SET(CMAKE_C_FLAGS "-pthread -ggdb -Wextra -Wall -pedantic -std=c89")
ENDIF(CMAKE_COMPILER_IS_GNUCXX)
IF(WIN32)
SET(CMAKE_C_FLAGS "ws2_32.lib")
ENDIF(WIN32)
However, when I compile on Visual Studio I get the following error:
fatal error C1083: Cannot open source file: 'ws2_32.lib': No such file or directory
What can I do to resolve this problem?
========= Edit
In the top level directory
# Project Client Server
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
# Name of project
PROJECT(CLIENT_SERVER)
# Compile with gcc c89 standard
IF(CMAKE_COMPILER_IS_GNUCXX)
MESSAGE(STATUS "GCC detected - Adding compiler flags")
SET(CMAKE_C_FLAGS "-pthread -ggdb -Wextra -Wall -pedantic -std=c89")
ENDIF(CMAKE_COMPILER_IS_GNUCXX)
IF(WIN32)
SET(CMAKE_C_FLAGS "ws2_32")
ENDIF(WIN32)
# Includes
INCLUDE_DIRECTORIES(${CLIENT_SERVER_SOURCE_DIR}/cltsvr_ults)
INCLUDE_DIRECTORIES(${CLIENT_SERVER_SOURCE_DIR}/server)
INCLUDE_DIRECTORIES(${CLIENT_SERVER_SOURCE_DIR}/client)
# libraries
LINK_DIRECTORIES($CLIENT_SERVER/cltsvr_ults)
# Add subdirectories
ADD_SUBDIRECTORY(client)
ADD_SUBDIRECTORY(server)
ADD_SUBDIRECTORY(cltsvr_ults)
ADD_SUBDIRECTORY(test_client)
ADD_SUBDIRECTORY(test_server)
In the subdirectory of client I have this CMakeLists.txt
# libray called client from client.c
ADD_LIBRARY(client client)
And in the subdirectory of test_clt where I create and link my executable.
# Test client add executable
INCLUDE_DIRECTORIES($CLIENT_SERVER_SOURCE_DIR/client)
INCLUDE_DIRECTORIES($CLIENT_SERVER_SOURCE_DIR/cltsvr_ults)
# Link the library
LINK_DIRECTORIES($CLIENT_SERVER/client)
# Add the executable
ADD_EXECUTABLE(clt test_clt)
# Link the executable to the client library
IF(WIN32)
TARGET_LINK_LIBRARIES(clt client ws2_32)
ENDIF(WIN32)
Disclaimer: My answer is of philosophical nature which should encourage you to avoid touching CMAKE_C_FLAGS directly. For the direct answer that just solves your problem look what Bill ( the lead architect of the CMake btw. ) wrote.
The thing about CMake is, that it lets you describe what you want to do without referring to a specific compiler or platform. What CMake does is building the compiler and linker flags from your usage of
include_directories
add_definitions
add_library
add_executable
target_link_libraries
If there are no external dependencies, other than the compiler itself, this is all you need. For external dependencies use
find_package
It defines a set of variables, like
find_package(SDL)
defines
SDL_INCLUDE_DIR
SDL_LIBRARY
for usage with respectively include_directories and target_link_libraries. CMake ships with a bunch of so called module files, like FindSDL.cmake and many others can be googled.
The next lower level is to use
find_path
find_library
which are used in the Find???.cmake modules itself.
The CMAKE_C_FLAGS variable is composed by CMake from these commands. Modifying it means you bypass CMake. There are cases, like for special optimization flags, you want to do this, but at this point all power and thus responsibility transfered from CMake to you.
By adding ws2_32.lib to the C_FLAGS, you are using it at compile time, and not link time. If you look at the error message, you can see it it treating the file as if it were a c++ source file: Cannot open source file: 'ws2_32.lib'. target_link_libraries(target ws2_32) should work.
You need to use the Target Link Libraries command. The target would be the executable you're building.
EDIT: You shouldn't specify the libs you're linking against in C_FLAGS. You can do something like TARGET_LINK_LIBRARIES(execName, ws_32, ...). I'm not 100% sure if you need the .lib. Been a while since I used CMake.