Übergabe zusätzlicher Variablen von der Befehlszeile an make

614

Kann ich Variablen als Befehlszeilenargumente an ein GNU-Makefile übergeben? Mit anderen Worten, ich möchte einige Argumente übergeben, die schließlich zu Variablen im Makefile werden.

Pablo
quelle

Antworten:

754

Sie haben mehrere Möglichkeiten, Variablen von außerhalb Ihres Makefiles einzurichten:

  • Aus der Umgebung - Jede Umgebungsvariable wird in eine Makefile-Variable mit demselben Namen und Wert umgewandelt.

    Möglicherweise möchten Sie auch die -eOption (auch bekannt als --environments-override) aktivieren, und Ihre Umgebungsvariablen überschreiben Zuweisungen, die in Makefile vorgenommen wurden (es sei denn, diese Zuweisungen selbst verwenden die overrideDirektive . Es wird jedoch nicht empfohlen, und es ist viel besser und flexibler, die ?=Zuweisung (die bedingte Variable) zu verwenden Zuweisungsoperator, wirkt sich nur aus, wenn die Variable noch nicht definiert ist):

    FOO?=default_value_if_not_set_in_environment
    

    Beachten Sie, dass bestimmte Variablen nicht von der Umgebung geerbt werden:

    • MAKE wird vom Namen des Skripts erhalten
    • SHELLwird entweder in einem Makefile festgelegt oder standardmäßig auf /bin/sh(Begründung: Befehle werden im Makefile angegeben und sind shell-spezifisch).
  • Über die Befehlszeile - makekann variable Zuweisungen als Teil seiner Befehlszeile übernehmen, gemischt mit Zielen:

    make target FOO=bar
    

    Aber dann werden alle Zuweisungen an FOOVariablen innerhalb des Makefiles ignoriert, es sei denn, Sie verwenden die overrideDirektive bei der Zuweisung. (Der Effekt ist der gleiche wie bei der -eOption für Umgebungsvariablen.)

  • Exportieren aus dem übergeordneten Make - Wenn Sie Make aus einem Makefile aufrufen, sollten Sie Variablenzuweisungen wie folgt normalerweise nicht explizit schreiben:

    # Don't do this!
    target:
            $(MAKE) -C target CC=$(CC) CFLAGS=$(CFLAGS)
    

    Stattdessen könnte eine bessere Lösung darin bestehen, diese Variablen zu exportieren. Wenn Sie eine Variable exportieren, wird sie in die Umgebung jedes Shell-Aufrufs übernommen. Wenn Sie über diese Befehle Aufrufe ausführen, wählen Sie diese Umgebungsvariable wie oben angegeben aus.

    # Do like this
    CFLAGS=-g
    export CFLAGS
    target:
            $(MAKE) -C target
    

    Sie können auch alle Variablen exportieren , indem Sie exportohne Argumente verwenden.

P Shved
quelle
11
von der Kommandozeile etwas mit Leerzeichen zu tunmake A='"as df"'
Ciro Santilli 16 冠状 病 六四 六四 事件 16.
4
Scheint, als würden Sie nach Problemen fragen, wenn Sie sich um Umgebungsvariablen kümmern. Zum einen ist es ein Debugging-Albtraum, wenn es an Ort A und nicht an Ort B funktioniert, nur weil sie unterschiedliche Umgebungen haben.
James Moore
12
Nur aus Erfahrung ist der Export von Dingen wie CFLAGS ein Rezept für einen Albtraum für große Projekte. In großen Projekten gibt es häufig Bibliotheken von Drittanbietern, die nur mit einem bestimmten Satz von Flags kompiliert werden (die niemand stört). Wenn Sie CFLAGS exportieren, überschreibt das CFLAGS Ihres Projekts die Bibliotheken von Drittanbietern und löst Kompilierungsfehler aus. Eine alternative Möglichkeit könnte darin bestehen, sie als zu definieren export PROJECT_MAKE_ARGS = CC=$(CC) CFLAGS=$(CFLAGS)und weiterzugeben make -C folder $(PROJECT_MAKE_FLAGS). Wenn es eine Möglichkeit gibt, das Makefile der Bibliothek anzuweisen, die Umgebung zu ignorieren, wäre dies ideal (im Gegensatz zu -e).
RD
24
WARNUNG: Im Abschnitt "Exportieren vom übergeordneten Make" oben "Tun Sie dies nicht!" ist kritisch irreführend . Passing Variablen auf der Aufgabenüberschreibungen Befehlszeile in der Unter Make - Datei aber exportierten Variablen haben nicht außer Kraft setzen Zuordnungen in der Sub-Make - Datei. Diese beiden Methoden zum Übergeben von Variablen an ein Sub-Makefile sind nicht äquivalent und sollten nicht verwechselt werden.
Jonathan Ben-Avraham
4
Jede Differenz ? make target FOO=bar make FOO=bar target?
Gfan
213

Der einfachste Weg ist:

make foo=bar target

