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.
Related
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'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
I am using CMake 3.8.2, GNU make 4.2.1 and GCC 6.4.0 for my C++14 project and I noticed a strange behavior when building. I am using CMake for an out-of-source build in a sub-folder called "build" where I run cmake .. followed by make.
CMake runs fine without any errors and make will build all source files like I expect until it is done compiling and starts linking them. It will then fail with an error
[ 83%] ...
[100%] Linking CXX executable myproject
/usr/bin/ld: some-source-file.cc.o: undefined reference to symbol '_ZNKSt7__cxx1118basic_stringstreamIcSt11char_traitsIcESaIcEE3strEv##GLIBCXX_3.4.21'
Interestingly it doesn't show any compiler warnings up to this point and only shows the above mentioned linker error.
Now when I ignore the error and simply run cmake .. and then make again (just like I did before) I get all the compiler warnings that my code should produce and everything links perfectly fine, even though I didn't change any code or CMake-related files in the meantime.
I can reproduce this behavior by deleting all files in the build dir by running rm -r *.
Here is my CMakeLists.txt file:
# Define minimum required CMake version
cmake_minimum_required(VERSION 3.8.2)
# Setting compiler related settings
set(CMAKE_CXX_COMPILER "${CMAKE_SOURCE_DIR}/toolchain/binary/gcc-6.4.0/bin/gcc")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wconversion -O2 -lstdc++")
set(CMAKE_CXX_STANDARD 14)
# Define project name
project(MyProject)
# Find source files
file(GLOB_RECURSE SOURCES application/*.cc)
# Adding third-party sources
set(SOURCES ${SOURCES} "third-party/cpp-base64/base64.cpp")
# Executable to be built from which source files
add_executable(myproject ${SOURCES})
# Find and include and link Botan
find_library(BOTAN botan-2 "third-party/botan/build/lib")
include_directories("third-party/botan/build/include/botan-2")
# Includes that are part of the project
include_directories("${CMAKE_SOURCE_DIR}/application/include")
# Include nlohmann/json
include_directories("third-party/json/src")
# Include cpp-base64 by René Nyffenegger
include_directories("third-party/cpp-base64")
find_package(Boost REQUIRED COMPONENTS program_options)
if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
endif()
# Link third-party libraries
target_link_libraries(myproject ${Boost_LIBRARIES} ${BOTAN})
Note: I am required to check-in the compiler and libraries I am using, which is why I specified them in the CMake file.
If it only works the second time it has to do with cached variables.
So I'm pretty sure that it will work the first time if you modify CMAKE_CXX_COMPILER setting by adding set(... CACHE INTERNAL "") to:
set(CMAKE_CXX_COMPILER "${CMAKE_SOURCE_DIR}/toolchain/binary/gcc-6.4.0/bin/gcc" CACHE INTERNAL "")
And move set(CMAKE_CXX_FLAGS ...) after the project() command.
But please also be noted that you shouldn't put the compiler into your CMakeLists.txt.
References
CMake: In which Order are Files parsed (Cache, Toolchain, …)?
Passing compiler options cmake
CMake Error at CMakeLists.txt:30 (project): No CMAKE_C_COMPILER could be found
Is there a way to use the Clang compiler while mixing C++ and Fortran?
Until now I use cmake with
project(mixing CXX Fortran)
but this triggers the use of g++.
-- The CXX compiler identification is GNU 6.2.0
CMakeLists.txt of my project with Fortran mixing:
cmake_minimum_required(VERSION 3.7.0)
project(mixing CXX Fortran)
# SET UP ROOT https://root.cern.ch/how/integrate-root-my-project-cmake
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} /opt/local/libexec/root6/etc/root/cmake)
find_package(ROOT REQUIRED COMPONENTS MATH MINUIT2)
include(${ROOT_USE_FILE})
include_directories(Experiment Theory ${ROOT_INCLUDE_DIRS})
add_executable(mixing main.cpp)
target_link_libraries(mixing ${ROOT_LIBRARIES})
Not working, because g++ cannot use the needed Clang flag -stdlib=libc++ of the ROOT library.
You can always override c/c++ compiler by changing CMAKE_<LANG>_COMPILER, where <LANG> in your case is C or CXX.
You can set your CC and CXX environment variables to override defaults for CMAKE_C_COMPILER / CMAKE_CXX_COMPILER:
CC=clang CXX=clang++ cmake
You can set these on command line when invoking cmake:
cmake -D CMAKE_C_COMPILER=clang -D CMAKE_CXX_COMPILER=clang++
You can also set these directly in your cmake file:
set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_COMPILER clang++)
make sure however that you do that at the very top of your cmake file before any project/enable_language directive is used.
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.