CMAKE override variable set in CMakeLists.txt via commandline - cmake

I have a CMakeLists.txt with the following in it, that I can not modify:
set(BUILD_SHARED_LIBS ON)
I want to override this variable use the commandline. I tried this:
cmake -UBUILD_SHARED_LIBS -DBUILD_SHARED_LIBS=OFF ..
but it has no effect. Is there any way to tell cmake to use a value from the commandline instead of this value?
Note: I am aware that using the cache like shown below would solve the problem, but as I cannot edit the file, that sadly is not an option:
set(BUILD_SHARED_LIBS ON CACHE BOOL "library build mode")

Using command line you cannot override setting of the normal (non-cached) variable.
If you pass a variable via command line, then it is always a cache variable. At the time when normal flavor of the variable is set in the CMakeLists.txt, both flavors exist. But when a variable is dereferenced, CMake prefers normal flavor to the cached one. See more in the variables' documentation.

Related

CMake if(DEFINED MY_COMPILE_DEF) does not work. How can I use precompile definition as conditional?

I'm trying to use a compile definition as a conditional to build a Gtest executable. The problematic CMake code is as follows:
add_compile_definitions(TEST_BENCH)
if(DEFINED TEST_BENCH)
enable_testing()
endif()
This does not work though. I've read a few similar questions and answers that have been regarding the use of ${my_var} syntax which is not the case in my code.
Can compile definitions be used in conditionals, and if so how?
Use a cmake (cache) variable, which will also allow users to configure your project properly.
set(TEST_BENCH OFF CACHE BOOL "Enables testing of your project")
if(TEST_BENCH)
add_compile_definition(TEST_BENCH)
enable_testing()
endif()
Then the user (and you) can configure your project according to their needs with the help of ccmake or cmake-gui or with cmake -DTEST_BENCH=ON. I believe target_compile_definitions is generally preferred over global add_compile_definitions.
Still, I wouldn't advise it, you can match COMPILE_DEFINITIONS variable that is modified by add_compile_definition with the TEST_BENCH and that way check if the macro is set or not.
In short, add_compile_definitions() is for source files while set() is for CMake variables. if(DEFINED) is to check your CMake or env variables thus you need to use set().
Credit to #squareskittles
https://stackoverflow.com/a/61815468/2324483

What's the effect of export CMAKE_PREFIX_PATH=...?

