Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Система построения проектов CMake. Учебник.pdf
X
- •Введение
- •Модульное программирование
- •Автоматизация построения проектов
- •Обзор инструментов построения проектов
- •qmake
- •Генераторы
- •Входные файлы
- •Пути
- •Синтаксис
- •Команды
- •Упражнения
- •Тест рубежного контроля
- •Проектное задание
- •Основные концепции
- •Строки
- •Свойства
- •Примеры простых проектов
- •Команды общего назначения
- •cmake_minimum_required()
- •project()
- •include()
- •message()
- •Команды описания целей
- •add_executable()
- •add_library()
- •add_subdirectory()
- •Команды настроек целей
- •include_directories()
- •target_include_directories()
- •add_definitions(), add_compile_options()
- •target_compile_definitions()
- •target_compile_options()
- •target_compile_features()
- •target_link_libraries()
- •add_dependencies()
- •Команды обработки данных
- •math()
- •list()
- •Команды управляющих конструкций
- •foreach(), endforeach()
- •Команды работы с файлами
- •get_filename_component()
- •Команды добавления специальных целей
- •configure_file()
- •add_test(), enable_testing()
- •install()
- •add_custom_target()
- •Прочие команды
- •find_package()
- •get_property(), set_property()
- •Виды конфигураций
- •Выражения генераторов
- •Информационные выражения
- •Логические выражения
- •Преобразующие выражения
- •Вспомогательные выражения
- •Упражнения
- •Тест рубежного контроля
- •Проектное задание
- •Интерфейс подключения библиотек
- •Подключение заголовочной библиотеки
- •Частичная подмена стандартной библиотеки
- •Интерфейс подключения библиотек
- •Локализация приложения
- •Установка приложения
- •Инструменты разработки
- •Управление версиями
- •Генерирование документации
- •Упражнения
- •Тест рубежного контроля
- •Проектное задание
- •Заключение
- •Библиография
- •Ответы на тесты

2.6. Команды настроек целей
сгенерировать более эффективный код, желательно объявление этих функций с атрибутом __declspec (dllimport). Чтобы обойтись одним заголовочным файлом, обычно в таких случаях используются директивы препроцессора. Таким образом,
окончательная версия заголовочного файла может быть следующей:
#ifndef MY_DLL_H__
#define MY_DLL_H__
#ifdef _MSC_VER
// Если используется Microsoft Visual C
++
#ifdef MY_DLL_BUILD
// Если файл подключается из проекта библиотеки
#define MY_DLL_INTERFACE __declspec (dllexport)
#else // MY_DLL_BUILD
// Если файл подключается из проекта клиента
#define MY_DLL_INTERFACE __declspec (dllimport)
#endif // MY_DLL_BUILD (else)
#else // _MSC_VER
// Если используется любой другой компилятор
#define MY_DLL_INTERFACE
#endif // _MSC_VER (else)
int MY_DLL_INTERFACE my_dll_f();
// ...
#endif // MY_DLL_H__
111

2. Основы языка CMake
Если определён символ препроцессора MY_DLL_BUILD
(предполагается, что он определён при построении библиотеки и не определён во всех остальных проектах),
символ MY_DLL_INTERFACE, который используется в объявлениях экспортируемых функций, определяется как
__declspec (dllexport), в противном случае — как
__declspec (dllimport). Теперь описание цели библиоте-
ки может выглядеть следующим образом:
add_library(my_dll SHARED my_dll.cpp my_dll.h)
target_compile_definitions(
my_dll
PRIVATE -DMY_DLL_BUILD)
set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
Для определения символа MY_DLL_BUILD в цели используется команда target_compile_definitions() (п. 2.6.4). Использование в ней аргумента PRIVATE приводит к тому, что символ не будет определён в других целях, подключающих библиотеку. В отличие от команды add_definitions() (п. 2.6.3),
команда target_compile_definitions() не делает символ
MY_DLL_BUILD определённым для других целей текущего подпроекта.
Описание цели исполняемого файла, использующего динамическую библиотеку (в текущем или отдельном подпроекте),
может быть следующим:
112

