c++ - 如何在 cmake 工具链文件中为已知的自定义编译器设置编译功能以使用 target_compile_features
问题描述
我有最小的hello world样本:
#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;
}
所以我创建了最小的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)
现在,如果我使用 known for CMake 编译器,所有工作都按预期工作(如 MSVC、clang++、g++)。但是,如果我从一些带有工具链文件cmake的 SDK 中尝试一些自定义编译器(基于 clang) ,请说:
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
我也尝试设置CMAKE_CXX_KNOWN_FEATURES
但没有任何变化。如何target_compile_features(01-1-hello-world PUBLIC cxx_std_17)
在自定义编译器的 cmake 工具链文件中制作作品?提前致谢!
解决方案
我也尝试设置 CMAKE_CXX_KNOWN_FEATURES
您很可能忘记清除构建树。重新运行 cmake 时,工具链文件中的变量不会“刷新”。在对工具链文件进行修改时,您必须完全删除构建文件并重新配置 cmake。它应该工作。请注意,这CMAKE_*_KNOWN_FEATURES
是功能列表,请使用list(APPEND CMAKE_CXX_COMPILE_FEATURES ...)
.
作为功能读者的参考,并且因为 cmake 使用了很多全局变量,我想发布sdcc
C 语言编译器的工作原理。CXX*
对于 C,因为它更简单,所以对于 C++,它与变量完全相同。变量的含义可以从它们的名字中推断出来。
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
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
之后 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
之后,您将看到它调用宏时Detecting C compile features
生成的众所周知的消息:CMakeDetermineCompileFeatures.cmake
cmake_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
...
最后但同样重要的是,您可以定义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
但真正合适的地方是Compilers/SDCC-C.cmake
在CMAKE_MODULE_PATH
路径中创建并放在include(Compiler/CMakeCommonCompilerMacros)
那里,例如MSVC-CXX.cmake所做的那样。
推荐阅读
- python - 什么是健身房。空间?
- c# - 读取给定线程的 AsyncLocal 值
- angular - 如果一个动作已在另一个动作中分派,如何进行单元测试?
- vb.net - 初始化 WCF 客户端 (MVVM) 时出现异常
- swift - Swift - 从目录压缩文件而不在 zip 目录中创建目录
- javascript - 使用 express.js 保存用户最后路线位置的最佳方法是什么
- excel - PowerQuery,excel:如何动态检测外部源中是否存在某些标签并为每个系列创建一个包含每个标签点的表格?
- html - css伪类颜色属性不起作用
- c - 如何在c中从父进程重新启动子进程
- powershell - 如何将 Select-Object 的结果作为参数传递给命令