I have a constant MYPROJECT
in my ~/.bashrc
file:
export MYPROJECT = /home/loom/my_project
I can see the constant is defined in the terminal:
loom@loom$ ls -ld $MYPROJECT
drwxr-xr-x 25 loom loom 4096 Jul 21 22:12 /home/loom/my_project
I tried to use the constant in my CMakeLists.txt
:
add_executable(booo src/main.cpp ${MYPROJECT}/foo/trunk/bar/File.h)
However, it produces an error:
CMake Error at CMakeLists.txt:17 (add_executable):
Cannot find source file:
/foo/trunk/bar/File.h
Tried extensions .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp
.hxx .in .txx
CMake Error: CMake can not determine linker language for target: booo
CMake Error: Cannot determine link language for target "booo".
It is processed without errors if I have used explicit path without $MYPROJECT
:
add_executable(booo src/main.cpp /home/loom/my_project/foo/trunk/bar/File.h)
How to use path defined in .bashrc
in cmake?
Instead of
add_executable(booo src/main.cpp ${MYPROJECT}/foo/trunk/bar/File.h)
use
add_executable(booo src/main.cpp $ENV{MYPROJECT}/foo/trunk/bar/File.h)
The CMake documentation states:
Use the syntax $ENV{VAR} to read environment variable VAR. See also
the set() command to set ENV{VAR}.
https://cmake.org/cmake/help/v3.4/variable/ENV.html
Turning my comment into an answer
There are a lot of ways you could do this in CMake. Out of bad experiences with using environment variables directly inside CMake projects (they have to be valid not only during the first call to CMake configuration/generation but also later during all consecutive builds), I would recommend to transfer your constant into a cached CMake variable.
I'm using one of the following ways in my projects:
Injecting MYPROJECT
CMake via its -D option
, e.g.
cmake -DMYPROJECT:PATH=$MYPROJECT ..
Then CMake would cache this value in its own MYPROJECT
internal variable.
When you get values from the "outside" you should think about what to do if no value is provided or it's not a valid directory. Throwing a fatal error and/or retry with a default value?
The following example shows only transformation steps and sanity checks (no default value retry):
if (NOT DEFINED MYPROJECT OR NOT IS_DIRECTORY MYPROJECT)
file(TO_CMAKE_PATH "$ENV{MYPROJECT}" _ENV_MYPROJECT_REL)
get_filename_component(_ENV_MYPROJECT "${_ENV_MYPROJECT_REL}" ABSOLUTE)
if (NOT _ENV_MYPROJECT)
message(FATAL_ERROR "Environment variable MYPROJECT not provided.")
else()
set(MYPROJECT "${_ENV_MYPROJECT}" CACHE INTERNAL "")
endif()
endif()
Using find_path()
, which will also cache its result:
find_path(
MYPROJECT_INCLUDE_DIR
NAMES File.h
PATHS ENV MYPROJECT
/home/loom/my_project
PATH_SUFFIXES foo/trunk/bar
)
if (NOT MYPROJECT_INCLUDE_DIR)
...
Or - assuming your external project does not only consists of header files but also libraries like foo.a
- following CMake's A Sample Find Module and extending the find_path()
code from above by:
find_library(
MYPROJECT_LIBRARY
NAMES foo
PATHS ENV MYPROJECT
PATH_SUFFIXES foo/lib
)
if(MYPROJECT_INCLUDE_DIR AND MYPROJECT_LIBRARY AND NOT TARGET MyProject::MyProject)
add_library(MyProject::MyProject UNKNOWN IMPORTED)
set_target_properties(
MyProject::MyProject
PROPERTIES
IMPORTED_LOCATION "${MYPROJECT_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${MYPROJECT_INCLUDE_DIR}"
)
endif()
Now you can use it directly as any other CMake target with
add_executable(booo src/main.cpp)
target_link_libraries(booo MyProject::MyProject)
More References
- What's the CMake syntax to set and use variables?
- preferred cmake project structure