3.7.3. Common variables

Since every CMakeLists.txt is a listfile hence the common listfile variables like CMAKE_CURRENT_LIST_DIR or CMAKE_CURRENT_LIST_FILE are available. For CMakeLists.txt added by add_subdirectory there will be no difference between CMAKE_CURRENT_LIST_DIR and CMAKE_CURRENT_SOURCE_DIR, also CMAKE_CURRENT_LIST_FILE will be always a full path to CMakeLists.txt. However it’s not always true for other types of CMake listfiles.

3.7.3.1. CMAKE_CURRENT_LIST_*

Information about any kind of listfile can be taken from CMAKE_CURRENT_LIST_FILE and CMAKE_CURRENT_LIST_DIR variables:

# Top-level CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(foo NONE)

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")

include(mymodule)
# cmake/mymodule.cmake

message("Full path to module: ${CMAKE_CURRENT_LIST_FILE}")
message("Module located in directory: ${CMAKE_CURRENT_LIST_DIR}")
[cmake-sources]> rm -rf _builds
[cmake-sources]> cmake -Hpath-to-module -B_builds
Full path to module: /.../cmake-sources/path-to-module/cmake/mymodule.cmake
Module located in directory: /.../cmake-sources/path-to-module/cmake
-- Configuring done
-- Generating done
-- Build files have been written to: /.../cmake-sources/_builds

3.7.3.2. CMAKE_CURRENT_LIST_DIR vs CMAKE_CURRENT_SOURCE_DIR

The difference between those two variables is about type of information they provide. A CMAKE_CURRENT_SOURCE_DIR variable describes a source tree and should be read as a current source tree directory. Here is a list of sibling variables describing source/binary trees:

  • CMAKE_SOURCE_DIR

  • CMAKE_BINARY_DIR

  • PROJECT_SOURCE_DIR

  • PROJECT_BINARY_DIR

  • CMAKE_CURRENT_SOURCE_DIR

  • CMAKE_CURRENT_BINARY_DIR

The next files always exist:

  • ${CMAKE_SOURCE_DIR}/CMakeLists.txt

  • ${CMAKE_BINARY_DIR}/CMakeCache.txt

  • ${PROJECT_SOURCE_DIR}/CMakeLists.txt

  • ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt

A CMAKE_CURRENT_LIST_DIR variable describes a current listfile (it is not necessarily CMakeLists.txt, it can be somemodule.cmake), and should be read as a directory of a currently processed listfile, i.e. directory of CMAKE_CURRENT_LIST_FILE. Here is another list of sibling variables:

  • CMAKE_CURRENT_LIST_FILE

  • CMAKE_CURRENT_LIST_LINE

  • CMAKE_CURRENT_LIST_DIR

  • CMAKE_PARENT_LIST_FILE

3.7.3.3. Example

Assume we have an external CMake module that calculates SHA1 of CMakeLists.txt and saves it with some custom info to a sha1 file in a current binary directory:

# External module: mymodule.cmake

file(READ "${CMAKE_CURRENT_LIST_DIR}/info/message.txt" _mymodule_message)
file(SHA1 "${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt" _mymodule_cmakelists_sha1)
file(
    WRITE
    "${CMAKE_CURRENT_BINARY_DIR}/sha1"
    "${_mymodule_message}\nsha1(CMakeLists.txt) = ${_mymodule_cmakelists_sha1}\n"
)

mymodule.cmake uses some resource. Resource info/message.txt is a file with content:

Message from external module

To read this resource we must use CMAKE_CURRENT_LIST_DIR because file located in same external directory as module:

# External module: mymodule.cmake

file(READ "${CMAKE_CURRENT_LIST_DIR}/info/message.txt" _mymodule_message)
file(SHA1 "${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt" _mymodule_cmakelists_sha1)
file(
    WRITE
    "${CMAKE_CURRENT_BINARY_DIR}/sha1"
    "${_mymodule_message}\nsha1(CMakeLists.txt) = ${_mymodule_cmakelists_sha1}\n"
)

To read CMakeLists.txt we must use CMAKE_CURRENT_SOURCE_DIR because CMakeLists.txt located in source directory:

# External module: mymodule.cmake

file(READ "${CMAKE_CURRENT_LIST_DIR}/info/message.txt" _mymodule_message)
file(SHA1 "${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt" _mymodule_cmakelists_sha1)
file(
    WRITE
    "${CMAKE_CURRENT_BINARY_DIR}/sha1"
    "${_mymodule_message}\nsha1(CMakeLists.txt) = ${_mymodule_cmakelists_sha1}\n"
)

Subdirectory boo uses this module:

# boo/CMakeLists.txt

message("Processing boo/CMakeList.txt")

add_subdirectory(baz)
add_subdirectory(bar)

