Setting environment variable in cmake - cmake

I am trying to move from an own written tool to cmake for Windows to simplify our build environment.
We have a tool in the build process that requires to have set environment variables. I would like to set them with cmake but don't know how. What I have tried:
set(ENV{MYENVVAR} "My-Content")
I would expect that I can read this environment variable again with
message($ENV{MYENVVAR})
But this does not work. Even setting a variable before invoking cmake (instead of setting it in cmake) does not help, I cant read the variable in cmake.
What do I do wrong?
Edit:
I do invoke cmake again after changing CMakeLists.exe.
I do set environment variables with set MYENVVAR=My-Content in Windows cmd.exe and then invoke cmake from exactly this console.
cmake is version 3.20.0 for Windows.

You're going to need to produce a minimal, reproducible example. Here's my best attempt based on your question and unfortunately, the best I can say is "works for me":
alex#alex-ubuntu:~$ export MYENVVAR=FooBarBaz
alex#alex-ubuntu:~$ cat test.cmake
cmake_minimum_required(VERSION 3.20)
message($ENV{MYENVVAR})
set(ENV{MYENVVAR} "My-Content")
message($ENV{MYENVVAR})
alex#alex-ubuntu:~$ cmake -P test.cmake
FooBarBaz
My-Content
alex#alex-ubuntu:~$ echo $MYENVVAR
FooBarBaz
So CMake can both read the environment variable and write to it in-process, but it does not affect the controlling process's (in this case bash; in your case cmd.exe) environment.

Related

How to set the PATH environment variable for CMAKE ExternalProject_Add_Step? [duplicate]

