56

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?

Nathan Osman
  • 71,149
  • 71
  • 256
  • 361
  • 2
    I'd suggest that since you are creating a new process (from your comments) then the new process will be provided its own environemt, not inherit the environment of the main process. If you create a child process of the main process, then the environment should be inherited - but I know nothing of `cmake` so I may be way off here. You should however use `backslash` as directory-separators, not `/` as `/` is a switch-prefix. Sometimes `/` works happily, but it's not reliable. – Magoo Jan 27 '16 at 05:24

4 Answers4

65

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.

sakra
  • 62,199
  • 16
  • 168
  • 151
  • Does that add an implicit dependency to "somecommand" if it is the name of a target? Which is done if "somecommand" appears as first position – Johannes Schaub - litb Jul 03 '23 at 14:52
  • @JohannesSchaub-litb I don't think so. Use the `DEPENDS` option or `add_dependencies` to make the dependency explicit. – sakra Jul 03 '23 at 17:02
  • I figured that you can use `$` if it is a target. This will also automatically add a dependency, and resolves the target name to the path of the binary. – Johannes Schaub - litb Jul 06 '23 at 16:34
26

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.

Tsyvarev
  • 60,011
  • 17
  • 110
  • 153
  • 2
    what to write instead 3 dots ? What the "real_command"? What the "args"? Poor answer – ilw Jan 31 '19 at 18:06
  • The first argument for `add_custom_target()` is the target name. `` is a replacement for original `COMMAND` parameter and `args...` is the original command's arguments. – Tsyvarev Jan 31 '19 at 20:39
  • 2
    Without full example i'm totally not understand how this command work, sorry – ilw Jan 31 '19 at 21:02
  • 1
    If you don't understand what `add_custom_target` does, you may look into [documentation](https://cmake.org/cmake/help/v3.9/command/add_custom_target.html) or ask a new question on Stack Overflow. Current question post contains invocation `add_custom_target(newtarget somecommand)`, so both answers (sakra's one and my) implies that meaning of this invocation is known to the readers. – Tsyvarev Jan 31 '19 at 21:10
  • Cmake documentation without example - i still don't understand after spend many time! So, this answers not help me. – ilw Jan 31 '19 at 21:19
  • Вы вроде русский, https://ru.stackoverflow.com/questions/939302/clion-%d0%b8-cmake%d0%b8%d0%b7%d0%bc%d0%b5%d0%bd%d0%b8%d1%82%d1%8c-%d0%b4%d0%be%d0%b1%d0%b0%d0%b2%d0%b8%d1%82%d1%8c-%d0%bf%d0%b5%d1%80%d0%b5%d0%bc%d0%b5%d0%bd%d0%bd%d1%83%d1%8e-%d0%be%d0%ba%d1%80%d1%83%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f-%d0%bf%d0%b5%d1%80%d0%b5%d0%b4-%d0%b7%d0%b0%d0%bf%d1%83%d1%81%d0%ba%d0%be%d0%bc-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f – ilw Jan 31 '19 at 21:23
  • partially related – ilw Jan 31 '19 at 21:29
  • The quotes in wrapper.bat caused me problems. The resulting PATH variable value included the quotes which caused the first and last directories to not work correctly. Removing the quotes fixed the problem. – David Lechner Mar 30 '19 at 20:30
  • Thanks for the correction. I had wrote the script without checking it. Now the answer is fixed. – Tsyvarev Mar 30 '19 at 20:44
1

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.

Rob L
  • 2,351
  • 13
  • 23
0

The command works for me

add_custom_target(
    run
    DEPENDS ${PROJECT_NAME}
    COMMAND ASAN_OPTIONS=alloc_dealloc_mismatch=0 ./${PROJECT_NAME}
)
Sunding Wei
  • 1,803
  • 17
  • 12