Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Система построения проектов CMake. Учебник.pdf
Скачиваний:
0
Добавлен:
08.09.2026
Размер:
2 Мб
Скачать
☆
2.12. Поддержка нескольких конфигураций построения
}
Описание цели библиотеки выглядит следующим образом (файл my_plugin/CMakeLists.txt):
add_library(my_plugin MODULE my_plugin.cpp)
Теперь возникает задача создания теста для библиотеки. Очевидно, тестовая программа должна загружать библиотеку по заданному пути к ней, используя для этого, например, функ­ции интерфейса POSIX. Поскольку библиотека и тест могут со­бираться в разных подкаталогах, надёжным способом ссылки на библиотеку будет указание полного пути к ней, который можно передавать программе через аргумент командной стро­ки.
Исходный код теста (файл my_test/my_test.cpp):
#include <dlfcn.h>
#include <iostream>
#include <cstddef>
using namespace std;
int main(int nArgC, char *apszArgV[])
{
if (nArgC < 2)
{
cerr << "Wrong usage" << endl;
return 1;
231
2. Основы языка CMake
} // if (nArgC < 2)
//
void *pvHandle = dlopen(
apszArgV[1], RTLD_LOCAL | RTLD_LAZY);
if (NULL == pvHandle)
{
cerr << "Cannot open library" << apszArgV[1] <<
": " << dlerror() << endl;
return 2;
} // if (NULL == pvHandle)
//
int nRet = 0;
//
typedef int (*PFN_T)();
const char *pcszName = "my_plugin_f";
PFN_T pfn = (PFN_T) dlsym(pvHandle, pcszName);
if (NULL == pfn)
{
cerr << "Cannot get function " << pcszName <<
": " << dlerror() << endl;
nRet = 3;
} // if (NULL == pfn)
else
232
{
const int cn = (*pfn)();
if (cn != 31)
{
2.12. Поддержка нескольких конфигураций построения
cerr << "The return value is different: " <<
cn << endl;
nRet = 4;
} // if (cn != 31)
} // if (NULL == pfn) (else)
//
dlclose(pvHandle);
//
return nRet;
} // main()
Здесь сначала проверяется, что программе был передан хо­тя бы один аргумент. Если это так, он передаётся функции POSIX
dlopen(), которая выполняет динамическую загрузку модуля [13]. Если загрузка выполнена успешно, при помощи функции
dlsym() в модуле выполняется поиск адреса функции с именем
«my_plugin_f», который присваивается переменной-указателю
на функцию pfn. Если эта функция найдена, выполняется её кос­венный вызов и проверка возвращённого значения.
Описание цели теста (файл my_test/CMakeLists.txt):
add_executable(my_test my_test.cpp)
target_link_libraries(my_test -ldl)
Здесь цель связывается с системной библиотекой libdl, ко­торая экспортирует функции dlopen(), dlsym() и т. д.
Описание проекта верхнего уровня имеет следующий вид (файл CMakeLists.txt):
233
2. Основы языка CMake
cmake_minimum_required(VERSION 2.8)
enable_testing()
add_subdirectory(my_plugin)
add_subdirectory(my_test)
add_test(
NAME my_plugin_test
COMMAND my_test "$<TARGET_FILE:my_plugin>")
Здесь командой add_test() (п. 2.10.2) добавляется тест, который запускает приложение-результат сборки це­ли my_test с путём к библиотеке в аргументе командной строки. Последний получается вычислением выражения
$<TARGET_FILE:my_plugin>. ∗
Замечания:
— В приведённом примере при определении теста невозмож-
но обойтись без выражения генераторов, записав команду
add_test() подобным образом:
add_test(
NAME my_plugin_test
COMMAND my_test my_plugin)
234
Хотя имя цели my_test заменяется на путь к исполняемо-
му файлу, поскольку указано вместо имени команды, имя
my_plugin уже указано в качестве её аргумента. Поэтому
2.12. Поддержка нескольких конфигураций построения
при запуске теста оно будет передано программе в неиз­менном виде.
— Тестовое приложение можно также реализовать с ис-
пользованием функций Windows API LoadLibrary(), GetProcAddress() и т. д.
N

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

Логические выражения генераторов (табл. 2.15) после вы­числения заменяются на «1» или «0» в зависимости от истинно­сти их условия.
Таблица 2.15
Логические выражения генераторов
Выражение Условие
Основные
STREQUAL:hстрока1i,hстрока2i hстрока1i hстрока2i
EQUAL:hчисло1i,hчисло2i hчисло1i hчисло2i
VERSION_EQUAL:hверсия1i,hверсия2i hверсия1i hверсия2i
VERSION_LESS:hверсия1i,hверсия2i hверсия1i < hверсия2i
VERSION_GREATER:hверсия1i,hверсия2i hверсия1i > hверсия2i
BOOL:hстрокаi Истинность/
ложность строки в соответствии с табл. 2.1
Составные
235
2. Основы языка CMake
Выражение Условие
NOT:hзначi
AND:hзнач1i(,hзначni
OR:hзнач1i(,hзначni
Продолжение табл. 2.15
0, если hзначi 1
 
1, иначе
)
1, если ∀k hзначki  1
 
0, иначе
)
0, если ∀k hзначki  0
 
