Bagaimana cara menyalin file DLL ke folder yang sama dengan yang dapat dieksekusi menggunakan CMake?

98

Kami menggunakan CMake untuk membuat file Visual Studio dari sumber kami di SVN kami. Sekarang alat saya membutuhkan beberapa file DLL berada di folder yang sama dengan file yang dapat dieksekusi. File DLL berada dalam folder di samping sumber.

Bagaimana saya bisa mengubah saya CMakeLists.txtsehingga proyek Visual Studio yang dihasilkan sudah memiliki file DLL tertentu di folder rilis / debug atau akan menyalinnya saat kompilasi?

Tikar
sumber

Jawaban:

122

Saya akan menggunakan add_custom_commanduntuk mencapai ini bersama cmake -E copy_if_different.... Untuk menjalankan info lengkap

cmake --help-command add_custom_command
cmake -E


Jadi dalam kasus Anda, jika Anda memiliki struktur direktori berikut:

/CMakeLists.txt
/src
/libs/test.dll

dan target CMake Anda yang menerapkan perintah ini MyTest, Anda dapat menambahkan yang berikut ini ke 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


Jika Anda hanya ingin seluruh konten /libs/direktori disalin, gunakan 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>)


Jika Anda perlu menyalin dll yang berbeda tergantung pada konfigurasinya (Rilis, Debug, misalnya) maka Anda dapat memilikinya di subdirektori yang diberi nama dengan konfigurasi yang sesuai:, /libs/Releasedan /libs/Debug. Anda kemudian perlu memasukkan jenis konfigurasi ke jalur ke dll dalam add_custom_commandpanggilan, seperti ini:

add_custom_command(TARGET MyTest POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_directory
        "${PROJECT_SOURCE_DIR}/libs/$<CONFIGURATION>"
        $<TARGET_FILE_DIR:MyTest>)
Fraser
sumber
3
Catatan singkat untuk apa yang berhasil dalam kasus saya seandainya itu membantu orang lain di masa depan: Saya memiliki proyek perpustakaan statis yang dapat dieksekusi secara opsional dengan tautan utama, dan perpustakaan itu memerlukan DLL untuk disalin jika ditambahkan. Jadi di file CMakeLists.txt perpustakaan itu saya gunakan ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>untuk tujuan target. Jika tidak, itu akan menyalinnya ke jalur build perpustakaan, yang tidak berguna.
AberrantWolf
bukankah itu tujuan dari install()arahan cmake untuk merakit binari? Atau mungkin membuat LIBRARYsesuatu? Saya tidak terlalu tahu tentang rantai alat.
Sandburg
1
$<TARGET_FILE_DIR:MyTest>- apa itu? Cara mencetak info, apa sebenarnya maksudnya
ilw
Kecuali saya melewatkan sesuatu ketika saya mengintegrasikan perintah, metode ini tidak berfungsi untuk pustaka yang ditambahkan IMPORTED_LIBRARIES. Ia mengeluh tentang tidak dapat menjalankan perintah post-build ketika tidak ada yang dibangun.
Tzalumen
2
Setelah menguji dan mendorong cmake saya: Jika Anda menggunakan IMPORTEDperpustakaan, dan perlu merelokasi DLL, Anda perlu menggunakan perintah varian. Jika Anda telah menambahkan IMPORTEDperpustakaan MyImportedLibAnda seperti yang akan Anda gunakan COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MyImportedLib> $<TARGET_FILE_DIR:MyTest>Perhatikan bahwa untuk menjalankan beberapa perintah post build Anda membutuhkan semuanya terikat ke dalam satu perintah khusus misalnyaadd_custom_command(TARGET MyTest POST_BUILD COMMAND #your first command# COMMAND #Your second command#)
Tzalumen
24

Saya meletakkan baris-baris ini di file CMakeLists.txt tingkat atas saya. Semua pustaka dan file yang dapat dieksekusi yang dikompilasi oleh CMake akan ditempatkan di tingkat teratas dari direktori build sehingga file yang dapat dieksekusi dapat menemukan perpustakaan dan mudah untuk menjalankan semuanya.

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

Perhatikan bahwa ini tidak menyelesaikan masalah OP menyalin biner yang telah dikompilasi dari direktori sumber proyek.

David Grayson
sumber
7

Saya mengalami masalah ini hari ini ketika mencoba membuat Windows membangun program saya. Dan saya akhirnya melakukan penelitian sendiri karena semua jawaban ini tidak memuaskan saya. Ada tiga masalah utama:

  • Saya ingin build debug ditautkan dengan library versi debug dan build rilis masing-masing ditautkan dengan build rilis library.

  • Selain itu, saya ingin versi file DLL yang benar (Debug / Release) disalin ke direktori keluaran.

  • Dan saya ingin mencapai semua ini tanpa menulis skrip yang rumit dan rapuh.

Setelah menjelajahi beberapa manual CMake dan beberapa proyek multiplatform di github, saya menemukan solusi ini:

Deklarasikan perpustakaan Anda sebagai target dengan atribut "IMPORTED", rujuk file debug dan rilisnya .lib dan .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")

Tautkan target ini dengan proyek Anda seperti biasa

target_link_libraries(YourProg sdl2 ...)

Buat langkah custom build untuk menyalin file dll ke tujuannya jika sudah diubah sejak build sebelumnya

add_custom_command ( TARGET YourProg POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
    $<TARGET_FILE:sdl2> $<TARGET_FILE_DIR:YourProg>
)
Ancaman kecil
sumber
5

Tambahan untuk jawaban yang diterima, ditambahkan sebagai jawaban terpisah sehingga saya mendapatkan pemformatan kode:

Jika Anda membangun dll Anda dalam proyek yang sama, mereka biasanya berada di direktori Release, Debug, dll. Anda harus menggunakan variabel lingkungan Visual Studio untuk menyalinnya dengan benar. misalnya:

"${PROJECT_BINARY_DIR}/your_library/\$\(Configuration\)/your_library.dll"

untuk sumber dan

"${CMAKE_CURRENT_BINARY_DIR}/\$\(Configuration\)/your_library.dll"

untuk tujuan. Perhatikan pelariannya!

Anda tidak dapat menggunakan variabel CMake CMAKE_BUILD_TYPE untuk konfigurasi karena telah diselesaikan pada waktu pembuatan proyek VS dan akan selalu menjadi apa pun defaultnya.

Dana Robinson
sumber
8
Bagian terakhir dari jawaban yang diterima membahas hal ini dengan cara CMake yang lebih bersih menggunakan$<CONFIGURATION>
Chuck Claunch
4

Anda juga dapat menggunakan perintah find_library:

find_library(<some_var> NAMES <name_of_lib> PATHS "<path/to/lib>")

Dengan EXECUTABLE_PATH yang ditentukan, misalnya:

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

Anda dapat memindahkan file .dll yang Anda butuhkan, dengan file

file(COPY ${<some_var>}
    DESTINATION ${EXECUTABLE_OUTPUT_PATH})
Felipe Thorn
sumber
2

Ini berguna untuk salah satunya

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)
Sai Kiran Nadipilli
sumber
1

