CMake cannot find environment variables within WSL - cmake

Cmake cannot find an environment variable defined in /etc/profile from within WSL.
I've tried putting the variable in other file such as /etc/environment but could not get it to echo in WSL. Finally using /etc/profile I get an echo.
/etc/environment
TEST="/some/path"
echo $TEST
>>
/etc/profile
TEST="/some/path"
echo $TEST
>>/some/path
My CMakeLists.txt has the following lines:
set(TEST $ENV{TEST})
message(STATUS "Output: ${TEST}")
When building, it outputs
>>Output:
This question had a similar issue : Here. Nonetheless I've already tried using bash.exe -i. Also tried setting the next line in my CMakeLists.txt
set(ENV{BASH_ENV}"~/.bashrc")

Related

CMake do something when command fails

I use CMake. A custom build step saves error output when it fails.
FIND_PROGRAM (BASH bash HINTS /bin)
SET (BASH_CMD "my-script input.file >output.file 2>error.file")
ADD_CUSTOM_COMMAND (
OUTPUT output.file
COMMAND ${CMAKE_COMMAND} -E env ${BASH} -c "${BASH_CMD}"
...)
This works. If my-script fails for the given input.file then the stderr is saved in error.file, however when I run make and the target fails to build, the normal output does not make the location of error.file obvious. (The actual path of this file is generated in a tangly way.)
I don't want the noisy stderr to show in the terminal during make. I would like to do something like
MESSAGE ("input.file failed, see error.file")
(ideally coloured red or something) to be executed when the command for output.file failed.
Can I express this behaviour in CMakeLists.txt recipes?
Not sure about the highlighting, but you could create a cmake script file executing the command via execute_process, check it's error code and print a custom message in case there's an issue. The following example runs on windows, not on linux, but this should be sufficient for demonstration.
Some command that fails: script.bat
echo "some long message" 1>&2
exit 1
CMake script: execute_script_bat.cmake
execute_process(COMMAND script.bat RESULT_VARIBALE _EXIT_CODE ERROR_FILE error.log)
if (NOT _EXIT_CODE EQUAL 0)
message(FATAL_ERROR "command failed; output see ${CMAKE_SOURCE_DIR}/error.log")
endif()
CMakeLists.txt
add_custom_command(
OUTPUT output.file
COMMAND "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_SOURCE_DIR}/execute_script_bat.cmake")
Additional info can be passed by adding -D "SOME_VARIABLE=some value" arguments after "${CMAKE_COMMAND}"

How to run execute_process in cmake with wildcard?

Below is the CMakeLists.txt file, that tries to execute terminal command with wildcard character *.txt. Currently it gives error ls: cannot access '*.txt': No such file or directory. But, when I try to run without the wildcard it runs as expected, ie it lists the files in the current directory.
Is there any way I could use wild cards in execute_process?
cmake_minimum_required(VERSION 3.8)
project(foo)
execute_process(COMMAND ls *.txt
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE result
OUTPUT_VARIABLE curr_out
ERROR_VARIABLE curr_out
)
message(STATUS "${result} : ${curr_out}")
Filename expansion one of expansions done by your shell before the command is executed and it causes *.txt to expand to the list of files using special rules.
You have to run the shell to cause *.txt to expand.
COMMAND sh -c "ls *.txt"
Using file(GLOB tmp "*.txt") and passing tmp would be a more cmake-ish way.

Setting a NEW environment variable with CMake?

