CMake project, source and binary directory variables

Introduction

CMake variables like CMAKE_SOURCE_DIR are predefined variables in CMake that provide information about the build and source directory structure.

Directory Variables

  1. CMAKE_SOURCE_DIR:

    • Represents the top-level directory containing the root CMakeLists.txt file.
  2. CMAKE_BINARY_DIR:

    • Refers to the top-level build directory where CMake generates the build files.
  3. PROJECT_SOURCE_DIR:

    • Refers to the source directory of the current project (set by project() in CMakeLists.txt).
    • If there are multiple nested projects, this variable changes for each.
  4. PROJECT_BINARY_DIR:

    • Refers to the binary directory of the current project.
    • Similar to CMAKE_BINARY_DIR, but specific to the scope of the project.
  5. CMAKE_CURRENT_SOURCE_DIR:

    • Represents the directory containing the CMakeLists.txt file currently being processed.
    • Different from CMAKE_SOURCE_DIR, as it reflects the current directory in a hierarchical project.
  6. CMAKE_CURRENT_BINARY_DIR:

    • Points to the build directory corresponding to the CMAKE_CURRENT_SOURCE_DIR.
  7. CMAKE_CURRENT_LIST_DIR

  • Points to the directory where the currently executed CMakeLists.txt or *.cmake file resides.
  • It is useful when you need to include or reference files relative to the location of the current script.

CMAKE_CURRENT_LIST_DIR VS CMAKE_CURRENT_SOURCE_DIR

The short answer is when include(a_file), they are different inside a_file. To show that I run an experiment where different cases can happen.

The example project has this structure:

Example
|
|___ sub
|     |___ CMakeLists.txt
|
|___ modules
|      |___ mod.cmake
|
|___ CMakeLists.txt

The main CMake file is shown below, where a subdirectory added, a function and a macro are called and a module loaded.

# Example/CMakeLists.txt
cmake_minimum_required(VERSION 3.23)
project(myExample LANGUAGES CXX)

message("CMAKE_CURRENT_LIST_DIR=" ${CMAKE_CURRENT_LIST_DIR})
message("CMAKE_CURRENT_SOURCE_DIR=" ${CMAKE_CURRENT_SOURCE_DIR})

add_subdirectory(sub)

include(${CMAKE_CURRENT_SOURCE_DIR}"/modules/mod.cmake")

printFunc()
printMacro()

The other CMake file is:

# sub/CMakeLists.txt
message("in sub_dir")
message("CMAKE_CURRENT_LIST_DIR=" ${CMAKE_CURRENT_LIST_DIR})
message("CMAKE_CURRENT_SOURCE_DIR=" ${CMAKE_CURRENT_SOURCE_DIR})

The module is:

message("in module")
message("CMAKE_CURRENT_LIST_DIR=" ${CMAKE_CURRENT_LIST_DIR})
message("CMAKE_CURRENT_SOURCE_DIR=" ${CMAKE_CURRENT_SOURCE_DIR})

function(printFunc)
  message("in function")
  message("CMAKE_CURRENT_LIST_DIR=" ${CMAKE_CURRENT_LIST_DIR})
  message("CMAKE_CURRENT_SOURCE_DIR=" ${CMAKE_CURRENT_SOURCE_DIR})
endfunction()

macro(printMacro)
  message("in macro")
  message("CMAKE_CURRENT_LIST_DIR=" ${CMAKE_CURRENT_LIST_DIR})
  message("CMAKE_CURRENT_SOURCE_DIR=" ${CMAKE_CURRENT_SOURCE_DIR})
endmacro()

The results are:

CMAKE_CURRENT_LIST_DIR=path/to/Example
CMAKE_CURRENT_SOURCE_DIR=path/to/Example
in sub_dir
CMAKE_CURRENT_LIST_DIR=path/to/Example/sub
CMAKE_CURRENT_SOURCE_DIR=path/to/Example/sub
in module
CMAKE_CURRENT_LIST_DIR=path/to/Example/modules
CMAKE_CURRENT_SOURCE_DIR=path/to/Example
in function
CMAKE_CURRENT_LIST_DIR=path/to/Example
CMAKE_CURRENT_SOURCE_DIR=path/to/Example
in macro
CMAKE_CURRENT_LIST_DIR=path/to/Example
CMAKE_CURRENT_SOURCE_DIR=path/to/Example

Therefore, both are almost acting the same except when Include() is called and CMake moves into the included file. There is another subtle difference that is a consequence of the previous point: CMAKE_CURRENT_LIST_DIR can be set to a directory that doesn’t contain any CMakeLists.txt file.

We also learn that inside a function or macro both CMAKE_CURRENT_LIST_DIR and CMAKE_CURRENT_SOURCE_DIR are set to the caller directory not where function or macro are defined.

Tags ➡ C++

Subscribe

I notify you of my new posts

Latest Posts

Comments

0 comment