WriteCompilerDetectionHeader
Устарело начиная с версии 3.20: Этот модуль доступен только если политика CMP0120 не установлена в NEW. Не используйте его в новом коде.
Добавлен в версии 3.1.
Этот модуль предоставляет функцию write_compiler_detection_header().
Эта функция может использоваться для генерации файла, подходящего для включения в препроцессор, который содержит макросы, предназначенные для использования в исходном коде:
write_compiler_detection_header(
FILE <file>
PREFIX <prefix>
[OUTPUT_FILES_VAR <output_files_var> OUTPUT_DIR <output_dir>]
COMPILERS <compiler> [...]
FEATURES <feature> [...]
[BARE_FEATURES <feature> [...]]
[VERSION <version>]
[PROLOG <prolog>]
[EPILOG <epilog>]
[ALLOW_UNKNOWN_COMPILERS]
[ALLOW_UNKNOWN_COMPILER_VERSIONS]
)
Это генерирует файл <file> с макросами, у всех которых есть префикс <prefix>.
По умолчанию всё содержимое записывается непосредственно в <file>. Можно указать OUTPUT_FILES_VAR, чтобы сделать так, что содержимое, специфичное для компилятора, записывалось в отдельные файлы. Эти отдельные файлы затем доступны в <output_files_var> и могут быть использованы вызывающей стороной, например, для установки. OUTPUT_DIR определяет относительный путь от основного <file> к файлам, специфичным для компилятора. Например:
write_compiler_detection_header(
FILE climbingstats_compiler_detection.h
PREFIX ClimbingStats
OUTPUT_FILES_VAR support_files
OUTPUT_DIR compilers
COMPILERS GNU Clang MSVC Intel
FEATURES cxx_variadic_templates
)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/climbingstats_compiler_detection.h
DESTINATION include
)
install(FILES
${support_files}
DESTINATION include/compilers
)
VERSION может быть использовано для указания версии API, которая будет сгенерирована. Будущие версии CMake могут ввести альтернативные API. Конкретный API выбирается, если значение <version> больше или равно версии CMake, которая представила данный API, и меньше версии CMake, представившей последующий API. Значение переменной CMAKE_MINIMUM_REQUIRED_VERSION используется, если явная версия не указана. (Начиная с версии CMake 3.31.1 существует только одна версия API.)
PROLOG может быть указано как текстовое содержимое, которое будет записано в начале заголовка. EPILOG может быть указано как текстовое содержимое, которое будет записано в конце заголовка.
Должны быть указаны по крайней мере один <compiler> и один <feature>. Компиляторы, известные CMake, но не указанные, обнаруживаются, и для них генерируется препроцессор #error. Для каждого компилятора, известного CMake, генерируется макрос препроцессора, соответствующий <PREFIX>_COMPILER_IS_<compiler>, который содержит значение 0 или 1.
Возможные идентификаторы компиляторов документированы с переменной CMAKE_<LANG>_COMPILER_ID. Доступные возможности в этой версии CMake перечислены в глобальных свойствах CMAKE_C_KNOWN_FEATURES и CMAKE_CXX_KNOWN_FEATURES. Справочная информация о компиляционных возможностях находится в руководстве cmake-compile-features(7).
Добавлен в версии 3.2: Добавлены MSVC и AppleClang поддержка компиляторов.
Добавлен в версии 3.6: Добавлен Intel поддержка компиляторов.
Изменено в версии 3.8: Мета-возможности {c,cxx}_std_* игнорируются, если запрошены.
Добавлен в версии 3.8: ALLOW_UNKNOWN_COMPILERS и ALLOW_UNKNOWN_COMPILER_VERSIONS заставляют модуль генерировать условия, которые рассматривают неизвестные компиляторы как просто лишенные всех возможностей. Без этих опций, по умолчанию, для неизвестных компиляторов и версий генерируется #error.
Добавлен в версии 3.12: BARE_FEATURES определяет макросы совместимости с именем, используемым в более новых версиях стандарта языка, поэтому код может использовать имя новой возможности безусловно.
Макросы проверки возможностей
Для каждого компилятора генерируется макрос препроцессора, соответствующий <PREFIX>_COMPILER_IS_<compiler>, который содержит либо 0, либо 1, в зависимости от используемого компилятора. Макросы препроцессора для компонент версии компилятора генерируются, соответствующие <PREFIX>_COMPILER_VERSION_MAJOR <PREFIX>_COMPILER_VERSION_MINOR и <PREFIX>_COMPILER_VERSION_PATCH, содержащие десятичные значения для соответствующих компонент версии компилятора, если они определены.
Генерируется проверка препроцессора, основанная на версии компилятора, определяющая, включена ли каждая возможность. Генерируется макрос препроцессора, соответствующий <PREFIX>_COMPILER_<FEATURE>, где <FEATURE> – это имя <feature> в верхнем регистре, который содержит значение 0 или 1, в зависимости от того, поддерживает ли используемый компилятор данную возможность:
write_compiler_detection_header( FILE climbingstats_compiler_detection.h PREFIX ClimbingStats COMPILERS GNU Clang AppleClang MSVC Intel FEATURES cxx_variadic_templates )
#if ClimbingStats_COMPILER_CXX_VARIADIC_TEMPLATES
template<typename... T>
void someInterface(T t...) { /* ... */ }
#else
// Compatibility versions
template<typename T1>
void someInterface(T1 t1) { /* ... */ }
template<typename T1, typename T2>
void someInterface(T1 t1, T2 t2) { /* ... */ }
template<typename T1, typename T2, typename T3>
void someInterface(T1 t1, T2 t2, T3 t3) { /* ... */ }
#endif
Макросы символов
Для определенных возможностей создаются дополнительные символьные определения, используемые как символы, которые могут быть условно определены пустыми:
class MyClass ClimbingStats_FINAL
{
ClimbingStats_CONSTEXPR int someInterface() { return 42; }
};
Макрос ClimbingStats_FINAL будет раскрываться как final, если компилятор (и его флаги) поддерживают возможность cxx_final, а макрос ClimbingStats_CONSTEXPR будет раскрываться как constexpr, если поддерживается cxx_constexpr.
Если BARE_FEATURES cxx_final было передано в качестве аргумента, то ключевое слово final будет определено и для старых компиляторов.
Следующие возможности генерируют соответствующие определения символов, и если они доступны как BARE_FEATURES:
Возможность | Определение | Символ | bare |
|---|---|---|---|
|
|
| да |
|
|
| да |
|
|
| |
|
|
| |
|
|
| да |
|
|
| да |
|
|
| |
|
|
| да |
Макросы реализации совместимости
Некоторые возможности подходят для обертывания в макрос с реализацией обратной совместимости, если компилятор не поддерживает эту возможность.
Когда возможность cxx_static_assert не предоставляется компилятором, реализация обратной совместимости доступна через макросы-функции <PREFIX>_STATIC_ASSERT(COND) и <PREFIX>_STATIC_ASSERT_MSG(COND, MSG) . Макросы раскрываются как static_assert если эта возможность компилятора доступна, и как реализация обратной совместимости в противном случае. В первом случае условие строит в поле сообщения static_assert. Во втором случае сообщение MSG передается в поле сообщения static_assert, или игнорируется, если используется реализация обратной совместимости.
Возможность cxx_attribute_deprecated предоставляет определение макроса <PREFIX>_DEPRECATED, которое раскрывается как стандартный атрибут [[deprecated]] или специфичный для компилятора декоратор, например, __attribute__((__deprecated__)), используемый компиляторами GNU.
Возможность cxx_alignas предоставляет определение макроса <PREFIX>_ALIGNAS, которое раскрывается как стандартный декоратор alignas или специфичный для компилятора декоратор, например, __attribute__ ((__aligned__)), используемый компиляторами GNU.
Возможность cxx_alignof предоставляет определение макроса <PREFIX>_ALIGNOF, которое раскрывается как стандартный декоратор alignof или специфичный для компилятора декоратор, например, __alignof__, используемый компиляторами GNU.
Возможность | Определение | Символ | bare |
|---|---|---|---|
|
|
| |
|
|
| |
|
|
| да |
|
|
| |
|
|
| |
|
|
| |
|
|
| |
|
|
|
Сценарий использования, который возникает с такими макросами устаревания, — это устаревание всей библиотеки. В этом случае все публичные API в библиотеке могут быть помечены макросом <PREFIX>_DEPRECATED. Это приводит к очень шумному выводу сборки при сборке самой библиотеки, поэтому макрос может быть определён пустым в этом случае при сборке устаревшей библиотеки:
add_library(compat_support ${srcs})
target_compile_definitions(compat_support
PRIVATE
CompatSupport_DEPRECATED=
)
Пример использования
Примечание
Этот раздел был перенесен из руководства cmake-compile-features(7), поскольку он использует модуль WriteCompilerDetectionHeader, который удален политикой CMP0120.
Возможно, предпочтительнее использовать доступные функции компиляции, не создавая жестких требований. Например, библиотека может предоставить альтернативные реализации в зависимости от того, доступна ли функция cxx_variadic_templates.
#if Foo_COMPILER_CXX_VARIADIC_TEMPLATES
template<int I, int... Is>
struct Interface;
template<int I>
struct Interface<I>
{
static int accumulate()
{
return I;
}
};
template<int I, int... Is>
struct Interface
{
static int accumulate()
{
return I + Interface<Is...>::accumulate();
}
};
#else
template<int I1, int I2 = 0, int I3 = 0, int I4 = 0>
struct Interface
{
static int accumulate() { return I1 + I2 + I3 + I4; }
};
#endif
Такой интерфейс зависит от использования правильных предопределений препроцессора для функций компилятора. CMake может сгенерировать заголовочный файл, содержащий такие определения, используя модуль WriteCompilerDetectionHeader. Модуль содержит функцию write_compiler_detection_header, которая принимает параметры для управления содержимым сгенерированного заголовочного файла:
write_compiler_detection_header(
FILE "${CMAKE_CURRENT_BINARY_DIR}/foo_compiler_detection.h"
PREFIX Foo
COMPILERS GNU
FEATURES
cxx_variadic_templates
)
Такой заголовочный файл может быть использован внутри исходного кода проекта, а также может быть установлен и использован в интерфейсе кода библиотеки.
Для каждой функции, перечисленной в FEATURES, в заголовочном файле создается определение препроцессора, которое определяется как 1 или 0.
Кроме того, некоторые функции требуют дополнительных определений, таких как функции cxx_final и cxx_override. Вместо использования в коде #ifdef, ключевое слово final абстрагируется с помощью символа, который определяется как final, эквивалентом для конкретного компилятора, или пустым значением. Таким образом, код C++ может быть написан для безусловного использования символа, а поддержка компилятора определяет, к чему он будет расширяться:
struct Interface {
virtual void Execute() = 0;
};
struct Concrete Foo_FINAL {
void Execute() Foo_OVERRIDE;
};
В этом случае, Foo_FINAL будет расширяться до final, если компилятор поддерживает это ключевое слово, или до пустого значения в противном случае.
В этом случае, код проекта может захотеть включить определенный стандарт языка, если он доступен в компиляторе. Свойство целевого объекта CXX_STANDARD может быть установлено на желаемый стандарт языка для определенной цели, а переменная CMAKE_CXX_STANDARD может быть установлена для влияния на все последующие цели.
write_compiler_detection_header(
FILE "${CMAKE_CURRENT_BINARY_DIR}/foo_compiler_detection.h"
PREFIX Foo
COMPILERS GNU
FEATURES
cxx_final cxx_override
)
# Includes foo_compiler_detection.h and uses the Foo_FINAL symbol
# which will expand to 'final' if the compiler supports the requested
# CXX_STANDARD.
add_library(foo foo.cpp)
set_property(TARGET foo PROPERTY CXX_STANDARD 11)
# Includes foo_compiler_detection.h and uses the Foo_FINAL symbol
# which will expand to 'final' if the compiler supports the feature,
# even though CXX_STANDARD is not set explicitly. The requirement of
# cxx_constexpr causes CMake to set CXX_STANDARD internally, which
# affects the compile flags.
add_library(foo_impl foo_impl.cpp)
target_compile_features(foo_impl PRIVATE cxx_constexpr)
Функция write_compiler_detection_header также создает совместимый код для других функций, имеющих стандартные эквиваленты. Например, функция cxx_static_assert эмулируется с помощью шаблона и абстрагируется с помощью макросов функций <PREFIX>_STATIC_ASSERT и <PREFIX>_STATIC_ASSERT_MSG.
© 2000–2024 Kitware, Inc. and Contributors
Licensed under the BSD 3-clause License.
https://cmake.org/cmake/help/latest/module/WriteCompilerDetectionHeader.html