2.7. Команды обработки данных
add_executable(my_prog my_prog.cpp)
target_link_libraries(my_prog my_dll)
Команда target_link_libraries() транзитивно переносит интерфейсные требования проекта my_dll в проект
my_prog. В данном случае эти требования представляют собой
каталог библиотеки, который нужно использовать для поиска
заголовочных файлов (включается установкой специальной переменной CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE, п. 2.6.2).
Определение символа MY_DLL_BUILD в эти требования не входит, что и требовалось. ∗
2.6.8. add_dependencies()
add_dependencies(
hимя_целиifhимя_цели1i ... hимя_целиnig)
Команда устанавливает отношение зависимости при построении заданной цели от других. Команда аналогична команде target_link_libraries() (п. 2.6.7) за исключением того, что её аргументами могут быть только имена целей и что
она не устанавливает зависимостей по подключению библиотек во время компоновки. По сравнению с ней эта команда
применяется не так часто. Как правило, она используется при
установлении зависимостей для целей, созданных командой
add_custom_target() (п. 2.10.4).
113

2. Основы языка CMake
2.7. Команды обработки данных
2.7.1. set(), unset(), option()
set(
hимя_переменнойifhзначение1i ... hзначениеnig)
set(
hимя_переменнойi hзначениеi
f
f
CACHE hтипi hстрока_описанияifFORCE
PARENT_SCOPE
g g
g
)
hтипi F
FILEPATH
unset(hимя_переменнойifCACHE
option(
hимя_переменнойi hстрока_описанияifhзначениеig)
PATH
STRING
BOOL
INTERNAL
PARENT_SCOPEg)
Первый вариант команды set() предназначен для при-
сваивания заданной переменной списка из заданных значений
(п. 2.2.2). Таким образом, переменной будет присвоено значение
«hзначение1i; . . . ;hзначениеni».
Второй вариант команды set() при указании аргумента
CACHE или PARENT_SCOPE предназначен для установки значения
114

2.7. Команды обработки данных
переменной в другой области действия (п. 2.2.3). В этом случае
переменная не может быть переменной окружения.
— При помощи необязательного аргумента CACHE указывает-
ся, что команде следует осуществлять присваивание пере-
менной кэша. После этого аргумента указывается тип пе-
ременной и строка описания, которая будет использова-
на в качестве информации о переменной в утилите CMake
с оконным пользовательским интерфейсом. Тип перемен-
ной используется исключительно для удобства и влияет
на способ редактирования значения переменной, предо-
ставляемый графической утилитой CMake. Возможны сле-
дующие значения типов:
FILEPATH: в переменной хранится путь к файлу. Для редак-
тирования возможно использовать диалоговое окно
выбора файла.
PATH: в переменной хранится путь к каталогу. Для редак-
тирования возможно использовать диалоговое окно
выбора каталога.
STRING: в переменной хранится строка общего назначе-
ния. При редактировании используется обычное поле
ввода строки.
BOOL: в переменной хранится логическое значение
(п. 2.2.2). Для редактирования будет использовано
поле «выключателя».
INTERNAL: утилита CMake не будет отображать информа-
ции об этой переменной. Предполагается, что пере-
115

2. Основы языка CMake
менная используется для внутренних целей и должна
храниться в кэше.
После строки описания может быть указан необязательный аргумент FORCE. Его использование приводит к тому,
что переменной будет присвоено значение в любом случае, даже если она уже находится в кэше. По умолчанию,
если переменная уже там есть, присваивания не происходит. Такое поведение команды set() подходит в большинстве случаев, так как позволяет сохранять ранее отредактированные значения кэша. Также при присваивании будет
удалена из текущей области действия переменная с тем же
именем (см. пример ниже).
— При помощи необязательного аргумента PARENT_SCOPE
указывается, что следует осуществлять присваивание переменной родительской области действия.
Команда unset() позволяет удалить информацию о заданной переменной (CMake или окружения), т. е. вернуться к состоянию до первого её присваивания. Как и для предыдущей команды, необязательные аргументы CACHE и PARENT_SCOPE позволяют указать, к какой области действия следует применить
команду.
Команда option() аналогична команде set() с аргументами CACHE BOOL. По умолчанию переменной устанавливается
значение OFF.
Замечание: так как кэш представляет собой отдельную область
действия переменных, в нём могут храниться переменные с те-
116

