Copia il file dalla directory di origine alla directory binaria utilizzando CMake


100

Sto cercando di creare un semplice progetto su CLion. Usa CMake (sono nuovo qui) per generare Makefile per costruire il progetto (o una sorta di esso)

Tutto ciò di cui ho bisogno è trasferire un file non di progetto (una sorta di file di risorse) nella directory binaria ogni volta che eseguo il mio codice.

Quel file contiene i dati di prova e l'applicazione lo apre per leggerli. Ho provato diversi modi per farlo:

  • attraverso file(COPY ...

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

    Sembra buono ma funziona solo una volta e non ricopia il file dopo la prossima esecuzione.

  • attraverso add_custom_command

    • OUTPUT versione

      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 versione

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

    Ma nessuno funziona.

Che cosa sto facendo di sbagliato?

Risposte:


126

Puoi prendere in considerazione l'utilizzo di configure_file con l' COPYONLYopzione:

configure_file(<input> <output> COPYONLY)

A differenza di file(COPY ...)ciò che crea una dipendenza a livello di file tra input e output, ovvero:

Se il file di input viene modificato, il sistema di compilazione eseguirà nuovamente CMake per riconfigurare il file e generare nuovamente il sistema di compilazione.


12
Nota che configure_filenon funzionerà con le sottodirectory, anche se usi GLOB per creare un elenco di file.
Tarantola

63

entrambe le opzioni sono valide e mirano a due diversi passaggi della tua build:

  1. file(COPY ...copia il file nella fase di configurazione e solo in questa fase. Quando ricostruisci il tuo progetto senza aver cambiato la configurazione di cmake, questo comando non verrà eseguito.
  2. add_custom_command è la scelta preferita quando si desidera copiare il file in ogni fase di compilazione.

La versione giusta per il tuo compito sarebbe:

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

si può scegliere tra PRE_BUILD, PRE_LINK, POST_BUILD migliore è leggere la documentazione di add_custom_command

un esempio su come utilizzare la prima versione può essere trovato qui: Usa CMake add_custom_command per generare il sorgente per un altro target


1
È CMAKE_SOURCE_DIR o CMAKE_CURRENT_SOURCE_DIR?
Syaiful Nizam Yahya

1
@SyaifulNizamYahya usa CMAKE_CURRENT_SOURCE_DIRse il test/input.txtfile è relativo al CMakeLists.txtfile corrente . Se è relativo alla radice CMakeLists.txt, usa CMAKE_SOURCE_DIR.
Mark Ingram

16

La prima opzione che hai provato non funziona per due motivi.

Per prima cosa, ti sei dimenticato di chiudere la parentesi.

Secondo, DESTINATIONdovrebbe essere una directory, non un nome di file. Supponendo che tu abbia chiuso la parentesi, il file finirebbe in una cartella chiamata input.txt.

Per farlo funzionare, basta cambiarlo in

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

4

Suggerirei TARGET_FILE_DIRse si desidera che il file venga copiato nella stessa cartella del file .exe.

$ Directory del file principale (.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}>)

In VS, questo script cmake copierà input.txt nello stesso file dell'exe finale, indipendentemente dal suo debug o rilascio.


3

Questo è quello che ho usato per copiare alcuni file di risorse: il copy-files è un target vuoto per ignorare gli errori

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

Aggiungerei anche add_dependencies(MainTarget copy-files)per farlo funzionare automaticamente quando creo MainTarget
Herrgott il

Questa sembra la risposta migliore (+ commento di Herrgott) in quanto garantisce effettivamente che la versione corrente del sorgente sia sempre nella compilazione del post di destinazione. Per piccoli lavori di copia funziona bene, grazie. Mettere add_dependencies(MainTarget copy-files)il CMakeLists.txtfile root significa che questo può essere utilizzato in tutto il progetto.
satnhak

1

se si desidera copiare la cartella dalla directory Currant alla cartella binaria (cartella build)

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

allora il syntexe è:

file(COPY pathSource DESTINATION pathDistination)

0

Il configure_file suggerito è probabilmente la soluzione più semplice. Tuttavia, non eseguirà nuovamente il comando di copia se hai eliminato manualmente il file dalla directory di build. Per gestire anche questo caso, per me funziona quanto segue:

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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.