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.

Pablo
źródło

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.

P Shved
źródło
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

Mark Byers
źródło
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

nc3b
źródło
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.

Tomasz
źródło
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 [email protected] $^ $(LDLIBS)
ifneq (,$(findstring r,  $(MAKEFLAGS)))
    ./[email protected]
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ć)
Ciro Costa
źródło
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
YumaInaura
źródło
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

serup
źródło
4
export ROOT_DIR=<path/value>

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

parasrish
źródło