Passare ulteriori variabili dalla riga di comando per creare


614

Posso passare le variabili a un Makefile GNU come argomenti della riga di comando? In altre parole, voglio passare alcuni argomenti che alla fine diventeranno variabili nel Makefile.

Risposte:


754

Hai diverse opzioni per impostare le variabili dall'esterno del tuo makefile:

  • Dall'ambiente : ogni variabile di ambiente viene trasformata in una variabile makefile con lo stesso nome e valore.

    Potresti anche voler impostare l' -eopzione (aka --environments-override) su, e le tue variabili di ambiente sovrascriveranno le assegnazioni fatte in makefile (a meno che queste stesse assegnazioni non utilizzino la overridedirettiva . Tuttavia, non è raccomandato ed è molto meglio e flessibile usare l' ?=assegnazione (la variabile condizionale operatore di assegnazione, ha effetto solo se la variabile non è ancora definita):

    FOO?=default_value_if_not_set_in_environment
    

    Si noti che alcune variabili non sono ereditate dall'ambiente:

    • MAKE è ottenuto dal nome della sceneggiatura
    • SHELLè impostato all'interno di un makefile o il valore predefinito è /bin/sh(razionale: i comandi sono specificati all'interno del makefile e sono specifici della shell).
  • Dalla riga di comando : makepuò assumere assegnazioni variabili come parte della sua riga di comando, unita a target:

    make target FOO=bar
    

    Ma poi tutte le assegnazioni alla FOOvariabile all'interno del makefile verranno ignorate a meno che non si usi la overridedirettiva nell'assegnazione. (L'effetto è lo stesso -edell'opzione per le variabili di ambiente).

  • Esportazione dal genitore Make - se chiami Make da un Makefile, di solito non dovresti scrivere esplicitamente assegnazioni di variabili come questa:

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

    Invece, la soluzione migliore potrebbe essere quella di esportare queste variabili. L'esportazione di una variabile la rende nell'ambiente di ogni invocazione della shell e Effettua chiamate da questi comandi seleziona queste variabili di ambiente come specificato sopra.

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

    Puoi anche esportare tutte le variabili usando exportsenza argomenti.


11
passare dalla riga di comando con qualcosa che fa gli spazimake A='"as df"'
Ciro Santilli 16 冠状 病 六四 事件 法轮功

4
Sembra che stai chiedendo problemi se ti preoccupi delle variabili di ambiente. Per prima cosa, è un incubo di debug se funziona nel posto A e non nel posto B, solo perché hanno ambienti diversi.
James Moore,

12
Basandosi sull'esperienza, esportare cose come CFLAGS è una ricetta da incubo per grandi progetti. I grandi progetti hanno spesso librerie di terze parti che si compilano solo con un determinato set di flag (che nessuno si preoccupa di sistemare). Se si esportano CFLAGS, i CFLAGS del progetto finiscono per sovrascrivere le librerie di terze parti e generano errori di compilazione. Un modo alternativo potrebbe essere quello di definirlo export PROJECT_MAKE_ARGS = CC=$(CC) CFLAGS=$(CFLAGS)e passarlo come make -C folder $(PROJECT_MAKE_FLAGS). Se c'è un modo per dire al makefile della libreria di ignorare l'ambiente, sarebbe l'ideale (al contrario di -e).
RD

24
ATTENZIONE: Nella sezione "Esportazione dalla casa madre" sopra, "Non farlo!" è criticamente fuorviante . Il passaggio di variabili nella riga di comando ha la precedenza sulle assegnazioni nel sub-makefile ma le variabili esportate non hanno la precedenza sulle assegnazioni nel sub-makefile. Questi due metodi per passare le variabili a un sub-makefile non sono equivalenti e non devono essere confusi.
Jonathan Ben-Avraham,

4
Qualche differenza? make target FOO=bar make FOO=bar target?
gfan,

213

Il modo più semplice è:

make foo=bar target

