I wrote a simple CMake script to test the use of command line arguments:
cmake_minimum_required(VERSION 3.5)
project(sample)
set(CMAKE_C_STANDARD 99)
if(DEPLOY)
message("deploying application")
endif()
if(DEV)
message("developing application")
endif()
set(DEV OFF)
set(DEPLOY OFF)
message("lorem ipsum dolor sit atmen")
When I run cmake CMakeLists.txt -DDEV=ON , the result is:
developing application
lorem ipsum dolor sit atmen
-- Configuring done
-- Generating done
So far, so good. Now, I run cmake CMakeLsists.txt -DDEPLOY=ON and the result is:
deploying application
developing application
lorem ipsum dolor sit atmen
-- Configuring done
-- Generating done
I was hoping to have only the line deploying application, instead, both conditional messages appeared. So it seems the DEV flag set previously is still on. How can I disble the persistent state of those flags?
Had help from a friend!
From the documentation of cmake unset() command, I just had to replace the lines
set(DEV OFF)
set(DEPLOY OFF)
by these:
unset(DEV CACHE)
unset(DEPLOY CACHE)
cmake unset() documentation
Related
Consider the following CMakeLists.txt file:
project(MyProject)
cmake_minimum_required(VERSION 3.16)
add_executable(MyApp main.cpp)
message(${CMAKE_CXX_FLAGS})
Now, running this:
$ cmake --DCMAKE_BUILD_TYPE=Debug <path_to_directory>
I get an error that the CMAKE_CXX_FLAGS is not set. (more accurately - message is called with wrong number of arguments).
I try to understand what exactly the CMAKE_BUILD_TYPE is causing by default - i.e. how it translates to compiler options/flags.
After building the project, I can clearly see that when running with CMAKE_BUILD_TYPE set to Release, the file is smaller (around a third) than when running with it set to Debug, so clearly it has some effect.
First of all, you must always call cmake_minimum_required before any other commands.
cmake_minimum_required(VERSION 3.16)
project(MyProject)
add_executable(MyApp main.cpp)
message(STATUS "CMAKE_CXX_FLAGS = ${CMAKE_CXX_FLAGS}")
Now, to answer your question...
Why is CMAKE_CXX_FLAGS empty?
Because it is intended to be set on the command line by a user of your build. This is the place where you would inject flags that apply to all C++ compiler invocations, regardless of configuration.
I try to understand what exactly the CMAKE_BUILD_TYPE is causing by default - i.e. how it translates to compiler options/flags.
On a multi configuration generator, like Visual Studio or Xcode, it does nothing. On a single configuration generator (like Makefiles or Ninja), the variable sets the active config. That means that all the variables listed in the documentation with <CONFIG> in the name get ${CMAKE_BUILD_TYPE} substituted in for <CONFIG> and used alongside their non-<CONFIG> variants.
There are four configurations that CMake provides:
Debug -- don't optimize and ensure debug symbols are enabled. On GCC this is -g.
Release -- full optimization, disable assert(). On GCC this is -O3 -DNDEBUG.
MinSizeRel -- release mode, but optimize for size. On GCC this is -Os -DNDEBUG.
RelWithDebInfo -- release mode, but optimize less to facilitate debugging. Include debug symbols. On GCC this is -O2 -g -DNDEBUG.
I'm trying to use different target property based on build configuration.
There is imported target called libmongocxx and it has 3 properties for different configs:
IMPORTED_LOCATION_DEBUG
IMPORTED_LOCATION_RELEASE
IMPORTED_LOCATION_RELWITHDEBINFO
So, to copy necessary dependencies to build directory I tried to use the following code:
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"$<TARGET_PROPERTY:libmongocxx,$<$<CONFIG:Debug>:IMPORTED_LOCATION_DEBUG>$<$<CONFIG:Release>:IMPORTED_LOCATION_RELEASE>$<$<CONFIG:RelWithDebInfo>:IMPORTED_LOCATION_RELWITHDEBINFO>>"
$<TARGET_FILE_DIR:${PROJECT_NAME}>)
The problem is: this works great when I run configuration from IDE (I tried CLion and VS2017), but the same CMakeLists.txt fails to configure when I run cmake from command line.
The error cmake shows:
CMake Error at CMakeLists.txt:93 (add_custom_command):
Error evaluating generator expression:
$<TARGET_PROPERTY:libmongocxx,$<$<CONFIG:Debug>:IMPORTED_LOCATION_DEBUG>$<$<CONFIG:Release>:IMPORTED_LOCATION_RELEASE>$<$<CONFIG:RelWithDebInfo>:IMPORTED_LOCATION_RELWITHDEBINFO>>
$<TARGET_PROPERTY:...> expression requires a non-empty property name.
By the way, I already found out that the same task can be more easily solved by using TARGET_FILE generator expression, but still, why different behavior in IDE and from command line?
I discovered this on CMake version 3.12.3, but later tested on 3.14.4 (cmd line only) and it still fails.
Update
Here is minimal example to reproduce the issue.
No dependencides required. test.cpp is empty file.
Configuration completes successfully from VS2017 but fails from cmd line.
CMakeLists.txt:
project(test LANGUAGES CXX)
cmake_minimum_required(VERSION 3.8.0)
add_executable(${PROJECT_NAME} test.cpp)
set_target_properties(${PROJECT_NAME} PROPERTIES
IMPORTED_LOCATION_DEBUG "libd.dll"
IMPORTED_LOCATION_RELEASE "lib.dll"
IMPORTED_LOCATION_RELWITHDEBINFO "libi.dll"
)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"$<TARGET_PROPERTY:${PROJECT_NAME},$<$<CONFIG:Debug>:IMPORTED_LOCATION_DEBUG>$<$<CONFIG:Release>:IMPORTED_LOCATION_RELEASE>$<$<CONFIG:RelWithDebInfo>:IMPORTED_LOCATION_RELWITHDEBINFO>>"
$<TARGET_FILE_DIR:${PROJECT_NAME}>
)
Command line:
cmake -G "Visual Studio 15 2017 Win64" ..
Update2
Can't agree this question is a duplicate.
The other question is about correct configuration of Visual Studio build.
This question is about usage of cmake generator expressions and about using cmake from command line.
The Visual Studio IDE CMake plugin only uses RelWithDebInfo and Debug configurations (at least for me). When invoking by the command line the default is all four standard configurations: Debug;Release;MinSizeRel;RelWithDebInfo.
Your CMakeLists.txt is incomplete because MinSizeRel is not defined or being used so there is no information for the MinSizeRel configuration.
BTW, CMAKE_BUILD_TYPE is ignored for multi-configuration generators. CMAKE_CONFIGURATION_TYPES defines which build types should be considered during generation.
So either add in the missing values or change CMAKE_CONFIGURATION_TYPES.
I have a CMake project where I want to prevent make package to do anything more than print a message on some platforms.
I know how to add a message, even a fatal one, but that runs during cmake-generation, not during builds. Do I have to resort to some add_custom_command? And that won't give me what I want, since that creates a new build target...
How can I override the package target for some platforms to just show a message?
why include cpack in your cmake list at all?
In order for a cmake project to have a cpack controlled package target, your project should include a line like:
include(CPack)
and also setting up some cpack-related properties. If you don't want that, you can just take out that line.
As shu pointed out, you can do something like this:
if (! WIN32)
include(cpack)
else()
cmake_policy(SET CMP0037 OLD)
add_custom_target(package
#add dependencies on other targets here
#[[DEPENDS install]]
COMMAND ${CMAKE_COMMAND} -E echo "custom target for non windows platforms!"
)
endif()
Note that by default, you will not be allowed to override reserved targets like test and package. We are turning off that policy here to write our own package target.
I have some options in my CMakeLists.txt file that can be selected with -D on the command line, like this:
# Set some options the user may choose
OPTION(USE_MPI "Use the MPI library for parallelization" OFF)
OPTION(USE_OPENMP "Use OpenMP for parallelization" OFF)
OPTION(TESTING "Enable testing of both Fortran and Python code" OFF)
OPTION(PYTHON_TOOLS "Build the python helper tools" OFF)
OPTION(BUILD_DOCS "Build the documentation; turns on PYTHON_TOOLS" OFF)
and I can activate one of them with something like
$ cmake . -DUSE_MPI=ON
Sometimes I forget what the options I have chosen are. It would be nice if there was some sort of -h flag I could use to display those on the command line in an automated way (in the style of python's argparse).
Is there an automated way to generate help documentation for a particular CMakeLists.txt, and/or call that help with some sort of -h or --help flag? I'm looking for something that will give me this behavior:
$ cmake . --help
USE_MPI - Use the MPI library for parallelization (Default: OFF)
USE_OPENMP - Use OpenMP for parallelization (Default: OFF)
TESTING - Enable testing of both Fortran and Python code (Default: OFF)
PYTHON_TOOLS - Build the python helper tools (Default: OFF)
BUILD_DOCS - Build the documentation; turns on PYTHON_TOOLS (Default: OFF)
If there is no automated way, is there at least an easy way to pass --help or -h to CMakeLists.txt so that I can manually write a help message?
I think the closest to what you're looking for is the -L command line arg. Running cmake . -LH should configure your project, then output all your cached, non-advanced variables along with their help strings.
The i arg also allows you to see the current values of options, but this actually runs cmake in command line "wizard mode" - it configures the project, asking you to set/update each variable one at a time.
I start using CMake to build my c++ source files, I see a strange comportament when I build inicially:
'cmake ../' will gerate the directory structure
'make' will build all
any successive make command will build nothing, as expected
'cmake ../' will apparent do nothing
'make' WILL REBUILD all
any successive make command will build nothing, as expected
There is my CMakelists.txt:
cmake_minimum_required(VERSION 2.6)
set(CMAKE_CXX_COMPILER "g++")
set(CMAKE_CXX_FLAGS "-Wall -pipe")
set(var_target CommonBase)
set(var_path_source base)
project(Prj_${var_target})
file(GLOB_RECURSE var_sources ${var_path_source}/*.cpp)
add_library(${var_target} SHARED ${var_sources})
install(TARGETS ${var_target} DESTINATION ${PROJECT_SOURCE_DIR}/install)
Looking better, at first 'cmake ../' command the file 'CMakeFiles/CommonBase.dir/depend.make' is empty, and the successive make command will insert the list of file dependencies
There is something wrong with my CMakelists.txt?
Thanks
There are a couple of issues here.
The actual cause of your problem is having the line set(CMAKE_CXX_FLAGS ...) before the project command.
The project command does quite a lot of work the first time it is run, and actually clears out this variable as a side-effect. So on your first run of CMake, the compiler flags are empty, and thereafter always contain what you set them to. (It's only the second time you run CMake which causes make to recompile all, not subsequent runs of CMake).
Try wrapping your project call with messages to see the effect:
message("CMAKE_CXX_FLAGS - ${CMAKE_CXX_FLAGS}")
project(Prj_${var_target})
message("CMAKE_CXX_FLAGS - ${CMAKE_CXX_FLAGS}")
Delete your CMakeCache.txt file (in your build root), then just run cmake .. repeatedly.
To fix this, move your set(CMAKE_CXX_FLAGS ...) to after the project command.
The second issue is that it's not recommended to set CMAKE_CXX_COMPILER in a CMakeLists.txt. Have a look at the comment below "Setting default compiler in CMake", and also the link there to CMake's FAQ entry How do I use a different compiler?