Post

05. CMakeLists.txt vs .cmake

05. CMakeLists.txt vs .cmake

CMakeLists.txt vs .cmake


Prerequisites

  • Basic understanding of CMake workflow (Configure → Build → Install)
  • cmake -S . -B build

. Why CMake Structure Matters

In small projects, a single CMakeLists.txt is often enough.

However, in real-world or large-scale projects (e.g., OpenCV), the build configuration becomes too complex to maintain in a single file.

To solve this, CMake supports **modularization using `.

2. Core Concep

1
2
CMakeLists.txt = Entry Point
.cmake         = Modular Components
  • CMakeLists.txt → main control file
  • .cmake → reusable logic, functions, and configurations
CommandPurpose
includeload reusable logic
add_subdirectoryadd build unit

3. CMakeLists.txt

3-1. Role

  • Starting point of the project
  • Defines build targets
  • Controls overall flow

3-2. Example

1
2
3
4
5
6
cmake_minimum_required(VERSION 3.10)
project(MyApp)

include(cmake/utils.cmake)

add_executable(MyApp main.cpp)

3-3. Key Characteristics

  • Required in every directory that participates in the build
  • Can exist in multiple directories
  • Connected via:
1
add_subdirectory(subdir)

4. .cmake Files

4-1. Role

  • Split complex logic into reusable modules
  • Store:

    • variables
    • functions / macros
    • configuration rules

4-2. Example

1
2
3
4
5
6
7
# cmake/utils.cmake

set(CMAKE_CXX_STANDARD 17)

function(print_message msg)
  message(${msg})
endfunction()

4-3. Usage

1
include(cmake/utils.cmake)

include() does NOT import like a module. It executes the file in-place.

1
2
3
4
5
6
7
8
9
10
11
12
cmake_minimum_required(VERSION 3.10)
project(MyApp)

-------include(cmake/utils.cmake) part---------
set(CMAKE_CXX_STANDARD 17)

function(print_message msg)
  message(${msg})
endfunction()
-----------------------------------------------

add_executable(MyApp main.cpp)
  • Executes code directly
  • Used for:

    • utilities
    • shared logic

5. Typical Large Project Structure

1
2
3
4
5
6
7
8
9
10
project/
 ├── CMakeLists.txt
 ├── cmake/
 │    ├── utils.cmake
 │    ├── options.cmake
 │    └── install.cmake
 ├── src/
 │    └── CMakeLists.txt
 └── lib/
      └── CMakeLists.txt
1
2
3
4
5
6
7
8
9
CMakeLists.txt
   ↓
include(.cmake files)
   ↓
add_subdirectory(...)
   ↓
Multiple CMakeLists.txt executed
   ↓
Single build graph generated

6. Why Use .cmake Files?

Without modularization:

1
2
3
4
5
# thousands of lines in one file
set(...)
if(...)
foreach(...)
install(...)

With .cmake:

1
2
3
include(options.cmake)
include(compiler.cmake)
include(install.cmake)
1
2
3
4
5
✔ CMakeLists.txt is the entry point
✔ .cmake files are modular building blocks
✔ include() executes code inline
✔ add_subdirectory() links multiple build units
✔ Large projects rely heavily on .cmake modularization
This post is licensed under CC BY 4.0 by the author.