CMake Grammer
1. Overview
CMake is a command-based scripting language where everything is treated as strings.
There are no strong types like C++ — behavior depends on how strings are interpreted.
2. Variables
2-1. set()
Description:
Creates or updates a variable.
Behavior:
- Stored in current scope
- Overwritten if called again
2-2. Access Variable
Description:
${} expands the variable into its value.
2-3. List Behavior
Description:
CMake treats lists as semicolon-separated strings.
2-4. unset()
1
2
| unset(VAR)
unset(VAR CACHE)
|
Description:
- Removes variable
- Optional
CACHE removes persistent value
3. Variable Expansion
3-1. Basic Expansion
Meaning:
Replace with value of VAR.
3-2. Indirect Expansion (Important)
1
2
3
4
| set(name FOO)
set(FOO hello)
message(${${name}})
|
Meaning:
${name} → FOO${FOO} → hello
✔ Used for dynamic variable access
3-3. Environment Variables
Description:
Access OS environment variables.
4. Condition (if)
1
2
3
4
| if(condition)
elseif(condition)
else()
endif()
|
Description:
Evaluates condition expressions.
4-1. Numeric Comparison
✔ Integer comparison
4-2. String Comparison
✔ Exact string match
4-3. Regex Match
✔ Regular expression
4-4. Logical Operators
1
2
3
| if(A AND B)
if(A OR B)
if(NOT A)
|
4-5. Existence Check
1
2
| if(DEFINED VAR)
if(EXISTS file.txt)
|
✔ Check if variable or file exists
4-6. Combined Pattern (Advanced)
1
| if(DEFINED ${variable} AND "${${variable}}")
|
Meaning:
- Check if referenced variable exists
- Check if value is TRUE
✔ Common in large projects (e.g., OpenCV)
5. Dynamic Expression Execution
1
2
3
| set(cond 2 GREATER 1)
if(${cond})
|
Behavior:
✔ CMake executes expanded string as condition
6. Loops
6-1. foreach()
1
2
3
| foreach(x a b c)
message(${x})
endforeach()
|
Description:
Iterates over values.
6-2. List Iteration
✔ Expands list first
6-3. Range Loop
✔ Numeric iteration
6-4. while()
1
2
| while(condition)
endwhile()
|
✔ Loop while condition is true
7. Functions and Macros
7-1. function()
1
2
3
| function(foo x)
message(${x})
endfunction()
|
Behavior:
- Has its own scope
- Variables are local
7-2. macro()
1
2
3
| macro(foo x)
message(${x})
endmacro()
|
Behavior:
- No scope
- Acts like text substitution
✔ Used in OpenCV (OCV_OPTION)
7-3. Arguments
1
2
3
| ${ARGV0}
${ARGV1}
${ARGN}
|
8. Cache Variables
1
| set(VAR value CACHE STRING "description")
|
Description:
Stores variable in CMakeCache.txt
Why Important
- Persists between configure runs
- User can override via CLI or GUI
Types
| Type | Meaning |
|---|
| STRING | text |
| BOOL | ON/OFF |
| PATH | directory |
| FILEPATH | file |
FORCE
1
| set(VAR value CACHE STRING "" FORCE)
|
✔ Override existing cache value
9. option()
1
| option(USE_CUDA "Enable CUDA" ON)
|
Description:
Creates user-configurable boolean option.
10. include() vs add_subdirectory()
include()
✔ Executes file inline ✔ No target creation
add_subdirectory()
✔ Executes another CMakeLists.txt ✔ Adds build targets
11. Targets
11-1. Executable
1
| add_executable(App main.cpp)
|
11-2. Library
1
| add_library(MyLib STATIC lib.cpp)
|
11-3. Linking
1
| target_link_libraries(App MyLib)
|
Description:
Defines dependency between targets.
11-4. Include Directories
1
| target_include_directories(App PUBLIC include/)
|
11-5. Compile Options
1
| target_compile_options(App PRIVATE -O2)
|
11-6. Definitions
1
| target_compile_definitions(App PRIVATE USE_FEATURE)
|
12. install()
1
2
| install(TARGETS App DESTINATION bin)
install(FILES a.h DESTINATION include)
|
Description:
Defines how build outputs are copied into a structured install directory.
12-1. Basic Concept
install() does not build anything.
It copies and organizes artifacts produced during build.
Example result:
1
2
3
4
| install/
├── bin/
├── lib/
├── include/
|
12-2. Common Signatures
Install targets
1
| install(TARGETS App DESTINATION bin)
|
✔ Executables / libraries
Install files
1
| install(FILES a.h DESTINATION include)
|
✔ Headers or config files
Install directories
1
| install(DIRECTORY include/ DESTINATION include)
|
✔ Entire folder copy
12-3. COMPONENT (Important)
1
2
| install(TARGETS App DESTINATION bin COMPONENT runtime)
install(FILES a.h DESTINATION include COMPONENT dev)
|
Description:
COMPONENT groups install rules into logical parts.
Why it exists
Allows partial installation.
1
| cmake --install build --component dev
|
✔ installs only development files (headers)
Typical Convention
| Component | Meaning |
|---|
| runtime | executables |
| dev | headers, cmake configs |
| library | shared/static libs |
Important Insight
1
2
| COMPONENT is NOT a variable and NOT a folder name.
It is a label used by CMake to group install rules.
|
13. File Operations
1
2
| file(GLOB SRC "*.cpp")
file(COPY src DESTINATION build)
|
14. string()
1
2
| string(REPLACE "a" "b" OUT ${VAR})
string(TOUPPER ${VAR} OUT)
|
Description:
Performs string manipulation.
14-1. REPLACE
1
2
| set(VAR "apple")
string(REPLACE "a" "b" OUT ${VAR})
|
Result:
14-2. TOUPPER / TOLOWER
1
| string(TOUPPER "hello" OUT)
|
Result:
14-3. CONCAT
1
| string(CONCAT OUT "Hello " "World")
|
Result:
14-4. REGEX
1
| string(REGEX MATCH "h.*o" OUT "hello")
|
✔ Pattern matching
Important Insight
1
2
| string() does NOT modify variables directly.
It always writes to an output variable.
|
15. list()
1
2
3
| list(APPEND MYLIST item)
list(REMOVE_ITEM MYLIST item)
list(LENGTH MYLIST len)
|
Description:
Manipulates list variables.
15-1. Append
1
2
| set(MYLIST a b)
list(APPEND MYLIST c)
|
Result:
15-2. Remove
1
| list(REMOVE_ITEM MYLIST b)
|
Result:
15-3. Length
1
| list(LENGTH MYLIST len)
|
Result:
15-4. Get Element
1
| list(GET MYLIST 0 first)
|
✔ Index-based access
Important Insight
1
| CMake lists are just strings separated by ';'
|
16. message()
1
2
3
4
| message("Hello")
message(STATUS "Info")
message(WARNING "Warning")
message(FATAL_ERROR "Stop")
|
Description:
Outputs messages during configure/build.
16-1. Levels
| Level | Meaning |
|---|
| STATUS | normal info |
| WARNING | warning message |
| AUTHOR_WARNING | dev warning |
| FATAL_ERROR | stop execution |
Example
1
| message(STATUS "Building project...")
|
Behavior
1
| message(FATAL_ERROR "Something failed")
|
✔ Immediately stops CMake
Important Insight
1
2
| message() is mainly used during configure phase
for debugging and logging
|
17. Built-in Variables
1
2
3
4
5
| CMAKE_SYSTEM_NAME
CMAKE_SOURCE_DIR
CMAKE_BINARY_DIR
CMAKE_CURRENT_SOURCE_DIR
CMAKE_CURRENT_BINARY_DIR
|
18-1. Single-line
18-2. Multi-line
1
2
3
| #[[
This is a multi-line comment
]]
|
Important Behavior
1
| Comments are ignored during parsing
|
Common Usage
1
2
| # Enable CUDA if available
option(USE_CUDA "Enable CUDA" ON)
|
Important Insight
1
2
| CMake has no inline comment syntax (like // or /* */)
Only # and #[[ ]] are valid
|
19. Key Concepts
1
2
3
4
5
6
7
| ✔ Everything is string-based
✔ ${} controls execution
✔ if() evaluates expressions, not just values
✔ CACHE variables persist
✔ include executes code
✔ add_subdirectory builds structure
✔ target is the core abstraction
|