Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In CMake, how can I find the directory of an included file?

Tags:

file

cmake

People also ask

Where does CMake look for include files?

cmake is searched first in CMAKE_MODULE_PATH , then in the CMake module directory. There is one exception to this: if the file which calls include() is located itself in the CMake builtin module directory, then first the CMake builtin module directory is searched and CMAKE_MODULE_PATH afterwards.

What is include directory in CMake?

The include directories are added to the INCLUDE_DIRECTORIES directory property for the current CMakeLists file. They are also added to the INCLUDE_DIRECTORIES target property for each target in the current CMakeLists file. The target property values are the ones used by the generators.

Where are CMake modules located?

Allowing CMakeLists files to make use of reusable modules enables the entire community to share reusable sections of code. For CMake, these sections are called cmake-modules and can be found in the Modules subdirectory of your installation.

Where do I find CMakeLists txt?

CMakeLists. txt is placed at the root of the source tree of any application, library it will work for. If there are multiple modules, and each module can be compiled and built separately, CMakeLists. txt can be inserted into the sub folder.


People have reported seemingly contradictory facts about how CMAKE_CURRENT_LIST_DIR behaves. Now I know the reason for the confusion:

First, in my Linux environment:

$ cd /path/to/home  
$ mkdir cmake-test  
$ cd cmake-test  
$ mkdir source  
$ mkdir source/subdirectory  
$ mkdir build  

I create these two files:

$ cat source/CMakeLists.txt  
include(subdirectory/foo.cmake)  

$ cat source/subdirectory/foo.cmake  
message("CMAKE_CURRENT_LIST_DIR is ${CMAKE_CURRENT_LIST_DIR}")  

CMake works as reported by Fraser and Robert Dailey:

$ cd build  
$ cmake ../source  
CMAKE_CURRENT_LIST_DIR is /path/to/home/cmake-test/source/subdirectory  
[...]  

However, I add a function to foo.cmake, which I call from CMakeLists.txt:

$ cat ../source/subdirectory/foo.cmake  
message("CMAKE_CURRENT_LIST_DIR is ${CMAKE_CURRENT_LIST_DIR}")  
function(bar)  
    message("CMAKE_CURRENT_LIST_DIR in bar() is ${CMAKE_CURRENT_LIST_DIR}")  
endfunction()  

$ cat ../source/CMakeLists.txt  
include(subdirectory/foo.cmake)  
bar()  

Then:

$ cmake ../source  
CMAKE_CURRENT_LIST_DIR is /path/to/home/cmake-test/source/subdirectory  
CMAKE_CURRENT_LIST_DIR in bar() is /path/to/home/cmake-test/source  
[...]  

So, the value of CMAKE_CURRENT_LIST_DIR in foo.cmake is not the same at the time foo.cmake is included and when bar() is called. This is according to the specification of CMAKE_CURRENT_LIST_DIR.

Here is one possible solution for accessing the directory of foo.cmake from within bar():

$ cat ../source/subdirectory/foo.cmake  
set(DIR_OF_FOO_CMAKE ${CMAKE_CURRENT_LIST_DIR})  
function(bar)  
    message("DIR_OF_FOO_CMAKE in bar() is ${DIR_OF_FOO_CMAKE}")  
endfunction()  

after which I get the behavior I was looking for:

$ cmake ../source  
DIR_OF_FOO_CMAKE in bar() is /path/to/home/cmake-test/source/subdirectory  
[...]  

See CMAKE_CURRENT_LIST_DIR:

Full directory of the listfile currently being processed.

As CMake processes the listfiles in your project this variable will always be set to the directory where the listfile which is currently being processed (CMAKE_CURRENT_LIST_FILE) is located. The value has dynamic scope. When CMake starts processing commands in a source file it sets this variable to the directory where this file is located. When CMake finishes processing commands from the file it restores the previous value. Therefore the value of the variable inside a macro or function is the directory of the file invoking the bottom-most entry on the call stack, not the directory of the file containing the macro or function definition.

Example

I have the following structure:

C:\Work\cmake-test\CMakeLists.txt
C:\Work\cmake-test\subfolder\test.cmake

In my CMakeLists.txt:

include( subfolder/test.cmake )

In my test.cmake:

message( "Current dir: ${CMAKE_CURRENT_LIST_DIR}" )

The result I get when I run CMake from C:\Work\cmake-test is:

Current dir: C:/Work/cmake-test/subfolder


In CMake 3.17, you have a new variable available, called CMAKE_CURRENT_FUNCTION_LIST_DIR, which can be used inside a function. It is undefined outside of a function definition.

function(foo)
  configure_file(
    "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/some.template.in"
    some.output
  )
endfunction()

Prior to CMake 3.17, CMAKE_CURRENT_FUNCTION_LIST_DIR functionality has to be approximated with CMAKE_CURRENT_LIST_DIR by the following workaround, taken from CMake documentation:

set(_THIS_MODULE_BASE_DIR "${CMAKE_CURRENT_LIST_DIR}")

function(foo)
  configure_file(
    "${_THIS_MODULE_BASE_DIR}/some.template.in"
    some.output
  )
endfunction()

The include() command searches for modules in ${CMAKE_MODULE_PATH} first and then in CMake Modules dir.

So you can just check for file presence with if(EXISTS ${CMAKE_MODULE_PATH}/foo.cmake) and if(EXISTS ${CMAKE_ROOT}/Modules/foo.cmake).