如何检查编译器对特定关键字/属性的支持?CMake检测C编译器特性方法
Great question! Checking compiler support for specific keywords or attributes is a must for cross-platform C development, and CMake gives you all the tools you need to do this reliably. Let's break this down step by step, covering both general strategies and your specific use cases.
General Ways to Check Compiler Support
Before diving into your specific checks, here are the two most reliable approaches for verifying compiler features:
- Leverage compiler-specific predefined macros: Most compilers define macros (like
__GNUC__for GCC/clang,_MSC_VERfor MSVC) that let you conditionally check for compiler families and versions directly in your code. - Test compilation of minimal code snippets: This is the gold standard—CMake provides modules like
CheckCSourceCompilesthat attempt to compile a tiny piece of code using the feature you're checking. If it compiles successfully, you know the feature is supported.
Detecting Visibility Attributes (__hidden / visibility("hidden"))
First, note that __hidden is less common; most compilers use attribute-based syntax instead:
- GCC, clang, and other GNU-compatible compilers use
__attribute__((visibility("hidden"))) - MSVC uses
__declspec(hidden)
Here's how to detect these with CMake:
Step 1: Use CMake's CheckCSourceCompiles Module
Add this to your CMakeLists.txt:
include(CheckCSourceCompiles) # Check for GCC-style visibility attribute check_c_source_compiles(" #include <stdio.h> __attribute__((visibility(\"hidden\"))) void test_hidden() {} int main() { test_hidden(); return 0; } " HAVE_VISIBILITY_HIDDEN) # Check for MSVC-style __declspec(hidden) check_c_source_compiles(" #include <stdio.h> __declspec(hidden) void test_hidden() {} int main() { test_hidden(); return 0; } " HAVE_DECLSPEC_HIDDEN) # Define a unified macro for your code to use if(HAVE_VISIBILITY_HIDDEN) add_compile_definitions(HAVE_HIDDEN_ATTRIBUTE=1) add_compile_definitions(HIDDEN_ATTRIBUTE="__attribute__((visibility(\"hidden\")))") elif(HAVE_DECLSPEC_HIDDEN) add_compile_definitions(HAVE_HIDDEN_ATTRIBUTE=1) add_compile_definitions(HIDDEN_ATTRIBUTE="__declspec(hidden)") else() # Fallback to empty if no support add_compile_definitions(HIDDEN_ATTRIBUTE="") endif()
Step 2: Use the Macro in Your C Code
Now you can use HIDDEN_ATTRIBUTE to mark functions/variables with hidden visibility portably:
HIDDEN_ATTRIBUTE void my_internal_function() { // Implementation }
Detecting the restrict Keyword
restrict is a C99 standard keyword for optimizing pointer access, but some compilers use alternatives (like MSVC's __restrict for older versions). Here's how to detect support:
CMake Check Code
Add this to your CMakeLists.txt:
# Check for standard C99 restrict check_c_source_compiles(" #include <stdio.h> void test_restrict(int* restrict ptr) { *ptr = 0; } int main() { int x; test_restrict(&x); return 0; } " HAVE_RESTRICT) # Check for MSVC's __restrict as a fallback check_c_source_compiles(" #include <stdio.h> void test_restrict(int* __restrict ptr) { *ptr = 0; } int main() { int x; test_restrict(&x); return 0; } " HAVE___RESTRICT) # Define a unified macro for your code if(HAVE_RESTRICT) add_compile_definitions(RESTRICT_KEYWORD="restrict") elif(HAVE___RESTRICT) add_compile_definitions(RESTRICT_KEYWORD="__restrict") else() add_compile_definitions(RESTRICT_KEYWORD="") endif()
Use the Macro in Your Code
Now you can write portable code with the restrict keyword:
void process_data(int* RESTRICT_KEYWORD input, int* RESTRICT_KEYWORD output, size_t size) { // Optimized implementation that assumes no pointer aliasing }
Bonus: Global Visibility Control
If you want to set hidden visibility for all symbols (common in shared libraries), you can check for compiler flags like -fvisibility=hidden (GCC/clang) with CMake's CheckCCompilerFlag module:
include(CheckCCompilerFlag) check_c_compiler_flag("-fvisibility=hidden" SUPPORTS_FVISIBILITY_HIDDEN) if(SUPPORTS_FVISIBILITY_HIDDEN) add_compile_options(-fvisibility=hidden) endif()
This complements the per-symbol attribute checks if you want a global default.
内容的提问来源于stack exchange,提问作者einpoklum

