Spec-Zone.ru › CMake 3.29

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.29.9 существует только одна версия API.)

PROLOG может быть указано как текстовое содержимое для записи в начале заголовка. EPILOG может быть указано как текстовое содержимое для записи в конце заголовка.

Должен быть указан по крайней мере один <compiler> и один <feature>. Компиляторы, известные CMake, но не указанные, распознаются, и для них генерируется препроцессор #error. Макрос препроцессора, соответствующий <PREFIX>_COMPILER_IS_<compiler>, генерируется для каждого компилятора, известного CMake, содержащий значение 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

c_restrict

<PREFIX>_RESTRICT

restrict

да

cxx_constexpr

<PREFIX>_CONSTEXPR

constexpr

да

cxx_deleted_functions

<PREFIX>_DELETED_FUNCTION

= delete

cxx_extern_templates

<PREFIX>_EXTERN_TEMPLATE

extern

cxx_final

<PREFIX>_FINAL

final

да

cxx_noexcept

<PREFIX>_NOEXCEPT

noexcept

да

cxx_noexcept

<PREFIX>_NOEXCEPT_EXPR(X)

noexcept(X)

cxx_override

<PREFIX>_OVERRIDE

override

да

Макросы реализации совместимости

Некоторые функции подходят для обертывания в макрос с обратной совместимостью, если компилятор не поддерживает эту функцию.

Когда функция 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

cxx_alignas

<PREFIX>_ALIGNAS

alignas

cxx_alignof

<PREFIX>_ALIGNOF

alignof

cxx_nullptr

<PREFIX>_NULLPTR

nullptr

да

cxx_static_assert

<PREFIX>_STATIC_ASSERT

static_assert

cxx_static_assert

<PREFIX>_STATIC_ASSERT_MSG

static_assert

cxx_attribute_deprecated

<PREFIX>_DEPRECATED

[[deprecated]]

cxx_attribute_deprecated

<PREFIX>_DEPRECATED_MSG

[[deprecated]]

cxx_thread_local

<PREFIX>_THREAD_LOCAL

thread_local

Пример использования, который возникает с такими макросами устаревания, — это устаревание всей библиотеки. В этом случае все публичные 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
END_OF_DOCUMENT_MARKER ```

Такой интерфейс зависит от использования правильных препроцессорных определений для функций компилятора. 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/v3.29/module/WriteCompilerDetectionHeader.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API