CMake kullanılarak yürütülebilir dosya ile aynı klasöre DLL dosyaları nasıl kopyalanır?


100

SVN'mizdeki kaynaklarımızın Visual Studio dosyalarını oluşturmak için CMake kullanıyoruz. Şimdi benim aracım bazı DLL dosyalarının yürütülebilir dosya ile aynı klasörde olmasını gerektiriyor. DLL dosyaları, kaynağın yanında bir klasörde bulunur.

Nasıl değiştirebilirim benim CMakeLists.txtoluşturulan Visual Studio projesi ya zaten serbest bırakma / ayıklama klasörlere belirli DLL dosyaları olacak ya derleme üzerine kopyalamak edeceğini böyle?

Yanıtlar:


126

Bunu add_custom_commandbaşarmak için kullanırdım cmake -E copy_if_different.... Tam bilgi için çalıştırın

cmake --help-command add_custom_command
cmake -E


Yani sizin durumunuzda, aşağıdaki dizin yapısına sahipseniz:

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

ve komutun uygulandığı CMake hedefiniz ise MyTest, CMakeLists.txt dosyanıza aşağıdakileri ekleyebilirsiniz:

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


Sadece /libs/dizinin tüm içeriğinin kopyalanmasını istiyorsanız , şunu kullanın 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>)


Yapılandırmaya bağlı olarak farklı dll'leri kopyalamanız gerekiyorsa (Sürüm, Hata Ayıklama, örn.), Bunları ilgili yapılandırma ile adlandırılan alt dizinlerde bulundurabilirsiniz: /libs/Releaseve /libs/Debug. Daha sonra konfigürasyon tipini çağrıdaki dll yoluna şu şekilde enjekte etmeniz gerekir 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
Gelecekte başka birine yardımcı olması durumunda benim durumumda neyin işe yaradığına dair hızlı not: Ana yürütülebilir dosyanın isteğe bağlı olarak bağlandığı statik bir kitaplık projem var ve bu kitaplık, eklenmesi halinde kopyalanacak bir DLL gerektirir. Bu kütüphanenin CMakeLists.txt dosyasında ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>hedef hedef için kullandım . Aksi takdirde, işe yaramaz olan kütüphane oluşturma yoluna kopyalar.
AberrantWolf

cmake install()direktiflerinin amacı ikili dosyaları bir araya getirmek değil mi? Ya da belki bir LIBRARYşeyler yapmak? Alet zincirini gerçekten bilmiyorum.
Sandburg

1
$<TARGET_FILE_DIR:MyTest>- bu ne? Bilgi nasıl yazdırılır, tam olarak ne anlama gelir?
ilw

Komutu entegre ederken bir şeyi kaçırmadıysam, bu yöntem eklenen kitaplıklar için çalışmaz IMPORTED_LIBRARIES. Hiçbir şey inşa edilmediğinde bir derleme sonrası komutunu çalıştıramamaktan şikayet ediyor.
Tzalumen

