如何将CMake参数转发到ExternalProject?

28

我已经(大部分)成功地为googletest设置了ExternalProject_Add。但是,我注意到像我的C++编译器选择、构建类型等这样的东西并没有自动转发到ExternalProject。

我可以通过在对ExternalProject_Add的调用中将其添加到CMAKE_ARGS中来轻松添加任何标志,如下所示:

CMAKE_ARGS -DBUILD_SHARED_LIBS:BOOL=${BUILD_SHARED_LIBS}
然而,这需要我列举所有可能需要转发到googletests的CMake调用的参数,而该列表相当庞大。如果我想要每个其他ExternalProject_Add,我也需要创建相同的列表。那似乎很脆弱和容易出错。
有没有办法告诉CMake“转发”用户提供的配置呢?换句话说,如果我这样调用CMake:
cmake <path-to-project> -DCMAKE_C_COMPILER=/usr/bin/clang -DSOME_RANDOM_FLAG=stuff

那么我希望我的 ExternalProject_Add 调用可以提供相同的编译器选择和值给 SOME_RANDOM_FLAG无需显式列出这些名称。我不确定仅仅传递 CMake 的 ARGV 是否可行,因为说:

CC=/usr/bin/clang cmake <path-to-project>

希望能够完美地工作。

有什么想法可以实现这一点吗?

3个回答

11

在长时间的尝试后,CMake邮件列表中Don Hinton终于回答了这个问题。虽然Fraser的解决方案非常接近,但仍可以传递一些特定于项目的参数,可能会导致一些不可预测的行为。

以下方法可以正常工作。希望这能帮助人们节省一些时间来解决这个问题:

cmake_minimum_required(VERSION 3.1)

# MUST be done before call to 'project'
get_cmake_property(vars CACHE_VARIABLES)
foreach(var ${vars})
  get_property(currentHelpString CACHE "${var}" PROPERTY HELPSTRING)
    if("${currentHelpString}" MATCHES "No help, variable specified on the command line." OR "${currentHelpString}" STREQUAL "")
        # message("${var} = [${${var}}]  --  ${currentHelpString}") # uncomment to see the variables being processed
        list(APPEND CL_ARGS "-D${var}=${${var}}")
    endif()
endforeach()

project(SuperBuild)

include(ExternalProject)

ExternalProject_Add(ext_proj
  ...

  CMAKE_ARGS ${CL_ARGS}
)

邮件列表线程链接:https://cmake.org/pipermail/cmake/2018-January/067002.html


从邮件列表中:请注意,如果CMakeCache.txt已经存在,则此方法将无法正常工作。如果您重新运行cmake,则一些缓存的变量将被混合在一起,就好像您在调用“project”之后使用了此代码一样。为了解决这个问题,只需通过set(CL_ARGS ${CL_ARGS} CACHE STRING "comment")将您的CL_ARGS保存到缓存中,并将整个结构包装在if (NOT CL_ARGS)中即可。 - akwky

4

我不知道有什么可靠的方法来实现这一点,而且我很确定没有标准的"CMake方式",但是我对一个类似问题的回答关于捕获CMake命令行参数可能会有所帮助?


嗯,那真是不幸。我看过的一个东西是cmake的'-C <initial-cache>'选项。我认为如果我使用该参数将ExternalProject_Add cmake调用指向我的顶级CMakeCache.txt,它会起作用。但是-C选项不想要CMakeCache.txt文件,它想要其他东西(“不是缓存格式文件”)。您有任何想法如何使顶级cmake调用发出可以由带有-C的较低级别cmake使用的内容吗? - acm
很抱歉,这种方法并不健壮。-C选项实际上只是一种传递命令行选项的方式 - 它正在寻找一堆set(... CACHE ...)类型的命令。你可以使用一个初始缓存文件,然后在CMakeLists.txt中自己解析它以得出它创建的各种设置。但这需要知道文件的路径,并且如果您希望它们到达gtest,则始终需要通过-C文件传递命令行参数。我希望这个CMake限制会在更多人开始使用ExternalProject_Add时得到更多关注。 - Fraser
1
感谢你的见解。我接受了你的答案,因为它似乎是最有前途的,即使不是特别令人满意。很明显,在CMake这个领域存在一些困难。ExternalProject_Add和FindPackage之间的阻抗不匹配是另一个头疼问题,“超级构建器”是一个非常糟糕的解决方案。我刚刚成功地通过切换从ExternalProject_Add到使用add_subdirectory来引入googletest来绕过我的问题,这是行得通的。这确实意味着需要将其克隆到我的源树中,这正是我希望避免的,但你能做什么呢? - acm
我遇到了类似的问题。在我看来,@acm最新的评论似乎是迄今为止最有前途的解决方法:使用一堆git子模块(或类似的东西)加上add_subdirectory,而不是使用ExternalProject_Add - thiagowfx

0
  1. 创建一个工具链文件,包含CMake变量,例如:
    # /tmp/toolchain.cmake
    set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Targeting macOS version" FORCE)
    set(CMAKE_C_COMPILER_LAUNCHER "sccache" CACHE STRING "C compiler launcher" FORCE)
    
  2. 将环境变量CMAKE_TOOLCHAIN_FILE设置为工具链文件
    export CMAKE_TOOLCHAIN_FILE=/tmp/toolchain.cmake
    
  3. 运行cmake来配置根项目

现在,CMake外部项目应该自动继承环境变量CMAKE_TOOLCHAIN_FILE

请参阅https://cmake.org/cmake/help/latest/variable/CMAKE_TOOLCHAIN_FILE.html


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接