Anda mungkin perlu menambahkan target khusus dan membuatnya bergantung pada salah satu target yang dapat dieksekusi.

Untuk menyalin file menggunakan fungsi di atas, gunakan:

COMMAND ${CMAKE_PROGRAM} -E copy_if_different ${CMAKE_BINARY_DIR}/path/to/file.dll ${CMAKE_BINARY_DIR}/where/to/put/file.dll`
panahd
sumber
0

Saya seorang pemula CMake, tetapi saya tetap ingin berbagi pengalaman saya. Dalam kasus saya, saya memerlukan salinan pasca-pemasangan agar semua biner saya masuk. Dalam kasus biner pihak ketiga yang dapat diimpor dalam CMake, berikut ini yang berfungsi untuk saya:

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()

Jelas IMPORTED_LOCATION_RELEASE dapat memiliki varian tergantung pada bagaimana perpustakaan bersama dibuat / dipasang. Bisa jadi IMPORTED_LOCATION_DEBUG.

Mungkin ada cara yang lebih baik untuk mendapatkan nama properti itu, saya tidak tahu.

Norman Pellet
sumber
0

Memindahkan file selama build menggunakan install

Saya mengalami masalah ini saat mencoba mengikuti tutorial resmi CMake pada Langkah 9 . Ini adalah lokasi file yang ingin saya pindahkan:

src
 |_build
    |_Debug
       - `MathFunctions.dll`

Ini adalah lokasi yang saya inginkan untuk file tersebut:

src
 |_build
    |_install
         |_bin
             - `MathFunctions.dll`

Karena DLL ini dibuat sebagai pustaka bersama, yang saya lakukan hanyalah memasukkan baris ini ke CMakeLists.txtdalam subdirektori yang berisi kode sumber untuk pustaka tersebut.src/Mathfunctions/CMakeLists.txt

install(FILES ${PROJECT_BINARY_DIR}/$<CONFIG>/MathFunctions.dll
DESTINATION bin)

Berkat jawaban Anda, saya bisa memikirkan yang satu ini. Hanya satu baris, jadi saya rasa tidak apa-apa. The $<CONFIG>dapat memiliki dua nilai Debug atau Rilis Tergantung pada bagaimana proyek dibangun, sebagai pertanyaan awal yang diperlukan.

David Martinez C.
sumber