Основи складання проектів на с

Деякий час тому ми з вами познайомилися з Autotools. Незважаючи на те, що Autotools досі використовується в багатьох відомих проектах з відкритим вихідним кодом, інструмент цей важко назвати особливо зручним. Крім того, нормально працює він тільки в * nix системах, а в якомусь Windows користуватися Autotools, скажімо так, досить непросто. Загалом, Autotools - це легаси, і нормальні програмісти в наш час намагаються використовувати CMake або, наприклад, SCons. У цій замітці ми познайомимося з CMake.

Використання CMake в найпростішому випадку виглядає наступним чином. У корені сховища створюється файл CMakeLists.txt приблизно такого змісту:

cmake_minimum_required (VERSION 3.1)

find_library (PTHREAD_LIBRARY pthread)
find_library (PCRE_LIBRARY pcre)

include_directories (include)
set (CMAKE_CXX_STANDARD 17)
set (CMAKE_CXX_STANDARD_REQUIRED on)
set (CMAKE_CXX_FLAGS "$ -Wall -Wextra -Werror")

add_executable (main src / Main.cpp src / HttpServer.cpp)

Хочеться сподіватися, яка рядок тут що означає, пояснювати не потрібно. Потім вихідні складаються в каталог src, а заголовки - в каталог include. Для складання проекту говоримо:

mkdir build
cd build
cmake.
make

Просто, чи не так?

Крім наведеного вище find_library в CMake є ряд скриптів для підключення конкретних бібліотек. Зокрема, підключення OpenGL здійснюється якось так:

find_package (OpenGL REQUIRED)

CMake можна вказати конкретний тип Makefile'ов, які ви хочете отримати на виході:

Зокрема, багато програмістів для прискорення складання проектів вважають за краще використовувати Ninja:

cmake -G Ninja.
ninja -j1

Вибір між отладочной і релізной складанням здійснюється так:

cmake -DCMAKE_BUILD_TYPE = Release -G Ninja.
cmake -DCMAKE_BUILD_TYPE = RelWithDebInfo -G Ninja.
cmake -DCMAKE_BUILD_TYPE = MinSizeRel -G Ninja.
# Debug використовується за умовчанням
cmake -DCMAKE_BUILD_TYPE = Debug -G Ninja.

Замість запуску безпосередньо make або ninja можна сказати щось на кшталт:

cmake --build. --config Release --target main

Можна вибрати конкретний компілятор для складання проекту

cmake -DCMAKE_C_COMPILER = `which gcc` \
-DCMAKE_CXX_COMPILER = `which g ++` -G Ninja.

... а також вказати додаткові прапори компіляції:

cmake -DCMAKE_C_FLAGS = "-O0 -g" -DCMAKE_CXX_FLAGS = "-O0 -g".

cmake -DCMAKE_C_FLAGS = "-O0 -g -fprofile-arcs -ftest-coverage" \
-DCMAKE_EXE_LINKER_FLAGS = "-lgcov".

У світі C / C ++ нерідко буває, що сторонні бібліотеки, які використовують CMake, підключаються до проекту за допомогою сабмодулей Git. Підключення таких бібліотек до проекту здійснюється досить просто:

cmake_minimum_required (VERSION 2.8)

include_directories (deps / algorithms / include)
add_subdirectory (deps / algorithms / src)

add_executable (rbtree_example rbtree_example.c)
target_link_libraries (rbtree_example CAlgorithms)

У свою чергу, у бібліотеки файл src / CMakeList.txt повинен бути приблизно таким:

cmake_minimum_required (VERSION 2.8)

add_library (CAlgorithms STATIC
struct / ilist.c
struct / rbtree.c
struct / htable.c
common / utils.c
)

Взагалі, add_subdirectory може приймати шлях до будь-якого каталогу, в якому є файл CMakeLists.txt. Це дозволяє розбивати проект на підпроекти навіть в рамках одного сховища. Знову ж таки, у випадку з бібліотеками це дозволяє помістити тести в окремий підпроект, який не збиратиметься при підключенні бібліотеки в сторонні проекти.

Наприклад, в корені бібліотеки CMakeList.txt може бути таким:

cmake_minimum_required (VERSION 2.8)

add_subdirectory (src)
add_subdirectory (test)

Безпосередньо тести додаються в проект наступним чином:

cmake_minimum_required (VERSION 2.8)

set (CMAKE_C_FLAGS "$ -O0 -g")

add_executable (test_htable test_htable.c)
target_link_libraries (test_htable CAlgorithms)

add_executable (test_rbtree test_rbtree.c)
target_link_libraries (test_rbtree CAlgorithms)

add_test (test_htable "./test_htable")
add_test (test_rbtree "./test_rbtree")

Запуск тестів здійснюється простою командою:

make test
# Або, з включенням отладочного виведення:
make test ARGS = "-V"
# Або, якщо використовуєте Ninja:
ninja test

... виконаної в каталозі build.

Якщо ж ви використовуєте який-небудь PyTest. просто допишіть в CMakeList.txt щось на кшталт:

find_package (PythonInterp REQUIRED)

add_test (NAME python_test
COMMAND py.test --capture = no $ /tests/run.py)

Висновок тестів пишеться в файл Testing / Temporary / LastTest.log. До речі, подробиці про змінних оточення, доступних в CMake, таких, як CMAKE_SOURCE_DIR, можна знайти тут.

Крім розглянутих вище можливостей часто можна зустріти підтримку збірки проектів з різними можливостями. Зокрема, це використовується в Assimp і LLDB. При складанні проекту опції вибираються так:

cmake -DLLDB_DISABLE_CURSES: BOOL = TRUE.
cmake -DASSIMP_BUILD_ASSIMP_TOOLS = OFF.

Опції зазвичай описують в документації, але в крайньому випадку їх можна подивитися і через curses-інтерфейс:

В рамках одного поста, звичайно, не представляється можливим розглянути всі можливості CMake. Однак представленої вище інформації вам повинно цілком вистачити в 90% випадків. Повноцінні робочі приклади використання CMake ви знайдете, наприклад, в цьому. цьому. а також в цьому репозиторіях на GitHub. Приклади використання опцій і умовних операторів можна знайти в репозиторіях вже згаданих Assimp і LLDB. Ну і, звичайно ж, масу корисного ви знайдете на офіційному сайті CMake.

А чи користуєтеся ви CMake і якщо так, чи використовуєте якісь його можливості, про які не було розказано вище?

Сподобався пост? Поділися з іншими:

(Необхідно включити JS)