【问题标题】:How to set runtime PATH for CMake custom command on Windows如何在 Windows 上为 CMake 自定义命令设置运行时 PATH
【发布时间】:2015-04-16 11:12:49
【问题描述】:

我正在尝试将基于 *nix、基于 CMake 的项目移植到 Windows。主库所需的一个头文件是由自定义程序生成的,所以CMakeLists.txt文件包含如下内容:

add_executable(TableGenerator "TableGenerator.cpp")
target_link_libraries(TableGenerator ${LibFoo_LIBRARY})

add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Table.h"
                   COMMAND TableGenerator "${CMAKE_CURRENT_BINARY_DIR}/Table.h"
                   DEPENDS TableGenerator)

一个重要的细节是TableGenerator 使用外部共享库LibFoo。例如在 Linux 下,一切正常,因为 libfoo.so 安装在系统库目录之一,如 /usr/local/lib,或者 CMake 甚至在可执行文件中设置 rpath 属性,说明在哪里可以找到库。

然而,在 Windows 上,这类库通常不会安装到系统中,而只是被提取或编译到构建树中或附近的某个任意目录中。为了使TableGenerator 运行,foo.dll 需要在Dynamic-Link Library Search Order 路径之一(例如%WINDIR%\System32TableGenerator 的构建输出目录)中可用,这是不可取的。

如何为自定义命令设置PATH 环境变量,即不是during the CMake run 而是在实际的自定义构建步骤运行时使用?

【问题讨论】:

  • 通常您会将 DLL 的副本放在与可执行文件相同的目录中。
  • 确实,所有这些都是关于如何避免这样做。例如,一个实际的原因是,如果 DLL 有更多的 DLL 依赖项,其名称需要在子项目中全部硬编码。

标签: windows visual-studio dll path cmake


【解决方案1】:

虽然我仍在进行研究以正确提出问题,但我找到了三个解决方案。考虑到找到这些信息有多难,我还是决定在这里发布问题和答案。


1。使用全局变量CMAKE_MSVCIDE_RUN_PATH

有一个专门用于解决这个确切问题的特殊变量——CMAKE_MSVCIDE_RUN_PATH。如果设置,则会在自定义构建步骤脚本中添加如下一行:

set PATH=<CMAKE_MSVCIDE_RUN_PATH>;%PATH%

所以所有需要的就是在一个好地方做这样的事情:

set(CMAKE_MSVCIDE_RUN_PATH ${LibFoo_RUNTIME_LIBRARY_DIRS})

我最初只在 CMake 源代码中注意到这个变量,因为它在 CMake 3.10 之前没有记录。所以你可能无法在旧版本 CMake 的文档中找到它,但别担心,它是 supported since 2006

优点:
▪ 可以在一个中心位置启用
▪ 其他地方的任何add_custom_command() 命令都不需要更改
▪ 只设置路径本身,不需要显式编写批处理命令
▪ 具有明确名称和意图的显而易见的选择

缺点:
▪ 整个 CMake 项目和所有自定义命令的全局
▪ 仅适用于“Visual Studio 9 2008”及更高版本的生成器


2。使用两个 COMMAND 参数显式设置 PATH

在 Visual Studio 中为自定义构建步骤生成的脚本包含一些序言,然后是命令本身,然后是一些尾声。难道不能通过另一个COMMAND参数在真正的命令之前简单地添加set PATH=...吗?

documentation for add_custom_command() 说:

COMMAND
指定要在构建时执行的命令行。如果指定了多个COMMAND,它们将按顺序执行,但不一定必须组合成有状态的 shell 或批处理脚本。

所以不,这不能保证是可能的。但是 Visual Studio 项目生成器实际上是does it like this,即各个命令只是一个接一个地附加,所以下面的工作就完成了:

add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Table.h"
                   COMMAND set "PATH=${LibFoo_RUNTIME_LIBRARY_DIRS};%PATH%"
                   COMMAND TableGenerator "${CMAKE_CURRENT_BINARY_DIR}/Table.h"
                   DEPENDS TableGenerator)

