Что такое cmake
Перейти к содержимому

Что такое cmake

Записки программиста

Некоторое время назад мы познакомились с Autotools. Несмотря на то, что Autotools до сих пор используется во многих известных проектах с открытым исходным кодом, инструмент этот трудно назвать особо удобным. Кроме того, нормально работает он только в *nix системах, а в каком-нибудь Windows пользоваться Autotools, скажем так, весьма непросто. В общем, Autotools — это легаси, и нормальные программисты в наше время пытаются использовать CMake или, например, SCons. В этой заметке мы познакомимся с CMake.

Говоря простыми словами, CMake — это такая штука, в которой вы описываете проект, а она вам генерирует Makefile’ы в *nix системах, проекты Visual Studio под Windows, файлы конкретных редакторов и IDE, например Sublime Text, Code::Blocks, Eclipse или KDevelop, и так далее. Несмотря на спорный в некоторых моментах синтаксис, в последнее время CMake становится стандартом де-факто в мире C/C++. В частности, CMake используется в LLVM, Qt, MariaDB, Blender, KiCad, GNU Radio и ряде других проектов. Кроме того, в CLion, IDE для C/C++ от компании JetBrains, по умолчанию также создаются проекты, основанные на 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’ов, которые вы хотите получить на выходе:

cmake -G «Unix Makefiles» ..
cmake -G «MinGW Makefiles» ..
# для просмотра списка всех доступных генераторов:
cmake -G

