Yir*_*kha 14 windows dll path cmake visual-studio
我正在尝试将基于CMake的*nix项目移植到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)
Run Code Online (Sandbox Code Playgroud)
一个重要的细节是TableGenerator
使用外部共享库LibFoo
.例如在Linux下,一切正常,因为libfoo.so
它安装在一个系统库目录中/usr/local/lib
,或者CMake甚至在可执行文件中设置rpath属性,说明确切地找到库的位置.
但是,在Windows上,这些类通常不会安装到系统中,而是提取或编译到构建树中或附近的某个任意目录中.为了TableGenerator
运行,foo.dll
需要将其提供或复制到其中一个动态链接库搜索顺序路径(例如,%WINDIR%\System32
或构建输出目录TableGenerator
),这是不可取的.
如何PATH
为自定义命令设置环境变量,即在CMake运行期间但在实际自定义构建步骤运行时期间不使用?
Yir*_*kha 16
在进行研究以正确提问时,我找到了三种解决方案.考虑到找到这些信息有多难,我决定在这里发布问题和答案.
CMAKE_MSVCIDE_RUN_PATH
有一个特殊的变量专门用于解决这个确切的问题 - CMAKE_MSVCIDE_RUN_PATH.如果设置,则会将这样的行添加到自定义构建步骤脚本中:
set PATH=<CMAKE_MSVCIDE_RUN_PATH>;%PATH%
Run Code Online (Sandbox Code Playgroud)
所以所需要的就是这样的好地方:
set(CMAKE_MSVCIDE_RUN_PATH ${LibFoo_RUNTIME_LIBRARY_DIRS})
Run Code Online (Sandbox Code Playgroud)
我最初只在CMake源中注意到这个变量,因为它曾经在CMake 3.10之前没有记录.因此,您可能无法在旧版本的CMake的文档中找到它,但不要担心,它自2006年以来一直受到支持.
优点:
▪可以在一个中心位置启用
▪在add_custom_command()
其他地方的任何命令中根本不需要改变
▪只设置路径本身,不需要明确写入批处理命令
▪具有明确名称和意图的显而易见的选择
缺点:
▪整个CMake项目的全局和所有自定义命令
▪仅适用于"Visual Studio 9 2008"及以上生成器
COMMAND
参数显式设置PATH为Visual Studio中的自定义生成步骤生成的脚本包含一些序言,然后是命令本身,然后是一些结尾.是不是可以set PATH=...
通过另一个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)
Run Code Online (Sandbox Code Playgroud)
优点:
▪可以显式更改每个自定义命令的PATH
缺点:
▪依赖于生成器的未记录行为
▪有必要重写Windows的整个命令并使两个版本保持同步
▪必须明确更改每个自定义命令
file(GENERATE ...)
用于创建自定义脚本上述引用的文档add_custom_command()
仍在继续:
要运行完整脚本,请使用
configure_file()
命令或file(GENERATE)
命令创建它,然后指定aCOMMAND
以启动它.
由于附加的临时文件和命令,这有点乱:
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)
Run Code Online (Sandbox Code Playgroud)
请注意将可执行文件的路径作为参数发送的尴尬方式.这是必要的,因为脚本只写了一次,但TableGenerator
可能在不同的位置进行不同的配置(调试和发布).如果直接在内容中使用生成器表达式,则会打印CMake错误,并且除了一个配置外,项目将无法正确构建.
优点:
▪可以明确更改每个自定义命令的PATH▪
完整记录和推荐的解决方案
缺点:
▪CMakefiles中非常嘈杂
▪有必要重写Windows的整个命令并使两个版本保持同步
▪必须明确更改每个自定义命令
请参阅以下由Dvir Yitzchaki提供的其他答案.
我个人已经解决了#1的解决方案,因为它很简单,甚至在它被版本3.10中的CMake正确记录和支持之前.这对你来说应该是最好的方式,除非你需要做一些更特殊的事情.
Dvi*_*aki 11
除了 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)
Run Code Online (Sandbox Code Playgroud)
有关详细信息,请参阅http://www.cmake.org/pipermail/cmake/2006-March/008522.html。