Cmake руководство на русском

Время на прочтение
7 мин

Количество просмотров 458K

imageCMake — кроcсплатформенная утилита для автоматической сборки программы из исходного кода. При этом сама CMake непосредственно сборкой не занимается, а представляет из себя front-end. В качестве back-end`a могут выступать различные версии make и Ninja. Так же CMake позволяет создавать проекты для CodeBlocks, Eclipse, KDevelop3, MS VC++ и Xcode. Стоит отметить, что большинство проектов создаются не нативных, а всё с теми же back-end`ами.

Для того что бы собрать проект средствами CMake, необходимо в корне дерева исходников разместить файл CMakeLists.txt, хранящий правила и цели сборки, и произвести несколько простых шагов.
Разберёмся на примерах.

Пример 1. Hello, World:

Для начала напишем простейший хеловорлд и создадим структуру проекта:

main.cpp

#include <iostream>
int main(int argc, char** argv)
{
	std::cout << "Hello, World!" << std::endl;
	return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.8) # Проверка версии CMake.
									# Если версия установленой программы
									# старее указаной, произайдёт аварийный выход.

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

Синтаксис CMake похож на синтаксис bash, всё что после символа «#» является комментарием и обрабатываться программой не будет. CMake позволяет не засорять дерево исходных кодов временными файлами — очень просто и без лишних телодвижений сборка производится «Out-of-Source».

Создадим пустую директорию для временных файлов и перейдём туда.

fshp@panica-desktop:~$ mkdir tmp
fshp@panica-desktop:~$ cd tmp/
fshp@panica-desktop:~/tmp$

Теперь запустим команду cmake, передав ей в качестве параметра путь к папке с исходниками:

fshp@panica-desktop:~/tmp$ cmake ~/cmake/example_1/

— Build files have been written to: /home/fshp/tmp
fshp@panica-desktop:~/tmp$
fshp@panica-desktop:~/tmp$ ls
CMakeCache.txt CMakeFiles cmake_install.cmake Makefile
fshp@panica-desktop:~/tmp$

Видим, что в папке появилось несколько временных файлов, необходимых для сборки проекта.
Теперь можно запустить непосредственно make:

fshp@panica-desktop:~/tmp$ make
Scanning dependencies of target main
[100%] Building CXX object CMakeFiles/main.dir/main.cpp.o
Linking CXX executable main
[100%] Built target main
fshp@panica-desktop:~/tmp$ ./main
Hello, World!
fshp@panica-desktop:~/tmp$

Итак, наша программа собралась.
Папку tmp можно очищатьудалять без риска поломать исходники. Если CMakeLists.txt был изменен, то вызов make автоматически запустит cmake. Если исходники были перемещены, то нужно очистить временную директорию и запустить cmake вручную.

Пример 2. Библиотеки:

Если ваш проект содержит библиотеку, то CMake соберет ее без проблем.
Для этого усложним пример.

foo.cpp

#include <iostream>
void hello_world()
{
	std::cout << "Hello, World!" << std::endl;
}

main.cpp

#include "foo.h"
int main(int argc, char** argv)
{
	hello_world();
	return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)	 # Проверка версии CMake.
										# Если версия установленой программы
										# старее указаной, произайдёт аварийный выход.

project(hello_world)			# Название проекта

set(SOURCE_EXE main.cpp)		# Установка переменной со списком исходников для исполняемого файла

set(SOURCE_LIB foo.cpp)			# Тоже самое, но для библиотеки

add_library(foo STATIC ${SOURCE_LIB})	# Создание статической библиотеки с именем foo

add_executable(main ${SOURCE_EXE})	# Создает исполняемый файл с именем main

target_link_libraries(main foo)		# Линковка программы с библиотекой

Переменные могут хранить списки значений, разделённых пробеламитабуляциямипереносами:

set(SOURCE main.cpp foo.cpp)
set(HEADER main.h
			foo.h)

Оба варианта правильные
Что бы получить значение переменной ипользуем конструкцию:

${var_name}

Итак, эта версия нашего проекта включает в себя одну статическую библиотеку, собираемую из исходников. Если заменить «STATIC» на «SHARED», то получим библиотеку динамическую. Если тип библиотеки не указать, по умолчанию она соберётся как статическая.
При линковке указываются все необходимые библиотеки:

target_link_libraries(main  foo
							ogg
							vorbis)

Как и при ручной компиляции, имена библиотек указываются без стандартного префикса «lib».
Итак, сборка библиотек с CMake не вызывает проблем, при этом тип библиотеки статическаядинамическая меняется лишь одним параметром.

Пример 3. Подпроекты:

Подпроекты очень удобны, если ваша программа разбита на несколько библиотек или же проект состоит из нескольких программ.
Каждый подпроект является по сути полноценным проектом и может использоваться самостоятельно.
Теперь у нас «foo» находится в субдирректории и там же находится CMakeLists.txt подпроекта.

CMakeLists.txt

cmake_minimum_required(VERSION 2.8) # Проверка версии CMake.
									# Если версия установленой программы
									# старее указаной, произайдёт аварийный выход.

project(hello_world)				# Название проекта

set(SOURCE_EXE main.cpp)			# Установка переменной со списком исходников

include_directories(foo)			# Расположение заголовочных файлов

add_executable(main ${SOURCE_EXE})	# Создает исполняемый файл с именем main

add_subdirectory(foo)				# Добавление подпроекта, указывается имя дирректории

target_link_libraries(main foo)		# Линковка программы с библиотекой

main.cpp

#include "foo.h"
int main(int argc, char** argv)
{
	hello_world();
	return 0;
}

foo/CMakeLists.txt

cmake_minimum_required(VERSION 2.8) # Проверка версии CMake.
									# Если версия установленой программы
									# старее указаной, произайдёт аварийный выход.

project(foo)				# Название проекта

set(SOURCE_LIB foo.cpp)		# Установка переменной со списком исходников

add_library(foo STATIC ${SOURCE_LIB})# Создание статической библиотеки

foo/foo.cpp

#include <iostream>
void hello_world()
{
	std::cout << "Hello, World!" << std::endl;
}

В файле подпроекта ничего нового для вас нет. А вот в основном файле новые команды:

include_directories(foo)

main.cpp мы не меняли, а foo.h перенесли. Команда указывает компилятору, где искать заголовочные файлы. Может быть вызвана несколько раз. Хидеры будут искаться во всех указаных директориях.

add_subdirectory(foo)

Указываем директорию с подпроектом, который будет собран как самостоятельный.
Вывод: проекты на CMake можно объединять в довольно сложные иерархические структуры, причем каждый подпроект в реальности является самостоятельным проектом, который в свою очередь может сам состоять из подпроектов. Это позволяет легко разбить вашу программу на необходимое количество отдельных модулей. Примером такого подхода может служить KDE.

Пример 4. Поиск библиотек:

CMake обладает достаточно развитыми средствами поиска установленых библиотек, правда они не встроеные, а реализованы в виде отдельных модулей. В стандартной поставке довольно много модулей, но некоторые проекты (например Ogre) поставляют свои. Они позволяют системе автоматически определить наличие необходимых для линковки проекта библиотек.
На debian модули располагаются в /usr/share/cmake-2.8/Modules/ (у вас версия может отличаться). За поиск библиотек отвечают модули, называющиеся FindNAME.cmake, где NAME — имя библиотеки.

