Скопіюйте файл із вихідного каталогу у двійковий каталог за допомогою CMake


100

Я намагаюся створити простий проект на 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})
      

    Але ніхто з цього не працює.

Що я роблю неправильно?

Відповіді:


127

Ви можете використати файл configure_file з COPYONLYопцією:

configure_file(<input> <output> COPYONLY)

На відміну від file(COPY ...)цього створюється залежність рівня файлу між входом і виходом, тобто:

Якщо вхідний файл модифікований, система збирання повторно запустить CMake для перенастроювання файлу та генерування системи збирання заново.


12
Зауважте, що configure_fileне буде працювати з підкаталогами, навіть якщо ви використовуєте GLOB для створення списку файлів.
Тарантул

63

обидва варіанти є дійсними та націлені на два різні кроки вашої збірки:

  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

1
@SyaifulNizamYahya використовувати, CMAKE_CURRENT_SOURCE_DIRякщо test/input.txtфайл відносно поточного CMakeLists.txtфайлу. Якщо це відносно кореня CMakeLists.txt, тоді використовуйте CMAKE_SOURCE_DIR.
Марк Інграм

16

Перший варіант, який ви спробували, не працює з двох причин.

По-перше, ви забули закрити дужки.

По-друге, це 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

Це здається найкращою відповіддю (+ коментар Герргота), оскільки це насправді гарантує, що поточна версія джерела завжди знаходиться у збірці пункту призначення. Для невеликих копій це добре працює, дякую. Введення add_dependencies(MainTarget copy-files)кореневого CMakeLists.txtфайлу означає, що це можна використовувати протягом усього проекту.
satnhak

1

якщо ви хочете скопіювати папку з каталогу смородини в двійкову (побудувати папку) папку

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

тоді синтекс:

file(COPY pathSource DESTINATION pathDistination)

0

Запропонований файл_конфігурації - це, мабуть, найпростіше рішення. Однак вона не повторить команду копіювання, якщо ви вручну видалили файл із каталогу збірки. Для розгляду цієї справи для мене працює наступне:

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