I'm having trouble setting up options and CMake variables and getting them propagated to the CMake GUI.
For example, the following lines are in my CMakeLists.txt file:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -tR -DPOCO_DLL")
message("CMake flags: " ${CMAKE_CXX_FLAGS})
When running configure in the CMake GUI it prints "CMake flags: -tM -tR -DPOCO_DLL" indicating that setting the CMAKE_CXX_FLAGS "works".
The GUI however don't get updated and only shows "-tM" on the CMAKE_CXX_FLAGS line.
What is the proper way of setting up these CMAKE options in the CMakeLists file so they get propagated to the CMake GUI?
The trick is to set CMAKE_CXX_FLAGS before project(...) statement. But this will not be enough; you will also need to put it into the cache.
Also, if you plan to support setting it initially from the command line interface, and/or -C cmake option (locad initial cache), you will need to force put it into the cache, as shown:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -tR -DPOCO_DLL" CACHE STRING "Default CXX options" FORCE)
...
...
project(MyProject)
....
On the other hand, be very careful, because you are setting command line options at the moment you know nothing about the compiler, that is by default determined during execution of project statement.
Implicitly, this renders your CMakeLists.txt compiler dependant.
At the end, here is documentation about set cmake command
Related
I'd like to set the compiler version in CMake so I can switch between GCC and Clang just by commenting out a few lines.
Below is the top of my CMake script, with the two additional lines setting GCC as the compiler:
cmake_minimum_required(VERSION 3.4.1...3.17.2)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}")
project(test_project C CXX)
set (CMAKE_C_COMPILER "/usr/bin/gcc") # Adding these causes infinite loop
set (CMAKE_CXX_COMPILER "/usr/bin/g++")
message(STATUS "Compiler ID: ${CMAKE_CXX_COMPILER_ID}")
message(STATUS "Compiler Vers: ${CMAKE_CXX_COMPILER_VERSION}")
However, when I add the above two lines and run cmake .. the script enters an infinite loop, outputting:
You have changed variables that require your cache to be deleted
Configure will be re-run and you may have to reset some variables
The following variables have changed:
CMAKE_C_COMPILER= /usr/bin/cc
CMAKE_CXX_COMPILER= /usr/bin/c++
CMAKE_CXX_COMPILER= /usr/bin/c++
CMAKE_C_COMPILER= /usr/bin/cc
CMAKE_CXX_COMPILER= /usr/bin/c++
CMAKE_C_COMPILER= /usr/bin/cc
I'd eventually like to have something like this:
cmake_minimum_required(VERSION 3.4.1...3.17.2)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}")
project(test_project C CXX)
set (CMAKE_C_COMPILER "/usr/bin/gcc")
set (CMAKE_CXX_COMPILER "/usr/bin/g++")
#set (CMAKE_C_COMPILER "/usr/bin/clang")
#set (CMAKE_CXX_COMPILER "/usr/bin/clang++")
message(STATUS "Compiler ID: ${CMAKE_CXX_COMPILER_ID}")
message(STATUS "Compiler Vers: ${CMAKE_CXX_COMPILER_VERSION}")
Anyone know what's wrong?
It seems to be an ancient CMake bug, where the workaround proposed is just putting the variables before the project command:
cmake_minimum_required(VERSION 3.17.2)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}")
set(CMAKE_C_COMPILER "/usr/bin/gcc")
set(CMAKE_CXX_COMPILER "/usr/bin/g++")
project(test_project C CXX)
...
EDIT:
As other mentioned, this is not actually a bug, but design decision: project command selects compiler based on the provided settings, and it never should be altered after the command comes into play.
BTW, these variables are not for the set by the project. This is done intentionally so a user may choose the compiler he wants to build the project. The project maintainer should not decide for the user what compiler to use. Who told you that it must be only /usr/bin/*? What if GCC came from SCL (on RHEL/CentOS) where it gonna be installed to /opt/rh/devtoolset-N/... ... Please leave to users the freedom to choose what compiler to use!
These variables must be set via CLI, initial cache, toolchain file, presets, or environment variables.
This is probably a very simple thing but I can't find an answer for it.
For example I have the following compilation option in CMakeLists.txt
set(CMAKE_CXX_FLAGS_DEBUG "-O1 -g")
How can I use it? Doing
make CMAKE_CXX_FLAGS_DEBUG
fails.
I also can't directly do
make -O1 -g
CMakeLists.txt (shortened a bit and the name of the project anonymized):
cmake_minimum_required(VERSION 3.8)
# Set compiler
set(CMAKE_CXX_COMPILER "clang++")
set(CMAKE_C_COMPILER "clang")
# Set compilation options
set(CMAKE_CXX_FLAGS_DEBUG_INIT "-Wall -O0 -g")
set(CMAKE_CXX_FLAGS_RELEASE_INIT "-Wall")
set(CMAKE_BUILD_TYPE Debug)
# Set path to find additional dependencies
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
# Version of the std library
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# options for compilation
option(BUILD_AAAA "Build ..." ON)
# Set names of libraries
set(LIB_AAAA ${CMAKE_PROJECT_NAME})
if (BUILD_AAAA)
message(STATUS "Building sources.")
add_subdirectory(src)
endif()
# Configure AAAA.pc file and install it
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/AAAA.pc.in ${CMAKE_CURRENT_BINARY_DIR}/AAAA.pc #ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/AAAA.pc
DESTINATION lib/pkgconfig/)
If you define a target in cmake after setting variable, cmake initializes the properties of the target with the value of the variable, if you specify the right build type. No make options necessary; (I recommend using cmake --build . instead anyways to be build system independent.)
...
set(CMAKE_CXX_FLAGS_DEBUG "-O1 -g")
# with the correct configuration the flags are automatically applied to the following executable
add_executable(HelloWorld main.cpp)
Command line (assuming the working directory containing CMakeLists.txt and are on Linux):
mkdir buildDebug
cmake -D CMAKE_BUILD_TYPE=Debug -S . -B buildDebug
cmake --build buildDebug
The second command sets up the project inside the buildDebug directory with the debug configuration and the third command builds the project (equivalent to make all run from inside buildDebug.
Edit after question update
You're setting the build type to Debug in the CMakeLists.txt file. I don't recommend doing this, since this prevents you from setting up the project with another configuration. If you want Debug to be the default configuration, I'd use a cache variable. There's a similar issue with setting the compiler in the CMakeLists.txt file; for setting the compiler you may be better of using a toolchain file.
As an alternative create a cmake script initializing cache variables with the desired values which allows you to pass multiple values with just passing the file name via -C option to cmake which may be a conventient way of providing a set of possible configurations.
The only thing that changes in the answer though is the fact that passing the build type via command line is not possible in the current state of the cmake project, i.e. -D CMAKE_BUILD_TYPE=Debug could be removed from the second command line command.
I have a C++ project which uses CMake as its build system. I'd like the following behavior:
If cmake is invoked as cmake .., then CMAKE_CXX_FLAGS is -O3 -Wall -Wextra
If cmake is invoked as cmake .. -DCMAKE_BUILD_TYPE=Debug, then CMAKE_CXX_FLAGS is -g -Wall -Wextra
I tried the following
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
set(CMAKE_CXX_FLAGS "-O3 -Wall -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "-g -Wall -Wextra")
But this has a big problem. First of all, if the second invocation is used, then both -O3 and -g flags are passed to the compiler. Besides, if I use the second invocation and the first thereafter, CMAKE_BUILD_TYPE stays Debug although not explicitly ordered so - so I get a Debug build although I want an optimized build.
Why? What can I do to get the desired behavior?
First off: recommended usage of CMake is to always specify CMAKE_BUILD_TYPE explicitly on the command line (if and only if using a single-configuration generator). Your use case deviates from this best practice, so treat this answer as "how you can do it," not necessarily as "how you should do it."
To address the first issue, you should be able to do this early in your CMakeList:
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
set(CMAKE_CXX_FLAGS "-Wall -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "-g")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
This will make sure that if you do not specify a build type at all, it will default to "Release" and thus CMAKE_CXX_FLAGS_RELEASE will be used.
The second one is harder to tackle. Variables passed from the command line (such as CMAKE_BUILD_TYPE=Debug) are cached by CMake and thus re-used in subsequent invocations (that is necessary, since CMake can re-trigger itself if you modify its inputs between builds).
The only solution is to make the user switch the build type explicitly again, using cmake .. -DCMAKE_BUILD_TYPE=Release.
Consider why this is necessary: as I said, CMake can re-trigger itself as part of a build if CMake's input (CMakeLists.txt files or their dependencies) has changed since last CMake ran. In such case, it will also be run without command-line arguments such as -DCMAKE_BUILD_TYPE=whatever, and will rely on the cache to supply the same value as last time. This scenario is indistinguishable from you manually running cmake .. without additional arguments.
I could provide a hacky solution to always reset CMAKE_BUILD_TYPE to Release if not specified explicitly on the command line. However, it would also mean that a buildsystem generated as Debug would get re-generated as Release if automatic re-generation happened. I am pretty sure that's not what you want.
For CXX flags specific for Release target, you should set
CMAKE_CXX_FLAGS_RELEASE
instead of
CMAKE_CXX_FLAGS
In your case you can use:
set(CMAKE_CXX_FLAGS "-Wall -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "-g")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
A more modern CMake approach (which I suggest, if you are using CMake version 2.8.12 or newer), is well described in this StackOverflow answer and involves the use of target_compile_options.
The default optimization level for various release modes is O3, which often isn't the best choice. Within CMakeLists.txt file, these can be modified to O2:
# Modify compile flags to change optimization level from O3 to O2
string(REGEX REPLACE "([\\/\\-]O)3" "\\12"
CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
string(REGEX REPLACE "([\\/\\-]O)3" "\\12"
CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
string(REGEX REPLACE "([\\/\\-]O)3" "\\12"
CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}")
string(REGEX REPLACE "([\\/\\-]O)3" "\\12"
CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
These regular expressions will be modified (e.g.):
-O3 to -O2 usually for Linux-based compilers
/O3 to /O2 usually for Windows-based compilers
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.
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.