В частности, многие программисты для ускорения сборки проектов предпочитают использовать 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 clang ` \
-DCMAKE_CXX_COMPILER= ` which clang++ ` -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. Если вас интересует тема написания модульных тестов на C++, она более подробно раскрыта в заметке Тестирование кода на C++ с помощью Google Test.

Если же вы используете какой-нибудь 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 и если да, используете ли какие-то его возможности, о которых не было рассказано выше?

Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.

Что это и зачем нужно

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

CMake может проверять наличие необходимых библиотек и подключать их, собирать проекты под разными компиляторами и операционными системами. Т.е. у вас есть куча кода и файлик, содержащий информацию для cmake, и чтобы скомпилить это дело где-нибудь еще, вам нужно просто запустить там cmake, который сделает всё сам. Удобно, полезно, просто.

Краткое описание

Если нет желания/времени/сил читать весь туториал и Вы используете какой-нибудь QtCreator (или любая другая IDE, умеющая работать с cmake), то:

  • Создайте в IDE проект под cmake
  • Найдите в папке с проектом CMakeFiles.txt
  • Пробегитесь глазами по туториалу, соотнося его с вашим CMakeFiles.txt

Про подключение библиотек рекомендуется все-таки прочитать целиком.

Старт

Предполагается, что найти и скачать сам cmake ты, %username%, в состоянии. //а если нет?

Предположим, у Вас есть исходничек «test.cpp» (// а если нет?)(А если нет, то CMake тебе трогать рано). Для начала нужно создать файлик для cmake, который обычно называют «CMakeLists.txt», и написать туда вот это:

add_executable(test test.cpp)

Теперь запускаем (из консоли) в этой папке команду «cmake CMakeLists.txt» (аргументом можно передавать не только файл, но и директорию, в которой он лежит, тогда cmake найдет его сам).

cmake будет использовать переданный (или найденный) файл проекта (тот самый CMakeLists.txt), и в текущей директории будет создавать проект. Проект — это много-много файлов и директорий (примечание: поэтому лучше запускать cmake из другой директории, чтобы можно было, например, быстро удалить все бинарники), из которых нас больше всего интересует Makefile.

Makefile — это файл, нужный для утилиты make. Именно она запускает компиляторы, линковщики и прочие радости. Запускаем make в каталоге сборки (т.е. там же, где Вы запускали cmake). В консоли вылезет примерно такой текст:

Scanning dependencies of target test [100%] Building CXX object CMakeFiles/test.dir/test.cpp.o Linking CXX executable test [100%] Built target test

А у Вас в папочке появится исполняемый файл «test». Запустите, убедитесь, что это действительно то, что ожидается от компиляции файла «test.cpp».

Подробное описание

Поразбираемся с различными возможностями cmake.

Указание необходимой версии cmake

cmake_minimum_required(VERSION 2.6)

Указывайте высокую минимальную версию CMake. Если используемая версия cmake меньше 2.6, он не захочет работать. Писать эту команду всегда — хороший стиль (cmake будет пыхтеть и обижаться, если вы не укажете версию, но собирать всё равно всё будет).

Название проекта

project(visualization)

Указывает, что этот cmake-файл является корневым для некоторого проекта. С проектами связаны определенные переменные и поведение cmake (читайте документацию).

Переменные

В cmake можно создавать текстовые переменные. Команда

set(VARIABLE The variable's value)

запишет в переменную «VARIABLE» значение «The variable’s value». Чтобы где-либо использовать значение этой переменной, нужно написать $.

Чтобы добавить к переменной некий текст, можно сделать так:

set(VARIABLE "$ new text")

Как видите, использовать значение можно и внутри кавычек. Переменные активно используются различными библиотеками — для установки флагов, параметров сборки/линковки и прочих вкусностей, об этом чуть-чуть попозже.

Пример коше’гного проекта со списком сорцов в отдельной переменной:

cmake_minimum_required(VERSION 2.6) set(SOURCES test.cpp lib1.cpp lib2.cpp) add_executable(test $)

Устанавливаем команды компилятору

add_definitions(-DSOME_IMPORTANT_DEFINITION)

Эта команда используется для установки дефайнов, которыe можно проверить в коде через, например, #ifdef SOME_IMPORTANT_DEFINITION.

set(CMAKE_CXX_FLAGS "$ -std=c++11 -Wall")

Эта команда добавит к флагам, используемым при сборке c++-кода, флаги -std=c++11 и -Wall.

Кто не знает: «-std=c++11» включает в gcc поддержку стандарта c++11, «-Wall» говорит gcc выводить все предупреждения (очень советую, помогает отловить много глупых багов и писать аккуратный код).

Если ваша версия GCC меньше, чем 4.7.0, вместо -std=c++11 нужно использовать -std=c++0x.

В GCC 4.8.0 появился флаг -std=c++1y, в котором начинают реализовывать фичи следующего стандарта.

Папка с хедерами

Допустим, Вы хотите, чтобы хедеры (файлики, подключаемые через #include) искались еще и в каталогах «headers/» и «more_headers/»:

include_directories("headers/" "more_headers/")

Надеюсь, и это понятно.

Самое важное — подключение библиотек

Научимся искать и подключать библиотеки при помощи cmake на примере Boost. Для начала установим переменные для буста:

set(Boost_USE_STATIC_LIBS OFF) set(Boost_USE_MULTITHREADED ON)

Первое — мы не хотим, чтобы буст подключался к нам статически (т.е. хотим динамическую линковку). Если ты, %username%, не знаешь, что это, пока просто забей и используй этот флаг так, как написано. Но в ближайшее время узнай, о чем речь. Второй флаг разрешает бусту внутри своих магических реализаций использовать треды для распараллеливания и прочих радостей.

Итак, мы установили флаги. Давайте найдем буст!

Допустим, нам нужны компоненты буста под названием chrono (библиотека для работы со временем) и filesystem (библиотека для работы с файловой системой):

find_package(Boost COMPONENTS chrono filesystem REQUIRED)

Win, будут искаться только нужные библиотеки, и их расположение будет записано в переменную Boost_LIBRARIES.

Опция «REQUIRED» говорит о том, что библиотека необходима проекту. Без нее cmake решит, что отсутствие данной библиотеки — не так уж и страшно, и будет собирать дальше.

Добавим директории с хедерами буста для поиска в них хедеров:

include_directories($)

Итак, осталось найденные библиотеки подключить к исполняемому файлу.

target_link_libraries(test $)

В качестве библиотек нужно указать пути к необходимым собранным библиотекам. cmake нашел указанные нами библиотеки и записал в переменную, чем мы и пользуемся.

Заметим, что эту команду нужно вызывать после того, как создан target сборки (через add_executable).

Пример хорошего CMakeLists.txt и где он будет лежать

Итак, полный пример использования всего этого. У нас есть некая директория (отныне считаем ее «/sources»), и в ней лежат исходники

/sources/lib1/main.cpp /sources/lib2/main.cpp /sources/main.cpp

В корне «/» лежит файл «/CMakeLists.txt»:

cmake_minimum_required(VERSION 2.8) project(cmake-example) set(Boost_USE_STATIC_LIBS OFF) set(Boost_USE_MULTITHREADED ON) find_package(Boost COMPONENTS chrono filesystem REQUIRED) set(CMAKE_CXX_FLAGS "$\$$ -std=c++11 -Wall") set(SRC_LIST lib1/main.cpp lib2/main.cpp main.cpp) add_executable($\$$ $\$$) target_link_libraries($\$$ $\$$)

Если Вам что-то в нём не понятно — перечитайте соответствующую информацию выше.

Создаем директорию «/build» (не «/sources/build»), переходим в нее, запускаем в ней «cmake ..». «..» — метка родительской директории. cmake возьмет из нее наш CMakeLists.txt и по нему создаст проект в папке «/build». Чтобы проект собрать, запускаем «make» в той же папке «/build».

Таким образом, в корне у нас есть:

  • CMakeLists.txt
  • директория с исходниками
  • каталог сборки

Все разделено, автоматизировано и удобно.

Как создать библиотеку в поддиректории и слинковать ее с основной программой

Пусть в ./ лежит основной проект, а в ./subdir мы хотим сделать либу, а в ./build построить проект.

project(MegaLibrary) set(SOURCES lib.cpp) set(HEADERS lib.h) add_library(lib $\$$ $\$$) target_include_directories(lib PUBLIC $\$$)
project(MainProject) set(MAIN_PROJECT_SRC_LIST main) # Other stuff
add_executable(main $\$$) add_subdirectory(subdir) target_link_libraries(main lib)

Теперь можно в файлах основного проекта делать #include «lib.h» (см. документацию по target_include_directories).

В ./build запускаем «cmake .. && make» и получаем собранный проект.

Как использовать CMake в связке с QtCreator

Интеграция с cmake у QtCreator не очень тесная, тем не менее, работать с ним можно.

Создаем новый проект без использования Qt, выбираем «Проект на С++ с использованием CMake». Создастся дефолтный файл сборки, который просто добавляет все исходники в директории проекта и компилирует их в один бинарник.

Как добавить header в проект, чтобы его было видно в списке файлов

Если вы создали файл header.h в директорию проекта, просто строчку

add_executable($\$$ $\$$)
add_executable($\$$ $\$$ "header.h")

Что такое cmake

На первом шаге проект нужно сконфигурировать, то есть создать финальный скрипт сборки, запустив cmake в будущем каталоге сборки.

# Сейчас мы в каталоге `myapp` с файлом CMakeLists.txt # Создадим каталог `myapp-release` и перейдём в него. mkdir --parents ../myapp-release cd ../myapp-release # Сконфигурируем проект для сборки в Release. # Флаг установит опцию CMAKE_BUILD_TYPE в значение "Release", # интерпретатор cmake считает это переключением на Release конфигурацию. cmake -DCMAKE_BUILD_TYPE=Release ../myapp 

На втором шаге нужно запустить финальный скрипт. Не вызывайте make ! Утилита cmake сделает это сама:

# Просим CMake запустить сборку в каталоге `myapp-release` # Можно добавить флаг `--target mylibrary` для сборки только mylibrary # Можно добавить флаг `--clean-first`, чтобы в начале новой сборки # стирать остатки предыдущей. cmake --build . # Аналогичный способ для GNU/Linux. Его по привычке советуют в сети, хотя # make доступен не всегда, а cmake --build работает на всех платформах. make 

Структура CMakeLists.txt

В начале главного файла CMakeLists.txt ставят метаинформацию о минимальной версии CMake и названии проекта:

# Указывайте последнюю доступную вам версию CMake. cmake_minimum_required(VERSION 3.8) # Синтаксис: project( VERSION LANGUAGES CXX), # теги VERSION и LANGUAGES необязательные. project(libmodel3d) 

Затем следует список инструкций, служащих для вычисления различных переменных, создания целей сборки, подключения проектов из подкаталогов и так далее. Например, подключить дополнительный CMakeLists.txt из подкаталога можно так:

# Простая версия: подключает скрипт по пути /CMakeLists.txt add_subdirectory() # Расширенная версия: дополнительно установит подкаталог сборки подпроекта add_subdirectory( ) 

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

# Синтаксис: add_executable( ) # Добавлять `.h` необязательно, но лучше для работы из IDE: # - IDE определит заголовок как часть проекта # - cmake будет отслеживать изменения в заголовке и пересобирать # проект при изменениях. add_executable(pngconverter main.cpp PngReader.h PngReader.cpp) 

Целью также может быть библиотека, статическая или динамическая.

# Синтаксис: add_library( [STATIC|SHARED|INTERFACE] ) # Тип библиотеки (staic или shared) зависит от параметров сборки add_library(libpngutils PngUtils.h PngUtils.cpp) # Тип библиотеки: static add_library(libpngtools STATIC PngTools.h PngTools.cpp) 

Автогенерация проекта для Visual Studio (Windows)

Если используется Visual C++, то путь немного другой: на шаге конфигурирования создаётся проект для Visual Studio, который затем можно собрать из IDE либо так же из командной строки.

Созданный проект Visual Studio нельзя изменять и использовать постоянно, потому что при генерации проекта используются абсолютные пути и другие неприемлемые для постоянной работы вещи.

# Сейчас мы в каталоге `myapp` с файлом CMakeLists.txt # Сгенерируем проект Visual Studio для сборки. mkdir --parents ../myapp-build cd ../myapp-build # Конфигурируем для сборки с Visual Studio 2017, версия тулчейна v140 cmake -G "Visual Studio 2017" 

Если проект был сконфигурирован успешно, то в каталоге ../myapp-build появятся автоматически сгенерированный BUILD_ALL.sln и проекты для Visual Studio. Их можно открыть к IDE, либо собрать из командной строки с помощью cmake. Названия опций говорят сами за себя:

cmake --build . \ --target myapp \ --config Release \ --clean-first 

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

Не используйте директивы include_directories , add_definitions , add_compile_options ! Они меняют глобальные настройки для всех целей, это создаёт проблемы при масштабировании.

  • Используйте target_link_libraries для добавления статических и динамических библиотек, от которых зависит цель
  • Используйте target_include_directories вместо include_directories для добавления путей поиска заголовков, от которых зависит цель
  • Используйте target_compile_definitions вместо add_definitions для добавления макросов, с которыми собирается цель
  • Используйте target_compile_options для добавления специфичных флагов компилятора, с которыми собирается цель
# Добавляем цель - статическую библиотеку add_library(mylibrary STATIC \ ColorDialog.h ColorDialog.cpp \ ColorPanel.h ColorPanel.cpp) # ! Осторожно - непереносимый код ! # Добавляем к цели путь поиска заголовков /usr/include/wx-3.0 # Лучше использовать find_package для получения пути к заголовкам. target_include_directories(mylibrary /usr/include/wx-3.0) 

Вы можете выбирать область видимости настройки:

  • PUBLIC делает настройку видимой для текущей цели и для всех зависящих от неё целей
  • PRIVATE делает настройку видимой только для текущей цели
  • INTERFACE делает настройку видимой только для всех зависящих от неё целей

Пример использования областей видимости:

# Каталог include будет добавлен к путям поиска заголовков в текущей цели и во всех зависимых целях target_include_directories(myTarget PUBLIC ./include) # Каталог src будет добавлен к путям поиска заголовков только в текущей цели target_include_directories(myTarget PUBLIC ./src) 

Схема зависимостей условного проекта:

Схема

Выбор стандарта и диалекта C++

Для настройки стандарта и флагов языка C++ не добавляйте флаги напрямую!

# ! Устаревший метод - прямое указание флага ! target_compile_options(hello PRIVATE -std=c++11) 

В CMake версии 3.8+ вы можете прямо потребовать включить нужный стандарт:

# Источник: https://cmake.org/cmake/help/latest/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.html # Включаем C++ 2017 target_compile_features(myapp cxx_std_17) # Альтернатива: включаем C++ 2014 target_compile_features(myapp cxx_std_14) # Альтернатива: включаем C++ 2011 target_compile_features(myapp cxx_std_11) 

В CMake версии до 3.7 включительно можно использовать set_target_properties (если не работает, то у вас слишком старый CMake):

# Стандарт: C++ 2014, расширения языка от производителя компилятора отключены set_target_properties(myapp PROPERTIES CXX_STANDARD 14 CXX_STANDARD_REQUIRED YES CXX_EXTENSIONS NO ) 

Для разработчиков библиотек есть более тонкий контроль над возможностями языка:

# API библиотеки (т.е. заголовки) требуют лямбда-функций и override, # реализация библиотеки требует ещё и range-based for. target_compile_features(mylibrary PUBLIC cxx_override cxx_lambdas PRIVATE cxx_range_for) 

Функции в CMake

CMake позволяет объявлять функции командами function(name) / endfunction() и макросы командами macro(name) / endmacro() . Предпочитайте функции, а не макросы, т.к. у функций есть своя область видимости переменных, а у макросов — нет.

function(hello_get_something var_name) . # Установить переменную в области видимости вызывающей стороны # можно с помощью тега PARENT_SCOPE set($var_name> $ret> PARENT_SCOPE) endfunction() 

Добавление исходников к цели с target_sources

Лучше добавлять специфичные исходники с помощью target_sources, а не с помощью дополнительных переменных.

add_library(hello hello.cxx) if(WIN32) target_sources(hello PRIVATE system_win.cxx) elseif(UNIX) target_sources(hello PRIVATE system_posix.cxx) else() target_sources(hello PRIVATE system_generic.cxx) endif() 

Интерфейс к утилитам командной строки

# Создать каталог debug-build cmake -E make_directory debug-build # Перейти в каталог debug-build cmake -E chdir debug-build 

Функция find_package

Функция find_package принимает имя библиотеки как аргумент и обращается к CMake, чтобы найти скрипт для настройки переменных данной библиотеки. В итоге при сборке либо возникает ошибка из-за того что пакет не найден, либо добавляются переменные, хранящие пути поиска заголовков, имена библиотек для компоновщика и другие параметры.

Пример подключения Boost, вызывающего встроенный в CMake скрипт FindBoost:

# Весь Boost без указания конкретных компонентов find_package(Boost REQUIRED) # Теперь доступны переменные # - Boost_INCLUDE_DIRS: пути к заголовочным файлам # - Boost_LIBRARY_DIRS: пути к статическим/динамическим библиотекам # - Boost_LIBRARIES: список библиотек для компоновщика # - Boost__LIBRARY: библиотека для компоновки с компонентом библиотек Boost 

Пример подключения библиотеки Bullet с помощью встроенного скрипта FindBullet и компоновки с приложением my_app:

# Вызываем встроенный скрипт FindBullet.cmake find_package(Bullet REQUIRED) # Добавляем пути поиска заголовков к цели my_app target_include_directories(my_app $BULLET_INCLUDE_DIRS>) # Добавляем список библиотек для компоновки с целью my_app target_link_libraries(my_app $BULLET_LIBRARIES>) 

PS-Group

  • PS-Group
  • sshambir@gmail.com
  • ps-group
  • image/svg+xml sshambir

Знакомство с CMake. Часть 1. Установка, CMakeLists.txt, сборка.

Многие, кто начинал создавать собственные программы, пользовался какой-либо системой сборки. В общем, система сборки – это набор инструментов, облегчающий работу с компилятором. Это включает в себя компиляцию, линковку, установку, а также сбор исходных файлов для передачи их компилятору и слежение за зависимостями. Также современные системы сборки облегчают работу с библиотеками, позволяют создавать переносимые проекты и выполняют ещё массу других вкусностей. Эта статья посвящена популярной системе сборки CMake и расскажет, как правильно её установить и настроить, а также будет рассмотрен простой пример её использования. Она рассчитана на тех, что хоть немного знаком с понятиями make, Makefile, компиляция, линковка.

Установка в Linux.

Для популярных дистрибутивов Linux типа Debian, Gentoo, Fedora и т.д. CMake давно лежит в официальных репозиториях. Нам нужно всего лишь установить пакет cmake с помощью менеджера пакетов. Как правило, он устанавливается в системные директории, и необходимости править переменные окружения нету. Можете проверить её работоспособность, выполнив

cmake --version 

Если же в репозитории нет такого пакета, то можно его собрать вручную. Скачиваем Unix/Linux Source, например, cmake-3.5.0-rc3.tar.gz, распаковываем и собираем:

tar -xzf cmake-3.5.0-rc3.tar.gz sudo make install 

Если нет необходимости устанавливать в системную /usr директорию, можно в аргументе —prefix прописать нужный корень установки. По умолчанию, без явного указания —prefix, установка будет произведена в /usr/local. -j используется для ускорения сборки, например, на 4-х ядерном процессоре можно указать -j4, и сборка будет вестись параллельно в 4 потока.

Установка в Windows.

Для Windows на сайте CMake лежит установочный файл msi. Рекомендую при установке отметить галочку добавления пути в переменные окружения PATH для всех пользователей. Тогда, после перелогинивания, CMake будет доступен из любого места. Проверить можно, открыв cmd и выполнив тот же

cmake --version 

Основная цель работы CMake – создание Makefile или проекта для конкретной среды программирования по файлу проекта CMakeLists.txt. За тип создаваемых файлов отвечает аргумент -G. Можно посмотреть поддерживаемые генераторы, выполнив

 cmake -G 

Т.е. любой проект с использованием этой системы сборки начинается с создания CMakeLists.txt, в котором описывается проект.

CMakeLists.txt

Основную документацию можно посмотреть на сайте CMake, а здесь я расскажу коротко об основных правилах написания этого файла. В этом файле описываются исходные файлы, подключаемые библиотеки, параметры компиляции, подпроекты и правила установки. В одном файле разрешается создавать несколько исполняемых файлов или библиотек и подключать несколько подпроектов. Под подпроектом я подразумеваю просто другую папку с CMakeLists.txt. В этом и состоит основная прелесть CMake – он не накладывает никаких ограничений на состав и сложность проекта. Один файл может описывать как самостоятельное приложение, так и быть корневым файлом сложного программного комплекса. Или, например, в одном файле можно описать сборку библиотеки и исполняемого файла, использующего эту библиотеку, а также тут же подключить ещё парочку подпроектов.

Итак, пример простейшего CMakeLists.txt:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *