Klingt so, als ob Sie wirklich ein Skript schreiben möchten, das Ihr Skript als Quelle für das Setzen von Envvars verwendet und dann make ausführt, anstatt make source zum Skript selbst zu machen ...
Um die gestellte Frage zu beantworten: Sie können nicht .
Das grundlegende Problem ist, dass ein untergeordneter Prozess die Umgebung des Elternteils nicht ändern kann. Die Schale wird um diesen durch keinen neuen Prozess gabeln , wenn source‚ing, aber nur diese Befehle in der aktuellen Inkarnation der Shell ausgeführt wird . Das funktioniert gut, ist aber makenicht /bin/sh(oder für welche Shell auch immer Ihr Skript gedacht ist) und versteht diese Sprache nicht (abgesehen von den Teilen, die sie gemeinsam haben).
Chris Dodd und Foo Bah haben eine mögliche Problemumgehung angesprochen, daher schlage ich eine andere vor (vorausgesetzt, Sie führen GNU make aus): Verarbeiten Sie das Shell-Skript in make-kompatiblen Text und fügen Sie das Ergebnis hinzu:
shell-variable-setter.make: shell-varaible-setter.sh
postprocess.py @^
# ...else
include shell-variable-setter.make
endif
Sie können kein Skript für ein ganzes Makefile "erstellen", aber Sie können dies für ein einzelnes Rezept tun.
Jaroslaw Nikitenko
Ja source compilationEnv.sh; $(CC) -c -o $< $^oder ähnliches funktioniert als Aktionslinie.
dmckee --- Ex-Moderator Kätzchen
1
Sie können include .env(oder eine beliebige Schlüsselwertdatei) verwenden, um Variablen für das gesamte Makefile zugänglich zu machen und dann nur die erforderlichen Variablen an das jeweilige Rezept zu übergeben.
Rypel
94
Die Standard-Shell für Makefile wird /bin/shnicht implementiert source.
Das Ändern der Shell auf /bin/bashmacht es möglich:
@VivekAditya Dies ist natürlich eine äußerst nützliche Sache. Beachten Sie jedoch, dass das OP darum gebeten hat, eine Variable für die Verwendung durch makeund nicht nur für die Verwendung in Aktionszeilen festzulegen. So macht man Letzteres, aber es gibt keinen direkten Weg, Ersteres zu tun.
Wenn Sie lediglich Umgebungsvariablen für Make festlegen möchten, behalten Sie diese in der Makefile-Syntax bei und verwenden Sie den includeBefehl.
include other_makefile
Wenn Sie das Shell-Skript aufrufen müssen, erfassen Sie das Ergebnis in einem shellBefehl:
JUST_DO_IT=$(shell source_script)
Der Shell-Befehl sollte vor den Zielen ausgeführt werden. Dadurch werden die Umgebungsvariablen jedoch nicht festgelegt.
Wenn Sie Umgebungsvariablen im Build festlegen möchten, schreiben Sie ein separates Shell-Skript, das Ihre Umgebungsvariablen und Aufrufe erstellt. Lassen Sie dann im Makefile die Ziele das neue Shell-Skript aufrufen.
Wenn Ihr ursprüngliches Makefile beispielsweise ein Ziel hat a, möchten Sie Folgendes tun:
# mysetenv.sh#!/bin/bash
. <script to source>
export FLAG=1
make "$@"# Makefile
ifeq($(FLAG),0)
export FLAG=1
a:
./mysetenv.sh a
else
a:
.. do it
endif
Ich habe keine Kontrolle über das Skript. Muss es beschaffen.
Brooksbp
Erfasst dies die Umgebungsvariablen, wenn sie nicht exportiert werden? Auf den ersten Blick scheint es so, als würde eine neue Shell aufgerufen, ein Befehl ausgeführt, dann beendet und in die alte Umgebung zurückgekehrt.
Brooksbp
@brooksbp Der Shell-Befehl erfasst die Umgebungsvariablen nicht. Wenn Sie jedoch ein Shell-Skript schreiben, das das Original enthält, wird dies der Fall sein. Ich werde es weiter erklären
Foo Bah
17
Mit GNU Make 3.81 kann ich ein Shell-Skript aus make beziehen, indem ich:
Beachten Sie, dass sourcemit GNU Make 4.1 (und möglicherweise auch 4.0) das Beibehalten und Befehlen in derselben Zeile erforderlich wird. Mit 3.81 kann ich verschiedene Zeilen verwenden. Aus Gründen der Portabilität funktioniert eine Zeile in diesen Versionen. Das Aufrufen eines externen Skripts ist jedoch besser lesbar, wenn die Zeile zu lang wird!
Eric Platon
Bist du sicher? Mehrere Zeilen haben in 3.81 bei mir nicht funktioniert, wie ich in der Antwort erwähnt habe. Make führt jede Zeile in einer eigenen Unterschale aus, sodass mehrere Zeilen in keiner Version funktionieren sollten. Vielleicht haben Sie ein ungewöhnliches Betriebssystem oder machen Build?
Samuel
1
Mehrere
@ user5359531 Ja, das stimmt.
Samuel
10
Das funktioniert bei mir. Ersetzen Sie env.shdurch den Namen der Datei, die Sie beschaffen möchten. Es funktioniert, indem die Datei in Bash bezogen und die geänderte Umgebung nach dem Formatieren in eine aufgerufene Datei makeenvausgegeben wird, die dann vom Makefile bezogen wird.
IGNORE := $(shell bash -c "source env.sh; env | sed 's/=/:=/' | sed 's/^/export /' > makeenv")
include makeenv
Nizza zum Einstellen der richtigen Compiler-Umgebungen (hier 64-Bit). Vielen Dank.
Revher
Ist die Syntax, um dies auszuführen: "make IGNORE"?
John
@ John, nein. Einfach make.
GDW2
Was passiert , wenn die Werte der Variablen in Ihrem env.shspeziellen Make - Zeichen enthalten, wie #oder $. Wenn Sie dies tun, werden include makeenvdiese Werte alle durcheinander gebracht.
Donhector
6
Einige Konstrukte sind in shellund in gleich GNU Make.
var=1234
text="Some text"
Sie können Ihr Shell-Skript ändern, um die Definitionen zu erstellen. Sie müssen alle einfach seinname=value Typen sein.
Dh
[script.sh]
. ./vars.sh
[Makefile]
include vars.sh
Dann können das Shell-Skript und das Makefile dieselbe Informationsquelle gemeinsam nutzen. Ich habe diese Frage gefunden, weil ich nach einem Manifest allgemeiner Syntax gesucht habe, das in Gnu Make- und Shell-Skripten verwendet werden kann (es ist mir egal, welche Shell).
Edit: Shells und verständlich machen $ {var} . Dies bedeutet, dass Sie usw. verketten können. Var = "Eine Zeichenfolge" var = $ {var} "Zweite Zeichenfolge"
Ähm, ein Shell-Skript wie das oben genannte erzeugt keine unordentlichen Details wie in der akzeptierten Antwort. Am Ende ähnelt es einer kbuild- Datei.
Kunstloser Lärm
1
shellVariablen und makeVariablen sind nicht immer transparent austauschbar. Wenn Sie includesie in Ihrer haben Makefile, müssen sie der makeSyntax entsprechen, die vorschreibt, dass bestimmte Zeichen maskiert werden. Zum Beispiel ein Shell - Variablenwert wie SECRET='12#34$56'in Ihrem .vars.shwerden Sie Probleme verursachen , wenn sie unterwegs verwenden Sie es nachinclude vars.sh
donhector
1
Ich denke, es gibt zwei Anwendungsfälle; Das OP hat keine Kontrolle über das Skript. Ihr Standpunkt ist also sehr gut, da Sie höchstwahrscheinlich Daten erhalten, die maskiert werden müssen. Dies sind "% $ #". Wenn der Anwendungsfall darin besteht, Variablen zwischen Tools zu teilen, die Umgebungsvariablen verwenden und make erstellen, kann diese Lösung funktionieren. Es hat den Vorteil, dass nur eine Informationsquelle und keine zusätzlichen Prozesse vorhanden sind. Wenn Sie keine Kontrolle über das Shell-Skript haben, ist diese Antwort nicht so nützlich. Auch fraglich, warum Sie "$% #" in einem Variablennamen wollen würden. Wenn Sie Elemente berechnen, müssen Sie dem Abschnitt "Bearbeiten:" folgen.
Kunstloses Rauschen
3
Ich mag die Antwort von Foo Bah sehr, bei der make das Skript aufruft und das Skript zurückruft, um make zu erstellen. Um diese Antwort zu erweitern, habe ich Folgendes getan:
# setenv.shexport SOME_DIR=$PWD/path/to/some/dir
if [ -n "$1" ]; then# The first argument is set, call back into make.$1$2fi
Dies hat den zusätzlichen Vorteil, dass $ (MAKE) verwendet wird, falls jemand ein eindeutiges make-Programm verwendet, und dass auch alle in der Befehlszeile angegebenen Regeln verarbeitet werden, ohne dass der Name jeder Regel dupliziert werden muss, wenn SOME_DIR nicht definiert ist .
Wenn Sie eine ältere Version von make haben und .DEFAULT_GOAL nicht unterstützt wird, schlägt der erste Zweig des ifndef mit "make: *** Keine Ziele. Stop." Fehl. Sie können dies beheben, indem Sie der impliziten Regel "all" hinzufügen, und zwar wie folgt: "all%:". Beachten Sie, dass dies bei neueren Versionen von make zu einer Warnung "*** gemischte implizite und normale Regeln: veraltete Syntax" führt.
Samuel
1
Meine Lösung hierfür: (vorausgesetzt, Sie haben bash, die Syntax für $@ist tcshzum Beispiel anders )
Haben Sie ein Skript sourceThenExec.shals solches:
#!/bin/bashsource whatever.sh
$@
Stellen Sie Ihren Zielen in Ihrem Makefile bash sourceThenExec.shbeispielsweise Folgendes vor:
Wenn Sie die Variablen in die Umgebung übertragen möchten , damit sie an untergeordnete Prozesse übergeben werden, können Sie die Bashs set -aund verwenden set +a. Ersteres bedeutet: "Wenn ich eine Variable setze, setze auch die entsprechende Umgebungsvariable." Das funktioniert also für mich:
check:
bash -c "set -a && source .env.test && set +a && cargo test"
Das wird alles in Pass .env.testauf cargo testals Umgebungsvariablen.
Beachten Sie, dass Sie auf diese Weise eine Umgebung an Unterbefehle weitergeben können, aber keine Makefile-Variablen festlegen können (die sowieso anders sind). Wenn Sie Letzteres benötigen, sollten Sie hier einen der anderen Vorschläge ausprobieren.
Eine andere Möglichkeit wäre, ein sh-Skript zu erstellen, beispielsweise run.shdie erforderlichen Skripte zu erstellen und make innerhalb des Skripts aufzurufen.
#!/bin/shsource script1
source script2 and so on
make
Antworten:
Um die gestellte Frage zu beantworten: Sie können nicht .
Das grundlegende Problem ist, dass ein untergeordneter Prozess die Umgebung des Elternteils nicht ändern kann. Die Schale wird um diesen durch keinen neuen Prozess gabeln , wenn
source
‚ing, aber nur diese Befehle in der aktuellen Inkarnation der Shell ausgeführt wird . Das funktioniert gut, ist abermake
nicht/bin/sh
(oder für welche Shell auch immer Ihr Skript gedacht ist) und versteht diese Sprache nicht (abgesehen von den Teilen, die sie gemeinsam haben).Chris Dodd und Foo Bah haben eine mögliche Problemumgehung angesprochen, daher schlage ich eine andere vor (vorausgesetzt, Sie führen GNU make aus): Verarbeiten Sie das Shell-Skript in make-kompatiblen Text und fügen Sie das Ergebnis hinzu:
shell-variable-setter.make: shell-varaible-setter.sh postprocess.py @^ # ... else include shell-variable-setter.make endif
unordentliche Details als Übung hinterlassen.
quelle
source compilationEnv.sh; $(CC) -c -o $< $^
oder ähnliches funktioniert als Aktionslinie.include .env
(oder eine beliebige Schlüsselwertdatei) verwenden, um Variablen für das gesamte Makefile zugänglich zu machen und dann nur die erforderlichen Variablen an das jeweilige Rezept zu übergeben.Die Standard-Shell für Makefile wird
/bin/sh
nicht implementiertsource
.Das Ändern der Shell auf
/bin/bash
macht es möglich:# Makefile SHELL := /bin/bash rule: source env.sh && YourCommand
quelle
make
und nicht nur für die Verwendung in Aktionszeilen festzulegen. So macht man Letzteres, aber es gibt keinen direkten Weg, Ersteres zu tun.SHELL
auf Ihren eigenen Wrapper einstellen . Hier gezeigt gist.github.com/ingydotnet/99f7e259319f6b90e50a754f3053be7fWenn Sie lediglich Umgebungsvariablen für Make festlegen möchten, behalten Sie diese in der Makefile-Syntax bei und verwenden Sie den
include
Befehl.Wenn Sie das Shell-Skript aufrufen müssen, erfassen Sie das Ergebnis in einem
shell
Befehl:Der Shell-Befehl sollte vor den Zielen ausgeführt werden. Dadurch werden die Umgebungsvariablen jedoch nicht festgelegt.
Wenn Sie Umgebungsvariablen im Build festlegen möchten, schreiben Sie ein separates Shell-Skript, das Ihre Umgebungsvariablen und Aufrufe erstellt. Lassen Sie dann im Makefile die Ziele das neue Shell-Skript aufrufen.
Wenn Ihr ursprüngliches Makefile beispielsweise ein Ziel hat
a
, möchten Sie Folgendes tun:# mysetenv.sh #!/bin/bash . <script to source> export FLAG=1 make "$@" # Makefile ifeq($(FLAG),0) export FLAG=1 a: ./mysetenv.sh a else a: .. do it endif
quelle
Mit GNU Make 3.81 kann ich ein Shell-Skript aus make beziehen, indem ich:
rule: <tab>source source_script.sh && build_files.sh
build_files.sh "ruft" die von source_script.sh exportierten Umgebungsvariablen ab.
Beachten Sie, dass mit:
rule: <tab>source source_script.sh <tab>build_files.sh
wird nicht funktionieren. Jede Zeile wird in einer eigenen Unterschale ausgeführt.
quelle
source
mit GNU Make 4.1 (und möglicherweise auch 4.0) das Beibehalten und Befehlen in derselben Zeile erforderlich wird. Mit 3.81 kann ich verschiedene Zeilen verwenden. Aus Gründen der Portabilität funktioniert eine Zeile in diesen Versionen. Das Aufrufen eines externen Skripts ist jedoch besser lesbar, wenn die Zeile zu lang wird!Das funktioniert bei mir. Ersetzen Sie
env.sh
durch den Namen der Datei, die Sie beschaffen möchten. Es funktioniert, indem die Datei in Bash bezogen und die geänderte Umgebung nach dem Formatieren in eine aufgerufene Dateimakeenv
ausgegeben wird, die dann vom Makefile bezogen wird.IGNORE := $(shell bash -c "source env.sh; env | sed 's/=/:=/' | sed 's/^/export /' > makeenv") include makeenv
quelle
ifdef _intel64onosx
<br/>GCC=/opt/intel/bin/icc
<br/>CFLAGS= -m64 -g -std=c99
IGNORE :=$(shell bash -c "source /opt/intel/bin/iccvars.sh intel64; env | sed 's/=/:=/' | sed 's/^/export /' > makeenv")
include makeenv
make
.env.sh
speziellen Make - Zeichen enthalten, wie#
oder$
. Wenn Sie dies tun, werdeninclude makeenv
diese Werte alle durcheinander gebracht.Einige Konstrukte sind in
shell
und in gleichGNU Make
.var=1234 text="Some text"
Sie können Ihr Shell-Skript ändern, um die Definitionen zu erstellen. Sie müssen alle einfach sein
name=value
Typen sein.Dh
[script.sh]
[Makefile]
Dann können das Shell-Skript und das Makefile dieselbe Informationsquelle gemeinsam nutzen. Ich habe diese Frage gefunden, weil ich nach einem Manifest allgemeiner Syntax gesucht habe, das in Gnu Make- und Shell-Skripten verwendet werden kann (es ist mir egal, welche Shell).
Edit: Shells und verständlich machen $ {var} . Dies bedeutet, dass Sie usw. verketten können. Var = "Eine Zeichenfolge" var = $ {var} "Zweite Zeichenfolge"
quelle
shell
Variablen undmake
Variablen sind nicht immer transparent austauschbar. Wenn Sieinclude
sie in Ihrer habenMakefile
, müssen sie dermake
Syntax entsprechen, die vorschreibt, dass bestimmte Zeichen maskiert werden. Zum Beispiel ein Shell - Variablenwert wieSECRET='12#34$56'
in Ihrem.vars.sh
werden Sie Probleme verursachen , wenn sie unterwegs verwenden Sie es nachinclude vars.sh
Ich mag die Antwort von Foo Bah sehr, bei der make das Skript aufruft und das Skript zurückruft, um make zu erstellen. Um diese Antwort zu erweitern, habe ich Folgendes getan:
# Makefile .DEFAULT_GOAL := all ifndef SOME_DIR %: <tab>. ./setenv.sh $(MAKE) $@ else all: <tab>... clean: <tab>... endif
- -
# setenv.sh export SOME_DIR=$PWD/path/to/some/dir if [ -n "$1" ]; then # The first argument is set, call back into make. $1 $2 fi
Dies hat den zusätzlichen Vorteil, dass $ (MAKE) verwendet wird, falls jemand ein eindeutiges make-Programm verwendet, und dass auch alle in der Befehlszeile angegebenen Regeln verarbeitet werden, ohne dass der Name jeder Regel dupliziert werden muss, wenn SOME_DIR nicht definiert ist .
quelle
Meine Lösung hierfür: (vorausgesetzt, Sie haben
bash
, die Syntax für$@
isttcsh
zum Beispiel anders )Haben Sie ein Skript
sourceThenExec.sh
als solches:#!/bin/bash source whatever.sh $@
Stellen Sie Ihren Zielen in Ihrem Makefile
bash sourceThenExec.sh
beispielsweise Folgendes vor:Sie können natürlich so etwas wie
STE=bash sourceThenExec.sh
oben in Ihr Makefile einfügen und dies kürzen:All dies funktioniert, weil
sourceThenExec.sh
eine Unterschale geöffnet wird, die Befehle dann jedoch in derselben Unterschale ausgeführt werden.Der Nachteil dieser Methode ist, dass die Datei für jedes Ziel bezogen wird, was möglicherweise unerwünscht ist.
quelle
Wenn Sie die Variablen in die Umgebung übertragen möchten , damit sie an untergeordnete Prozesse übergeben werden, können Sie die Bashs
set -a
und verwendenset +a
. Ersteres bedeutet: "Wenn ich eine Variable setze, setze auch die entsprechende Umgebungsvariable." Das funktioniert also für mich:check: bash -c "set -a && source .env.test && set +a && cargo test"
Das wird alles in Pass
.env.test
aufcargo test
als Umgebungsvariablen.Beachten Sie, dass Sie auf diese Weise eine Umgebung an Unterbefehle weitergeben können, aber keine Makefile-Variablen festlegen können (die sowieso anders sind). Wenn Sie Letzteres benötigen, sollten Sie hier einen der anderen Vorschläge ausprobieren.
quelle
Wenn Sie nur wenige bekannte Variablen benötigen, die in makefile exportiert werden können, finden Sie hier ein Beispiel für meine Verwendung.
$ grep ID /etc/os-release ID=ubuntu ID_LIKE=debian $ cat Makefile default: help rule/setup/lsb source?=. help: -${MAKE} --version | head -n1 rule/setup/%: echo ID=${@F} rule/setup/lsb: /etc/os-release ${source} $< && export ID && ${MAKE} rule/setup/$${ID} $ make make --version | head -n1 GNU Make 3.81 . /etc/os-release && export ID && make rule/setup/${ID} make[1]: Entering directory `/tmp' echo ID=ubuntu ID=ubuntu
- http://rzr.online.fr/q/gnumake
quelle
Je nach Ihrer Version von Make und umschließenden Hülle, können Sie eine schöne Lösung über implementieren
eval
,cat
und Verkettungs Anrufe mit&&
:ENVFILE=envfile source-via-eval: @echo "FOO: $${FOO}" @echo "FOO=AMAZING!" > $(ENVFILE) @eval `cat $(ENVFILE)` && echo "FOO: $${FOO}"
Und ein kurzer Test:
quelle
Eine andere Möglichkeit wäre, ein sh-Skript zu erstellen, beispielsweise
run.sh
die erforderlichen Skripte zu erstellen und make innerhalb des Skripts aufzurufen.#!/bin/sh source script1 source script2 and so on make
quelle
Versuchen Sie dies, es wird funktionieren, das Skript befindet sich im aktuellen Verzeichnis.
quelle