1, иначе
Системные
CONFIG:hстрокаi Равенство использу-
PLATFORM_ID:hстрокаi Равенство целевой
C_COMPILER_ID:hстрокаi Равенство имени
CXX_COMPILER_ID:hстрокаi Равенство имени
*
емой конфигурации строке без учёта реги­стра
платформы строке
компилятора C стро­ке
компилятора C
++
236
строке
2.12. Поддержка нескольких конфигураций построения
Окончание табл. 2.15
Выражение Условие
C_COMPILER_VERSION:hверсияi Равенство версии
компилятора C за­данной
CXX_COMPILER_VERSION:hверсияi Равенство версии
компилятора C заданной
)
COMPILE_FEATURES:hвозм1i(,hвозмki
*
Эти выражения введены для удобства, их можно заменить комбинацией нескольких других выражений.
**
При помощи этого выражения можно условно включать в проект реализацию участков кода на основе новых возмож­ностей компилятора и без их использования, если компиля-
Доступность всех воз­можностей в исполь­зуемом компиляторе
(п. 2.6.6)
**
++
тор их не поддерживает (например, при помощи шаблонов C++11 с переменным количеством параметров или с ограни­ченным, поддерживаемых C++98).

2.12.5. Преобразующие выражения

Преобразующие выражения (табл. 2.16) вычисляются в за-
висимости от входных аргументов.
237
2. Основы языка CMake
Преобразующие выражения генераторов
Выражение Результат
Таблица 2.16
0:hстрокаi Пустая строка
1:hстрокаi hстрокаi
*
*
LOWER_CASE:hстрокаi hстрокаi в нижнем регистре
UPPERR_CASE:hстрокаi hстрокаi в верхнем регистре
JOIN:hстрока1i,hстрока2i hстрока1i, в которой все вхож-
дения точки с запятой замене­ны на hстрока2i
**
MAKE_C_IDENTIFIER:hстрокаi hстрокаi, преобразованная
к виду, который может быть использован в качестве кор­ректного идентификатора в языке C
***
Системные
LINK_ONLY:hстрокаi Пустая строка, если выраже-
ние вычисляется при опреде­лении транзитивных требова­ний (п. 2.6.7), иначе hстрокаi
BUILD_INTERFACE:hстрокаi hстрокаi, если цель использует-
ся другой целью в пределах то­го же проекта, иначе пустая строка
238
****
2.12. Поддержка нескольких конфигураций построения
Окончание табл. 2.16
Выражение Результат
INSTALL_INTERFACE:hстрокаi hстрокаi, если цель экс-
портируется командой install(EXPORT ...), иначе пустая строка
*
Предполагается, что эти выражения будут использоваться
****
совместно с логическими выражениями (см. табл. 2.15), кото­рые заменяются на 0 или 1 (пример: $<$<CONFIG:debug>:-D
_DEBUG>).
**
Предполагается, что это выражение будет использовать­ся для обработки свойств целей, представляющих списки
(см. пример ниже).
***
Например, идентификатор CMake «01-hello» будет преобра-
зован к «_01_hello».
****
Предполагается, что эти команды будут использоваться в командах target_include_directories() (п. 2.6.2) и т. п. для цели библиотеки, имеющей правило для установки
(install(EXPORT ...), п. 2.10.3).
ПРИМЕРЫ
1)
set(
DEFS
"$<TARGET_PROPERTY:prog,COMPILE_DEFINITIONS>")
239
2. Основы языка CMake
target_compile_options(
prog
PRIVATE "-D $<JOIN:${DEFS}, -D >")
Здесь для удобства строка с выражением разбита на две: первая в переменной DEFS содержит выражение, которое при вычислении заменяется на значение свой­ства COMPILE_DEFINITIONS цели prog. Это свойство со­держит список определений символов препроцессора, заполняемый командами add_definitions() (п. 2.6.3) и target_compile_definitions() (п. 2.6.4). Внутри коман­ды target_compile_options() (п. 2.6.5) эта строка под­ставляется внутрь другого выражения JOIN, которое при вычислении заменяет в этом списке все точки с запя­той, разделяющие его элементы, на строки « -D ». Стро­ка «-D » перед выражением добавляется перед первым определением. Таким образом, всё выражение после вы­числения генератором развернётся в список аргументов формата компилятора gcc, определяющих заданные симво­лы («-D MY_DEF1 -D MY_DEF2 ...») в предположении, что свойство COMPILE_DEFINITIONS содержит непустой спи­сок.
2) Пусть проект приложения реализует некоторые возмож-
240
ности средствами, зависящими от целевой операционной системы. Например, в Windows он может использовать
Windows API, а в POSIX-совместимых системах — соответ-
ственно API POSIX. Разработчик выделил все зависящие
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]