Добавил:
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.8. Команды управляющих конструкций
но, выполняются все команды до соответствующей команды
endwhile().
Команда break() досрочно прерывает выполнение
ближайшего охватывающего цикла while() или foreach()
(п. 2.8.3).
Команда continue(), которая появилась в CMake 3.2, досрочно переходит к следующей итерации ближайшего цикла.
2.8.3. foreach(), endforeach()
foreach(hимя_переменнойi hзначение1i ... hзначениеni)
hкомандыi
endforeach()
foreach(
hимя_переменнойi IN
f
g g
LISTSfhсписок1i ... hсписокni
f
ITEMSfhзначение1i ... hзначениеni
g g
)
foreach(hимя_переменнойi RANGE hмаксимумi)
foreach(hимя_переменнойi RANGE hстартi hстопifhшагig)
Первая форма команды foreach() выполняет все команды до соответствующей команды endforeach() в количестве
раз, равном количеству передаваемых ей значений. При этом
на каждой итерации цикла переменная с заданным именем бу-
141

2. Основы языка CMake
дет последовательно принимать значения со второго по последний аргумент команды foreach().
Вторая форма команды foreach() аналогична первой,
но удобнее неё в определённых случаях. В ней можно указывать
имена переменных-списков, значения которых будут обходиться в цикле (после необязательного аргумента LISTS), а также сами значения непосредственно (после необязательного аргумента ITEMS). Пустые списки рассматриваются как списки без элементов.
Третья форма команды foreach() выполняет тело цикла с целочисленными значениями переменной от 0 до заданного максимума. Таким образом, тело цикла выполняется
«hмаксимумi + 1» раз.
Наконец, последняя форма команды foreach() выполняет
тело цикла с целочисленными значениями переменной в заданном отрезке с заданным шагом (1 по умолчанию). Тело цикла
выполняется, пока значение переменной не превышает значения hстопi. Таким образом, тело цикла будет выполнено всего
«hстопi − hстартi + 1÷ hшагi» раз (здесь используется деление на-
цело с недостатком).
ПРИМЕР
Пусть проект верхнего уровня должен состоять из нескольких независимых подпроектов. Требуется организовать схему,
предусматривающую возможность исключения каждого подпроекта из общего построения в целях экономии времени разработчиков, которым для работы не нужно собирать все компоненты системы. Компонент выбирается для построения, если де-
142

2.8. Команды управляющих конструкций
рево его исходных файлов загружается из отдельного репозитария кода в каталог корневого проекта. В каждом таком проекте есть его описание в файле CMakeLists.txt. Кроме этого, разработчик может исключить проект из построения при помощи
флага настройки из кэша CMake.
Файл CMakeLists.txt корневого проекта может быть реа-
лизован следующим образом:
cmake_minimum_required(VERSION 2.8)
project(complex_project)
set(
SUBPROJECTS
program1 program2 super_program
)
include(build.cmake)
Здесь для удобства разработчиков все детали реализации
перенесены во вспомогательный файл build.cmake, который
подключается командой include() (п. 2.4.3). Таким образом,
корневой CMakeLists.txt, который, скорее всего, придётся редактировать чаще, имеет небольшой размер. Список компонент
присваивается переменной SUBPROJECTS при помощи команды
set() (п. 2.7.1).
Файл build.cmake может иметь следующее содержимое:
foreach(PROJ ${SUBPROJECTS})
143

2. Основы языка CMake
set(
MY_BUILD_${PROJ} TRUE
CACHE BOOL "Build the ${PROJ} subproject")
if(MY_BUILD_${PROJ} AND
EXISTS
"${CMAKE_SOURCE_DIR}/${PROJ}/CMakeLists.txt")
message(
STATUS
"The project ${PROJ} will be included")
add_subdirectory(${PROJ})
else()
message(
STATUS
"The project ${PROJ} will NOT be included")
endif()
endforeach()
Здесь команда foreach() организует перебор значений
списка из переменной SUBPROJECTS, присваивая каждое из них
последовательно переменной PROJ. В теле цикла при помощи
команды set() создаётся логическая переменная в кэше (если на текущий момент её там ещё нет), значение которой
определяет включение подпроекта в построение. Имя переменной получается конкатенацией строки «MY_BUILD_» и имени
подпроекта. Далее команда if() (п. 2.8.1) проверяет условие,
при котором подпроект будет включён в построение. Для этого необходимо, чтобы значение соответствующей переменной
144

2.8. Команды управляющих конструкций
было истинным и чтобы исходные файлы подпроекта были
загружены в дерево корневого проекта. Последнее проверяется существованием файла CMakeLists.txt в каталоге с именем подпроекта, который должен находиться в каталоге корневого проекта. Путь к нему содержится в специальной переменной CMAKE_SOURCE_DIR. Подпроект подключается командой
add_subdirectory() (п. 2.5.3).
Команда foreach() может быть также записана в следую-
щем виде:
foreach(PROJ IN LISTS SUBPROJECTS)
После первой обработки проекта системой CMake будет
создан файл кэша в каталоге построения с переменными
MY_BUILD_program1 и т. д. Дальше включение отдельных компонент в построение можно настроить, например, при помощи
утилиты CMake с графическим интерфейсом (рис. 2.9). ∗
145