Perhaps I am missing something obvious, but I can't seem to figure out how to explicitly set environment variables that can be seen by processes launched through add_custom_target().
I tried the following:
set(ENV{PATH} "C:/Some/Path;$ENV{PATH}")
add_custom_target(newtarget somecommand)
Unfortunately, the %PATH% environment variable appears unchanged to somecommand. (I have set up a Gist that reproduces the problem here.)
What am I doing wrong?
A portable way of setting environment variables for a custom target is to use CMake's command-line tool mode command env:
env [--unset=NAME]... [NAME=VALUE]... COMMAND [ARG]...
Run command in a modified environment.
E.g.:
add_custom_target(newtarget ${CMAKE_COMMAND} -E env NAME=VALUE somecommand)
Also see Command Line Tool Mode.
You set environment variable at configuration step, but command specified for add_custom_target is executed at build step. See also CMake FAQ: How can I get or set environment variables?
[...]
environment variables SET in the CMakeLists.txt only
take effect for cmake itself (configure-time),
so you cannot use this method to set an environment variable
that a custom command might need (build-time).
Barring environment variable support by various CMake commands
(e.g. add_custom_command(), currently not supported yet),
an acceptable workaround may be to invoke shell scripts instead
which wrap the commands to be executed.
Currently add_custom_target (and others commands, which define actions for build step, e.g. add_custom_command) doesn't support simple setting environment variables. As adviced in this bugreport, for set variable's value without spaces on Linux you may prepend command with "VAR=VAL" clauses. For general cases you may prepare wrapper script, which setups environment and run actual command:
On Windows:
wrapper.bat:
#ECHO OFF
set PATH=C:\\Some\\Path;%PATH%
%*
CMakeLists.txt:
add_custom_target(...
COMMAND cmd /c ${CMAKE_CURRENT_SOURCE_DIR}/wrapper.bat <real_command> args...
)
On Linux:
wrapper.sh:
export "PATH=/Some/Path:$PATH"
eval "$*"
CMakeLists.txt:
add_custom_target(...
COMMAND /bin/sh ${CMAKE_CURRENT_SOURCE_DIR}/wrapper.sh <real_command> args...
)
If value of variable depends on configuration, you may configure wrapper script with configure_file.
UPDATE:
As noted by #sakra, env tool mode of cmake executable can be used as a wrapper script:
add_custom_target(...
COMMAND ${CMAKE_COMMAND} -E env "PATH=C:/Some/Path;$ENV{PATH}" <real_command> args...
)
This way is available since CMake 3.2.
A late answer to this, but perhaps it will help somebody. We use the && operator to do this in our cmake files on Windows.
set(MY_COMMAND set "PATH=C:\\some\\path\;%PATH%"&&
somecommand)
add_custom_target(TARGET newtarget COMMAND ${MY_COMMAND})
Note that you cannot have a space before the && (for reasons I don't understand completely). Also, spaces are a real pain to deal with here, so I don't know if I have it right if c:\some\path has spaces. It does work if your original path has spaces.
The command works for me
add_custom_target(
run
DEPENDS ${PROJECT_NAME}
COMMAND ASAN_OPTIONS=alloc_dealloc_mismatch=0 ./${PROJECT_NAME}
)

Is it possible to alter CMAKE_MODULE_PATH from CMake commandline?

Edit: The accepted answer actually shows that it is pretty normally possible to set CMAKE_MODULE_PATH as any other CMake variable e.g. via the -DCMAKE_MODULE_PATH path CLI parameter. It seems that in my case there is some included CMake script that calls set(CMAKE_MODULE_PATH /library_path), which erases all previous paths set to the variable. That's why I couldn't get the variable to do what I wanted it to do. I'll leave the question here in case anybody else faces this kind of situation.
I'm building a (3rd party) project that uses the Protobuf library (but this question is general). My system has a system-wide install of a newer version of Protobuf than the project is compatible with. So I've downloaded and compiled from source an older version of Protobuf.
The project uses CMake, and in its CMakeLists.txt, there is:
find_package(Protobuf REQUIRED)
Which, however, finds the (incompatible) system install. Of course, CMake doesn't know about my custom build of Protobuf. But how do I tell it?
I've created a FindProtobuf.cmake file in, say, ~/usr/share/cmake-3.0/Modules/ and want the build process to use this one for finding Protobuf. But I haven't succeeded forcing CMake to pick up this one and not the system one. I think the reason is quite obvious from the CMake docs of find_package:
The command has two modes by which it searches for packages: “Module” mode and “Config” mode. Module mode is available when the command is invoked with the above reduced signature. CMake searches for a file called Find<package>.cmake in the CMAKE_MODULE_PATH followed by the CMake installation. If the file is found, it is read and processed by CMake. ... If no module is found and the MODULE option is not given the command proceeds to Config mode.
So until I succeed to change CMAKE_MODULE_PATH, CMake will just pick up the FindProtobuf.cmake installed to the default system path and won't ever proceed to the "Config" mode where I could probably make use of CMAKE_PREFIX_PATH.
It's important for me to not edit the CMakeLists.txt since it belongs to a 3rd party project I don't maintain.
What I've tried (all without success):
calling CMAKE_MODULE_PATH=~/usr/share/cmake-3.0/Modules cmake ... (the env. variable is not "transferred" to the CMake variable with the same name)
calling cmake -DCMAKE_MODULE_PATH=~/usr/share/cmake-3.0/Modules ... (doesn't work, probably by design?)
calling Protobuf_DIR=path/to/my/protobuf cmake ... (the project doesn't support this kind of override for Protobuf)
It seems to me that, unfortunately, the only way to alter the CMAKE_MODULE_PATH used by find_package is to alter it from within CMakeLists.txt, which is exactly what I want to avoid.
Do you have any ideas/workarounds on how not to touch the CMakeLists.txt and still convince find_package to find my custom Protobuf?
For reference, the CMake part of this project is on github .
As a direct answer to your question, yes, you can set CMAKE_MODULE_PATH at the command line by running cmake -DCMAKE_MODULE_PATH=/some/path -S /path/to/src -B /path/to/build.
But that probably doesn't do what you want it to do; see below.
The Bitbucket link you supplied is dead, but here are a few suggestions that might help.
Avoid writing your own find modules, especially when the upstream supplies CMake config modules.
You can direct CMake to your custom Protobuf installation by setting one of CMAKE_PREFIX_PATH or Protobuf_ROOT (v3.12+) to the Protobuf install root.
You can tell find_package to try CONFIG mode first by setting CMAKE_FIND_PACKAGE_PREFER_CONFIG to true (v3.15+). Then set Protobuf_DIR to the directory containing ProtobufConfig.cmake.
Failing all else, you can manually set the variables documented in CMake's own FindProtobuf module, here: https://cmake.org/cmake/help/latest/module/FindProtobuf.html
All these variables can be set at the configure command line with the -D flag.
There are very few environment variables that populate CMake variables to start and I would avoid relying on them. There is an exhaustive list here: https://cmake.org/cmake/help/latest/manual/cmake-env-variables.7.html. CMAKE_MODULE_PATH is not among them.

cmake: setting default values for arguments

My UNIX Makefile is as follows:
param=0
run:
./foo -r "fun($(param))"
So if I do make run, I get ./foo - r "fun(0)" and
for make run param=10, I get ./foo -r "fun(10)".
Now I want to generate similar Makefile using cmake.
add_custom_target(
run
./foo -r "\"fun($(param))\""
)
How do I set the default value for param within cmake configuration file?
The concept in CMake is a bit different. You can define "cache variables" (basically variables that are remembered for subsequent builds in the same build dir, and can be customized by users) that come with default values and documentation strings and such. These can then be changed either by passing -D name:type=value options to cmake, or using one of the friendlier frontends (e.g. ccmake, the curses UI for CMake).
Example based on your question:
SET(param 0 CACHE STRING "Test variable defaulting to '0'")
# ...
add_custom_target(run ./foo -r "\"fun(${param})\"")
You'll find more details in the exhaustive docs for CMake.
PS. this is for variables inside CMake and specifically CMakeLists.txt itself; the possibility to change the value is not carried over into the generated Makefile as far as I can tell. I'm not sure that's possible in the first place because it probably wouldn't be compatiable with all of the targets supported by CMake (e.g. Visual Studio projects and what not). In any case, CMake doesn't seem to have been designed for generating build files used independently of CMake.
Use
set (projectname_param 0)
to set it.

How can I get cmake command from cmake-gui?

I use cmake-gui to configure OpenCV, and I want to use same configure on some other computer.
Cause I use ssh without X forwarding, so I can't use cmake-gui to configure again.
I don't kown how to use cmake to complete my configure, so I wonder that cmake-gui can generate the command use for cmake?
Is there anyway to do this?
There is an option called: Tools-> Show my Changes which displays exactly what you have configured relating to the original configuration. One version are the copy&paste command line parameters and the other version is nicely human readable.
By default you cannot do what you want because that path is stored in CMAKE_COMMAND which is an INTERNAL variable so it is not visible in the GUI. You can manually read it from the cache using a command like grep CMAKE_COMMAND CMakeCache.txt | cut -d = -f 2. Alternatively you can update your CMakeLists.txt to put the value of CMAKE_COMMAND in the cache so that you can read it using the GUI. For example:
set(USED_CMAKE_PATH ${CMAKE_COMMAND} CACHE FILEPATH
"The path to the CMake executable used to configure this project" FORCE)
Additionally if you are using the "Unix Makefiles" generator there are two targets provided for this:
rebuild_cace which is equivalent to cmake .
edit_cache which is equivalent to ccmake . or cmake-gui . depending upon your install.
Note: I used CMake version 2.8.10.2 to test this, but I expect it to work with any version.

Can I add an 'environment variable' in CMake GUI Wizard?

A CMake script I am using expects an environment variable XXX_HOME to be set, but I don't have this and don't want to add it.
Is there a way to trick CMake into thinking this variable exists, with a value I set, in the CMake cache - ideally using the CMake GUI - so I don't have to edit the CMake scripts? I tried adding a setting in the GUI XXX_HOME = ... but it didn't work.
Can't you run cmake-gui from an environment with the environment variable set? I do this all the time on windows using batch files and shortcuts to the visual studio command prompt so that I can build for different compilers / different bit depths in totally different build trees with the same source.
In linux you also should be able to set the variable on the same line as cmake-gui. Like this XXX_HOME="/usr/src/xxx" cmake-gui