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.
CMake documentation
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:
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 byadd_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 toPROJECT_SOURCE_DIR
if you decide to move declaration of your project or decide to detach some part of the code and add newproject
command in the middle of the source tree. Consider using extra variable with clean separate purpose for such jobset(FOO_MY_RESOURCES "${CMAKE_CURRENT_LIST_DIR}/resources")
instead of referring to${PROJECT_SOURCE_DIR}/resources
.CMAKE_CURRENT_SOURCE_DIR
this is a directory withCMakeLists.txt
. If you’re using this variable internally you can substitute it withCMAKE_CURRENT_LIST_DIR
. In case you’re creating module for external usage consider moving all functionality tofunction
.
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