Руководство CMake. Шаг 1. Базовая отправная точка
С чего начать работу с CMake? Этот шаг познакомит вас с базовыми синтаксисом, некоторыми командами и переменными CMake. По мере введения этих концепций мы проработаем три упражнения и создадим простой проект CMake.
Каждое упражнение на этом этапе начинается с некоторой исходной информации. Затем предоставляется цель и список полезных ресурсов. Каждый файл в разделе «Редактируемые файлы» находится в каталоге 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.
Полезные ресурсы
Редактируемые файлы
- 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.
Полезные ресурсы
Редактируемы файлы
- 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;
}