คัดลอกไฟล์จากไดเร็กทอรีต้นทางไปยังไดเร็กทอรีไบนารีโดยใช้ CMake


110

ฉันกำลังพยายามสร้างโปรเจ็กต์ง่ายๆบน CLion ใช้ CMake (ฉันใหม่ที่นี่) เพื่อสร้าง Makefiles เพื่อสร้างโครงการ (หรือบางประเภท)

สิ่งที่ฉันต้องทำคือถ่ายโอนไฟล์ที่ไม่ใช่โปรเจ็กต์ (ไฟล์ทรัพยากรบางประเภท) ไปยังไดเร็กทอรีไบนารีทุกครั้งเมื่อฉันเรียกใช้โค้ดของฉัน

ไฟล์นั้นมีข้อมูลการทดสอบและแอปพลิเคชันเปิดขึ้นเพื่ออ่าน ฉันลองทำหลายวิธี:

  • ผ่าน file(COPY ...

    file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/input.txt
            DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/input.txt
    

    ดูดี แต่ใช้งานได้เพียงครั้งเดียวและไม่คัดลอกไฟล์หลังจากการรันครั้งต่อไป

  • ผ่าน add_custom_command

    • OUTPUT รุ่น

      add_custom_command(
              OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/input.txt
              COMMAND ${CMAKE_COMMAND} -E copy
                      ${CMAKE_CURRENT_SOURCE_DIR}/input.txt
                      ${CMAKE_CURRENT_BINARY_DIR}/input.txt)
      
    • TARGET รุ่น

      add_custom_target(foo)
      add_custom_command(
              TARGET foo
              COMMAND ${CMAKE_COMMAND} copy
                      ${CMAKE_CURRENT_BINARY_DIR}/test/input.txt
                      ${CMAKE_SOURCE_DIR})
      

    แต่ไม่มีใครใช้งานได้

ผมทำอะไรผิดหรือเปล่า?

คำตอบ:


139

คุณอาจพิจารณาใช้config_fileกับCOPYONLYตัวเลือก:

configure_file(<input> <output> COPYONLY)

ไม่เหมือนกับการfile(COPY ...)สร้างการพึ่งพาระดับไฟล์ระหว่างอินพุตและเอาต์พุตนั่นคือ:

หากไฟล์อินพุตถูกแก้ไขระบบบิลด์จะรัน CMake อีกครั้งเพื่อกำหนดค่าไฟล์ใหม่และสร้างระบบบิลด์อีกครั้ง


14
โปรดทราบว่าconfigure_fileจะไม่ทำงานกับไดเรกทอรีย่อยแม้ว่าคุณจะใช้ GLOB เพื่อสร้างรายการไฟล์ก็ตาม
ทารันทูล่า

1
นอกจากนี้ทราบว่านี้ไม่ได้เป็น "การพึ่งพาในระดับไฟล์" ระหว่าง input และ output: มันเป็นเมืองขึ้นระหว่างการป้อนข้อมูลและขั้นตอน CMake กำหนดค่า ดังนั้นแทนที่จะเป็นการพึ่งพาการสร้างแบบปกติซึ่งการเปลี่ยนไฟล์ต้นฉบับจะสร้างเฉพาะไฟล์อ็อบเจ็กต์ที่เกี่ยวข้องขึ้นมาใหม่สิ่งนี้ทำให้ cmake ทั้งหมดกำหนดค่าใหม่ซึ่งอาจมีผลข้างเคียงอื่น ๆ
Seth Johnson

68

ตัวเลือกทั้งสองใช้ได้และกำหนดเป้าหมายขั้นตอนที่แตกต่างกันสองขั้นตอนของการสร้างของคุณ:

  1. file(COPY ...คัดลอกไฟล์ในขั้นตอนการกำหนดค่าและในขั้นตอนนี้เท่านั้น เมื่อคุณสร้างโปรเจ็กต์ใหม่โดยไม่ได้เปลี่ยนคอนฟิกูเรชัน cmake คำสั่งนี้จะไม่ถูกเรียกใช้งาน
  2. add_custom_command เป็นตัวเลือกที่ต้องการเมื่อคุณต้องการคัดลอกไฟล์ในแต่ละขั้นตอนการสร้าง

เวอร์ชันที่เหมาะสมสำหรับงานของคุณคือ:

add_custom_command(
        TARGET foo POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy
                ${CMAKE_SOURCE_DIR}/test/input.txt
                ${CMAKE_CURRENT_BINARY_DIR}/input.txt)

คุณสามารถเลือกระหว่างPRE_BUILD, PRE_LINK, POST_BUILD ที่ดีที่สุดคือคุณอ่านเอกสารของadd_custom_command

ตัวอย่างวิธีใช้เวอร์ชันแรกสามารถพบได้ที่นี่: ใช้ CMake add_custom_command เพื่อสร้างซอร์สสำหรับเป้าหมายอื่น


1
เป็น CMAKE_SOURCE_DIR หรือ CMAKE_CURRENT_SOURCE_DIR
Syaiful Nizam Yahya

2
@SyaifulNizamYahya ใช้CMAKE_CURRENT_SOURCE_DIRถ้าtest/input.txtไฟล์นั้นสัมพันธ์กับCMakeLists.txtไฟล์ปัจจุบัน ถ้ามันเทียบกับรากใช้แล้วCMakeLists.txt CMAKE_SOURCE_DIR
Mark Ingram

มีวิธีรับชื่อไฟล์เป้าหมายใน cmake หรือไม่? โดยไม่ต้องเข้ารหัสชื่อไฟล์? เช่นฉันกำลังสร้างไฟล์ lib cmake มีตัวแปรเพื่อรับชื่อไฟล์ targte หรือไม่ ชอบlibSomething.so?
Rika

17

ตัวเลือกแรกที่คุณลองใช้ไม่ได้ด้วยเหตุผลสองประการ

ขั้นแรกคุณลืมปิดวงเล็บ

ประการที่สองDESTINATIONควรเป็นไดเร็กทอรีไม่ใช่ชื่อไฟล์ สมมติว่าคุณปิดวงเล็บไฟล์จะไปอยู่ในโฟลเดอร์ที่เรียกว่าinput.txt.

เพื่อให้ใช้งานได้เพียงแค่เปลี่ยนเป็น

file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/input.txt
     DESTINATION ${CMAKE_CURRENT_BINARY_DIR})

4

ฉันขอแนะนำTARGET_FILE_DIRว่าคุณต้องการให้คัดลอกไฟล์ไปยังโฟลเดอร์เดียวกับไฟล์. exe ของคุณ

$ ไดเรกทอรีของไฟล์หลัก (.exe, .so.1.2, .a)

add_custom_command(
  TARGET ${PROJECT_NAME} POST_BUILD
  COMMAND ${CMAKE_COMMAND} -E copy 
    ${CMAKE_CURRENT_SOURCE_DIR}/input.txt 
    $<TARGET_FILE_DIR:${PROJECT_NAME}>)

ใน VS สคริปต์ cmake นี้จะคัดลอก input.txt ไปยังไฟล์เดียวกับ exe สุดท้ายของคุณไม่ว่าจะเป็นการดีบักหรือรีลีสก็ตาม


3

นี่คือสิ่งที่ฉันใช้ในการคัดลอกไฟล์ทรัพยากรบางไฟล์: ไฟล์คัดลอกเป็นเป้าหมายว่างเปล่าเพื่อละเว้นข้อผิดพลาด

 add_custom_target(copy-files ALL
    COMMAND ${CMAKE_COMMAND} -E copy_directory
    ${CMAKE_BINARY_DIR}/SOURCEDIRECTORY
    ${CMAKE_BINARY_DIR}/DESTINATIONDIRECTORY
    )

ฉันจะเพิ่มadd_dependencies(MainTarget copy-files)เพื่อให้มันทำงานโดยอัตโนมัติเมื่อฉันสร้าง MainTarget
Herrgott

ดูเหมือนว่าจะเป็นคำตอบที่ดีที่สุด (+ ความคิดเห็นของ Herrgott) เนื่องจากช่วยให้มั่นใจได้ว่าเวอร์ชันปัจจุบันของแหล่งที่มาจะอยู่ในการสร้างโพสต์ปลายทางเสมอ สำหรับงานถ่ายเอกสารขนาดเล็กสิ่งนี้ใช้ได้ดีขอบคุณ การใส่ไฟล์add_dependencies(MainTarget copy-files)รูทCMakeLists.txtหมายความว่าสิ่งนี้สามารถใช้ได้ตลอดทั้งโครงการ
เสาร์

2

หากคุณต้องการคัดลอกโฟลเดอร์จากไดเรกทอรีลูกเกดไปยังโฟลเดอร์ไบนารี (สร้างโฟลเดอร์)

file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/yourFolder/ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/yourFolder/)

ดังนั้น syntexe คือ:

file(COPY pathSource DESTINATION pathDistination)

1

config_file ที่แนะนำน่าจะเป็นวิธีที่ง่ายที่สุด อย่างไรก็ตามจะไม่เรียกใช้คำสั่งคัดลอกซ้ำหากคุณลบไฟล์ออกจากไดเร็กทอรี build ด้วยตนเอง เพื่อจัดการกับกรณีนี้สิ่งต่อไปนี้ใช้ได้กับฉัน:

add_custom_target(copy-test-makefile ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/input.txt)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/input.txt
                   COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/input.txt
                                                    ${CMAKE_CURRENT_BINARY_DIR}/input.txt
                   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/input.txt)

0

หากคุณต้องการใส่เนื้อหาexampleลงในinstallโฟลเดอร์หลังจากสร้าง:

code/
  src/
  example/
  CMakeLists.txt

ลองเพิ่มสิ่งต่อไปนี้ในของคุณCMakeLists.txt:

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