2. Основы языка CMake
Рис. 2.9. Редактирование переменных кэша в утилите CMake
с графическим интерфейсом пользователя
2.8.4. function(), endfunction(), return()
function(hимя_функцииifhпараметр1i ... hпараметрnig)
hкомандыi
endfunction()
return()
Команда function() запоминает все команды, следующие
после неё до соответствующей команды endfunction(), без их
исполнения. Кроме этого, создаётся новая команда с именем
hимя_функцииi. При её вызове сохранённые ранее команды исполняются. При этом все ссылки на формальные параметры
вида ${hпараметр1i} заменяются значениями фактических аргу-
ментов, переданных команде.
146

2.8. Команды управляющих конструкций
Любую команду, определённую при помощи function(),
можно вызывать с переменным количеством аргументов. Для
доступа к ним можно использовать специальные переменные,
приведённые в табл. 2.11.
Таблица 2.11
Специальные переменные CMake для доступа
к аргументам функций
Перменная Значение
ARGC Общее количество аргументов
ARGV0, ARGV1,
. ..
Первый, второй и т. д. фактические аргументы
ARGV Список всех аргументов
ARGN Список дополнительных аргументов, пере-
данных в дополнение к объявленным
ПРИМЕР
В следующем фрагменте кода:
function(dump_vars)
message(STATUS ==============)
message(STATUS "Dumping ${ARGC} variables:")
foreach(VAR_NAME ${ARGN})
message(
STATUS " ${VAR_NAME} == \"${${VAR_NAME}}\"")
endforeach()
message(STATUS ==============)
147

2. Основы языка CMake
endfunction()
dump_vars(DATA GREETING VALUES)
создаётся команда с именем dump_vars, которая выполняет
отладочную печать значений всех переменных, имена которых передаются ей в качестве аргументов. Список аргументов ${ARGN} обрабатывается при помощи команды foreach()
(п. 2.8.3). Команда message() (п. 2.4.4) в теле цикла печатает имя очередной переменной, которое хранится в переменной VAR_NAME (подстановка ${VAR_NAME}), и её значение
(${${VAR_NAME}}).
Вызов команды dump_vars() в последней строке приводит
к выводу на печать следующей информации:
-- ==============
-- Dumping 3 variables:
-- DATA == "message(Hello)"
-- GREETING == "Hello"
-- VALUES == "a;b;c\;d"
-- ==============
Замечания:
∗
— При помощи языковых конструкций вида «${hаргументi}»
и «${${hаргументi}}» можно организовать передачу в функции переменных по ссылке.
148

2.8. Команды управляющих конструкций
— Функциональностью, аналогичной команде dump_vars()
из приведённого выше примера, обладает команда
cmake_print_variables() из стандартного модуля CMake
CMakePrintHelpers.
— В стандартном модуле CMakeParseArguments определена
команда cmake_parse_arguments(), которая предназначе-
на для облегчения синтаксического разбора списков аргу-
ментов функций. С её помощью можно определять тре-
бования для аргументов функций, аналогичные стандарт-
ным командам CMake.
ПРИМЕР
function(quote VAR_NAME)
set(${VAR_NAME} "\"${${VAR_NAME}}\"" PARENT_SCOPE)
endfunction()
set(STR "some string")
message(${STR})
quote(STR)
message(${STR})
N
Здесь создаётся пользовательская команда quote(), которой передаётся имя переменной. Команда добавляет в начало
и конец значения этой переменной символы двойных кавычек. Изменение переменной осуществляется командой set()
(п. 2.7.1) с аргументом PARENT_SCOPE, так как переменная нахо-
149

2. Основы языка CMake
дится во внешней по отношению к функции quote() области
действия (п. 2.2.3).
В результате исполнения последних четырёх строк кода
на печать будет выведена следующая информация:
some string
"some string"
Команда return(), как и в других языках программирова-
ния, позволяет досрочно прервать выполнение пользователь-
∗
ской команды и передать управление следующей за ней команде. Также команда return() способна прервать выполнение текущего модуля CMake и обработку подпроекта. Таким
образом, этой командой можно досрочно прервать исполнение команд include() (п. 2.4.3), add_subdirectory() (п. 2.5.3)
и find_package() (п. 2.11.1). Наконец, командой return() можно прервать обработку описания проекта верхнего уровня.
2.9. Команды работы с файлами
2.9.1. get_filename_component()
get_filename_component(
hимя_переменнойi hпуть_к_файлуi hкомпонентi
f
CACHEg)
get_filename_component(
150
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
