Как скопировать файлы DLL в ту же папку, что и исполняемый файл, с помощью CMake?

98

Мы используем CMake для создания файлов Visual Studio наших источников в SVN. Теперь мой инструмент требует, чтобы некоторые DLL-файлы находились в той же папке, что и исполняемый файл. Файлы DLL находятся в папке рядом с источником.

Как я могу изменить свой CMakeLists.txtтак, чтобы сгенерированный проект Visual Studio либо уже имел определенные файлы DLL в папках выпуска / отладки, либо копировал их при компиляции?

Мат
источник

Ответы:

123

Я бы использовал 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 в зависимости от конфигурации (например, Release, Debug), вы можете разместить их в подкаталогах, названных с соответствующей конфигурацией:, /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>)
Fraser
источник
3
Краткое примечание о том, что сработало в моем случае на случай, если это поможет кому-то еще в будущем: у меня есть проект статической библиотеки, с которым необязательно связывается основной исполняемый файл, и эта библиотека требует, чтобы DLL была скопирована, если она добавлена. Итак, в файле CMakeLists.txt этой библиотеки я использовал ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>для целевого назначения. В противном случае он скопировал бы его в путь сборки библиотеки, что было бесполезно.
AberrantWolf,
Разве не целью install()директив cmake является сборка двоичных файлов? Или может что-то делать LIBRARY? Я действительно не знаю набор инструментов.
Sandburg
1
$<TARGET_FILE_DIR:MyTest>- что это? Как распечатать информацию, что именно означает
ilw
Если я что-то не пропустил при интеграции команды, этот метод не работает для добавленных библиотек IMPORTED_LIBRARIES. Он жалуется на то, что не может запустить команду после сборки, когда ничего не построено.
Tzalumen
2
После тестирования и поддержки моего cmake: если вы используете IMPORTEDбиблиотеки и вам нужно переместить библиотеки DLL, вам нужно использовать вариантную команду. Если вы добавили свою IMPORTEDбиблиотеку, как MyImportedLibвы бы использовали, COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MyImportedLib> $<TARGET_FILE_DIR:MyTest>обратите внимание, что для запуска нескольких команд пост-сборки вам нужно, чтобы все они были связаны в одну пользовательскую команду, напримерadd_custom_command(TARGET MyTest POST_BUILD COMMAND #your first command# COMMAND #Your second command#)
Tzalumen
24

Я помещаю эти строки в свой файл CMakeLists.txt верхнего уровня. Все библиотеки и исполняемые файлы, скомпилированные CMake, будут размещены на верхнем уровне каталога сборки, чтобы исполняемые файлы могли находить библиотеки и легко запускать все.

set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})

Обратите внимание, что это не решает проблему OP по копированию предварительно скомпилированных двоичных файлов из исходного каталога проекта.

Дэвид Грейсон
источник
7

У меня возникла эта проблема сегодня, когда я пытался сделать сборку Windows для моей программы. И в итоге я сам провел небольшое исследование, поскольку все эти ответы меня не удовлетворили. Было три основных вопроса:

  • Я хотел, чтобы отладочные сборки были связаны с отладочными версиями библиотек, а выпускные сборки были связаны с выпускными сборками библиотек соответственно.

  • В дополнение к этому я хотел, чтобы правильные версии файлов DLL (Debug / Release) копировались в выходные каталоги.

  • И я хотел добиться всего этого без написания сложных и хрупких скриптов.

После просмотра некоторых руководств по CMake и некоторых многоплатформенных проектов на github я нашел это решение:

Объявите свою библиотеку как цель с атрибутом «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>
)
Незначительная угроза
источник
5

Дополнение к принятому ответу, добавленное как отдельный ответ, поэтому я получаю форматирование кода:

Если вы создаете свои библиотеки 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 и всегда будет тем, что по умолчанию.

Дана Робинсон
источник
8
Последняя часть принятого ответа обращается к этому более чистым способом с использованием CMake$<CONFIGURATION>
Chuck Claunch
4

Вы также можете использовать команду 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})
Фелипе Торн
источник
2

Это полезно для одного из них

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)
Сай Киран Надипилли
источник
1

Вероятно, вам нужно добавить настраиваемую цель и сделать ее зависимой от одной из ваших исполняемых целей.

Чтобы скопировать файл с помощью вышеуказанной функции, используйте:

COMMAND ${CMAKE_PROGRAM} -E copy_if_different ${CMAKE_BINARY_DIR}/path/to/file.dll ${CMAKE_BINARY_DIR}/where/to/put/file.dll`
стрелка
источник
0

Я новичок в 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.

Может, есть лучший способ получить это название свойства, я не знаю.

Норман Пелле
источник
0

Перемещение файлов во время сборки с помощью install

У меня возникла эта проблема, когда я пытался следовать официальному руководству CMake на шаге 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 В зависимости от того, как строится проект, как это требуется оригинальный вопрос.

Дэвид Мартинес К.
источник