Erstellen Sie eine Variable in einem Makefile, indem Sie den Inhalt einer anderen Datei lesen


81

Wie kann ich eine Variable im laufenden Betrieb aus dem Makefile erstellen, deren Wert den gesamten Inhalt einer anderen Datendatei darstellt?

Antworten:


49

Ich vermute, dass Sie eine Variable in Ihrem Makefile auf den Inhalt einer anderen Datei setzen möchten:

FILE=test.txt
VARIABLE=`cat $(FILE)`

target:
    echo $(VARIABLE)

3
Eigentlich kann ich die VARIABLE-Definition nicht über alles setzen: weil PATH_TO_MY_DATA_FILE erst existiert, wenn einige Befehle im all: target ausgeführt wurden. Als Alternative habe ich die Dinge in zwei Makefiles aufgeteilt (eine Untermarke erstellt) und die VARIABLE oben in der Untermarke deklariert und sie funktioniert jetzt wie ein Zauber.
Srinath

26
Dies ist eine falsche Antwort. Der Wert von VARIABLEist eine Zeichenfolge cat $(FILE)(in Anführungszeichen), die nur in einem Rezept von der Shell erweitert wird. Versuchen Sie, den Wert wie folgt zu drucken $(info ${VARIABLE}).
Maxim Egorushkin

3
@ MaximEgorushkin Es ist nicht falsch. Sie müssen nur VARIABLEals Versprechen betrachten. Dies ist die einzige Version, die mit älteren Versionen von funktioniert make. Beide :=und $(shell ...)sind GNU-Erweiterungen.
12.

7
Abgestimmt. Dies wird catjedes Mal ausgeführt , wenn die Regel ausgeführt wird. Dies ist normalerweise nicht beabsichtigt und sollte gewarnt werden, da es langsam ist. Wenn die Datei eine Pipe ist, hat sie außerdem unbeabsichtigte Nebenwirkungen. Die Zuweisung sollte mit erfolgen, :=damit die Regel nicht ausgewertet wird, wenn die Variable ersetzt wird, sondern wenn die Variable definiert wird. Der Ersetzungswert sollte $(shell cat $(FILE))so sein, dass der catBefehl direkt von make ausgeführt wird, nicht später von den Rezeptregeln.
Christian Hujer

2
@antred, make ist Teil des Standard-UNIX / POSIX-Toolset, das auch cat enthält. Wenn Sie installieren, ist es normal, alle anderen grundlegenden Tools zu installieren, und es gibt sehr seltene Umstände, unter denen dies zu Schwierigkeiten führen kann. Verlassen aufcat eher auf komplexe als auf alternative Regeln verlassen, werden Ihre Makefiles viel einfacher zu verstehen und fast genauso portabel oder manchmal portabler.
Michael

81

Angenommen, GNU machen:

file := whatever.txt
variable := $(shell cat ${file})

4
@ceving Verwenden Sie die Standard-GNU-Marke. Solaris make ist eine nicht tragbare Anwendung.
Maxim Egorushkin

7
Gnu machen ist weder Standard noch tragbarer als Solaris machen. "Beliebt" ist dein Wort. Wenn wir ernsthaft über Portabilität und Standardkonformation nachdenken, bleiben Sie bei posix.
盐 友情 留. 无 16

3
In diesem Fall würde ich mich für "Popular" entscheiden - Nicht-GNU-Make ist einfach zu primitiv. Wenn Sie weiterhin Betriebssysteme der 90er Jahre unterstützen möchten, ist die Antwort von @ bb-generation wahrscheinlich genau das, was Sie brauchen (obwohl Sie in vielen Fällen in Schwierigkeiten geraten). In allen anderen Fällen ist GNU Make entweder leicht verfügbar oder - wahrscheinlicher - die Standardeinstellung. Nutzen Sie es daher bitte.
Guss

1
GNU make läuft überall, also ist es viel portabler als jedes andere Fabrikat. "Standard" kann subjektiv sein, selbstverständlich.
MarcH

