# CMake

{% embed url="<https://cmake.org/cmake/help/latest/guide/tutorial/index.html#guide:CMake%20Tutorial>" %}

CMake – кроссплатформенная автоматизированная система сборки проектов. Непосредственно сборкой она не занимается, а только генерирует Makefile, который потом будет выполнен утилитой make.

Использует текстовый файл CMakeLists.txt для описания зависимостей и настроек для сборки проекта.

Минимальный CMakeLists.txt для создания исполняемого файла

```cmake
# Создает исполняемый файл с именем main из исходника main.c
add_executable(test_project main.c)  
```

<figure><img src="/files/oFsqPxPN0JER7uSVP56Y" alt=""><figcaption></figcaption></figure>

```powershell
"cmake.exe" --build ...\cmake-build-release --target DebuggingExample -j 25
[1/2] Building C object CMakeFiles/DebuggingExample.dir/main.c.obj
[2/2] Linking C executable DebuggingExample.exe

Build finished
```

Также можно указать минимальную необходимую версию утилиты:

```cmake
cmake_minimum_required(VERSION 3.10)
```

Проекты в CMake задаются конструкцией `project`. Также можно добавить версию проекта.

```cmake
project(cmake_test_project)
project(cmake_test_project VERSION 1.0)
```

Версия стандарта указывается через конструкцию `set`:

```cmake
# C standart
set(CMAKE_C_STANDARD 17)
set(CMAKE_C_STANDARD_REQUIRED True)

# C++ standart
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED True)
```

Можно создавать текстовые переменные. Затем созданные переменные можно использовать в дальнейших конструкциях

```cmake
set(SOURCES test.c)
add_executable(cmake_test_project ${SOURCES})
```

Preprocessor definitions

```cmake
add_definitions(-DMY_DEBUG_MACROS)
```

Добавление флагов компиляции:

```cmake
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O2")
```

Целью сборки может быть не только исполняемый файл, но и библиотека:

```cmake
add_library(libjpegtools STATIC JpegTools.h JpegTools.c) # статическая библиотека
add_library(libjpegtools SHARED JpegTools.h JpegTools.c) # динамическая библиотека
```

Указание include directories:

```cmake
include_directories("headers/" "include/") # задание для всех целей проекта
# target_include_directories(myTarget PUBLIC ./include)  # для определённой цели
```

Указание libraries directories:

```cmake
link_directories(${OpenCL_LIBRARY}) # задание для всех целей проекта
# target_link_directories(myTarget PUBLIC opencv_world3416.lib)  # для определённой цели
```

Вы можете выбирать область видимости настройки: *PUBLIC* делает настройку видимой для текущей цели и для всех зависящих от неё целей, *PRIVATE* делает настройку видимой только для текущей цели и *INTERFACE* делает настройку видимой только для всех зависящих от неё целей.

Пример с подключением заголовочных и библиотеки

```cmake
cmake_minimum_required(VERSION 3.20)
project(ocl1 C)

set(CMAKE_C_STANDARD 17)

set(OpenCL_INCLUDE_DIRS "$ENV{OCL_ROOT_x64}/include")
set(OpenCL_LIBRARY "$ENV{OCL_ROOT_x64}/lib")

find_package(OpenCL 1.2 REQUIRED)
include_directories(${OpenCL_INCLUDE_DIRS})
link_directories(${OpenCL_LIBRARY})

add_executable(ocl1 opencl_example.c)
target_include_directories (ocl1 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries (ocl1 "OpenCL.lib")
```

CMake по умолчанию создаёт таргеты в поддиректориях (`build/Debug`, `build/Release` и пр.). Для удобства можно задать post-build событие для вызова команды копирования exe-файла в удобное место. Например, скопировать к исходникам можно следующим способом:

```cmake
add_custom_command(TARGET ocl1 POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:ocl1> ${PROJECT_SOURCE_DIR}/ocl1.exe
    COMMENT "Created ${PROJECT_SOURCE_DIR}/ocl1.exe"
)
```

`find_package()` - принимает имя библиотеки как аргумент и обращается к CMake, чтобы найти скрипт для настройки переменных данной библиотеки. За поиск библиотек отвечают модули, называющиеся FindNAME.cmake, где NAME – имя библиотеки. При успешном нахождении компонента будут добавлены переменные, хранящие пути поиска заголовков, имена библиотек для линкера и пр. В примере ниже при нахождении `OpenMP` добавляются переменные `${OpenMP_C_FLAGS}` и `${OpenMP_CXX_FLAGS}`.

```cmake
OPTION (USE_OpenMP "Use OpenMP" ON)
IF(USE_OpenMP)
   FIND_PACKAGE(OpenMP)
   IF(OPENMP_FOUND)
       SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
       SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
   ENDIF()
ENDIF()
```

Пример с Boost (весь, без указания конкретных компонентов):

```cmake
find_package(Boost REQUIRED)
# После этого становятся доступны:
  # Boost_INCLUDE_DIRS: пути к заголовочным файлам
  # Boost_LIBRARY_DIRS: пути к библиотекам
  # Boost_LIBRARIES: список файлов библиотек
```

## Конфигурация и сборка

После настройки CMakeLists.txt настроить конфигурацию и затем уже запустить процесс сборки.

Конфигурация настраивается следующим образом: указываются пути до исходников и до результатов сборки (промежуточных файлов и результата сборки). Дополнительно можно указать переменные для CMake ([generator](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html), build\_type и пр.).

{% tabs %}
{% tab title="Ninja/Unix-Makefiles" %}
Single-config системы сборки. Ниже приведён пример конфигурации сборки в режимах Debug и Release.

```shell
# Configure the build
cmake -S . -B build/ -D CMAKE_BUILD_TYPE=Debug

# Actually build the binaries
cmake --build build/
```

```shell
# Configure a release build
cmake -S . -B build/ -D CMAKE_BUILD_TYPE=Release

# Build release binaries
cmake --build build/
```

{% endtab %}

{% tab title="Ninja Multi-Config, Visual Studio" %}
Multi-configuration generators. Конфигурация указывается при сборке.

```shell
# Configure the build
cmake -S . -B build

# Build debug binaries
cmake --build build --config Debug

# Build release binaries
cmake --build build --config Release
```

{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://skkv-itmo.gitbook.io/c-cpp-cookies/build/build-systems/cmake.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
