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 的 CMake 版本且小於引入其後續 API 的 CMake 版本的 <version>
值來選擇給定的 API。如果未明確指定版本,則會使用 CMAKE_MINIMUM_REQUIRED_VERSION
變數的值。(截至 CMake 3.31.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)
手冊遷移而來,因為它依賴於 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
功能。 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
函式巨集來抽象化。