26

GNU make Version 4.2 unterstützt das Lesen von Dateien. In Bezug auf Maxim Egorushkins großartige Antwort gibt es jetzt eine optionale Möglichkeit, dieses Problem zu lösen:

FILE     := test.txt
variable :=$(file < $(FILE))

Ein Fehler wurde behoben. Variablennamen unterscheiden zwischen Groß- und Kleinschreibung. Die Namen 'foo', 'FOO' und 'Foo' beziehen sich alle auf verschiedene Variablen. ( gnu.org/software/make/manual/html_node/Using-Variables.html )
Jaroslaw Nikitenko

Anführungszeichen werden ebenfalls nicht benötigt. $ (Datei <"$ (FILE)") versucht, "test.txt" zu öffnen.
Cagney

14

catexistiert unter Windows nicht. Lösung, die für Linux und Windows funktioniert:

cat := $(if $(filter $(OS),Windows_NT),type,cat)
variable := $(shell $(cat) filename)

Erläuterung: Unter Windows scheint immer eine OSUmgebungsvariable definiert zu sein, die gleich 'Windows_NT' ist. Auf diese Weise wird für Windows der typeBefehl für Nicht-Windows catverwendet.



4

Wenn Sie GNU make verwenden, können Sie diesen Effekt auch erzielen, indem Sie ein make "include" eines anderen Makefiles verwenden:

Aus dem Makefile:

include "./MyFile.mak"

Erstellen Sie eine Datei "MyFile.mak" mit Inhalt:

FILE := "my file content"
FILE += "more content 1"
FILE += "more content 2"

das scheint nicht zu funktionieren, ich bekommeMakefile:1: "./MyFile.mak": No such file or directory
knocte

Das bedeutet wahrscheinlich, dass Sie eine Nicht-GNU-Version von make verwenden ... oder eine wirklich alte Version von GNU make ... versuchen Sie: "make -v"
Bill Moore

mit make in mac, nicht sicher, ob von homebrew gebündelt oder installiert, make -vgibtGNU Make 3.81
knocte

Stellen Sie sicher, dass Sie TAB-Zeichen im Makefile nicht versehentlich in SPACE-Zeichen konvertiert haben? Make ist in dieser Hinsicht als Python fast nervig.
Bill Moore

Ich habe dies auf meinem Mac zum Laufen gebracht, indem ich die Anführungszeichen entfernt habe, z. B.: include ./MyFile
Charlie Tran

3

Da die Plattform nicht angegeben wurde, funktioniert sie unter Solaris folgendermaßen:

VERSION:sh = cat VERSION

all:
        echo $(VERSION)

0

Hier ist eine portablere Lösung, die mit MAKEVersion 3 funktioniert , für die filekeine Direktive verfügbar ist. Der Nachteil ist, dass dabei eine temporäre Datei erstellt werden muss.

$(shell echo define my_variable > file.tmp)
$(shell cat my_file.txt >> file.tmp)
$(shell echo endef >> file.tmp)
include file.tmp

Die Hauptidee ist die Verwendung einer defineDirektive, die speziell zum Deklarieren mehrzeiliger Variablen entwickelt wurde. Natürlich können Sie die Verwendung vermeidenshell einer temporären Datei wenn Sie den Dateiinhalt explizit für die Verwendung von Makefile schreiben können.

Denken Sie daran, dass Ihre Datei, wenn sie $Zeichen enthält , MAKEversucht, diese als Variablen / Anweisungen zu my_variableerweitern, wenn sie erweitert wird (oder wenn sie zugewiesen ist, von denen Sie sie definieren :=). Wenn Sie dies vermeiden möchten, müssen Sie sie maskieren, bevor Sie Dateiinhalte einfügen. Zum Beispiel können Sie stattdessen catFolgendes tun:

$(shell sed 's/\$$/$$$$/g' my_file.txt >> file.tmp)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.