จะคัดลอกไฟล์ DLL ไปไว้ในโฟลเดอร์เดียวกับไฟล์ปฏิบัติการโดยใช้ CMake ได้อย่างไร


100

เราใช้ CMake เพื่อสร้างไฟล์ Visual Studio ของแหล่งที่มาของเราใน SVN ของเรา ตอนนี้เครื่องมือของฉันต้องการไฟล์ DLL บางไฟล์เพื่อให้อยู่ในโฟลเดอร์เดียวกับไฟล์ปฏิบัติการ ไฟล์ DLL อยู่ในโฟลเดอร์ข้างแหล่งที่มา

ฉันจะเปลี่ยนของฉันได้อย่างไรCMakeLists.txtว่าโครงการ Visual Studio ที่สร้างขึ้นจะมีไฟล์ DLL เฉพาะอยู่แล้วในโฟลเดอร์ release / debug หรือจะคัดลอกเมื่อทำการคอมไพล์

คำตอบ:


126

ฉันต้องการใช้เพื่อให้บรรลุนี้พร้อมกับ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 ในการรวบรวมไบนารี? หรืออาจจะ cmake LIBRARYสิ่งของ? ฉันไม่รู้จัก toolchain จริงๆ
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 จะอยู่ในระดับบนสุดของไดเร็กทอรี build เพื่อให้ไฟล์เรียกทำงานสามารถค้นหาไลบรารีและรันทุกอย่างได้ง่าย

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>สามารถมีสองค่าตรวจแก้จุดบกพร่องหรือวางจำหน่ายขึ้นอยู่กับว่าโครงการจะสร้างเป็นคำถามเดิมที่จำเป็น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.