I am trying to set a new environment variable with CMake. Said environment variable does not exist prior to calling cmake and I don't need it to exist after my script has run. The problem is that I can modify existing environment variables, but I cannot create a new environment variable.
Here's a test I did:
$ echo $LD_LIBRARY_PATH
No output.
In CMake script:
message(STATUS "$ENV{LD_LIBRARY_PATH}")
No output.
In shell:
$ echo $LANGUAGE
en_CA:en
In CMake script:
message(STATUS "$ENV{LANGUAGE}")
en_CA:en
Obviously I can display an existing variable without issues, the problem is when I try to add a new one. Here's the second test I did:
In CMake script:
set(ENV{'LD_LIBRARY_PATH'} "potato")
message(STATUS "$ENV{LD_LIBRARY_PATH}")
No output
In CMake script:
set(ENV{'LANGUAGE'} "$ENV{LANGUAGE}:potato")
message(STATUS "$ENV{LANGUAGE}")
Output:
en_CA:en:potato
This is problematic to me. How can I go about setting a NEW environment variable?
As #Tsyvarev pointed out, there should not be quotes around LD_LIBRARY_PATH in set(ENV{'LD_LIBRARY_PATH'} "potato")

CMake file in script mode inheriting variables

How can I call to a cmake file in script mode (-P) from other cmake file, so this "cmake child" knows all variable of its parent? Because, if I have a lot of variables the child needs, I have to write many -D options, and I want to avoid it.
Example:
// CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
set(teststr "Hello World!")
add_custom_command(test
${CMAKE_COMMAND} -Dteststr=${teststr} -P test.cmake
)
// test.cmake
message("${teststr}")
$ cmake .
$ make test
Hello world!
Built target test
Works fine!. But, without "-Dteststr":
// CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
set(teststr "Hello World!")
add_custom_command(test
${CMAKE_COMMAND} -P test.cmake
)
// test.cmake
message("${teststr}")
$ cmake .
$ make test
Built target test
Of course, without -D option, the "teststr" variable, in test.cmake, is unset, and thus, the output is empty.
Any option to call test.cmake in "heritage mode", or something like that?
You can pass arguments to a script with cmake -P.
If you call:
cmake -P <script-file> <arg3> <arg4> <arg5> ...
then the variables CMAKE_ARGC, CMAKE_ARGV0, CMAKE_ARGV1, ... will be available for the script.
See documentation for CMAKE_ARGC and CMAKE_ARGV0.
The other way is to define variables, just like with the non-script cmake command. However there's one thing to be aware of: you need to define the variables before -P:
cmake -DVAR=VALUE -DFOO=BAR -P <script-file> <arg5> <arg6> ...
Now in the cmake VAR and FOO will be available.
Also, note that the numbering of the args after the script-file will be shifted accordingly.
There's no particularly easy way to do this that I know of.
You could write all the current variables in the parent CMakeLists.txt to a separate file and then include this in your test.cmake:
# CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
set(teststr "Hello World!")
set(CacheForScript ${CMAKE_BINARY_DIR}/CMakeCacheForScript.cmake)
file(WRITE ${CacheForScript} "")
get_cmake_property(Vars VARIABLES)
foreach(Var ${Vars})
if(${Var})
string(REPLACE "\\" "\\\\" ${Var} ${${Var}})
endif()
file(APPEND ${CacheForScript} "set(${Var} \"${${Var}}\")\n")
endforeach()
add_custom_target(test ${CMAKE_COMMAND} -P ${CMAKE_SOURCE_DIR}/test.cmake)
# test.cmake
include(${CMAKE_BINARY_DIR}/CMakeCacheForScript.cmake)
message("${teststr}")

How do I initialize a CMake variable with the result of a shell command

Is there a way to set a variable in a CMake script to the output of a shell command?
Something like SET(FOO COMMAND "echo bar") would come to mind
You want the execute_process command.
In your case, on Windows:
execute_process(COMMAND CMD /c echo bar OUTPUT_VARIABLE FOO)
or on Linux, simply:
execute_process(COMMAND echo bar OUTPUT_VARIABLE FOO)
In this particular case, CMake offers a cross-platform solution. CMake can itself be used to run commands that can be used on all systems, one of which is echo. To do this, CMake should be passed the command line arg -E. For the full list of such commands, run cmake -E help
Inside a CMake script, the CMake executable is referred to by ${CMAKE_COMMAND}, so the script needs to do:
execute_process(COMMAND ${CMAKE_COMMAND} -E echo bar OUTPUT_VARIABLE FOO)