优点:
▪ PATH 可以为每个自定义命令显式更改

缺点:
▪ 依赖于生成器的未记录行为
▪ 有必要为 Windows 重写整个命令并保持两个版本同步
▪ 每个自定义命令都必须明确更改


3。使用file(GENERATE ...) 创建自定义脚本

上面引用的documentation for add_custom_command() 继续:

要运行完整的脚本,请使用configure_file() 命令或file(GENERATE) 命令创建它,然后指定COMMAND 来启动它。

由于额外的临时文件和命令,这有点混乱:

file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/RunTableGenerator.cmd"
              CONTENT "set PATH=${LibFoo_RUNTIME_LIBRARY_DIRS};%PATH%
                       %1 ${CMAKE_CURRENT_BINARY_DIR}/Table.h")
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Table.h"
                   COMMAND "${CMAKE_CURRENT_BINARY_DIR}/RunTableGenerator.cmd" "$<TARGET_FILE:TableGenerator>"
                   DEPENDS TableGenerator)

请注意将可执行文件的路径作为参数发送的尴尬方式。这是必要的,因为脚本只编写一次,但TableGenerator 可能针对不同的配置(调试和发布)位于不同的位置。如果直接在内容中使用生成器表达式,则会打印 CMake 错误,并且项目将无法为除一种配置之外的所有配置正确构建。

优点:
▪ 可以为每个自定义命令显式更改 PATH
▪ 完整记录和推荐的解决方案

缺点:
▪ CMakefiles 中非常嘈杂
▪ 有必要为 Windows 重写整个命令并保持两个版本同步
▪ 每个自定义命令都必须明确更改


4。通过 CMake 包装器启动自定义命令

请参阅下面由 Dvir Yitzchaki 提供的其他答案。


我个人选择了解决方案 #1,因为它干净且简单,甚至在 CMake 版本 3.10 中正确记录和支持它之前。这也应该是您前进的最佳方式,除非您需要做一些更特别的事情。

【讨论】:

  • 不幸的是,我没有设法让它在我的设置上工作....不得不使用后期构建 custom_target 复制 dll。 CMAKE_MSVCIDE_RUN_PATH 变量的结果应该在哪里看到?我在 vcxproj 文件中看到一些行显示为 CustomBuild...但无法从 VS 启动调试器并加载 DLL:/
  • 我明白了。这个问题涉及 CMake 自定义命令(例如,您在项目中有 blah.template,它通过一些预处理器转换为 blah.h 作为编译的一部分)。您想更改 VS 下运行/调试应用程序的 DLL 路径,这是另一回事。您可以通过在“项目属性 > 调试 > 环境”下手动添加路径来避免复制 DLL,例如Path=$(SolutionDir)external\somelib\bin;%Path%。不幸的是,在 CMake 中实现自动化似乎更难——请参阅gitlab.kitware.com/cmake/cmake/issues/8884 了解更多信息。
  • 好的,我不确定,现在很清楚了。谢谢!
  • 在第 2 节中作为自定义命令投票帮助我在 Linux 中设置 PYTHONPATH。相当于PYTHONPATH=&lt;mypath&gt; python script.py
【解决方案2】:

除了 Yirkha 写的之外,还有另一种方法,那就是通过 cmake 运行可执行文件并使用 cmake 的 -E 选项来设置环境。

所以你的情况是:

add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Table.h"
               COMMAND ${CMAKE_COMMAND} -E env "PATH=${LibFoo_RUNTIME_LIBRARY_DIRS}" $<TARGET_FILE:TableGenerator> "${CMAKE_CURRENT_BINARY_DIR}/Table.h"
               DEPENDS TableGenerator)

详情请见http://www.cmake.org/pipermail/cmake/2006-March/008522.html

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-24
    • 2016-10-18
    • 2013-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多