2
My cmake'ı test edip hazırladıktan sonra: IMPORTEDKitaplıklar kullanıyorsanız ve DLL'leri yeniden konumlandırmanız gerekiyorsa, bir variant komutu kullanmanız gerekir. Eğer eklediyseniz IMPORTEDolarak kütüphaneyi MyImportedLibkullanırsınız COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MyImportedLib> $<TARGET_FILE_DIR:MyTest>Not birden sonrası inşa komutları çalıştırmak için bunları tek bir özel komut örneğin içine bağlanmış gerekadd_custom_command(TARGET MyTest POST_BUILD COMMAND #your first command# COMMAND #Your second command#)
Tzalumen

24

Bu satırları üst düzey CMakeLists.txt dosyama koyuyorum. CMake tarafından derlenen tüm kitaplıklar ve çalıştırılabilir dosyalar, çalıştırılabilir dosyaların kitaplıkları bulabilmesi ve her şeyin çalıştırılması kolay olması için yapı dizininin en üst düzeyine yerleştirilecektir.

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

Bunun, OP'nin projenin kaynak dizininden önceden derlenmiş ikili dosyaları kopyalama sorununu çözmediğini unutmayın.


8

Bugün programımın Windows derlemesini yapmaya çalıştığımda bu sorunu yaşadım. Ve tüm bu cevaplar beni tatmin etmediği için kendim biraz araştırma yaptım. Üç ana sorun vardı:

  • Hata ayıklama yapılarının kitaplıkların hata ayıklama sürümleriyle bağlantılı olmasını ve sürüm yapılarının sırasıyla kitaplıkların yayın sürümleriyle bağlantılı olmasını istedim.

  • Buna ek olarak, DLL dosyalarının (Debug / Release) doğru sürümlerinin çıktı dizinlerine kopyalanmasını istedim.

  • Tüm bunları karmaşık ve kırılgan senaryolar yazmadan başarmak istedim.

Github'da bazı CMake kılavuzlarına ve bazı çoklu platform projelerine göz attıktan sonra şu çözümü buldum:

Kitaplığınızı "IMPORTED" özniteliğiyle bir hedef olarak bildirin, hata ayıklamasına bakın ve .lib ve .dll dosyalarını yayınlayın.

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

Bu hedefi her zamanki gibi projenize bağlayın

target_link_libraries(YourProg sdl2 ...)

Önceki derlemeden bu yana bir şekilde değiştirilmişse, dll dosyasını hedefine kopyalamak için özel derleme adımı yapın

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

5

Kabul edilen cevaba bir ek, ayrı bir cevap olarak eklendi, böylece kod formatını alıyorum:

Eğer dll'lerinizi aynı proje içerisinde oluşturuyorsanız, bunlar genellikle Release, Debug vb. Dizinlerde olacaktır. Bunları doğru şekilde kopyalamak için Visual Studio ortam değişkenlerini kullanmanız gerekir. Örneğin:

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

kaynak için ve

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

hedef için. Kaçışa dikkat edin!

Yapılandırma için CMake CMAKE_BUILD_TYPE değişkenini kullanamazsınız çünkü VS proje oluşturma zamanında çözülür ve her zaman varsayılan ne olursa olsun olacaktır.


8
Kabul edilen cevabın son kısmı, bunu daha temiz CMake kullanarak ele alır$<CONFIGURATION>
Chuck Claunch

5

Ayrıca find_library komutunu da kullanabilirsiniz:

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

Tanımlanmış bir EXECUTABLE_PATH ile, örneğin:

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

çalıştırılabilir dosyanızın ihtiyaç duyduğu .dll dosyalarını taşıyabilirsiniz.

file(COPY ${<some_var>}
    DESTINATION ${EXECUTABLE_OUTPUT_PATH})

2

Bu onlardan biri için yararlıdır

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

Muhtemelen özel hedef eklemeniz ve bunu yürütülebilir hedeflerinizden birine bağlı yapmanız gerekir.

Yukarıdaki işlevi kullanarak dosyayı kopyalamak için şunu kullanın:

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

0

Ben bir CMake acemisiyim, ancak yine de deneyimlerimi paylaşmak istedim. Benim durumumda, tüm ikili dosyalarımın içeride olması için bir yükleme sonrası kopyasına ihtiyacım vardı. CMake içinde içe aktarılabilen üçüncü taraf ikili dosyası söz konusu olduğunda, aşağıdaki işler benim için çalışıyor:

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

Açıkçası, IMPORTED_LOCATION_RELEASE, paylaşılan kitaplığın nasıl oluşturulduğuna / kurulduğuna bağlı olarak değişkenlere sahip olabilir. IMPORTED_LOCATION_DEBUG olabilir.

Belki o mülk adını almanın daha iyi bir yolu vardır, bilmiyorum.


0

Derleme sırasında dosyaları taşıma install

Adım 9'daki CMake resmi eğitimini izlemeye çalışırken bu sorunu yaşadım . Bu, taşımak istediğim dosyanın konumuydu:

src
 |_build
    |_Debug
       - `MathFunctions.dll`

Dosyanın içinde olmasını istediğim konum buydu:

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

Bu DLL paylaşılan kitaplık olarak oluşturulan bu yana, tüm ı bu çizgiyi içerecek şekilde yaptığım CMakeLists.txtiçinde alt dizin Kütüphane için kaynak kodu içeriyordusrc/Mathfunctions/CMakeLists.txt

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

Cevaplarınız sayesinde bunun üzerine düşünebilirim. Sadece bir satır, yani bence tamam. $<CONFIG>İki değerlere sahip olabilir ayıklama veya Yayın orijinal soru gerektiği gibi, proje oluşturulma biçimi bağlı.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.