cmake 如何将$捕获< CONFIG>到PRE_BUILD add_custom_command中的变量中?

unhi4e5o  于 2023-10-20  发布在  其他
关注(0)|答案(3)|浏览(115)

$<CONFIG>返回正确的配置,但是否可以将其值存储到变量中?怎么做?
下面的最小示例似乎只需要在它调用的add_custom_commandGetCurrentConfiguration.cmake中类似于set(currentBuildType $<CONFIG>)的东西,但我不知道什么语法可能允许它。
CMakeLists.txt:

cmake_minimum_required(VERSION 3.26.0...3.26.3)
project(LinkLibraryWithoutConfigCmake VERSION 0.0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

add_executable(targetExe Main.cpp)

set(absolutePathToInstallTrunk /opt/somewhere/install)
set(currentBuildType unknown)

add_custom_command(TARGET targetExe PRE_BUILD
    COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/GetCurrentConfiguration.cmake
    COMMAND ${CMAKE_COMMAND} -E echo "-- In add_custom_command echo:"
    COMMAND ${CMAKE_COMMAND} -E echo "   CONFIG = $<CONFIG>, CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}, currentBuildType = ${currentBuildType}"
)

./GetCurrentConfiguration.cmake

set(currentBuildType $<CONFIG>)

function(GetBuildType returnBuildType)
    set(${returnBuildType} $<CONFIG> PARENT_SCOPE)
    message(STATUS "In function GetBuildType:\n   CONFIG = $<CONFIG>, CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}, returnBuildType: ${returnBuildType}")
endfunction()

GetBuildType(currentBuildType)

message(STATUS "In GetCurrentConfiguration.cmake:\n   CONFIG = $<CONFIG>, CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}, currentBuildType = ${currentBuildType}")

以下是单配置(#1和#2)和多配置(#3和#4)生成器的configure/build命令的输出:

1

cmake -S . -B buildNinja -G Ninja -D CMAKE_BUILD_TYPE=Debug

cmake --build buildNinja

-- In function GetBuildType:
   CONFIG = `$<CONFIG>`, CMAKE_BUILD_TYPE = , returnBuildType: currentBuildType

-- In GetCurrentConfiguration.cmake:
   CONFIG = `$<CONFIG>`, CMAKE_BUILD_TYPE = , currentBuildType = `$<CONFIG>`

-- In add_custom_command echo:
   **CONFIG = Debug**, CMAKE_BUILD_TYPE = Debug, currentBuildType = unknown

2

cmake -S . -B buildNinja -G Ninja -D CMAKE_BUILD_TYPE=Release

cmake --build buildNinja

-- In function GetBuildType:
   CONFIG = `$<CONFIG>`, CMAKE_BUILD_TYPE = , returnBuildType: currentBuildType

-- In GetCurrentConfiguration.cmake:
   CONFIG = `$<CONFIG>`, CMAKE_BUILD_TYPE = , currentBuildType = `$<CONFIG>`

-- In add_custom_command echo:
   **CONFIG = Release**, CMAKE_BUILD_TYPE = Release, currentBuildType = unknown

3

cmake -S . -B buildNinjaMC -G "Ninja Multi-Config"

cmake --build buildNinjaMC --config Debug

-- In function GetBuildType:
   CONFIG = `$<CONFIG>`, CMAKE_BUILD_TYPE = , returnBuildType: currentBuildType

-- In GetCurrentConfiguration.cmake:
   CONFIG = `$<CONFIG>`, CMAKE_BUILD_TYPE = , currentBuildType = `$<CONFIG>`

-- In add_custom_command echo:
   **CONFIG = Debug**, CMAKE_BUILD_TYPE = , currentBuildType = unknown

4

cmake --build buildNinjaMC --config Release

-- In function GetBuildType:
   CONFIG = `$<CONFIG>`, CMAKE_BUILD_TYPE = , returnBuildType: currentBuildType

-- In GetCurrentConfiguration.cmake:
   CONFIG = `$<CONFIG>`, CMAKE_BUILD_TYPE = , currentBuildType = `$<CONFIG>`

-- In add_custom_command echo:
   **CONFIG = Release**, CMAKE_BUILD_TYPE = , currentBuildType = unknown

请注意,在每种情况下,最后一行都给出了CONFIG的正确值,因此似乎应该可以捕获它,但如何捕获呢?
这样做的目的是将currentBuildType附加到absolutePathToInstallTrunk,以便可以链接正确的导入库(这适用于没有 *Config.cmake的导入库),例如:在CMake脚本中,也会有:

add_library(StaticLib::StaticLib STATIC IMPORTED)

include(GNUInstallDirs)

target_include_directories(StaticLib::StaticLib
    INTERFACE
        ${absolutePathToInstallTrunk}/${CMAKE_INSTALL_INCLUDEDIR}
)

set_target_properties(StaticLib::StaticLib
    PROPERTIES
        IMPORTED_LOCATION ${absolutePathToInstallTrunk}/${CMAKE_INSTALL_LIBDIR}/${currentBuildType}/libStaticLibName.a
)

我尝试了一个简单的方法:

add_custom_command(TARGET targetExe PRE_BUILD
    COMMAND set(currentBuildType $<CONFIG>)
)

这将配置,但构建失败,并显示:

Environment variable ( currentBuildType Debug )  not defined

ninja: build stopped: subcommand failed.

我还尝试将CONFIG设置为一个函数中的变量,该函数返回parent_scope中的变量:

function(GetBuildType returnBuildType)
    set(${returnBuildType} $<CONFIG> PARENT_SCOPE)

该函数通过脚本在add_custom_command中调用:

COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/GetCurrentConfiguration.cmake

但是该值并没有像前面的输出中所示的那样设置。

js81xvg6

js81xvg61#

生成器表达式的全部意义在于,它是在 * 生成 * 阶段而不是在配置阶段进行评估/扩展的,因此它可以扩展为根据多配置生成器的构建配置而变化的值。值将在生成时扩展。直到生成时间(在配置时间期间,生成器表达式将只是:生成器表达式)。配置脚本中的CMake变量在配置时进行计算。
仅供参考,你尝试的很多事情都是...奇怪。首先,在脚本模式下运行另一个CMake作为自定义命令,脚本模式-CMake(据我所知)不会对生成器表达式做任何事情,因为它是脚本模式-它不会生成构建系统。因此,尝试使用$<CONFIG>将被视为字符串。
当你试图将一个变量传递给一个函数时,你要么需要使用一个变量(de)引用来传递值并在函数中使用该值,要么传递变量的名称,并在函数中“解引用”它。您的GetBuildType(currentBuildType)将变量名传递给函数,而您的函数只需取消引用其参数名即可获得字符串currentBuildType
在CMake脚本的自定义命令调用中引用CMAKE_BUILD_TYPE的尝试将扩展为空,因为脚本没有这样的变量,并且不存在的变量将扩展为空。要在脚本模式下调用CMake配置中的CMAKE_BUILD_TYPE变量,需要使用-D将该变量传递给脚本。
自定义命令在生成buildsystem之后的构建期间运行。生成器表达式在生成阶段进行计算,即生成构建系统的过程中。所以如果你想在自定义命令中使用生成器表达式...照做吧如果要将计算值传递给自定义命令中调用的脚本.照做吧然后在GetCurrentConfiguration.cmake中,$<CONFIG>生成器表达式的计算值将位于名为CONFIG的变量中。
不,没有技巧可以在作为自定义命令的一部分调用的CMake脚本中获取求值的生成器表达式,然后在配置自定义命令的配置脚本中获取该值。同样,自定义命令在构建时运行-完全在生成buildsystem完成之后。并且$<CONFIG>生成器表达式(和其他生成器表达式)在生成阶段之前不会被计算,因为在配置阶段不可能同时在一个变量中有多个单独的不同值。

mnowg1ta

mnowg1ta2#

这是一个更简单的解决方案,并根据上面的评论进行了更正:
CMakeLists.txt

cmake_minimum_required(VERSION 3.26.0...3.26.3)
project(Empty VERSION 0.0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

add_executable(targetExe Main.cpp)

include(GNUInstallDirs)
set(absolutePathToInstalledLibrary /opt/somewhere/install/${CMAKE_INSTALL_LIBDIR})

add_custom_command(TARGET targetExe PRE_BUILD
    COMMAND ${CMAKE_COMMAND} -D arg1=${absolutePathToInstalledLibrary} -D arg2=$<CONFIG> -P ${CMAKE_CURRENT_LIST_DIR}/GetCurrentConfiguration.cmake
    COMMAND ${CMAKE_COMMAND} -E echo "-- In add_custom_command echo:"
    COMMAND ${CMAKE_COMMAND} -E echo "   absolutePathToInstalledLibrary = ${absolutePathToInstalledLibrary}"
)

./GetCurrentConfiguration.cmake

set(installDirValidOnlyInThisScript ${arg1}/${arg2})

message(STATUS "In GetCurrentConfiguration.cmake:\n   installDirValidOnlyInThisScript = ${installDirValidOnlyInThisScript}")

输出为:

1

cmake -S . -B buildNinja -G Ninja -D CMAKE_BUILD_TYPE=Debug

cmake --build buildNinja

-- In GetCurrentConfiguration.cmake:
   installDirValidOnlyInThisScript = /opt/somewhere/install/lib/Debug

-- In add_custom_command echo:
   absolutePathToInstalledLibrary = /opt/somewhere/install/lib

2

cmake -S . -B buildNinja -G Ninja -D CMAKE_BUILD_TYPE=Release

cmake --build buildNinja

-- In GetCurrentConfiguration.cmake:
   installDirValidOnlyInThisScript = /opt/somewhere/install/lib/Release

-- In add_custom_command echo:
   absolutePathToInstalledLibrary = /opt/somewhere/install/lib

3

cmake -S . -B buildNinjaMC -G "Ninja Multi-Config"

cmake --build buildNinjaMC --config Debug

-- In GetCurrentConfiguration.cmake:
   installDirValidOnlyInThisScript = /opt/somewhere/install/lib/Debug

-- In add_custom_command echo:
   absolutePathToInstalledLibrary = /opt/somewhere/install/lib

4

cmake -S . -B buildNinjaMC -G "Ninja Multi-Config"

cmake --build buildNinjaMC --config Release

-- In GetCurrentConfiguration.cmake:
   installDirValidOnlyInThisScript = /opt/somewhere/install/lib/Release

-- In add_custom_command echo:
   absolutePathToInstalledLibrary = /opt/somewhere/install/lib
kupeojn6

kupeojn63#

currentBuildType作为参数传递给脚本(如@Tsyvarev所建议的):
COMMAND ${CMAKE_COMMAND} -D currentBuildType=$ -P ${CMAKE_CURRENT_LIST_LIST}/GetCurrentConfiguration.cmake
没有在该脚本中生成有效的配置,即打印${currentBuildType}将给出文字字符串“$<CONFIG>“,而不是“Release”或“RelWithDebInfo”。但是按照这个想法,这里有一些修改过的脚本可以工作-只要配置值只在调用的脚本中使用,并且在主CMakeLists.txt中不需要它:

cmake_minimum_required(VERSION 3.26.0...3.26.3)
project(LinkLibraryWithoutConfigCmake VERSION 0.0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

add_executable(targetExe Main.cpp)

include(GNUInstallDirs)
set(absolutePathToInstalledLibrary /opt/somewhere/install/${CMAKE_INSTALL_LIBDIR})

add_custom_command(TARGET targetExe PRE_BUILD
    COMMAND ${CMAKE_COMMAND} -D CMAKE_BUILD_TYPE=$<CONFIG> -D installDir=${absolutePathToInstalledLibrary} -P ${CMAKE_CURRENT_LIST_DIR}/GetCurrentConfiguration.cmake
    COMMAND ${CMAKE_COMMAND} -E echo "-- In add_custom_command ECHO:"
    COMMAND ${CMAKE_COMMAND} -E echo "   CONFIG = $<CONFIG>, CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}, absolutePathToInstalledLibrary = ${absolutePathToInstalledLibrary}"
)

./GetCurrentConfiguration.cmake

set(absolutePathToInstalledLibrary ${installDir}/${CMAKE_BUILD_TYPE}) # unfortunately this does not affect the "same" variable in parent CMakeLists.txt
set(installDirValidOnlyInThisScript ${installDir}/${CMAKE_BUILD_TYPE})

message(STATUS "In GetCurrentConfiguration.cmake:\n   CONFIG = $<CONFIG>, CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}, installDirValidOnlyInThisScript = ${installDirValidOnlyInThisScript}")

输出显示,单配置和多配置生成器的相关配置确实已被捕获,但它只保留在调用的脚本中,即到已安装库的路径有一个currect_appeared-它是“/release/”或/Release/”-但有点不幸的是,只在调用的脚本中:

1

cmake -S . -B buildNinja -G Ninja -D CMAKE_BUILD_TYPE= 0
cmake --build buildNinja
--在GetCurrentConfiguration.cmake中:CONFIG = $,CMAKE_BUILD_TYPE = NULL,installDirValidOnlyInThisScript = /opt/somewhere/install/lib/NULL
--在add_custom_command ECHO中:CONFIG = 0,CMAKE_BUILD_TYPE = 0,absolutePathToInstalledLibrary = /opt/somewhere/install/lib

2

cmake -S . -B buildNinja -G Ninja -D CMAKE_BUILD_TYPE=发行版
cmake --build buildNinja
--在GetCurrentConfiguration.cmake中:CONFIG = $,CMAKE_BUILD_TYPE = Release,installDirValidOnlyInThisScript = /opt/somewhere/install/lib/Release
--在add_custom_command ECHO中:CONFIG = Release,CMAKE_BUILD_TYPE = Release,absolutePathToInstalledLibrary = /opt/somewhere/install/lib

3

cmake -S . -B buildNinjaMC -G“Ninja Multi-Config”
cmake --build buildNinjaMC --config配置文件
--在GetCurrentConfiguration.cmake中:CONFIG = $,CMAKE_BUILD_TYPE = NULL,installDirValidOnlyInThisScript = /opt/somewhere/install/lib/NULL
--在add_custom_command ECHO中:CONFIG =配置文件,CMAKE_BUILD_TYPE =,absolutePathToInstalledLibrary = /opt/somewhere/install/lib

4

cmake -S . -B buildNinjaMC -G“Ninja Multi-Config”
cmake --build buildNinjaMC --config发布
--在GetCurrentConfiguration.cmake中:CONFIG = $,CMAKE_BUILD_TYPE = Release,installDirValidOnlyInThisScript = /opt/somewhere/install/lib/Release
--在add_custom_command ECHO中:CONFIG = Release,CMAKE_BUILD_TYPE =,absolutePathToInstalledLibrary = /opt/somewhere/install/lib
请注意,变量installDirValidOnlyInThisScript每次都有正确的值,但在父级CMakeLists.txt中,absolutePathToInstalledLibrary的值没有附加配置名称的后缀。

相关问题