Dann können Sie in Ihrem Makefile darauf verweisen $(foo). Beachten Sie, dass dies nicht automatisch an Untermarken weitergegeben wird.

Wenn Sie Untermarken verwenden, lesen Sie diesen Artikel: Übermitteln von Variablen an eine Untermarke

Mark Byers
quelle
2
Mit Untermarken meinen Sie die Makefiles includedim Haupt-Makefile?
Pablo
2
@ Michael: Es bedeutet, make erneut aus dem Makefile heraus aufzurufen. Ich habe meine Antwort aktualisiert, da Sie an diesem Detail interessiert zu sein scheinen.
Mark Byers
2
"Beachten Sie, dass dies nicht automatisch an Untermarken weitergegeben wird." Unwahr! "Standardmäßig werden nur Variablen, die aus der Umgebung oder der Befehlszeile stammen, an rekursive Aufrufe übergeben. Sie können die Exportanweisung verwenden, um andere Variablen zu übergeben." gnu.org/software/make/manual/html_node/…
ThomasMcLeod
82

Angenommen, Sie haben ein Makefile wie dieses:

action:
    echo argument is $(argument)

Sie würden es dann nennen make action argument=something

nc3b
quelle
5
So können das Ziel und die Argumente in Bezug auf die Position ausgetauscht werden?
Pablo
4
@ Michael: Ja (siehe die Antwort von Mark Byers)
nc3b
25

Aus dem Handbuch :

Variablen in make können aus der Umgebung stammen, in der make ausgeführt wird. Jede Umgebungsvariable, die make beim Start sieht, wird in eine make-Variable mit demselben Namen und Wert umgewandelt. Eine explizite Zuweisung im Makefile oder mit einem Befehlsargument überschreibt jedoch die Umgebung.

So können Sie (von Bash) tun:

FOOBAR=1 make

was zu einer Variablen FOOBARin Ihrem Makefile führt.

Thomas
quelle
2
Der andere Weg ist in der Tat in fast allen Fällen besser. Ich werde dies der Vollständigkeit halber hier belassen.
Thomas
Dies ist die einzige Antwort, die die Zuweisung von Variablen vor dem Befehl make in derselben Zeile anzeigt. Es ist zu beachten, dass dies kein Syntaxfehler ist.
M_M
7

Es gibt eine weitere Option, die hier nicht aufgeführt ist und im GNU Make-Buch von Stallman und McGrath enthalten ist (siehe http://www.chemie.fu-berlin.de/chemnet/use/info/make/make_7.html ). Es liefert das Beispiel:

archive.a: ...
ifneq (,$(findstring t,$(MAKEFLAGS)))
        +touch archive.a
        +ranlib -t archive.a
else
        ranlib archive.a
endif

Dabei wird überprüft, ob ein bestimmter Parameter in angezeigt wird MAKEFLAGS. Angenommen, Sie lernen Threads in C ++ 11 kennen und haben Ihre Studie auf mehrere Dateien ( class01, ..., classNM) aufgeteilt. Sie möchten: dann alle kompilieren und einzeln ausführen oder eine nacheinander kompilieren Zeit und führen Sie es aus, wenn ein Flag angegeben ist ( -rzum Beispiel). Sie könnten sich also Folgendes einfallen lassen Makefile:

CXX=clang++-3.5
CXXFLAGS = -Wall -Werror -std=c++11
LDLIBS = -lpthread

SOURCES = class01 class02 class03

%: %.cxx
    $(CXX) $(CXXFLAGS) -o [email protected] $^ $(LDLIBS)
ifneq (,$(findstring r,  $(MAKEFLAGS)))
    ./[email protected]
endif

all: $(SOURCES)

.PHONY: clean

clean:
    find . -name "*.out" -delete

Wenn Sie das haben, würden Sie:

  • eine Datei erstellen und ausführen w / make -r class02;
  • baue alle w / makeoder make all;
  • Erstellen und Ausführen aller w / make -r(Angenommen, alle enthalten bestimmte Assert-Inhalte und Sie möchten sie nur alle testen.)
Ciro Costa
quelle
6

es scheint

Befehl args überschreibt Umgebungsvariable

Makefile

send:
    echo $(MESSAGE1) $(MESSAGE2)

Beispiel ausführen

$ MESSAGE1=YES MESSAGE2=NG  make send MESSAGE2=OK
echo YES OK
YES OK
YumaInaura
quelle
5

Wenn Sie eine Datei mit dem Namen Makefile erstellen und eine Variable wie diese $ (unittest) hinzufügen, können Sie diese Variable auch mit Platzhaltern im Makefile verwenden

Beispiel:

make unittest=*

Ich verwende BOOST_TEST und indem ich dem Parameter --run_test = $ (unittest) einen Platzhalter gebe, kann ich den Test, mit dem mein Makefile ausgeführt werden soll, mit regulären Ausdrücken herausfiltern

serup
quelle
4
export ROOT_DIR=<path/value>

Verwenden Sie dann die Variable $(ROOT_DIR)im Makefile.

Parasrish
quelle