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 由任何大於或等於引入給定 API 的 CMake 版本且小於引入其後繼 API 的 CMake 版本的 <version>
值選定。如果未明確指定版本,則使用變數 CMAKE_MINIMUM_REQUIRED_VERSION
的值。(截至 CMake 版本 4.0.0,只有一個 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; }
};
如果編譯器(及其旗標)支援 cxx_final
功能,則 ClimbingStats_FINAL
巨集將展開為 final
,如果支援 cxx_constexpr
,則 ClimbingStats_CONSTEXPR
巨集將展開為 constexpr
。
如果將 BARE_FEATURES cxx_final
作為引數給定,則也會為舊編譯器定義 final
關鍵字。
以下功能產生對應的符號定義,如果它們作為 BARE_FEATURES
可用
功能 |
定義 |
符號 |
裸 |
---|---|---|---|
|
|
|
是 |
|
|
|
是 |
|
|
|
|
|
|
|
|
|
|
|
是 |
|
|
|
是 |
|
|
|
|
|
|
|
是 |
相容性實作巨集¶
如果編譯器不支援某些功能,則適合將這些功能包裝在具有向後相容性實作的巨集中。
當編譯器未提供 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]]
屬性或編譯器特定的裝飾器,例如 GNU 編譯器使用的 __attribute__((__deprecated__))
。
cxx_alignas
功能提供巨集定義 <PREFIX>_ALIGNAS
,它會展開為標準 alignas
裝飾器或編譯器特定的裝飾器,例如 GNU 編譯器使用的 __attribute__ ((__aligned__))
。
cxx_alignof
功能提供巨集定義 <PREFIX>_ALIGNOF
,它會展開為標準 alignof
裝飾器或編譯器特定的裝飾器,例如 GNU 編譯器使用的 __alignof__
。
功能 |
定義 |
符號 |
裸 |
---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
是 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
在整個程式庫中棄用時,會出現使用此類棄用巨集的情況。在這種情況下,程式庫中的所有公共 API 都可以使用 <PREFIX>_DEPRECATED
巨集裝飾。這會在建置程式庫本身時產生非常雜亂的建置輸出,因此在建置已棄用的程式庫時,可以將巨集定義為空
add_library(compat_support ${srcs})
target_compile_definitions(compat_support
PRIVATE
CompatSupport_DEPRECATED=
)
範例用法¶
注意
本節從 cmake-compile-features(7)
手冊遷移而來,因為它依賴於策略 CMP0120
移除的 WriteCompilerDetectionHeader
模組。
如果編譯功能可用,則可能會優先使用它們,而不會產生硬性要求。例如,程式庫可能會根據 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
功能。 final
關鍵字不是在 #ifdef
程式碼中使用,而是由符號抽象化,該符號定義為 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
函式巨集進行抽象化。