Kopieren Sie die Datei mit CMake aus dem Quellverzeichnis in das Binärverzeichnis

97

Ich versuche ein einfaches Projekt auf CLion zu erstellen. Es verwendet CMake (ich bin neu hier), um Makefiles zu generieren, um ein Projekt (oder eine Art davon) zu erstellen.

Alles, was ich tun muss, ist, jedes Mal, wenn ich meinen Code ausführe, eine Nicht-Projektdatei (eine Art Ressourcendatei) in ein Binärverzeichnis zu übertragen.

Diese Datei enthält Testdaten und wird von der Anwendung geöffnet, um sie zu lesen. Ich habe verschiedene Möglichkeiten ausprobiert:

  • Über file(COPY ...

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

    Sieht gut aus, funktioniert aber nur einmal und kopiert die Datei nach dem nächsten Lauf nicht erneut.

  • Über add_custom_command

    • OUTPUT Ausführung

      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 Ausführung

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

    Aber niemand davon funktioniert.

Was mache ich falsch?

Mongolrgata
quelle

Antworten:

126

Sie können configure_file mit der folgenden COPYONLYOption verwenden:

configure_file(<input> <output> COPYONLY)

Im Gegensatz file(COPY ...)dazu wird eine Abhängigkeit auf Dateiebene zwischen Eingabe und Ausgabe erstellt, d. H.

Wenn die Eingabedatei geändert wird, führt das Build-System CMake erneut aus, um die Datei neu zu konfigurieren und das Build-System erneut zu generieren.

tamas.kenez
quelle
12
Bitte beachten Sie, dass dies configure_filemit Unterverzeichnissen nicht funktioniert, selbst wenn Sie GLOB zum Erstellen einer Liste von Dateien verwenden.
Tarantula
63

Beide Optionen sind gültig und zielen auf zwei verschiedene Schritte Ihres Builds ab:

  1. file(COPY ...kopiert die Datei im Konfigurationsschritt und nur in diesem Schritt. Wenn Sie Ihr Projekt neu erstellen, ohne Ihre cmake-Konfiguration geändert zu haben, wird dieser Befehl nicht ausgeführt.
  2. add_custom_command ist die bevorzugte Wahl, wenn Sie die Datei bei jedem Erstellungsschritt kopieren möchten.

Die richtige Version für Ihre Aufgabe wäre:

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

Sie können wählen zwischen PRE_BUILD, PRE_LINKam POST_BUILD besten lesen Sie die Dokumentation von add_custom_command

Ein Beispiel zur Verwendung der ersten Version finden Sie hier: Verwenden Sie CMake add_custom_command, um eine Quelle für ein anderes Ziel zu generieren

jenseb
quelle
1
Ist es CMAKE_SOURCE_DIR oder CMAKE_CURRENT_SOURCE_DIR?
Syaiful Nizam Yahya
1
@SyaifulNizamYahya verwenden, CMAKE_CURRENT_SOURCE_DIRwenn die test/input.txtDatei relativ zur aktuellen CMakeLists.txtDatei ist. Wenn es relativ zur Wurzel ist CMakeLists.txt, verwenden Sie CMAKE_SOURCE_DIR.
Mark Ingram
16

Die erste Option, die Sie ausprobiert haben, funktioniert aus zwei Gründen nicht.

Zuerst haben Sie vergessen, die Klammer zu schließen.

Zweitens DESTINATIONsollte das ein Verzeichnis sein, kein Dateiname. Angenommen, Sie haben die Klammer geschlossen, wird die Datei in einem Ordner namens aufgerufen input.txt.

Damit es funktioniert, ändern Sie es einfach in

file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/input.txt
     DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
Deutsches Capuano
quelle
3

Ich würde vorschlagen, TARGET_FILE_DIRwenn Sie möchten, dass die Datei in denselben Ordner wie Ihre EXE-Datei kopiert wird.

$ Verzeichnis der Hauptdatei (.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 kopiert dieses cmake-Skript input.txt in dieselbe Datei wie Ihre endgültige Exe, unabhängig davon, ob es sich um ein Debug oder eine Version handelt.

Felix Xu
quelle
3

Dies ist, was ich verwendet habe, um einige Ressourcendateien zu kopieren: Die Kopierdateien sind ein leeres Ziel, um Fehler zu ignorieren

 add_custom_target(copy-files ALL
    COMMAND ${CMAKE_COMMAND} -E copy_directory
    ${CMAKE_BINARY_DIR}/SOURCEDIRECTORY
    ${CMAKE_BINARY_DIR}/DESTINATIONDIRECTORY
    )
Cory Lewis
quelle
Ich würde auch hinzufügen add_dependencies(MainTarget copy-files), damit es automatisch ausgeführt wird, wenn ich MainTarget
Herrgott
Dies scheint die beste Antwort zu sein (+ Herrgotts Kommentar), da tatsächlich sichergestellt wird, dass sich die aktuelle Version der Quelle immer im Ziel-Post-Build befindet. Für kleine Kopieraufträge funktioniert das gut, danke. Durch das Einfügen add_dependencies(MainTarget copy-files)der Stammdatei CMakeLists.txtkann diese im gesamten Projekt verwendet werden.
Satnhak
1

Wenn Sie den Ordner aus dem Johannisbeerverzeichnis in den Binärordner (Build-Ordner) kopieren möchten

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

dann ist die syntexe:

file(COPY pathSource DESTINATION pathDistination)
Amirouche Zeggagh
quelle
0

Die vorgeschlagene configure_file ist wahrscheinlich die einfachste Lösung. Der Kopierbefehl wird jedoch nicht erneut ausgeführt, wenn Sie die Datei manuell aus dem Erstellungsverzeichnis gelöscht haben. Um auch diesen Fall zu behandeln, funktioniert Folgendes für mich:

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
quelle