find_package(SDL REQUIRED)
if(NOT SDL_FOUND)
	message(SEND_ERROR "Failed to find SDL")
	return()
else()
	include_directories(${SDL_INCLUDE_DIR})
endif()
##########################################################
find_package(LibXml2 REQUIRED)
if(NOT LIBXML2_FOUND)
	message(SEND_ERROR "Failed to find LibXml2")
	return()
else()
	include_directories(${LIBXML2_INCLUDE_DIR})
endif()
##########################################################
find_package(Boost COMPONENTS thread-mt REQUIRED)
if(NOT Boost_FOUND)
	message(SEND_ERROR "Failed to find boost::thread-mt.")
	return()
else()
	include_directories(${Boost_INCLUDE_DIRS})
endif()
##########################################################
target_link_libraries(${TARGET} 
								${SDL_LIBRARY}
								${LIBXML2_LIBRARIES}
								${Boost_LIBRARIES})

Думаю, смысл должен быть понятен. Первый и второй блок — поиск библиотеки. Если в системе её нет, выведется сообщение об ошибке и завершается выполнение cmake. Третий блок похож, только он ищет не целый пакет библиотек, а лишь необходимый компонент. Каждый такой автоматизированый поиск определяет после выполнения как минимум 3 переменные:
SDL_FOUND, LIBXML2_FOUND, Boost_FOUND — признак присутствия бибилиотеки;
SDL_LIBRARY, LIBXML2_LIBRARIES, Boost_LIBRARIES — имена библиотек для линковки;
SDL_INCLUDE_DIR, LIBXML2_INCLUDE_DIR, Boost_INCLUDE_DIRS — пути к заголовочным файлам.
Если с первыми более или менее понятно, то вторые и третьи мне доставили много хлопот — половина имеет имена в единственном числе, половина — во множественном. Но оказалось, это легко отследить. В каждом модуле вначале есть коментарии, там описаны определяемые переменные. Посмотрите, например, /usr/share/cmake-2.8/Modules/FindLibXml2.cmake
Как видите, CMake способен сам определить наличие и местоположение необходимых библиотек и заголовочных файлов. В принципе, это должна уметь любая система автоматической сборки, иначе смысл в ней?

Пример 5. Внешние библиотеки и объектные файлы:

Если вы пишите для «дяди», а злой «дядя» любит самописные библиотеки и делиться исходниками не желает, поэтому присылает готовую библиотеку, то вы по адресу.
Объектные файлы в CMake стоят на ряду с исходниками — достаточно включить объектник в список файлов для компиляции.
С библиотеками потуже. Как известно, статическая библиотека это не что иное, как ar-архив, внутри которого лежат обычные объектники, никак не связаные между собой. Вы, наверное, уже догадались, как я поступал сначала. Да, просто потрошил библиотеку. Но потом был найден способ поэлегантнее:

add_library(netutil STATIC IMPORTED)
set_property(TARGET netutil PROPERTY
             IMPORTED_LOCATION Binary/game_client/libnetutil.a)

Слово «IMPORTED», указывает, что библиотека берётся извне.
В CMake каждая цель имеет параметры, а set_property позволяет их изменять.
Линкуется такая библиотека стандартно:

target_link_libraries(${TARGET} netutil)

Для динамических библиотек все аналогично, только тип «SHARED», расширение — «.so».
К сожалению, поддержка несистемных библиотек реализована немного костыльно. Возможно, я просто не знаю правильного варианта, поэтому буду рад, если «ткнете мордочкой». С другой стороны это не навороченый экзоскелет с системой жизнеобеспечения, а простейший костыль из двух строк.

Генераторы:

Как было сказано в начале, CMake умеет генерировать множество различных видов проектов. Это удобно и позволяет использовать CMake для практически любой популярной IDE.
Если запустить cmake без параметров, в конце будут описаны доступные генераторы. Пользоваться так:

fshp@panica-desktop:~/tmp$ cmake ~/cmake/example_3/ -G «KDevelop3 — Unix Makefiles»

Заключение:

Это не перевод мануала, а результат использования CMake в одном коммерческом проекте. Буду рад, если статья поможет хотя бы одному человеку — на русском языке подобной документации довольно мало.

