如何在Windows上为CMake自定义命令设置运行时PATH

我试图将一个* 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属性,说明在哪里find库。

然而,在Windows上,这些类库通常不会被安装到系统中,而只是被抽取或编译到构build树中或其附近的任意目录中。 为了使TableGenerator运行,需要将foo.dll存在或复制到Dynamic-Link Librarysearch顺序path之一(例如%WINDIR%\System32TableGenerator的构build输出目录),这是不可取的。

如何设置自定义命令的PATH环境variables,即不在CMake运行期间使用,而是在实际的自定义构build步骤运行时期间使用?

Solutions Collecting From Web of "如何在Windows上为CMake自定义命令设置运行时PATH"

在进行研究的同时,为了正确地提出问题,我找到了三个解决方案。 考虑到如何找到这些信息,我决定在这里张贴问题和答案。


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 3.10之前它是无证的。 所以你可能无法在老版本的CMake的文档中找到它,但是不用担心,它自2006年以来一直受到支持 。

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

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


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

在Visual Studio中为自定义构建步骤生成的脚本包含一些序言,然后是命令本身,然后是一些结语。 难道只能通过另一个COMMAND参数在实际命令之前添加set PATH=...吗?

add_custom_command()的文档说:

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

所以不,这不能保证是可能的。 但Visual Studio项目生成器实际上是这样做的 ,也就是说,各个命令只是一个接一个地追加,所以下面的工作:

 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 ...)创建一个自定义脚本

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解决方案,因为它干净而简单,甚至在版本3.10中得到了CMake的正确记录和支持。 除非你需要做更特别的事情,否则它应该是你最好的前进方式。

除了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