Copiez le fichier du répertoire source vers le répertoire binaire à l'aide de CMake

102

J'essaye de créer un projet simple sur CLion. Il utilise CMake (je suis nouveau ici) pour générer des Makefiles pour construire un projet (ou une sorte de celui-ci)

Tout ce dont j'ai besoin est de transférer un fichier non-projet (une sorte de fichier de ressources) dans un répertoire binaire à chaque fois que j'exécute mon code.

Ce fichier contient des données de test et l'application l'ouvre pour les lire. J'ai essayé plusieurs façons de le faire:

  • Via file(COPY ...

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

    Cela a l'air bien mais cela ne fonctionne qu'une seule fois et ne recopie pas le fichier après la prochaine exécution.

  • Via add_custom_command

    • OUTPUT version

      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 version

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

    Mais personne ne fonctionne.

Qu'est-ce que je fais mal?

Mongolrgata
la source

Réponses:

128

Vous pouvez envisager d'utiliser configure_file avec l' COPYONLYoption:

configure_file(<input> <output> COPYONLY)

Contrairement à file(COPY ...)cela, il crée une dépendance au niveau du fichier entre l'entrée et la sortie, c'est-à-dire:

Si le fichier d'entrée est modifié, le système de construction réexécutera CMake pour reconfigurer le fichier et générer à nouveau le système de construction.

tamas.kenez
la source
12
Veuillez noter que cela configure_filene fonctionnera pas avec les sous-répertoires, même si vous utilisez GLOB pour créer une liste de fichiers.
Tarantula
63

les deux options sont valides et ciblent deux étapes différentes de votre build:

  1. file(COPY ...copie le fichier à l'étape de configuration et uniquement à cette étape. Lorsque vous reconstruisez votre projet sans avoir changé votre configuration cmake, cette commande ne sera pas exécutée.
  2. add_custom_command est le choix préféré lorsque vous souhaitez copier le fichier à chaque étape de construction.

La bonne version pour votre tâche serait:

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

vous pouvez choisir entre PRE_BUILD, PRE_LINK, POST_BUILD mieux que vous est lu la documentation de add_custom_command

un exemple d'utilisation de la première version peut être trouvé ici: Utilisez CMake add_custom_command pour générer une source pour une autre cible

jenseb
la source
1
Est-ce CMAKE_SOURCE_DIR ou CMAKE_CURRENT_SOURCE_DIR?
Syaiful Nizam Yahya
1
@SyaifulNizamYahya à utiliser CMAKE_CURRENT_SOURCE_DIRsi le test/input.txtfichier est relatif au CMakeLists.txtfichier actuel . Si c'est relatif à la racine CMakeLists.txt, utilisez CMAKE_SOURCE_DIR.
Mark Ingram
16

La première option que vous avez essayée ne fonctionne pas pour deux raisons.

Tout d'abord, vous avez oublié de fermer la parenthèse.

Deuxièmement, le DESTINATIONdevrait être un répertoire, pas un nom de fichier. En supposant que vous fermiez la parenthèse, le fichier se retrouverait dans un dossier appelé input.txt.

Pour que cela fonctionne, changez-le simplement en

file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/input.txt
     DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
Allemand Capuano
la source
4

Je suggérerais TARGET_FILE_DIRsi vous voulez que le fichier soit copié dans le même dossier que votre fichier .exe.

$ Répertoire du fichier principal (.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}>)

Dans VS, ce script cmake copiera input.txt dans le même fichier que votre exe final, quel que soit son débogage ou sa version.

Félix Xu
la source
3

C'est ce que j'ai utilisé pour copier certains fichiers de ressources: les fichiers de copie sont une cible vide pour ignorer les erreurs

 add_custom_target(copy-files ALL
    COMMAND ${CMAKE_COMMAND} -E copy_directory
    ${CMAKE_BINARY_DIR}/SOURCEDIRECTORY
    ${CMAKE_BINARY_DIR}/DESTINATIONDIRECTORY
    )
Cory Lewis
la source
J'ajouterais également add_dependencies(MainTarget copy-files)pour le faire fonctionner automatiquement lorsque je construis MainTarget
Herrgott
Cela semble être la meilleure réponse (+ commentaire de Herrgott) car cela garantit en fait que la version actuelle de la source est toujours dans la version de publication de destination. Pour les petits travaux de copie, cela fonctionne bien, merci. Mettre add_dependencies(MainTarget copy-files)le CMakeLists.txtfichier racine signifie qu'il peut être utilisé tout au long du projet.
satnhak
1

si vous souhaitez copier le dossier du répertoire groseille vers le dossier binaire (dossier de construction)

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

alors le syntexe est:

file(COPY pathSource DESTINATION pathDistination)
Amirouche Zeggagh
la source
0

Le fichier configure_file suggéré est probablement la solution la plus simple. Cependant, il ne réexécutera pas la commande de copie si vous avez supprimé manuellement le fichier du répertoire de construction. Pour gérer également ce cas, ce qui suit fonctionne pour moi:

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)
ar31
la source