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

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