Using constant folder with cmake

2019-08-09 18:51发布

问题:

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?

回答1:

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



回答2:

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:

  1. 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.

  2. 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()
    
  3. 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)
        ...
    
  4. 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


标签: cmake