include(mymodule)
[cmake-sources]> rm -rf _builds
[cmake-sources]> cmake -Hwith-external-module/example -B_builds -DCMAKE_MODULE_PATH=`pwd`/with-external-module/external
Top level CMakeLists.txt
Processing foo/CMakeList.txt
Processing boo/CMakeList.txt
Processing boo/baz/CMakeLists.txt
Processing boo/bar/CMakeLists.txt
-- Configuring done
-- Generating done
-- Build files have been written to: /.../cmake-sources/_builds

Check a sha1 file created by the module:

[cmake-sources]> cat _builds/boo/sha1
Message from external module

sha1(CMakeLists.txt) = 9f0ceda4ca514a074589fc7591aad0635b6565eb

Verify a value manually:

[cmake-sources]> openssl sha1 with-external-module/example/boo/CMakeLists.txt
SHA1(with-external-module/example/boo/CMakeLists.txt)= 9f0ceda4ca514a074589fc7591aad0635b6565eb

This diagram will make everything clear:

../../_images/with-external-module.png

3.7.3.4. Recommendation

Instead of keeping in a head all this information you can remember just two variables:

  • CMAKE_CURRENT_LIST_DIR

  • CMAKE_CURRENT_BINARY_DIR

Note that in functions a CMAKE_CURRENT_LIST_DIR variable is set to the directory where a function is used, not where a function is defined (see function for details).

Use CMAKE_CURRENT_BINARY_DIR for storing generated files.

Warning

Do not use CMAKE_CURRENT_BINARY_DIR for figuring out the full path to objects that was build by native tool, e.g. using ${CMAKE_CURRENT_BINARY_DIR}/foo.exe is a bad idea since for Linux executable will be named ${CMAKE_CURRENT_BINARY_DIR}/foo and for multi-configuration generators it will be like ${CMAKE_CURRENT_BINARY_DIR}/Debug/foo.exe and really should be determined on a build step instead of generate step. In such cases generator expressions is helpful. For example $<TARGET_FILE:tgt>.

Make sure you fully understand what each variable means in other scenarios:

  • CMAKE_SOURCE_DIR/CMAKE_BINARY_DIR these variables point to the root of the source/binary trees. If your project will be added to another project as a subproject by add_subdirectory, the locations like ${CMAKE_SOURCE_DIR}/my-resource.txt will point to <top-level>/my-resource.txt instead of <my-project>/my-resource.txt

  • PROJECT_SOURCE_DIR/PROJECT_BINARY_DIR these variables are better then previous but still have kind of a global nature. You should change all paths related to PROJECT_SOURCE_DIR if you decide to move declaration of your project or decide to detach some part of the code and add new project command in the middle of the source tree. Consider using extra variable with clean separate purpose for such job set(FOO_MY_RESOURCES "${CMAKE_CURRENT_LIST_DIR}/resources") instead of referring to ${PROJECT_SOURCE_DIR}/resources.

  • CMAKE_CURRENT_SOURCE_DIR this is a directory with CMakeLists.txt. If you’re using this variable internally you can substitute it with CMAKE_CURRENT_LIST_DIR. In case you’re creating module for external usage consider moving all functionality to function.

With this recommendation previous example can be rewritten in next way:

# External module: mymodule.cmake

# This is not a part of the function so 'CMAKE_CURRENT_LIST_DIR' is the path
# to the directory with 'mymodule.cmake'.
set(MYMODULE_PATH_TO_INFO "${CMAKE_CURRENT_LIST_DIR}/info/message.txt")

function(mymodule)
  # When we are inside function 'CMAKE_CURRENT_LIST_DIR' is the path to the
  # caller, i.e. path to directory with CMakeLists.txt in our case.
  file(SHA1 "${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt" sha1)

  file(READ "${MYMODULE_PATH_TO_INFO}" msg)
  file(
      WRITE
      "${CMAKE_CURRENT_BINARY_DIR}/sha1"
      "${msg}\nsha1(CMakeLists.txt) = ${sha1}\n"
  )
endfunction()

Note

As you may notice we don’t have to use _long_variable names since function has it’s own scope.

And call a mymodule function instead of including a module:

# boo/CMakeLists.txt

message("Processing boo/CMakeList.txt")

add_subdirectory(baz)
add_subdirectory(bar)

mymodule()

Effect is the same:

[cmake-sources]> cat _builds/boo/sha1
Message from external module
sha1(CMakeLists.txt) = 36bcbf5f2f23995661ca4e6349e781160910b71f

[cmake-sources]> openssl sha1 with-external-module-good/example/boo/CMakeLists.txt
SHA1(with-external-module-good/example/boo/CMakeLists.txt)= 36bcbf5f2f23995661ca4e6349e781160910b71f