我们使用 CMake 在 SVN 中生成源代码的 Visual Studio 文件。现在我的工具需要一些 DLL 文件与可执行文件位于同一文件夹中。DLL 文件位于源代码旁边的文件夹中。
如何更改CMakeLists.txt
生成的 Visual Studio 项目在发布/调试文件夹中已有特定的 DLL 文件或在编译时复制它们?
我会add_custom_command
用cmake -E copy_if_different...
. 如需完整信息,请运行
cmake --help-command add_custom_command
cmake -E
因此,在您的情况下,如果您具有以下目录结构:
/CMakeLists.txt
/src
/libs/test.dll
并且您的命令适用的 CMake 目标是MyTest
,那么您可以将以下内容添加到您的 CMakeLists.txt 中:
add_custom_command(TARGET MyTest POST_BUILD # Adds a post-build event to MyTest
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..."
"${PROJECT_SOURCE_DIR}/libs/test.dll" # <--this is in-file
$<TARGET_FILE_DIR:MyTest>) # <--this is out-file path
如果您只想/libs/
复制目录的全部内容,请使用cmake -E copy_directory
:
add_custom_command(TARGET MyTest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${PROJECT_SOURCE_DIR}/libs"
$<TARGET_FILE_DIR:MyTest>)
如果您需要根据配置(例如发布、调试等)复制不同的 dll,那么您可以将它们放在以相应配置命名的子目录中:/libs/Release
和/libs/Debug
. 然后,您需要在调用中将配置类型注入到 dll 的路径中add_custom_command
,如下所示:
add_custom_command(TARGET MyTest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${PROJECT_SOURCE_DIR}/libs/$<CONFIGURATION>"
$<TARGET_FILE_DIR:MyTest>)
我将这些行放在我的顶级 CMakeLists.txt 文件中。CMake编译的所有库和可执行文件都将放在构建目录的顶层,以便可执行文件可以找到库并轻松运行所有内容。
set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
请注意,这并不能解决 OP 从项目源目录复制预编译二进制文件的问题。
我今天在尝试构建我的程序的 Windows 版本时遇到了这个问题。我最终自己做了一些研究,因为所有这些答案都不能让我满意。有三个主要问题:
我希望调试版本与库的调试版本链接,而发布版本分别与库的发布版本链接。
除此之外,我希望将正确版本的 DLL 文件(调试/发布)复制到输出目录。
我想在不编写复杂而脆弱的脚本的情况下实现这一切。
在 github 上浏览了一些 CMake 手册和一些多平台项目后,我找到了这个解决方案:
将您的库声明为具有“IMPORTED”属性的目标,引用其调试并发布 .lib 和 .dll 文件。
add_library(sdl2 SHARED IMPORTED GLOBAL)
set_property(TARGET sdl2 PROPERTY IMPORTED_IMPLIB_RELEASE "${SDL_ROOT_PATH}/lib/SDL2.lib")
set_property(TARGET sdl2 PROPERTY IMPORTED_LOCATION_RELEASE "${SDL_ROOT_PATH}/bin/SDL2.dll")
set_property(TARGET sdl2 PROPERTY IMPORTED_IMPLIB_DEBUG "${SDL_ROOT_PATH}/lib/SDL2d.lib")
set_property(TARGET sdl2 PROPERTY IMPORTED_LOCATION_DEBUG "${SDL_ROOT_PATH}/bin/SDL2d.dll")
像往常一样将此目标与您的项目链接
target_link_libraries(YourProg sdl2 ...)
如果自上次构建以来已以某种方式更改,则进行自定义构建步骤以将 dll 文件复制到其目标
add_custom_command ( TARGET YourProg POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:sdl2> $<TARGET_FILE_DIR:YourProg>
)
已接受答案的附录,作为单独的答案添加,因此我得到了代码格式:
如果您在同一个项目中构建 dll,它们通常位于 Release、Debug 等目录中。您必须使用 Visual Studio 环境变量来正确复制它们。例如:
"${PROJECT_BINARY_DIR}/your_library/\$\(Configuration\)/your_library.dll"
对于源和
"${CMAKE_CURRENT_BINARY_DIR}/\$\(Configuration\)/your_library.dll"
为目的地。注意逃跑!
您不能将 CMake CMAKE_BUILD_TYPE 变量用于配置,因为它在 VS 项目生成时已解决,并且始终是默认值。
您还可以使用命令 find_library:
find_library(<some_var> NAMES <name_of_lib> PATHS "<path/to/lib>")
使用定义的 EXECUTABLE_PATH,例如:
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
您可以移动可执行文件所需的 .dll 文件
file(COPY ${<some_var>}
DESTINATION ${EXECUTABLE_OUTPUT_PATH})
install
我在尝试遵循 CMake 官方教程Step 9时遇到了这个问题。这是我要移动的文件的位置:
src
|_build
|_Debug
- `MathFunctions.dll`
这是我希望文件所在的位置:
src
|_build
|_install
|_bin
- `MathFunctions.dll`
由于这个 DLL 是作为共享库生成的,我所做的只是将这一行包含在包含库源代码CMakeLists.txt
的子目录中src/Mathfunctions/CMakeLists.txt
install(FILES ${PROJECT_BINARY_DIR}/$<CONFIG>/MathFunctions.dll
DESTINATION bin)
感谢您的回答,我可以考虑这一点。只是一条线,所以我认为还可以。$<CONFIG>
可以有两个值Debug或Release取决于项目的构建方式,如原始问题所要求的。
这对其中一个很有用
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
${PROJECT_SOURCE_DIR}/lib CACHE
PATH "Directory where all the .lib files are dumped." FORCE)
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY
${PROJECT_SOURCE_DIR}/bin CACHE
PATH "Directory where .exe and .dll files are dumped." FORCE)
对于 Windows 用户,$<TARGET_RUNTIME_DLLS:tgt>
CMake 3.21+ 中有一个新的生成器表达式,您可以使用这个官方片段来复制目标所依赖的所有 DLL。
find_package(foo REQUIRED)
add_executable(exe main.c)
target_link_libraries(exe PRIVATE foo::foo foo::bar)
add_custom_command(TARGET exe POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:exe> $<TARGET_FILE_DIR:exe>
COMMAND_EXPAND_LISTS
)
您可能需要添加自定义目标并使其依赖于您的可执行目标之一。
要使用上述功能复制文件,请使用:
COMMAND ${CMAKE_PROGRAM} -E copy_if_different ${CMAKE_BINARY_DIR}/path/to/file.dll ${CMAKE_BINARY_DIR}/where/to/put/file.dll`
当前评分最高的答案中的以下命令取决于放在 /libs/ 中的输出。
add_custom_command(TARGET MyTest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${PROJECT_SOURCE_DIR}/libs/$<CONFIGURATION>"
$<TARGET_FILE_DIR:MyTest>)
我使用以下命令进行复制,这对我来说无处不在。请注意,我只是在此处复制输出 dll,而不是整个目录。另请注意,我正在对目标 /bin/ 目录进行硬编码,该目录特定于该项目。但我想分享$<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>/$<TARGET_FILE_NAME:${CMAKE_PROJECT_NAME}>
我认为很简洁的语法:
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>/$<TARGET_FILE_NAME:${CMAKE_PROJECT_NAME}>
${CMAKE_CURRENT_SOURCE_DIR}/bin/$<TARGET_FILE_NAME:${CMAKE_PROJECT_NAME}>)
我是 CMake 初学者,但我仍然想分享我的经验。在我的情况下,我需要一个安装后副本,以便我的所有二进制文件都在其中。对于可以在 CMake 中导入的第三方二进制文件,以下内容适用于我:
find_package( dependency REQUIRED )
if( MSVC )
# If done properly and if the dependency has a correct config file, IMPORTED_LOCATION_RELEASE should be defined
get_target_property( DEP_SHARED_LIB_PATH dependency IMPORTED_LOCATION_RELEASE )
# Create a bin directory in the install folder
add_custom_command(TARGET BGS POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_INSTALL_PREFIX}/bin/)
# Copy the shared lib file
add_custom_command(TARGET BGS POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${DEP_SHARED_LIB_PATH} ${CMAKE_INSTALL_PREFIX}/bin/)
endif()
显然 IMPORTED_LOCATION_RELEASE 可以有变体,具体取决于共享库的构建/安装方式。可能是 IMPORTED_LOCATION_DEBUG。
也许有更好的方法来获取该属性名称,我不知道。