在我们的项目中,我们有大量的配置源于各种目标硬件类型乘以少数模式。
为避免不必要的细节,我们假设配置的格式为<hw>_<mode>
<hw>
之一是:A
,B
或C
,<mode>
之一是:1
,2
或3
。此外,为了保持接近实际情况,我们假设A_3
和C_1
是不受支持的例外。 (但是,我认为这不重要。)
这使我们得到3 x 3 - 2 = 7支持的配置。
现在,我们希望根据配置进行设置(其中包括编译器和sysroot的路径)。此外,某些来源应仅包含在某些配置中。我们更愿意根据部分配置来完成。
例如,我们希望/this/g++
用于所有A_*
配置,/that/g++
用于所有其他配置。或者,我们希望为所有mode2.cpp
配置添加*_2
文件,而不是其他配置。
如果我们使用CMAKE_BUILD_TYPE
,这是一项简单的任务。我们可以用正则表达式(string(REGEX MATCH
)拆分它,并且每个部分都有变量。然后简单的if
完成了这项工作。
然而,这种方法对多配置生成器并不友好(目前看来只有Visual Studio和Xcode)。为了很好地使用多配置生成器AFAIK,我们必须使用generator expressions。
但问题是,我认为无法在生成器表达式中提取配置(CONFIG
)的部分。
例如,我可以这样做:
add_executable(my_prog
source_1.cpp
# ...
source_n.cpp
$<$<CONFIG:A_2>:mode2.cpp>
$<$<CONFIG:B_2>:mode2.cpp>
$<$<CONFIG:C_2>:mode2.cpp>
)
但考虑到我们迟早会添加新的硬件类型(或删除过时的硬件类型),这看起来不像是一种可维护的方法。
有没有办法在生成器表达式中进行某种形式的匹配?
到目前为止,我发现的唯一解决方法是使用这样的方法:
set(CONFIG_IS_MODE_2 $<OR:$<CONFIG:A_2>,$<CONFIG:B_2>,$<CONFIG:C_2>>)
add_executable(my_target
source_1.cpp
# ...
source_n.cpp
$<${CONFIG_IS_MODE_2}:mode2.cpp>
)
至少允许集中这些表达式,并且当添加新的硬件类型时,只有一个地方可以更新。但是,仍有许多变量需要更新。
有没有更好的解决方案?
答案 0 :(得分:1)
使用target_sources()
命令和function()
,您仍然可以使用正则表达式来匹配您的配置。
这看起来像这个示例代码:
cmake_minimum_required(VERSION 3.0)
project(TestConfigRegEx)
function(my_add_sources_by_config_regex _target _regex)
foreach(_config IN LISTS CMAKE_CONFIGURATION_TYPES CMAKE_BUILD_TYPE)
if (_config MATCHES "${_regex}")
target_sources(${_target} PRIVATE $<$<CONFIG:${_config}>:${ARGN}>)
endif()
endforeach()
endfunction()
file(WRITE main.cpp "int main() { return 0; }")
file(WRITE modeRelease.cpp "")
add_executable(my_target main.cpp)
my_add_sources_by_config_regex(my_target Release modeRelease.cpp)
但是这给了我一个来自CMake版本3.11.1 Visual Studio 15 2017
生成器端的错误:
Target "my_target" has source files which vary by configuration. This is
not supported by the "Visual Studio 15 2017" generator.
Config "Debug":
.../main.cpp
Config "Release":
.../main.cpp
.../modeRelease.cpp
奇怪的是它仍然会产生解决方案。
<强>替代强>
经典之一是添加包含配置的定义,并使用#if
检查处理C / C ++代码中的差异
您不是按配置区分,而是区分其他目标(例如my_target
和my_target_2
)