我是 CMake 的新手,在这里遇到了一些障碍,想知道是否有一个“优雅”的解决方案来解决这个问题,或者也许只是一个简单的解决方案。
作为示例,为了设置编译器标志,我正在执行以下操作:
target_compile_options(${PROJECT_NAME}
PUBLIC
$<$<CXX_COMPILER_ID:GNU>:"-some_gnu_flag">
$<$<CXX_COMPILER_ID:Clang>:"-some_clang_flag">
$<$<CXX_COMPILER_ID:MSVC>:"/some_msvc_flag">
)
这完全符合预期,除了当我尝试使用 clang-cl 作为编译器进行构建时,即:
cmake .. -G "Visual Studio 15 2017 Win64" -T "LLVM-vs2014"
CXX ID 被报告为 Clang(毕竟是 clang),但我不想使用 Clang 标志,我实际上想使用 MSVC 标志,因为 clang-cl 被设计为替代MSVC cl - 因此仅接受 MSVC 样式标志。
那么,有哪些好的解决方案可以解决这个问题,而又不会创建一些混乱的代码呢?我知道我可能可以做一堆 if() 检查并设置一些变量,但我试图坚持“现代 cmake”约定,这就是为什么我一开始就使用生成器表达式。
这是我当前的“解决方案”。我找到了 CMAKE_CXX_SIMULATE_ID 变量,它保存了我想要的信息 - 尽管这对我来说仍然感觉有点脏。
# Get compiler info
set(CXX_FLAGS_STYLE_GNU OFF)
set(CXX_FLAGS_STYLE_MSVC OFF)
set(CXX_FLAGS_STYLE_CLANGCL OFF)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CXX_FLAGS_STYLE_GNU ON)
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
if ("${CMAKE_CXX_SIMULATE_ID}" STREQUAL "MSVC")
set(CXX_FLAGS_STYLE_CLANGCL ON)
else ()
set(CXX_FLAGS_STYLE_GNU ON)
endif ()
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(CXX_FLAGS_STYLE_MSVC ON)
else ()
message(FATAL_ERROR "Unsupported compiler!")
endif ()
# Compiler flags
target_compile_options(${PROJECT_NAME}
PRIVATE
## GCC/Clang Flags
$<$<BOOL:${CXX_FLAGS_STYLE_GNU}>:"-someflag">
## MSVC flags
$<$<BOOL:${CXX_FLAGS_STYLE_MSVC}>:"/someflag">
## CLANG-CL flags
$<$<BOOL:${CXX_FLAGS_STYLE_CLANGCL}>:"-someflag">
)
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU") # GCC and Clang
elseif (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") # MSVC
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") # clang-cl
endif()
endif()
并将
GNU
标志导出到 clang-cl
:
# `GNU_COMPILE_OPTIONS`: (not official variable) the flags used for GNU frontend
foreach(option IN LISTS GNU_COMPILE_OPTIONS)
target_compile_options(${Target} ${Populate}
/clang:${option}
# or -XClang ${option}
)
endforeach()
CMAKE_<LANG>_SIMULATE_ID
描述了生成代码的 ABI 兼容性。,因此 clang
(Windows 上的官方 LLVM)和 clang-cl
都返回 MSVC
。