niosus
niosus

Reputation: 758

cmake execute_process cannot find source command

I have recently bumped into quite an interesting issue with cmake. The problem is the following:

I have a CMakeLists.txt that defines a fairly simple project. I want to be able to set a linux environment variable while building the project. For this I want to call a tiny script var_set.sh that does it. It looks like this:

#!/bin/bash
MY_VAR=$1
export MY_VAR

In the CMakeLists.txt I run it as follows:

execute_process(COMMAND source var_set.sh VALUE
            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
            RESULT_VARIABLE variable_RESULT)
message(STATUS ${variable_RESULT})
message(STATUS $ENV{MY_VAR})

the output of this is

-- No such file or directory

I believe the problem is the source command. If I use ./var_set.sh instead of source var_set.sh the script actually gets executed, but then, of course, I am unable to get the variable I want exported.

Does anybody know what can be the reason for this behavior?

UPD:

I come to an understanding that it is probably not at all possible to achieve what I originally want.

The original idea and motivation are the following. We have a relatively big project using ROS. It uses catkin_make to build everything. What it basically does is calles a cmake for all packages it finds in the subfolders in an order defined by CMakeLists.txt and a package.xml file (it is not important how this one looks like here). It also provides an overridden way to use find_package etc.

The problem is that there is a significant part of the code that is written in the way I have no means of influencing. This part relies on a library G2O (graph optimization) and the G2O package is not "catkinized", i.e. catkin has no means of knowing what libraries are provided.

G2O by itself defines quite some number of libraries and we are able to find them through FindG2O.cmake files (but if a library is, say, "core" we know it by the name "G2O_CORE_LIBRARY" set in FindG2O.cmake). We also use an environmental variable "G2O_ROOT" to point to the current g2o installation.

My idea was to set this environment variable while building the G2O (using a catkin meta package wrapped around it) and make this knowledge available to whoever gets built afterwards because this would enable an easy usage of FindG2O.cmake.

I understand this explanation is quite messy. Please ask if something is not clear.

It seems like what I am trying to achieve is not possible as catkin_make probably calls different cmake in a different subprocess and then, of course, I can do nothing to modify the parent process.

Upvotes: 5

Views: 5762

Answers (2)

maarten
maarten

Reputation: 376

Use the OUTPUT_VARIABLE option of execute_process.

Make your script look like this:

#!/bin/bash
MY_VAR=$1
echo "$MY_VAR"

And use it in your CMakeLists.txt as follows:

cmake_minimum_required(VERSION 2.6)
execute_process(COMMAND sh "var_set.sh" "VALUE" "VALUE2"
            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
            RESULT_VARIABLE variable_RESULT
            OUTPUT_VARIABLE variable_OUTPUT
)

message(STATUS ${variable_RESULT})
message(STATUS ${variable_OUTPUT})

The output of the CMake configuration step is then:

-- The C compiler identification is GNU 5.1.1
-- The CXX compiler identification is GNU 5.1.1
-- Check for working C compiler: /usr/lib64/ccache/cc
-- Check for working C compiler: /usr/lib64/ccache/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/lib64/ccache/c++
-- Check for working CXX compiler: /usr/lib64/ccache/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- 0
-- VALUE

-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/out

A drawback to this approach is that you will have to suppress all unwanted output in your script. Alternatively, use OUTPUT_FILE and post-process the file.

Upvotes: 0

zaufi
zaufi

Reputation: 7129

You just do it wrong. Even if source would work (but it can't because it is bash internal command and not a real binary/executable present in your filesystem), it wouldn't affect anything! Because cmake starts a child process (by means of execute_process()) and it will be terminated, w/ execution results available in corresponding variables. Setting any environment variables in a child process will not affect the parent environment.

So, you'd better to use $ENV{blah} to set desired variables. Or (better) just use CMake variables... there is a lot of ways to do that. Just give more details what do you want to implement.

Upvotes: 3

Related Questions