2.7. Команды обработки данных
ми же именами, что и у переменных других областей. При этом
такие переменные с одним именем будут разными.
ПРИМЕР
set(VALUE "value 1" CACHE STRING "Test value" FORCE)
set(VALUE "value 2")
message(${VALUE})
unset(VALUE)
message(${VALUE})
При исполнении этого фрагмента на печать будут выведе-
ны следующие строки:
value 2
N
value 1
Этот вывод демонстрирует принцип поиска переменных в различных областях действия (п. 2.2.3). Первая команда message() обращается к переменной в текущей области
действия. После удаления этой переменной вторая команда
message() уже обращается к переменной кэша.
Однако если в этот фрагмент внести небольшое изменение:
set(VALUE "value 1")
set(VALUE "value 2" CACHE STRING "Test value" FORCE)
message(${VALUE})
unset(VALUE)
message(${VALUE})
117

2. Основы языка CMake
то в этом случае вывод инструмента CMake будет уже следующим:
value 2
value 2
Такой вывод происходит потому, что, как было отмечено
выше, вторая команда set() удаляет из текущей области переменную с тем же именем. При этом команда unset() попытается удалить информацию об уже не существующей переменной
текущей области. ∗
2.7.2. math()
math(EXPR hимя_переменнойi hвыражениеi)
hвыражениеi :=
hцелочисленный_литералi
(hвыражениеi)
hвыражениеi hоперацияi hвыражениеi
hцелочисленный_литералi :=
hцифраi...hцифраi
hоперацияi :=
+
Эта команда позволяет вычислить арифметическое выражение и присвоить строковое представление его результата за-
118
-
*
/
%
|
&
^
~
<<
>>

2.7. Команды обработки данных
данной переменной. Поддерживаются целочисленные операнды и бинарные операции, аналогичные языку C.
Замечания:
— Так как унарные операции командой не поддерживают-
ся, выражения вида "-4 + 1" являются неправильными
с её точки зрения. Для представления отрицательных чисел следует вычитать положительные литералы из нуля.
— При использовании пробелов внутри выражения его необ-
ходимо заключать в кавычки.
N
2.7.3. list()
Команда list() реализует основные алгоритмы работы
со списками. Команда введена для удобства: её использование
необязательно, все задачи, которые она выполняет, можно реализовать другими средствами. Однако для сокращения исходного текста описания проектов и для придания ему большей ясности рекомендуется использовать эту команду там, где это возможно.
Так же как и команда set() (п. 2.7.1), команда list() может создавать новые переменные. Однако она создаёт их всегда в текущей области действия (п. 2.2.3), в отличие от команды set(), для которой можно указать аргументы CACHE
или PARENT_SCOPE. Таким образом, новый список создаётся в текущей области действия, даже если исходный список находится
в другой области. Чтобы скопировать полученное значение в исходную область, можно использовать команду set().
119

2. Основы языка CMake
ПРИМЕР
function(test)
list(APPEND TEST_LIST d e f)
set(TEST_LIST ${TEST_LIST} PARENT_SCOPE)
endfunction()
set(TEST_LIST a b c)
test()
message("${TEST_LIST}")
Этот фрагмент кода выведет на печать «a;b;c;d;e;f». Сначала в нём определяется команда test() при помощи команд
function()/endfunction() (п. 2.8.4). Далее команда set() присваивает значение переменной TEST_LIST. После этого исполняется команда test(), которая добавляет в конец списка три
значения. В результате создаётся переменная с тем же именем
TEST_LIST, но уже в области действия функции. Чтобы скопировать значение этой переменной в исходную область действия,
используется команда set() с аргументом PARENT_SCOPE. ∗
При обращении к элементам списков можно использовать
неотрицательные индексы 0, 1, 2, . . . для обращения к первому,
второму и т. д. элементу с начала или −1, −2, −3, . . . для обращения к первому, второму и т. д. с конца.
Замечание: при передаче командам значений индексов вне диа-
пазона элементов списка выводится сообщение об ошибке. Выполнение команд продолжается, но генерирование файлов ко-
120
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