Quindi nel tuo makefile puoi fare riferimento $(foo). Si noti che ciò non si propagherà automaticamente alle sub-marche.

Se si utilizzano sub -make , consultare questo articolo: Comunicazione di variabili a un sub-make


2
per sub-make intendi i makefile includednel makefile principale?
Pablo,

2
@Michael: Significa richiamare make dall'interno del makefile. Ho aggiornato la mia risposta poiché sembri essere interessato a questo dettaglio.
Mark Byers,

2
"Nota che questo non si propagherà automaticamente alle sub-marche." ! falso "Per impostazione predefinita, solo le variabili provenienti dall'ambiente o dalla riga di comando vengono passate a invocazioni ricorsive. È possibile utilizzare la direttiva export per passare altre variabili." gnu.org/software/make/manual/html_node/…
ThomasMcLeod

82

Supponi di avere un makefile come questo:

action:
    echo argument is $(argument)

Lo chiameresti quindi make action argument=something


5
quindi l'obiettivo e gli argomenti possono essere scambiati in termini di posizione?
Pablo,

4
@Michael: Sì (vedi la risposta di Mark Byers)
nc3b

25

Dal manuale :

Le variabili in make possono provenire dall'ambiente in cui make viene eseguito. Ogni variabile d'ambiente che crea vede all'avvio viene trasformata in una variabile make con lo stesso nome e valore. Tuttavia, un'assegnazione esplicita nel makefile, o con un argomento di comando, sovrascrive l'ambiente.

Quindi puoi fare (da bash):

FOOBAR=1 make

risultante in una variabile FOOBARnel tuo Makefile.


2
L'altro modo è davvero migliore in quasi tutti i casi. Lascio questo qui per completezza.
Thomas,

Questa è l'unica risposta che mostra l'assegnazione delle variabili prima del comando make sulla stessa riga - vale la pena sapere che questo non è un errore di sintassi.
M_M

7

C'è un'altra opzione non citata qui che è inclusa nel libro GNU Make di Stallman e McGrath (vedi http://www.chemie.fu-berlin.de/chemnet/use/info/make/make_7.html ). Fornisce l'esempio:

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

Implica la verifica se appare un determinato parametro MAKEFLAGS. Ad esempio .. supponiamo che tu stia studiando i thread in c ++ 11 e che tu abbia diviso il tuo studio su più file ( class01, ..., classNM) e che tu voglia: compilare quindi tutto ed eseguirlo singolarmente o compilarne uno in un tempo ed eseguirlo se viene specificato un flag ( -r, ad esempio). Quindi, potresti trovare quanto segue Makefile:

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

SOURCES = class01 class02 class03

%: %.cxx
    $(CXX) $(CXXFLAGS) -o $@.out $^ $(LDLIBS)
ifneq (,$(findstring r,  $(MAKEFLAGS)))
    ./$@.out
endif

all: $(SOURCES)

.PHONY: clean

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

Detto questo, dovresti:

  • compilare ed eseguire un file w / make -r class02;
  • costruisci tutto con / makeo make all;
  • compilare ed eseguire tutto w / make -r(supponiamo che tutti contengano un certo tipo di affermazione e che tu voglia solo testarli tutti)

6

sembra

Il comando args sovrascrive la variabile di ambiente

Makefile

send:
    echo $(MESSAGE1) $(MESSAGE2)

Esegui esempio

$ MESSAGE1=YES MESSAGE2=NG  make send MESSAGE2=OK
echo YES OK
YES OK

5

Se crei un file chiamato Makefile e aggiungi una variabile come questa $ (unittest), sarai in grado di usare questa variabile all'interno del Makefile anche con caratteri jolly

esempio :

make unittest=*

Uso BOOST_TEST e assegnando un carattere jolly al parametro --run_test = $ (unittest), allora sarò in grado di usare l'espressione regolare per filtrare il test. Voglio che il mio Makefile venga eseguito


4
export ROOT_DIR=<path/value>

Quindi utilizzare la variabile, $(ROOT_DIR)nel Makefile.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.