Як скопіювати файли DLL в ту саму папку, що й виконуваний файл, за допомогою CMake?


98

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

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

Відповіді:


122

Я б використав 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>)

3
Коротке зауваження щодо того, що працювало в моєму випадку, якщо це допоможе комусь іншому в майбутньому: у мене є проект статичної бібліотеки, з яким головний виконуваний файл необов’язково пов'язує, і ця бібліотека вимагає копіювання DLL у разі додавання. Отже, у файлі CMakeLists.txt цієї бібліотеки я використовував ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>цільовий пункт призначення. Інакше він скопіював би його до шляху побудови бібліотеки, що було марно.
AberrantWolf

хіба не мета install()директив cmake - зібрати бінарні файли? А може, виготовити LIBRARYречі? Я не дуже знаю інструментарій.
Сандбург

1
$<TARGET_FILE_DIR:MyTest>- що це? Як надрукувати інформацію, що саме означає
ilw

Якщо я не пропустив щось під час інтеграції команди, цей метод не працює для бібліотек, доданих IMPORTED_LIBRARIES. Він скаржиться на те, що не може запустити команду після побудови, коли нічого не побудовано.
Цалумен

2
Після тестування та підказування мого cmake: Якщо ви використовуєте IMPORTEDбібліотеки і вам потрібно перенести DLL-файли, вам потрібно використовувати команду variant. Якщо ви додали 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 (Налагодження / Випуск) у вихідні каталоги.

  • І я хотів досягти всього цього без написання складних і тендітних сценаріїв.

Переглянувши деякі посібники CMake та кілька мультиплатформенних проектів на github, я знайшов таке рішення:

Оголосіть свою бібліотеку цільовою за допомогою атрибута "ІМПОРТОВАНИЙ", посилайтеся на її налагодження та випустіть файли .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>
Чак Клаунч

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 В залежності від того, як будується проект, як це потрібно оригінальний питання.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.