Чем понравился CMake лично мне:

  • один проект — один файл. Не нужно хранить кучу скриптов настройки, сборки и прочего хлама;
  • Скорость работы в сравнении с autotools;
  • простой и понятный синтаксис, конечно с элегантностью питона не потягаться, но и не брейнфак, в конце концов.;
  • является front-end`ом для множества IDE;
  • отображение прогресса — довольно удобно;
  • цветной вывод — в серые будни немного краски не помешает;

Для Sublime Text есть плагин, добавляющий подсветку синтаксиса CMake, он так и называется — «CMake».
Примеры

Полное руководство по CMake. Часть вторая: Система сборки +37

C++, Системы сборки, C


Рекомендация: подборка платных и бесплатных курсов таргетированной рекламе — https://katalog-kursov.ru/

Введение

В данной статье рассмотрено использование системы сборки CMake, применяемой в колоссальном количестве проектов на C/C++. Строго рекомендуется прочитать первую часть руководства во избежание непонимания синтаксиса языка CMake, явным образом фигурирующего на протяжении всей статьи.

Ниже приведены примеры использования языка CMake, по которым Вам следует попрактиковаться. Экспериментируйте с исходным кодом, меняя существующие команды и добавляя новые. Чтобы запустить данные примеры, установите CMake с официального сайта.

Принцип работы

Система сборки CMake представляет из себя оболочку над другими платформенно зависимыми утилитами (например, Ninja или Make). Таким образом, в самом процессе сборки, как бы парадоксально это ни звучало, она непосредственного участия не принимает.

Система сборки CMake принимает на вход файл CMakeLists.txt с описанием правил сборки на формальном языке CMake, а затем генерирует промежуточные и нативные файлы сборки в том же каталоге, принятых на Вашей платформе.

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

Проверка версии CMake

Команда cmake_minimum_required проверяет запущенную версию CMake: если она меньше указанного минимума, то CMake завершает свою работу фатальной ошибкой. Пример, демонстрирующий типичное использование данной команды в начале любого CMake-файла:

# Задать третью минимальную версию CMake:
cmake_minimum_required(VERSION 3.0)

Как подметили в комментариях, команда cmake_minimum_required выставляет все флаги совместимости (смотреть cmake_policy). Некоторые разработчики намеренно выставляют низкую версию CMake, а затем корректируют функционал вручную. Это позволяет одновременно поддерживать древние версии CMake и местами использовать новые возможности.

Оформление проекта

В начале любого CMakeLists.txt следует задать характеристики проекта командой project для лучшего оформления интегрированными средами и прочими инструментами разработки.

# Задать характеристики проекта "MyProject":
project(MyProject VERSION 1.2.3.4 LANGUAGES C CXX)

Стоит отметить, что если ключевое слово LANGUAGES опущено, то по умолчанию задаются языки C CXX. Вы также можете отключить указание любых языков путём написания ключевого слова NONE в качестве списка языков или просто оставить пустой список.

Запуск скриптовых файлов

Команда include заменяет строку своего вызова кодом заданного файла, действуя аналогично препроцессорной команде include языков C/C++. Этот пример запускает скриптовый файл MyCMakeScript.cmake описанной командой:

message("'TEST_VARIABLE' is equal to [${TEST_VARIABLE}]")

# Запустить скрипт `MyCMakeScript.cmake` на выполнение:
include(MyCMakeScript.cmake)

message("'TEST_VARIABLE' is equal to [${TEST_VARIABLE}]")

В данном примере, первое сообщение уведомит о том, что переменная TEST_VARIABLE ещё не определена, однако если скрипт MyCMakeScript.cmake определит данную переменную, то второе сообщение уже будет информировать о новом значении тестовой переменной. Таким образом, скриптовый файл, включаемый командой include, не создаёт собственной области видимости, о чём упомянули в комментариях к предыдущей статье.

Компиляция исполняемых файлов

Команда add_executable компилирует исполняемый файл с заданным именем из списка исходников. Важно отметить, что окончательное имя файла зависит от целевой платформы (например, <ExecutableName>.exe или просто <ExecutableName>). Типичный пример вызова данной команды:

# Скомпилировать исполняемый файл "MyExecutable" из
# исходников "ObjectHandler.c", "TimeManager.c" и "MessageGenerator.c":
add_executable(MyExecutable ObjectHandler.c TimeManager.c MessageGenerator.c)

Компиляция библиотек

Команда add_library компилирует библиотеку с указанным видом и именем из исходников. Важно отметить, что окончательное имя библиотеки зависит от целевой платформы (например, lib<LibraryName>.a или <LibraryName>.lib). Типичный пример вызова данной команды:

# Скомпилировать статическую библиотеку "MyLibrary" из
# исходников "ObjectHandler.c", "TimeManager.c" и "MessageConsumer.c":
add_library(MyLibrary STATIC ObjectHandler.c TimeManager.c MessageConsumer.c)

  • Статические библиотеки задаются ключевым словом STATIC вторым аргументом и представляют из себя архивы объектных файлов, связываемых с исполняемыми файлами и другими библиотеками во время компиляции.
  • Динамические библиотеки задаются ключевым словом SHARED вторым аргументом и представляют из себя двоичные библиотеки, загружаемые операционной системой во время выполнения программы.
  • Модульные библиотеки задаются ключевым словом MODULE вторым аргументом и представляют из себя двоичные библиотеки, загружаемые посредством техник выполнения самим исполняемым файлом.
  • Объектные библиотеки задаются ключевым словом OBJECT вторым аргументом и представляют из себя набор объектных файлов, связываемых с исполняемыми файлами и другими библиотеками во время компиляции.

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

Бывают случаи, требующие многократного добавления исходных файлов к цели. Для этого предусмотрена команда target_sources, способная добавлять исходники к цели множество раз.

Первым аргументом команда target_sources принимает название цели, ранее указанной с помощью команд add_library или add_executable, а последующие аргументы являются списком добавляемых исходных файлов.

Повторяющиеся вызовы команды target_sources добавляют исходные файлы к цели в том порядке, в каком они были вызваны, поэтому нижние два блока кода являются функционально эквивалентными:

# Задать исполняемый файл "MyExecutable" из исходников
# "ObjectPrinter.c" и "SystemEvaluator.c":
add_executable(MyExecutable ObjectPrinter.c SystemEvaluator.c)

# Добавить к цели "MyExecutable" исходник "MessageConsumer.c":
target_sources(MyExecutable MessageConsumer.c)
# Добавить к цели "MyExecutable" исходник "ResultHandler.c":
target_sources(MyExecutable ResultHandler.c)

# Задать исполняемый файл "MyExecutable" из исходников
# "ObjectPrinter.c", "SystemEvaluator.c", "MessageConsumer.c" и "ResultHandler.c":
add_executable(MyExecutable ObjectPrinter.c SystemEvaluator.c MessageConsumer.c
ResultHandler.c)

Генерируемые файлы

Местоположение выходных файлов, сгенерированных командами add_executable и add_library, определяется только на стадии генерации, однако данное правило можно изменить несколькими переменными, определяющими конечное местоположение двоичных файлов:

  • Переменные RUNTIME_OUTPUT_DIRECTORY и RUNTIME_OUTPUT_NAME определяют местоположение целей выполнения.
  • Переменные LIBRARY_OUTPUT_DIRECTORY и LIBRARY_OUTPUT_NAME определяют местоположение библиотек.
  • Переменные ARCHIVE_OUTPUT_DIRECTORY и ARCHIVE_OUTPUT_NAME определяют местоположение архивов.

Исполняемые файлы всегда рассматриваются целями выполнения, статические библиотеки — архивными целями, а модульные библиотеки — библиотечными целями. Для «не-DLL» платформ динамические библиотеки рассматриваются библиотечными целями, а для «DLL-платформ» — целями выполнения. Для объектных библиотек таких переменных не предусмотрено, поскольку такой вид библиотек генерируется в недрах каталога CMakeFiles.

Важно подметить, что «DLL-платформами» считаются все платформы, основанные на Windows, в том числе и Cygwin.

Компоновка с библиотеками

Команда target_link_libraries компонует библиотеку или исполняемый файл с другими предоставляемыми библиотеками. Первым аргументом данная команда принимает название цели, сгенерированной с помощью команд add_executable или add_library, а последующие аргументы представляют собой названия целей библиотек или полные пути к библиотекам. Пример:

# Скомпоновать исполняемый файл "MyExecutable" с
# библиотеками "JsonParser", "SocketFactory" и "BrowserInvoker":
target_link_libraries(MyExecutable JsonParser SocketFactory BrowserInvoker)

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

Работа с целями

Как упомянули в комментариях, цели в CMake тоже подвержены ручному манипулированию, однако весьма ограниченному.

Имеется возможность управления свойствами целей, предназначенных для задания процесса сборки проекта. Команда get_target_property присваивает предоставленной переменной значение свойства цели. Данный пример выводит значение свойства C_STANDARD цели MyTarget на экран:

# Присвоить переменной "VALUE" значение свойства "C_STANDARD":
get_target_property(VALUE MyTarget C_STANDARD)

# Вывести значение полученного свойства на экран:
message("'C_STANDARD' property is equal to [${VALUE}]")

Команда set_target_properties устанавливает указанные свойства целей заданными значениями. Данная команда принимает список целей, для которых будут установлены значения свойств, а затем ключевое слово PROPERTIES, после которого следует список вида «<название свойства> <новое значение>»:

# Установить свойству 'C_STANDARD' значение "11",
# а свойству 'C_STANDARD_REQUIRED' значение "ON":
set_target_properties(MyTarget PROPERTIES C_STANDARD 11 C_STANDARD_REQUIRED ON)

Пример выше задал цели MyTarget свойства, влияющие на процесс компиляции, а именно: при компиляции цели MyTarget CMake затребует компилятора о использовании стандарта C11. Все известные именования свойств целей перечисляются на этой странице.

Также имеется возможность проверки ранее определённых целей с помощью конструкции if(TARGET <TargetName>):

# Выведет "The target was defined!" если цель "MyTarget" уже определена,
# а иначе выведет "The target was not defined!":
if(TARGET MyTarget)
    message("The target was defined!")
else()
    message("The target was not defined!")
endif()

Добавление подпроектов

Команда add_subdirectory побуждает CMake к незамедлительной обработке указанного файла подпроекта. Пример ниже демонстрирует применение описанного механизма:

# Добавить каталог "subLibrary" в сборку основного проекта,
# а генерируемые файлы расположить в каталоге "subLibrary/build":
add_subdirectory(subLibrary subLibrary/build)

В данном примере первым аргументом команды add_subdirectory выступает подпроект subLibrary, а второй аргумент необязателен и информирует CMake о папке, предназначенной для генерируемых файлов включаемого подпроекта (например, CMakeCache.txt и cmake_install.cmake).

Стоит отметить, что все переменные из родительской области видимости унаследуются добавленным каталогом, а все переменные, определённые и переопределённые в данном каталоге, будут видимы лишь ему (если ключевое слово PARENT_SCOPE не было определено аргументом команды set). Данную особенность упомянули в комментариях к предыдущей статье.

Поиск пакетов

Команда find_package находит и загружает настройки внешнего проекта. В большинстве случаев она применяется для последующей линковки внешних библиотек, таких как Boost и GSL. Данный пример вызывает описанную команду для поиска библиотеки GSL и последующей линковки:

# Загрузить настройки пакета библиотеки "GSL":
find_package(GSL 2.5 REQUIRED)

# Скомпоновать исполняемый файл с библиотекой "GSL":
target_link_libraries(MyExecutable GSL::gsl)

# Уведомить компилятор о каталоге заголовков "GSL":
target_include_directories(MyExecutable ${GSL_INCLUDE_DIRS})

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

Далее исполняемый файл MyExecutable линкуется с библиотекой GSL командой target_link_libraries с помощью переменной GSL::gsl, инкапсулирующей расположение уже скомпилированной GSL.

В конце вызывается команда target_include_directories, информирующая компилятора о расположении заголовочных файлов библиотеки GSL. Обратите внимание на то, что используется переменная GSL_INCLUDE_DIRS, хранящая местоположение описанных мною заголовков (это пример импортированных настроек пакета).

Вам, вероятно, захочеться проверить результат поиска пакета, если Вы указали опцию QUIET. Это можно сделать путём проверки переменной <PackageName>_FOUND, автоматически определяемой после завершения команды find_package. Например, в случае успешного импортирования настроек GSL в Ваш проект, переменная GSL_FOUND обратится в истину.

В общем случае, команда find_package имеет две разновидности запуска: модульную и конфигурационную. Пример выше применял модульную форму. Это означает, что во время вызова команды CMake ищет скриптовый файл вида Find<PackageName>.cmake в директории CMAKE_MODULE_PATH, а затем запускает его и импортирует все необходимые настройки (в данном случае CMake запустила стандартный файл FindGSL.cmake).

Способы включения заголовков

Информировать компилятора о располжении включаемых заголовков можно посредством двух команд: include_directories и target_include_directories. Вы решаете, какую из них использовать, однако стоит учесть некоторые различия между ними (идея предложена в комментариях).

Команда include_directories влияет на область каталога. Это означает, что все директории заголовков, указанные данной командой, будут применяться для всех целей текущего CMakeLists.txt, а также для обрабатываемых подпроектов (смотреть add_subdirectory).

Команда target_include_directories влияет лишь на указанную первым аргументом цель, а на другие цели никакого воздействия не оказывается. Пример ниже демонстрирует разницу между этими двумя командами:

add_executable(RequestGenerator RequestGenerator.c)
add_executable(ResponseGenerator ResponseGenerator.c)

# Применяется лишь для цели "RequestGenerator":
target_include_directories(RequestGenerator headers/specific)

# Применяется для целей "RequestGenerator" и "ResponseGenerator":
include_directories(headers)

В комментариях упомянуто, что в современных проектах применение команд include_directories и link_libraries является нежелательным. Альтернатива — это команды target_include_directories и target_link_libraries, действующие лишь на конкретные цели, а не на всю текущую область видимости.

Установка проекта

Команда install генерирует установочные правила для Вашего проекта. Данная команда способна работать с целями, файлами, папками и многим другим. Сперва рассмотрим установку целей.

Для установки целей необходимо первым аргументом описанной функции передать ключевое слово TARGETS, за которым должен следовать список устанавливаемых целей, а затем ключевое слово DESTINATION с расположением каталога, в который установятся указанные цели. Данный пример демонстрирует типичную установку целей:

# Установить цели "TimePrinter" и "DataScanner" в директорию "bin":
install(TARGETS TimePrinter DataScanner DESTINATION bin)

Процесс описания установки файлов аналогичен, за тем исключением, что вместо ключевого слова TARGETS следует указать FILES. Пример, демонстрирующий установку файлов:

# Установить файлы "DataCache.txt" и "MessageLog.txt" в директорию "~/":
install(FILES DataCache.txt MessageLog.txt DESTINATION ~/)

Процесс описания установки папок аналогичен, за тем исключением, что вместо ключевого слова FILES следует указать DIRECTORY. Важно подметить, что при установке будет копироваться всё содержимое папки, а не только её название. Пример установки папок выглядит следующим образом:

# Установить каталоги "MessageCollection" и "CoreFiles" в директорию "~/":
install(DIRECTORY MessageCollection CoreFiles DESTINATION ~/)

После завершения обработки CMake всех Ваших файлов Вы можете выполнить установку всех описанных объектов командой sudo checkinstall (если CMake генерирует Makefile), или же выполнить данное действие интегрированной средой разработки, поддерживающей CMake.

Наглядный пример проекта

Данное руководство было бы неполным без демонстрации реального примера использования системы сборки CMake. Рассмотрим схему простого проекта, использующего CMake в качестве единственной системы сборки:

+ MyProject
      - CMakeLists.txt
      - Defines.h
      - StartProgram.c
      + core
            - CMakeLists.txt
            - Core.h
            - ProcessInvoker.c
            - SystemManager.c

Главный файл сборки CMakeLists.txt описывает компиляцию всей программы: сперва происходит вызов команды add_executable, компилирующей исполняемый файл, затем вызывается команда add_subdirectory, побуждающая обработку подпроекта, и наконец, исполняемый файл линкуется с собранной библиотекой:

# Задать минимальную версию CMake:
cmake_minimum_required(VERSION 3.0)

# Указать характеристики проекта:
project(MyProgram VERSION 1.0.0 LANGUAGES C)

# Добавить в сборку исполняемый файл "MyProgram":
add_executable(MyProgram StartProgram.c)

# Требовать обработку файла "core/CMakeFiles.txt":
add_subdirectory(core)

# Скомпоновать исполняемый файл "MyProgram" со
# скомпилированной статической библиотекой "MyProgramCore":
target_link_libraries(MyProgram MyProgramCore)

# Установить исполняемый файл "MyProgram" в директорию "bin":
install(TARGETS MyProgram DESTINATION bin)

Файл core/CMakeLists.txt вызывается главным файлом сборки и компилирует статическую библиотеку MyProgramCore, предназначенную для линковки с исполняемым файлом:

# Задать минимальную версию CMake:
cmake_minimum_required(VERSION 3.0)

# Добавить в сборку статическую библиотеку "MyProgramCore":
add_library(MyProgramCore STATIC ProcessInvoker.c SystemManager.c)

После череды команд cmake . && make && sudo checkinstall работа системы сборки CMake завершается успешно. Первая команда запускает обработку файла CMakeLists.txt в корневом каталоге проекта, вторая команда окончательно компилирует необходимые двоичные файлы, а третья команда устанавливает скомпонованный исполняемый файл MyProgram в систему.

Заключение

Теперь Вы способны писать свои и понимать чужие CMake-файлы, а подробно прочитать про остальные механизмы Вы можете на официальном сайте.

Следующая статья данного руководства будет посвящена тестированию и созданию пакетов с помощью CMake и выйдет через неделю. До скорых встреч!

Добавлено 7 января 2023 в 23:23

С чего начать работу с CMake? Этот шаг познакомит вас с базовыми синтаксисом, некоторыми командами и переменными CMake. По мере введения этих концепций мы проработаем три упражнения и создадим простой проект CMake.

Руководство CMake. Шаг 1. Базовая отправная точка

Каждое упражнение на этом этапе начинается с некоторой исходной информации. Затем предоставляется цель и список полезных ресурсов. Каждый файл в разделе «Редактируемые файлы» находится в каталоге Step1 и содержит один или несколько комментариев TODO. Каждое TODO представляет собой одну или две строки кода, которые нужно изменить или добавить. TODO предназначены для выполнения в порядке нумерации, сначала выполните TODO 1, затем TODO 2 и т. д. В разделе «С чего начать» вы найдете несколько полезных советов и руководство по выполнению упражнения. Затем в разделе «Сборка и запуск» будет пошагово показано, как создать и протестировать упражнение. Наконец, в конце каждого упражнения обсуждается предполагаемое решение.

Также обратите внимание, что каждый шаг в руководстве основан на следующем. Так, например, исходный код для Шага 2 является полным решением для Шага 1.

Упражнение 1. Создание базового проекта

Самый простой проект CMake – это исполняемый файл, созданный из одного файла исходного кода. Для таких простых проектов достаточно файла CMakeLists.txt с тремя командами.

Примечание. Хотя CMake поддерживает команды, набранные в верхнем, нижнем и смешанном регистре, использование нижнего регистра предпочтительнее и будет использоваться на протяжении всего руководства.

Самый популярный файл CMakeLists.txt любого проекта должен начинаться с указания минимальной версии CMake с помощью команды cmake_minimum_required(). Она устанавливает параметры политики и гарантирует, что следующие функции CMake выполняются с совместимой версией CMake.

Чтобы начать проект, мы используем команду project() для установки имени проекта. Этот вызов требуется для каждого проекта и должен вызываться вскоре после cmake_minimum_required(). Как мы увидим позже, эту команду также можно использовать для указания другой информации на уровне проекта, такой как язык или номер версии.

Наконец, команда add_executable() указывает CMake создать исполняемый файл, используя указанные файлы исходного кода.

Цель

Узнать, как создать простой проект CMake.

Полезные ресурсы

  • add_executable()
  • cmake_minimum_required()
  • project()

Редактируемые файлы

  • CMakeLists.txt

С чего начать

Исходный код tutorial.cxx находится в каталоге Help/guide/tutorial/Step1 и может использоваться для вычисления квадратного корня числа. Этот файл на данном шаге редактировать не нужно.

В том же каталоге находится файл CMakeLists.txt, который вы должны заполнить. Начните с TODO 1 и проработайте до TODO 3.

Сборка и запуск

Как только TODO 1 – TODO 3 будут выполнены, мы будем готовы собрать и запустить наш проект! Сначала запустите исполняемый файл cmake или cmake-gui, чтобы сконфигурировать проект, а затем соберите его с помощью выбранного инструмента сборки.

Например, из командной строки мы можем перейти в каталог Help/guide/tutorial дерева исходного кода CMake и создать каталог сборки:

mkdir Step1_build

Затем перейдите в этот каталог сборки и запустите cmake, чтобы настроить проект и создать файлы нативной системы сборки:

cd Step1_build
cmake ../Step1

Затем вызовите эту систему сборки, чтобы скомпилировать/слинковать проект:

cmake --build .

Наконец, попробуйте использовать только что собранный Tutorial с этими командами:

Tutorial 4294967296
Tutorial 10
Tutorial

Решение

Как упоминалось выше, всё, что нам нужно для запуска, – это трехстрочный файл CMakeLists.txt. Первая строка – используем cmake_minimum_required() для установки версии CMake следующим образом:

TODO 1

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)

Следующим шагом для создания базового проекта является использование команды project() следующим образом, чтобы установить имя проекта:

TODO 2

CMakeLists.txt

project(Tutorial)

Последней командой для вызова базового проекта является add_executable(). Мы вызываем его так:

TODO 3

CMakeLists.txt

add_executable(Tutorial tutorial.cxx)

Упражнение 2. Определение стандарта C++

В CMake есть специальные переменные, которые либо создаются за кулисами, либо имеют значение для CMake, если они установлены кодом проекта. Многие из этих переменных начинаются с CMAKE_. Согласно соглашению об именовании избегайте этого префикса при создании переменных для ваших проектов. Две из этих специальных устанавливаемых пользователем переменных – CMAKE_CXX_STANDARD и CMAKE_CXX_STANDARD_REQUIRED. Их можно использовать вместе, чтобы указать стандарт C++, необходимый для сборки проекта.

Цель

Добавить функцию, которая требует C++11.

Полезные ресурсы

  • CMAKE_CXX_STANDARD
  • CMAKE_CXX_STANDARD_REQUIRED
  • set()

Редактируемы файлы

  • CMakeLists.txt
  • tutorial.cxx

С чего начать

Продолжаем редактировать файлы в каталоге Step1. Начните с TODO 4 и завершите TODO 6.

Во-первых, отредактируйте tutorial.cxx, добавив функцию, для которой требуется C++11. Затем обновите CMakeLists.txt, чтобы он требовал C++11.

Сборка и запуск

Давайте снова соберем наш проект. Поскольку мы уже создали каталог сборки и запустили CMake для упражнения 1, мы можем перейти к этапу сборки:

cd Step1_build
cmake --build .

Теперь мы можем попробовать использовать только что собранное приложение Tutorial с теми же командами, что и раньше:

Tutorial 4294967296
Tutorial 10
Tutorial

Решение

Начнем с добавления в наш проект функций C++11, заменив atof на std::stod в tutorial.cxx. Это выглядит следующим образом:

TODO 4

tutorial.cxx

  const double inputValue = std::stod(argv[1]);

Чтобы выполнить TODO 5, просто удалите #include <cstdlib>.

Нам нужно будет явно указать в коде CMake, что он должен использовать правильные флаги. Один из способов включить поддержку определенного стандарта C++ в CMake – использовать переменную CMAKE_CXX_STANDARD. Для этого руководства установите для переменной CMAKE_CXX_STANDARD в файле CMakeLists.txt значение 11, а для CMAKE_CXX_STANDARD_REQUIRED – значение True. Объявления CMAKE_CXX_STANDARD обязательно добавьте перед вызовом add_executable().

TODO 6

CMakeLists.txt

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

Упражнение 3. Добавление номера версии и сконфигурированного заголовочного файла

Иногда бывает полезно, чтобы переменная, определенная в файле CMakelists.txt, также была доступна в исходном коде. В этом случае мы хотели бы распечатать версию проекта.

Один из способов добиться этого – использовать сконфигурированный заголовочный файл. Мы создаем входной файл с одной или несколькими переменными для замены. Эти переменные имеют специальный синтаксис, похожий на @VAR@. Затем мы используем команду configure_file(), чтобы скопировать входной файл в заданный выходной файл и заменить эти переменные текущим значением VAR в файле CMakelists.txt.

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

Цель

Определить и сообщить номер версии проекта.

Полезные ресурсы

  • <PROJECT-NAME>_VERSION_MAJOR
  • <PROJECT-NAME>_VERSION_MINOR
  • configure_file()
  • target_include_directories()

Редактируемые файлы

  • CMakeLists.txt
  • tutorial.cxx

С чего начать

Продолжаем редактировать файлы из Step1. Начните с TODO 7 и завершите TODO 12. В этом упражнении мы начнем с добавления номера версии проекта в CMakeLists.txt. В том же файле используйте configure_file(), чтобы скопировать заданный входной файл в выходной файл и заменить некоторые значения переменных в содержимом входного файла.

Затем создайте входной заголовочный файл TutorialConfig.h.in, определяющий номера версий, которые будут принимать переменные, переданные из configure_file().

Наконец, обновите tutorial.cxx, чтобы распечатать номер его версии.

Сборка и запуск

Давайте снова соберем наш проект. Как и раньше, мы уже создали каталог сборки и запустили CMake, поэтому можем перейти к этапу сборки:

cd Step1_build
cmake --build .

Убедитесь, что теперь при запуске исполняемого файла без каких-либо аргументов выводится номер версии.

Решение

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

Сначала мы модифицируем файл CMakeLists.txt, чтобы использовать команду project() для установки имени проекта и номера версии. Когда вызывается команда project(), CMake за кулисами определяет Tutorial_VERSION_MAJOR и Tutorial_VERSION_MINOR.

TODO 7

CMakeLists.txt

project(Tutorial VERSION 1.0)

Затем мы используем configure_file() для копирования входного файла с заменой переменных, указанных CMake:

TODO 8

CMakeLists.txt

configure_file(TutorialConfig.h.in TutorialConfig.h)

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

Примечание. В этом руководстве мы будем ссылаться на сборку проекта и каталог бинарных файлов проекта как синонимы. Они одинаковы и не означают ссылку на каталог bin/.

Используем target_include_directories(), чтобы указать, где исполняемая цель должна искать включаемые файлы.

TODO 9

CMakeLists.txt

target_include_directories(Tutorial PUBLIC
                           "${PROJECT_BINARY_DIR}"
                           )

TutorialConfig.h.in – это входной заголовочный файл, который необходимо сконфигурировать. Когда configure_file() вызывается из нашего CMakeLists.txt, значения для @Tutorial_VERSION_MAJOR@ и @Tutorial_VERSION_MINOR@ будут заменены в TutorialConfig.h соответствующими номерами версий из проекта.

TODO 10

TutorialConfig.h.in

// сконфигурированные параметры и настройки для Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

Затем нам нужно изменить tutorial.cxx, включив в него сконфигурированный заголовочный файл TutorialConfig.h.

TODO 11

tutorial.cxx

#include "TutorialConfig.h"

Наконец, мы распечатываем имя исполняемого файла и номер версии, обновляя tutorial.cxx следующим образом:

TODO 12

tutorial.cxx

  if (argc < 2) {
    // сообщить версию
    std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
              << Tutorial_VERSION_MINOR << std::endl;
    std::cout << "Usage: " << argv[0] << " number" << std::endl;
    return 1;
  }

Теги

C++ / CppCMakeАвтоматизация сборкиПрограммированиеСистема сборки

Полное руководство по CMake. Часть первая: Синтаксис - 1

Введение

CMake — это открытый и кросс-платформенный набор утилит, предназначенных для автоматизации тестирования, компиляции и создания пакетов проектов на C/C++. Написав однажды небольшой и понятный всем скрипт, Вы тем самым обеспечите одинаковую сборку вашего проекта на любых платформах, где доступен CMake.

Язык CMake, будучи транслированным в нативный файл сборки (например, Makefile или Ninja), определяет процесс всего управления проектом. В Вашем распоряжении, с функциональной стороны, есть лишь команды, которые могут образовываться в довольно сложные конструкции. С них мы и начнём.

Запуск CMake

Ниже приведены примеры использования языка CMake, по которым Вам следует попрактиковаться. Экспериментируйте с исходным кодом, меняя существующие команды и добавляя новые. Чтобы запустить данные примеры, следуйте этим шагам:

  1. Установите программу CMake с официального сайта
  2. Создайте на рабочем столе текстовый файл CMakeLists.txt
  3. Добавьте в начало файла cmake_minimum_required(VERSION 3.0)
  4. Скопируйте туда исходные тексты необходимых примеров
  5. Если у Вас установлен консольный CMake, то запустить скрипт можно с помощью команды «cmake .«. Если у Вас графический CMake, то в первые два верхних поля приложения вбейте адрес Вашего рабочего стола, затем нажмите кнопку Generate. Результат появится в нижнем текстовом поле.

Команды

Команды в CMake подобны функциям во многих языках программирования. Чтобы вызвать команду, необходимо написать её имя, а затем передать ей обрамлённые в круглые скобки аргументы, отделённые символами пробелов. В приведённом примере команде message передаются шесть аргументов для вывода в консоль:

# Напечатает в консоль "CMake is the most powerful buildsystem!"
message("CMake " "is " "the " "most " "powerful " "buildsystem!")

Аргументы

Аргументы, обрамлённые в двоёные кавычки, позволяют внутри себя совершать экранирование и подстановку переменных. Необрамлённые аргументы не позволяют производить подобных вещей и не могут включать в себя символов ()#" и пробелов, однако более удобны для использования. Пример:

# Напечатает "Hello, my lovely CMake", один таб и "!":
message("Hello, my lovely CMaket!")

# Напечатает "Hello,_my_lovely_CMake!" без пробелов:
message(Hello,_my_lovely_CMake!)

Комментарии

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

Переменные

Переменные можно определить путём вызова команды set, а удалить вызовом unset. Получить значение переменной можно по конструкции ${VARIABLE}. Пример:

# Определить переменную VARIABLE со значением "Mr. Thomas":
set(VARIABLE "Mr. Thomas")

# Напечает "His name is: Mr. Thomas":
message("His name is: " ${VARIABLE})

# Удалить переменную VARIABLE:
unset(VARIABLE)

Логические выражения

Прежде чем приступать к изучению условных операторов и циклических конструкций, необходимо понимать работу логических выражений. Логические выражения используются при проверки условий и могут принимать одно из двух значений: правда или ложь. Например, выражение 52 LESS 58 обратится в правду, так как 52 < 58. Выражение 88 EQUAL 88 обратится в правду, 63 GREATER 104 обратится в ложь. Сравнивать можно не только числа, но и строки, версии, файлы, принадлежность к списку и регулярные выражения. Полный список логических выражений можно посмотреть тут.

Условные операторы

Условные операторы в CMake работают в точности как в других языках программирования. В данном примере сработает лишь первый условный оператор, который проверяет, что 5 > 1. Второе и третье условия ложны, так как 5 не может быть меньше или равняться одному. Блоки команд elseif(5 LESS 1) и else() необязательны, а endif() обязательна и сигнализирует о завершении предыдущих проверок.

# Напечатает "Of course, 5 > 1!":
if(5 GREATER 1)
    message("Of course, 5 > 1!")
elseif(5 LESS 1)
    message("Oh no, 5 < 1!")
else()
    message("Oh my god, 5 == 1!")
endif() 

Циклы

Циклы в CMake подобны циклам других языков программирования. В приведённом примере устанавливается значение переменной VARIABLE в Airport, а затем четыре вложенные команды последовательно исполняются пока значение переменной VARIABLE будет равняться Airport. Последняя четвёртая команда set(VARIABLE "Police station") устанавливает значение проверяемой переменной в Police station, поэтому цикл сразу остановится, не дойдя до второй итерации. Команда endwhile() сигнализирует о завершении списка вложенных в цикл команд.

# Напечатает в консоль три раза "VARIABLE is still 'Airport'":
set(VARIABLE Airport)
while(${VARIABLE} STREQUAL Airport)
    message("VARIABLE is still '${VARIABLE}'")
    message("VARIABLE is still '${VARIABLE}'")
    message("VARIABLE is still '${VARIABLE}'")
    set(VARIABLE "Police station")
endwhile()

Данный пример цикла foreach работает следующим образом: на каждой итерации данного цикла переменной VARIABLE присваивается следующее значение из списка Give me the sugar please!, а затем исполняется команда message(${VARIABLE}), которая выводит текущее значение переменной VARIABLE. Когда значений в списке не остаётся, то цикл завершает своё выполнение. Команда endforeach() сигнализирует о завершении списка вложенных в цикл команд.

# Напечатает "Give me the sugar please!" с новых строк:
foreach(VARIABLE Give me the sugar please!)
    message(${VARIABLE})
endforeach()

Существуют ещё 3 формы записи цикла foreach. Первый цикл в данном примере на место списка генерирует целые числа от 0 до 10, второй цикл генерирует в диапозоне от 3 до 15, а третий цикл работает в сегменте от 50 до 90, но с шагом 10.

# Напечатает "0 1 2 3 4 5 6 7 8 9 10" с новых строк:
foreach(VARIABLE RANGE 10)
    message(${VARIABLE})
endforeach()

# Напечатает "3 4 5 6 7 8 9 10 11 12 13 14 15" с новых строк:
foreach(VARIABLE RANGE 3 15)
    message(${VARIABLE})
endforeach()

# Напечатает "50 60 70 80 90" с новых строк:
foreach(VARIABLE RANGE 50 90 10)
    message(${VARIABLE})
endforeach()

Функции и макросы

Синтаксис CMake позволяет определять собственные команды, которые можно будет вызывать в точности как встроенные. Приведённый ниже пример демонстрирует использование функций и макросов: сначала определяются функция и макрос со своими собственными командами, а при их вызове их команды исполняются последовательно.

# Определение функции "print_numbers":
function(print_numbers NUM1 NUM2 NUM3)
    message(${NUM1} " " ${NUM2} " " ${NUM3})
endfunction()

# Определение макроса "print_words":
macro(print_words WORD1 WORD2 WORD3)
    message(${WORD1} " "  ${WORD2} " " ${WORD3})
endmacro()

# Вызов функции "print_numbers", которая напечатает "12 89 225":
print_numbers(12 89 225)

# Вызов макроса "print_words", который напечатает "Hey Hello Goodbye":
print_words(Hey Hello Goodbye)

Команда function первым аргументов принимает имя будущей функции, а остальные аргументы — это имена параметров, с которыми можно работать как с обычными переменными. Параметры видимы лишь определяемой функции, значит вне функции доступ к её параметрам мы получить не можем. Более того, все другие переменные, определяемые и переопределяемые внутри функции, видны лишь ей самой.

Макросы аналогичны функциям за тем исключением, что они не имеют собственной области видимости: все переменные внутри макросов рассматриваются как глобальные. Более подробно о различиях макросов и функций Вы можете почитать здесь.

Области видимости

В предыдущем разделе Вы узнали о том, что некоторые конструкции в CMake могут определять собственные области видимости. На самом деле, все переменные по умолчанию считаются глобальными (доступ к ним есть везде), за исключением тех, которые были определены и переопределены в функциях. Также имеются кэш-переменные, у которых своя собственная область видимости, но они применяются не столь часто.

Заключение

На этом синтаксис языка CMake заканчивается. Следующая статья выйдет примерно через пару дней и будет вводить в использование системы сборки CMake. До скорых встреч!

Автор: Gymmasssorla

Источник

Руководство по взаимодействию с пользователем

  • Introduction

    • Инструмент командной строки
    • cmake-gui tool
  • Генерация системы сборки

    • Командная строка среды
    • Командная строка -G опция
    • Выбор генератора в смоделированном виде
  • Установка Строить Переменные

    • Установка переменных в командной строке
    • Установка переменных с помощью cmake-gui
    • Кэш CMake
  • Presets

    • Использование предустановок в командной строке
    • Использование предустановок в смейк-гуи
  • Ссылка на систему Buildsystem

    • Выбор цели
    • Указание программы создания
  • Software Installation
  • Running Tests

Introduction

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

Хорошо себя зарекомендовавшие системы сборки на основе CMake не создают никаких результатов в исходном каталоге,поэтому обычно пользователь выполняет сборку вне исходного кода и выполняет сборку там.Сначала CMake должен быть проинструктирован о том,чтобы сгенерировать подходящую систему сборки,затем пользователь вызывает инструмент сборки для обработки сгенерированной системы сборки.Генерируемая система сборки специфична для машины,используемой для ее создания,и не подлежит перераспределению.Каждый потребитель предоставленного пакета исходного программного обеспечения должен использовать CMake для генерации системы сборки,специфичной для его системы.

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

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

Инструмент CMake может сообщать пользователю об ошибках при обработке предоставленных файлов CMake, например сообщать, что компилятор не поддерживается, или компилятор не поддерживает требуемый параметр компиляции, или зависимость не может быть найдена. Эти ошибки должны быть устранены пользователем путем выбора другого компилятора, installing dependencies или указания CMake, где их найти, и т. Д.

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

Простое, но типичное использование cmake(1) со свежей копией исходного кода программного обеспечения — это создать каталог сборки и вызвать там cmake:

$ cd some_software-1.4.2
$ mkdir build
$ cd build
$ cmake .. -DCMAKE_INSTALL_PREFIX=/opt/the/prefix
$ cmake --build .
$ cmake --build . --target install

Рекомендуется собирать в отдельном каталоге к исходному тексту,так как это позволяет сохранить исходный текст в первозданном виде,позволяет собрать один исходный текст с несколькими цепочками инструментов,а также позволяет легко очистить артефакты сборки,просто удалив каталог сборки.

Инструмент CMake может сообщать предупреждения, которые предназначены для поставщика программного обеспечения, а не для потребителя программного обеспечения. Такие предупреждения заканчиваются на «Это предупреждение для разработчиков проекта». Пользователи могут отключить такие предупреждения, передав флаг -Wno-dev в cmake(1) .

cmake-gui tool

Пользователи, более привыкшие к графическим интерфейсам, могут использовать инструмент cmake-gui(1) для вызова CMake и создания системы сборки.

Сначала должны быть заполнены исходный и двоичный каталоги.Всегда рекомендуется использовать разные каталоги для источника и сборки.

Choosing source and binary directories

Генерация системы сборки

Существует несколько инструментов пользовательского интерфейса, которые можно использовать для создания системы сборки из файлов CMake. Инструменты ccmake(1) и cmake-gui(1) помогают пользователю настроить различные необходимые параметры. Инструмент cmake(1) можно вызвать, чтобы указать параметры в командной строке. В этом руководстве описаны параметры, которые можно установить с помощью любого из инструментов пользовательского интерфейса, хотя режим настройки параметра отличается для каждого инструмента.

Командная строка среды

При вызове cmake(1) с системой сборки из командной строки, такой как Makefiles или Ninja , необходимо использовать правильную среду сборки, чтобы гарантировать доступность инструментов сборки. CMake должен иметь возможность найти подходящий build tool , компилятор, компоновщик и другие инструменты по мере необходимости.

В системах Linux соответствующие инструменты часто предоставляются в местах расположения всей системы и могут быть легко установлены с помощью системного менеджера пакетов.Могут также использоваться другие инструменты,предоставляемые пользователем или устанавливаемые в местах,не являющихся местами по умолчанию.

При кросс-компиляции некоторые платформы могут требовать установки переменных окружения или предоставлять скрипты для установки окружения.

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

При использовании Xcode может быть установлено более одной версии Xcode.Какая из них может быть выбрана несколькими разными способами,но наиболее распространенными из них являются:

  • Установка версии по умолчанию в настройках Xcode IDE.
  • Установка версии по умолчанию с помощью xcode-select командной строки xcode-select .
  • Overriding the default version by setting the DEVELOPER_DIR environment variable when running CMake and the build tool.

Для удобства cmake-gui(1) предоставляет редактор переменных окружения.

Командная строка -G опция

CMake по умолчанию выбирает генератор на основе платформы.Обычно генератора по умолчанию достаточно,чтобы пользователь мог приступить к сборке программного обеспечения.

Пользователь может переопределить генератор по умолчанию с помощью опции -G :

$ cmake .. -G Ninja

Вывод cmake --help включает список generators доступных пользователю на выбор. Обратите внимание, что имена генераторов чувствительны к регистру.

В Unix-подобных системах (включая Mac OS X) генератор Unix Makefiles используется по умолчанию. Вариант этого генератора также можно использовать в Windows в различных средах, таких как NMake Makefiles и MinGW Makefiles . Эти генераторы генерируют вариант Makefile , который можно запустить с помощью make , gmake , nmake или подобных инструментов. Дополнительную информацию о целевых средах и инструментах см. в документации по отдельным генераторам.

Генератор Ninja доступен на всех основных платформах. ninja — это инструмент сборки, похожий по сценариям использования на make , но с упором на производительность и эффективность.

В Windows cmake(1) можно использовать для создания решений для IDE Visual Studio. Версии Visual Studio можно указать по названию продукта IDE, которое включает четырехзначный год. Предоставляются псевдонимы для других средств, с помощью которых иногда упоминаются версии Visual Studio, например, две цифры, соответствующие версии продукта компилятора VisualC ++, или их сочетание:

$ cmake .. -G "Visual Studio 2019"
$ cmake .. -G "Visual Studio 16"
$ cmake .. -G "Visual Studio 16 2019"

Генераторы Visual Studio могут ориентироваться на разные архитектуры. Можно указать целевую архитектуру с помощью опции -A :

cmake .. -G "Visual Studio 2019" -A x64
cmake .. -G "Visual Studio 16" -A ARM
cmake .. -G "Visual Studio 16 2019" -A ARM64

В Apple генератор Xcode можно использовать для создания файлов проекта для Xcode IDE.

Некоторые IDE, такие как KDevelop4, QtCreator и CLion, имеют встроенную поддержку систем сборки на основе CMake. Эти IDE предоставляют пользовательский интерфейс для выбора базового генератора для использования, обычно это выбор между Makefile или генератором на основе Ninja .

Обратите внимание, что невозможно изменить генератор с помощью -G после первого вызова CMake. Чтобы изменить генератор, необходимо удалить каталог сборки и запустить сборку с нуля.

При создании файлов проектов и решений Visual Studio доступны несколько других параметров, которые можно использовать при первоначальном запуске cmake(1) .

Набор инструментов Visual Studio можно указать с помощью параметра -T :

$ 
$ cmake.exe .. -G "Visual Studio 16 2019" -A x64 -T ClangCL
$ 
$ cmake.exe .. -G "Visual Studio 16 2019" -A x64 -T v120_xp

В то время как параметр -A указывает архитектуру _target_, параметр -T может использоваться для указания деталей используемой цепочки инструментов. Например, -Thost=x64 можно указать для выбора 64-битной версии инструментов хоста. Ниже показано, как использовать 64-битные инструменты, а также строить для 64-битной целевой архитектуры:

$ cmake .. -G "Visual Studio 16 2019" -A x64 -Thost=x64

Выбор генератора в смоделированном виде

Кнопка «Configure» вызывает новое диалоговое окно для выбора используемого генератора CMake.

Configuring a generator

Все генераторы, доступные в командной строке, также доступны в cmake-gui(1) .

Choosing a generator

При выборе генератора Visual Studio доступны дополнительные опции по настройке генерируемой архитектуры.

Choosing an architecture for Visual Studio generators

Установка Строить Переменные

Программные проекты часто требуют установки переменных в командной строке при вызове CMake.Некоторые из наиболее часто используемых переменных CMake перечислены в таблице ниже:

Для управления сборками могут быть доступны и другие специфические для проекта переменные,такие как включение или выключение компонентов проекта.

CMake не предоставляет соглашения о том, как такие переменные именуются между различными предоставленными системами сборки, за исключением того, что переменные с префиксом CMAKE_ обычно относятся к параметрам, предоставляемым самим CMake, и не должны использоваться в сторонних параметрах, которые должны использовать свой собственный префикс. вместо. Инструмент cmake-gui(1) может отображать параметры в группах, определяемых их префиксом, поэтому третьим лицам имеет смысл убедиться, что они используют самосогласованный префикс.


© 2000–2022 Kitware, Inc. and Contributors
Licensed under the BSD 3-clause License.
https://cmake.org/cmake/help/v3.24/guide/user-interaction/index.html


CMake

3.25

  • Creating Packages

    На данном этапе проект MathFunctions экспортирует целевую информацию,необходимую для использования другими проектами.

  • CMake Tutorial

    В учебнике CMake представлено пошаговое руководство,которое охватывает общие проблемы системы сборки и помогает их решить.

  • Установка переменных в командной строке

    Переменные CMake могут быть заданы в командной строке как при создании начальной сборки:так и при последующих вызовах cmake(1):Можно использовать флаг -U

  • Использование руководства по зависимостям

    Использование готовых пакетов с помощью find_package()Проекты часто зависят от других активов и артефактов.

Понравилась статья? Поделить с друзьями:

А вот и еще наши интересные статьи:

  • Сукральфат инструкция по применению цена отзывы аналоги таблетки цена
  • Реле температуры рт 12 16 инструкция по применению
  • Аевит гель инструкция по применению цена
  • Пересмотр инструкции по профессиям или видам работ проводится
  • Инструкция по применению cleaning solution inktec инструкция по применению

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии