CMake CheckCSourceCompiles传递预定义给armlink及thread_local测试失败求助
I ran into exactly this issue with armcc and CMake's CHECK_C_SOURCE_COMPILES macro recently, so I know how frustrating it is when the code compiles fine manually but fails in CMake's test. Let's break down what's happening and how to fix it.
The Root Cause
When you use CHECK_C_SOURCE_COMPILES, CMake automatically passes the test's preprocessor definition (in your case, -DGCC_THREAD_LOCAL_AVAILABLE) to both the compiler (armcc) and the linker (armlink). The problem is that armlink doesn't recognize the -D flag—it's a compiler-only option. Even though your code compiles without errors, the link step fails because armlink chokes on the unexpected -D argument, causing the entire test to report failure.
The Solution: Use try_compile Instead
The CHECK_C_SOURCE_COMPILES macro is convenient but inflexible here. Instead, use CMake's try_compile command, which lets you explicitly control which flags go to the compiler vs. the linker, avoiding the accidental -D pass-through to armlink.
Here's a working example tailored to your use case:
# Test code to verify __thread support set(THREAD_LOCAL_TEST_SNIPPET "int main(){ static __thread int num; return 0;}") # Run the compile test with explicit control over flags try_compile( GCC_THREAD_LOCAL_AVAILABLE ${CMAKE_BINARY_DIR}/thread_local_test_build_dir # Temp build dir for the test SOURCES <STRING>${THREAD_LOCAL_TEST_SNIPPET} # Inline test code CMAKE_FLAGS "-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}" # Use your armcc compiler "-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}" # Reuse your existing C flags OUTPUT_VARIABLE TEST_COMPILE_OUTPUT # Capture output for debugging ) # Report the result if(GCC_THREAD_LOCAL_AVAILABLE) message(STATUS "✅ armcc supports __thread (thread_local)") else() message(STATUS "❌ armcc does NOT support __thread. Debug output:\n${TEST_COMPILE_OUTPUT}") endif()
Why This Works
try_compiledoesn't automatically inject the test result's preprocessor definition into the link command. It only uses the flags you explicitly specify.- By using
<STRING>for the source, you avoid creating temporary files (though you could also use a separate .c file if preferred). - The
OUTPUT_VARIABLElets you debug exactly what went wrong if the test fails, which is helpful for tweaking flags further if needed.
Alternative: Patch CHECK_C_SOURCE_COMPILES Behavior (Less Recommended)
If you really want to stick with CHECK_C_SOURCE_COMPILES, you can override how CMake handles link flags for armcc. Add this before calling the macro:
# Tell CMake not to pass compiler defines to armlink set(CMAKE_REQUIRED_LINK_OPTIONS "") set(CMAKE_C_LINK_FLAGS "")
But this can have side effects on other tests, so try_compile is the cleaner, more reliable approach.
内容的提问来源于stack exchange,提问作者g-217