When google-ing export CMAKE_PREFIX_PATH, you will often find the suggestion to cure the problem that CMake doesn't find this or that package by setting an environment variable:
export CMAKE_PREFIX_PATH=/path/to/package
I've convinced myself that setting this environment variable has the effect of appending /path/to/package to the list of paths specified in the CMake call using
cmake -DCMAKE_PREFIX_PATH="/path/to/package1;..." .
(I've tried this on macOS Catalina and Ubuntu 18.04 using CMake 3.15.5 and 3.16.0, respectively.)
The documentation doesn't mention any of this. In fact, it simply states:
By default this [CMAKE_PREFIX_PATH] is empty. It is intended to be set by the project.
(see CMake documentation). There's no mention of the effect of setting the environment variable.
This raises two questions:
Is this effect of setting the environment variable intended? Where is it documented? Is this the canonical way of adding prefix paths to all projects build in the environment?
As the documentation says, "It [CMAKE_PREFIX_PATH] is intended to be set by the project". Is there any reason why there shouldn't be a way to set a default CMAKE_PREFIX_PATH?
The effect of setting it as an environment variable is, by default, no effect. CMake defines it's own variables (those set with the set() command, or the -D command line argument) in a file called CMakeCache.txt in the root of your CMake project. Those are the variables which will affect your cmake script.
In order to access and environment variable in CMake, you need to specify the ENV Syntax
$ENV{VAR}
Hence, even if you set a CMAKE_PREFIX_PATH environment variable, it will have no effect unless you explicitly use it in you CMakeLists.txt.
(Edit: I have only verified this behavior on Windows 10 with CMake 3.16.3)
Setting the CMAKE_PREFIX_PATH environment variable works in finding things with function find_file, find_path, etc.
Just because by default these functions use the CMAKE_PREFIX_PATH environment variable as a path hint as well as the CMAKE_PREFIX_PATH variable set via -DCMAKE_PREFIX_PATH=xx or set function.

How to load additional parameter in CMAKE using ${CMAKE_CURRENT_SOURCE_DIR}?

I want to pass an additional parameter to cmake relative to where it is.
My libraries are in:
C:/bla/imgui
C:/bla/imgui-integration
From
C:/bla/imgui-integration/build folder I want to refer to C:/bla/imgui in a parameter named IMGUI_DIR :
cmake .. -DIMGUI_DIR="${CMAKE_CURRENT_SOURCE_DIR}/../imgui"
The problem is that I tried every combination of :
-DIMGUI_DIR="${CMAKE_CURRENT_SOURCE_DIR}/../../imgui"
-DIMGUI_DIR="${CMAKE_CURRENT_SOURCE_DIR}/imgui"
And none of them works.
Only works if I directly use:
-DIMGUI_DIR="C:/bla/imgui"
What am I doing wrong exactly?
As Tsyvarev said in a comment:
CMAKE_CURRENT_SOURCE_DIR is a CMake variable, which is set by CMake
when it interprets your project. But when running cmake <..> you use
shell scripting. You need to use abilities of the shell for prepare
needed parameters
I can't use cmake variables in the shell that will be interpreted inside cmake.

CMake requires me to manually copy CMAKE_INCLUDE_PATH

I'm trying to test a project on a cluster where I can't install some libraries in the default locations, so I'm trying to override the default CMake search path with the CMAKE_INCLUDE_PATH environment variable.
Unfortunately it doesn't seem to be picked up. I'm having to set the path explicitly with
include_directories("." $ENV{CMAKE_INCLUDE_PATH})
but this seems like a bit of a hack. So I have two questions:
Is this expected behavior?
Is there some cleaner way to add a directory to CMake's include path via an environment variable?
First of all, there is a predefined cmake variable CMAKE_INCLUDE_PATH variable that is a ";-list of directories specifying a search path for the find_file() and find_path() commands." This is not meant to specify the compiler include path.
Secondly, good use of cmake should not involve environment variables. To the extent you can, you should use the conventional cmake find_package to configure your build paths. When you need to explicitly add a path to the compiler include search path, then, yes, include_directories is what you need. But you should a cmake cache variable rather than environment variable. For details on setting a cache variable, see this page, which says
set(<variable> <value>... CACHE <type> <docstring> [FORCE])
For your example this becomes:
set(MYINCLUDE /usr/local/foo/include CACHE PATH "path to the foo include directory")
include_directories(${MYINCLUDE})
Then if you need to override the default /usr/local/foo/include, you may specify it with the command line used when invoking cmake; e.g., cmake -DMYINCLUDE=/home/foo/include .

CMake generated makefile does not expand all `make` variables

I have a projects that consists of modules that are built separately. Some modules use make only, others use cmake.
The top project has a makefile, which is used to trigger the build of the submodules. The makefile at the top defines make variables for pathes to libs, includes, and binaries. The submodules then use these variables.
My problem is that I cannot pass all these make variables to the projects that use cmake.
For the include directory, this work-around in CMakeLists.txt works:
INCLUDE_DIRECTORIES("/$(INCLUDE_DIR)")
The string is passed as is all the way to the generated makefile, and is then expanded by make upon building. The leading slash is needed. Without it, the content of INCLUDE_DIR gets prefixed by the cmake project root (it is then considered a relative path).
This solution does not work for linking:
LINK_DIRECTORIES("/$(LIB_DIR)")
The link command that I see upon building has the literal string -L/$(LIB_DIR). Removing the leading slash gives a warning about relative paths, and the link command has still the unexpanded $LIB_DIR.
How do I make sure that the expansion works for the make variable LIB_DIR passed though cmake to the generated makefile? Since it is make that runs the linker (I think?) I don't see why it wouldn't expand.
Is there another, less ugly solution, solution for fixing it for INCLUDE_DIR as well?
A backup solution is to let the top makefile define CMAKE variables. It should work fine, and is probably what I'll do if I can't make it work otherwise. But it would be nice to just define these variables once and make everything else take them into account.
One option is to use an environment variable to set a CMake variable. For example:
set (INCLUDE_DIR $ENV{INCLUDE_DIR})
then use the CMake variable like other CMake variables:
INCLUDE_DIRECTORIES(${INCLUDE_DIR})
If you want the variable to show up in cmake-gui or ccmake you can put it in the cache using the following:
set(INCLUDE_DIR $ENV{INCLUDE_DIR} CACHE PATH "An environment variable containing a path" FORCE)
for my projects I have wrapped the concept in a cmake function:
function( define_from_environment VariableName PackageName)
if (NOT DEFINED ${VariableName})
message( STATUS "${VariableName}=$ENV{${VariableName}}" )
if (NOT "$ENV{${VariableName}}" STREQUAL "")
set(${VariableName} $ENV{${VariableName}} CACHE PATH "Set the path variable ${VariableName} for ${PackageName}" FORCE)
endif (NOT "$ENV{${VariableName}}" STREQUAL "")
endif(NOT DEFINED ${VariableName})
endfunction( define_from_environment)
An example usage of this CMake function is
define_from_environment(GDCM_DIR GDCM)
which sets the CMake variable GDCM_DIR to a CMake cache variable if the environment variable GDCM_DIR is set.