Przekazywanie dodatkowych zmiennych z wiersza poleceń do wykonania


613

Czy mogę przekazywać zmienne do pliku makefile GNU jako argumenty wiersza poleceń? Innymi słowy, chcę przekazać kilka argumentów, które ostatecznie staną się zmiennymi w Makefile.

Odpowiedzi:


752

Masz kilka opcji konfigurowania zmiennych spoza twojego makefile:

  • Ze środowiska - każda zmienna środowiskowa jest przekształcana w zmienną makefile o tej samej nazwie i wartości.

    Możesz także ustawić -eopcję (aka --environments-override) na, a zmienne środowiskowe zastąpią przypisania dokonane w pliku makefile (chyba że te przypisania same używają overridedyrektywy . Jednak nie jest to zalecane, a korzystanie z ?=przypisania jest znacznie lepsze i elastyczne (zmienna warunkowa operator przypisania, działa tylko wtedy, gdy zmienna nie jest jeszcze zdefiniowana):

    FOO?=default_value_if_not_set_in_environment
    

    Zauważ, że niektóre zmienne nie są dziedziczone ze środowiska:

    • MAKE pochodzi od nazwy skryptu
    • SHELLjest albo ustawiony w pliku makefile, albo domyślnie ustawiony na /bin/sh(uzasadnienie: polecenia są określone w pliku makefile i są one specyficzne dla powłoki).
  • Z wiersza poleceń - makemoże przyjmować przypisania zmiennych jako część swojego wiersza poleceń, zmieszanego z celami:

    make target FOO=bar
    

    Ale wtedy wszystkie przypisania do FOOzmiennej w pliku makefile będą ignorowane, chyba że użyjesz overridedyrektywy w przypisaniu. (Efekt jest taki sam jak w przypadku -eopcji dla zmiennych środowiskowych).

  • Eksportowanie z nadrzędnego programu Make - jeśli wywołasz program Make z pliku Makefile, zwykle nie powinieneś jawnie zapisywać przypisań zmiennych takich jak to:

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

    Zamiast tego lepszym rozwiązaniem może być eksport tych zmiennych. Wyeksportowanie zmiennej powoduje, że staje się ona środowiskiem każdego wywołania powłoki, a wywołania tych poleceń wybierają te zmienne środowiskowe, jak określono powyżej.

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

    Możesz także wyeksportować wszystkie zmienne, używając exportbez argumentów.


10
przejść z wiersza poleceń coś ze spacjamimake A='"as df"'
Ciro Santilli 16 冠状 病 六四 事件 法轮功

4
Wygląda na to, że prosisz o kłopoty, jeśli zależy ci na zmiennych środowiskowych. Po pierwsze, to koszmar debugowania, jeśli działa w miejscu A, a nie w miejscu B, tylko dlatego, że mają różne środowiska.
James Moore

12
Bazując na doświadczeniu, eksportowanie rzeczy takich jak CFLAGS to przepis na koszmar dla dużych projektów. Duże projekty często mają biblioteki stron trzecich, które kompilują się tylko z danym zestawem flag (których naprawianie nie przeszkadza). Jeśli eksportujesz CFLAGS, CFLAGS twojego projektu ostatecznie zastępuje biblioteki innej firmy i powoduje błędy kompilacji. Alternatywnym sposobem może być zdefiniowanie export PROJECT_MAKE_ARGS = CC=$(CC) CFLAGS=$(CFLAGS)i przekazanie go jako make -C folder $(PROJECT_MAKE_FLAGS). Jeśli istnieje sposób, aby powiedzieć plikowi makefile biblioteki, aby ignorował środowisko, byłoby to idealne rozwiązanie (w przeciwieństwie do -e).
RD

24
OSTRZEŻENIE: W sekcji „Eksportowanie od rodzica Marka” powyżej „Nie rób tego!” jest bardzo mylące . Przekazywanie zmiennych w wierszu poleceń zastępuje przypisania w pod-makefile, ale wyeksportowane zmienne nie zastępują przypisań w pod-makefile. Te dwie metody przekazywania zmiennych do podpliku nie są równoważne i nie należy ich mylić.
Jonathan Ben-Avraham,

4
Jakaś różnica? make target FOO=bar make FOO=bar target?
gfan

213

Najprostszym sposobem jest:

make foo=bar target

Następnie w swoim makefile możesz się odwoływać $(foo). Zauważ, że nie będzie to automatycznie propagować do podwykonawców.

Jeśli używasz podwykonawców, zapoznaj się z tym artykułem: Przekazywanie zmiennych do podwykonawców


2
przez pod-sprawia, że ​​masz na myśli makefile includedw głównym makefile?
Pablo

2
@Michael: Oznacza to ponowne wywołanie make z pliku makefile. Zaktualizowałem swoją odpowiedź, ponieważ wydajesz się zainteresowany tymi szczegółami.
Mark Byers

2
„Pamiętaj, że nie będzie się to automatycznie przenosić do podwykonawców”. Nieprawdziwy! „Domyślnie tylko zmienne pochodzące ze środowiska lub wiersza poleceń są przekazywane do wywołań rekurencyjnych. Możesz użyć dyrektywy eksportowej, aby przekazać inne zmienne.” gnu.org/software/make/manual/html_node/…
ThomasMcLeod

82

Załóżmy, że masz taki plik makefile:

action:
    echo argument is $(argument)

Nazwałbyś to make action argument=something


5
więc cel i argumenty mogą być wymieniane pod względem pozycji?
Pablo

4
@Michael: Tak (patrz odpowiedź Mark Byers)
nc3b

25

Z instrukcji :

Zmienne w make mogą pochodzić ze środowiska, w którym make jest uruchamiany. Każda zmienna środowiskowa, która widzi, kiedy się uruchamia, jest przekształcana w zmienną make o tej samej nazwie i wartości. Jednak wyraźne przypisanie w pliku makefile lub za pomocą argumentu polecenia zastępuje środowisko.

Możesz więc zrobić (z bash):

FOOBAR=1 make

co daje zmienną FOOBARw twoim Makefile.


2
Drugi sposób jest rzeczywiście lepszy w prawie wszystkich przypadkach. Zostawię to tutaj dla kompletności.
Thomas

To jedyna odpowiedź, która pokazuje przypisanie zmiennych przed poleceniem make w tym samym wierszu - warto wiedzieć, że nie jest to błąd składniowy.
M_M

7

Jest jeszcze inna opcja, która nie jest tu cytowana, a która jest zawarta w książce GNU Make autorstwa Stallmana i McGratha (patrz http://www.chemie.fu-berlin.de/chemnet/use/info/make/make_7.html ). Podaje przykład:

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

Polega na sprawdzeniu, czy dany parametr pojawia się w MAKEFLAGS. Na przykład ... załóżmy, że studiujesz wątki w c ++ 11 i podzieliłeś swoje badanie na wiele plików ( class01, ..., classNM) i chcesz: skompilować wszystkie i uruchomić osobno lub skompilować jeden na czas i uruchom go, jeśli podano flagę ( -rna przykład). Więc możesz wymyślić następujące 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

Mając to, możesz:

  • zbuduj i uruchom plik w / make -r class02;
  • zbuduj wszystko w / makelub make all;
  • zbuduj i uruchom wszystko w / make -r(załóżmy, że wszystkie zawierają pewne pewne aserty i po prostu chcesz je wszystkie przetestować)

6

wydaje się

polecenie args zastępuje zmienną środowiskową

Makefile

send:
    echo $(MESSAGE1) $(MESSAGE2)

Uruchom przykład

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

5

Jeśli utworzysz plik o nazwie Makefile i dodasz zmienną taką jak ten $ (unittest), będziesz mógł używać tej zmiennej w Makefile nawet z symbolami wieloznacznymi

przykład:

make unittest=*

Używam BOOST_TEST i podając symbol wieloznaczny do parametru --run_test = $ (unittest), wtedy będę mógł użyć wyrażenia regularnego do odfiltrowania testu, który chcę uruchomić mój Makefile


4
export ROOT_DIR=<path/value>

Następnie użyj zmiennej $(ROOT_DIR)w Makefile.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.