如何在 cmake 工具链文件中设置编译功能以使已知的自定义编译器使用 target_compile_features

lea*_*ika 5 c++ cmake c++17

我有最小的你好世界样本:

#include <cstdlib>
#include <iostream>
#include <string_view>

int main(int /*argc*/, char* /*argv*/ [])
{
    using namespace std;

    string_view output_phrase("hello world");

    cout << output_phrase << endl;

    bool is_good = cout.good();

    int result = is_good ? EXIT_SUCCESS : EXIT_FAILURE;
    return result;
}
Run Code Online (Sandbox Code Playgroud)

所以我创建了最小的CMakeLists.txt文件:

cmake_minimum_required(VERSION 3.14)
project(01-1-hello-world CXX)
add_executable(01-1-hello-world main.cxx)
target_compile_features(01-1-hello-world PUBLIC cxx_std_17)
Run Code Online (Sandbox Code Playgroud)

现在,如果我使用已知的 CMake 编译器,一切都会按预期工作(如 MSVC、clang++、g++)。但是如果我尝试使用一些 SDK 中的自定义编译器(基于 clang)和工具链文件cmake 说:

CMakeLists.txt:5 (target_compile_features) 处的 CMake 错误:target_compile_features CXX 编译器不知道编译器功能“cxx_std_17”

“铛”

CMAKE_CXX_COMPILE_FEATURES所以我尝试在我的工具链文件中设置

set(CMAKE_CXX_COMPILE_FEATURES cxx_std_17) # we know custom-clang have c++17 support
Run Code Online (Sandbox Code Playgroud)

我也尝试设置CMAKE_CXX_KNOWN_FEATURES但没有任何改变。如何target_compile_features(01-1-hello-world PUBLIC cxx_std_17)在自定义编译器的 cmake 工具链文件中工作?提前致谢!

Kam*_*Cuk 2

我也尝试设置 CMAKE_CXX_KNOWN_FEATURES

您很可能忘记清除构建树。重新运行 cmake 时,工具链文件中的变量不会“刷新”。修改工具链文件时,必须完全删除构建文件并重新配置 cmake。它应该有效。请注意,这CMAKE_*_KNOWN_FEATURES是一个功能列表,请使用list(APPEND CMAKE_CXX_COMPILE_FEATURES ...)

供功能读者参考,并且由于 cmake 使用了很多全局变量,我想发布sdccC 语言编译器的工作原理。对于 C 来说,因为它更简单,所以它与 C++ 完全相同,它与CXX*变量类似。变量的含义可以从变量的名称中推断出来。

cat > toolchain-sdcc.cmake <<EOF
find_program(CMAKE_C_COMPILER NAMES sdcc)
set(CMAKE_CROSSCOMPILING TRUE)    
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

set(CMAKE_C_STANDARD_DEFAULT "11") # this is the default C standard the compiler uses without any option
set(CMAKE_C90_STANDARD_COMPILE_OPTION "--std-c89")
set(CMAKE_C90_EXTENSION_COMPILE_OPTION "--std-sdcc89")
set(CMAKE_C99_STANDARD_COMPILE_OPTION "--std-c99")
set(CMAKE_C99_EXTENSION_COMPILE_OPTION "--std-sdcc99")
set(CMAKE_C11_STANDARD_COMPILE_OPTION "--std-c11")
set(CMAKE_C11_EXTENSION_COMPILE_OPTION "--std-sdcc11")

list(APPEND CMAKE_C_COMPILE_FEATURES
    c_std_90
    c_std_99
    c_std_11
    c_function_prototypes
    c_restrict
    c_static_assert
    c_variadic_macros
)

EOF
Run Code Online (Sandbox Code Playgroud)

cat > CMakeLists.txt <<EOF
cmake_minimum_required(VERSION 3.11)
set(CMAKE_TOOLCHAIN_FILE sdcc.cmake)
project(a LANGUAGES C)
file(WRITE a.c "int main() {}")
add_executable(a a.c)
target_compile_features(a PUBLIC
    c_std_90
    c_std_99
    c_std_11
    c_function_prototypes
    c_restrict
    c_static_assert
    c_variadic_macros
)

EOF
Run Code Online (Sandbox Code Playgroud)

之后 cmake 找到编译功能并且项目可以构建。

还有一个CMakeDetermineCompileFeatures.cmake定义cmake_determine_compile_features是从调用中自动运行的project()。然后,如果该宏cmake_record_c_compile_features是由您的工具链定义的,则该宏用于确定 C 语言编译功能。所以你可以:

cat > toolchain-sdcc.cmake <<EOF
# ...
# remove list(APPEND CMAKE_C_COMPILE_FEATURES, not needed anymore  

# this macro will be called from `project()`
macro(cmake_record_c_compile_features)
    list(APPEND CMAKE_C90_COMPILE_FEATURES c_std_90 c_function_prototypes)
    list(APPEND CMAKE_C99_COMPILE_FEATURES c_std_99 c_restrict c_variadic_macros)
    list(APPEND CMAKE_C11_COMPILE_FEATURES c_std_11 c_static_assert)
    set(_result 0) # expected by cmake_determine_compile_features
endmacro()

EOF
Run Code Online (Sandbox Code Playgroud)

之后,您将看到调用宏时Detecting C compile features生成的众所周知的消息:CMakeDetermineCompileFeatures.cmakecmake_record_c_compile_features

$ cmake -S . -B _build
...
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done
...
Run Code Online (Sandbox Code Playgroud)

最后但并非最不重要的一点是,您可以定义CMAKE_C*_STANDARD__HAS_FULL_SUPPORT宏并使用内部定义宏的Compiler/CMakeCommonCompilerMacros模块cmake_determine_compile_features,并检查是否CMAKE_C*_STANDARD__HAS_FULL_SUPPORT定义,如果是,则启用该语言标准的所有功能:

cat > toolchain-sdcc.cmake <<EOF
# ...
set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
# will define cmake_record_c_compile_features macro
# that will inspect CMAKE_C*_STANDARD__HAS_FULL_SUPPORT variables
include(Compiler/CMakeCommonCompilerMacros)
EOF
Run Code Online (Sandbox Code Playgroud)

但真正正确的位置是Compilers/SDCC-C.cmakeCMAKE_MODULE_PATH路径中创建并放在include(Compiler/CMakeCommonCompilerMacros)那里,就像MSVC-CXX.cmake所做的那样。