Передача дополнительных переменных из командной строки, чтобы сделать

615

Могу ли я передать переменные в Makefile GNU в качестве аргументов командной строки? Другими словами, я хочу передать некоторые аргументы, которые в конечном итоге станут переменными в Makefile.

Pablo
источник

Ответы:

755

У вас есть несколько вариантов для установки переменных вне вашего make-файла:

  • Из среды - каждая переменная среды преобразуется в переменную makefile с тем же именем и значением.

    Вы также можете захотеть включить -eпараметр (aka --environments-override), и ваши переменные среды будут переопределять назначения, сделанные в make-файле (если только эти назначения сами не используют overrideдирективу . Однако это не рекомендуется, и намного лучше и гибче использовать ?=назначение (условная переменная) Оператор присваивания действует только в том случае, если переменная еще не определена):

    FOO?=default_value_if_not_set_in_environment
    

    Обратите внимание, что некоторые переменные не наследуются от окружения:

    • MAKE получается из названия скрипта
    • SHELLлибо устанавливается в make-файле, либо по умолчанию /bin/sh(обоснование: команды указываются в make-файле, и они зависят от оболочки).
  • Из командной строки - makeможет принимать переменные назначения как часть своей командной строки, смешанные с целями:

    make target FOO=bar
    

    Но тогда все присваивания FOOпеременной внутри make-файла будут игнорироваться, если вы не используете overrideдирективу в присваивании. (Эффект такой же, как с -eопцией для переменных среды).

  • Экспорт из родительского Make - если вы вызываете Make из Makefile, вам обычно не следует явно писать назначения переменных следующим образом:

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

    Вместо этого лучшим решением может быть экспорт этих переменных. Экспорт переменной превращает ее в среду каждого вызова оболочки, и вызовы Make из этих команд выбирают эти переменные среды, как указано выше.

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

    Вы также можете экспортировать все переменные, используя exportбез аргументов.

П Швед
источник
11
перейти из командной строки что-то с пробелами делатьmake A='"as df"'
Сиро Сантилли 法轮功 冠状 病 六四 事件 法轮功
4
Похоже, вы напрашиваетесь на неприятности, если вам небезразличны переменные среды. Во-первых, это кошмар отладки, если он работает в месте A, а не в месте B, просто потому, что у них разные среды.
Джеймс Мур
12
Основываясь на опыте, экспорт таких вещей, как CFLAGS, - это рецепт кошмара для больших проектов. Большие проекты часто имеют сторонние библиотеки, которые компилируются только с заданным набором флагов (которые никто не мешает исправлять). Если вы экспортируете CFLAGS, CFLAGS вашего проекта переопределяет стороннюю библиотеку и вызывает ошибки компиляции. Альтернативным способом может быть определение export PROJECT_MAKE_ARGS = CC=$(CC) CFLAGS=$(CFLAGS)и передача его как make -C folder $(PROJECT_MAKE_FLAGS). Если есть способ заставить make-файл библиотеки игнорировать окружение, это было бы идеально (напротив -e).
RD
24
ВНИМАНИЕ: В разделе «Экспорт из родительского Make» выше «Не делайте этого!» является критически вводит в заблуждение . Передача переменных в командной строке переопределяет назначения в подфайл-файле, но экспортированные переменные не переопределяют назначения в подфайл-файле. Эти два метода для передачи переменных во вспомогательный make-файл не эквивалентны и их не следует путать.
Джонатан Бен-Авраам
4
Какая разница? make target FOO=bar make FOO=bar target?
Gfan
213

Самый простой способ:

make foo=bar target

Тогда в вашем makefile вы можете сослаться $(foo). Обратите внимание, что это не будет распространяться на суб-производителей автоматически.

Если вы используете под-марку, см. Эту статью: Связь переменных с под-маркой

Марк Байерс
источник
2
под-заставляет вас иметь в виду make-файлы includedв главном make-файле?
Пабло
2
@Michael: Это означает, что вызов make снова изнутри make-файла. Я обновил свой ответ, так как вы, кажется, заинтересованы в этой детали.
Марк Байерс
2
Msgstr "Обратите внимание, что это не будет автоматически распространяться на суб-производителей". Неправда! «По умолчанию только переменные, полученные из среды или командной строки, передаются в рекурсивные вызовы. Вы можете использовать директиву export для передачи других переменных». gnu.org/software/make/manual/html_node/...
ThomasMcLeod
82

Скажем, у вас есть такой файл:

action:
    echo argument is $(argument)

Вы бы тогда назвали это make action argument=something

nc3b
источник
5
Таким образом, цель и аргументы могут быть изменены с точки зрения позиции?
Пабло
4
@ Майкл: Да (см. Ответ Марка Байерса)
nc3b
25

Из руководства :

Переменные в make могут происходить из среды, в которой запускается make. Каждая переменная окружения, которая видит, когда она запускается, преобразуется в переменную make с тем же именем и значением. Однако явное присваивание в make-файле или с аргументом команды переопределяет окружение.

Так что вы можете сделать (из Баш):

FOOBAR=1 make

в результате чего переменная FOOBARв вашем Makefile.

Томас
источник
2
Другой способ действительно лучше почти во всех случаях. Я оставлю это здесь для полноты.
Томас
Это единственный ответ, который показывает назначение переменных перед командой make в той же строке - стоит знать, что это не синтаксическая ошибка.
М_М
7

Есть еще один вариант, не упомянутый здесь, который включен в книгу GNU Make Stallman и McGrath (см. Http://www.chemie.fu-berlin.de/chemnet/use/info/make/make_7.html ). Это обеспечивает пример:

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

Это включает в себя проверку, если данный параметр появляется в MAKEFLAGS. Например ... предположим, что вы изучаете потоки в c ++ 11, и вы поделили свое исследование на несколько файлов ( class01, ..., classNM) и хотите: скомпилировать все затем и запустить по отдельности или скомпилировать один за время и запустить его, если указан флаг ( -rнапример). Итак, вы можете придумать следующее 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

Имея это, вы бы:

  • собрать и запустить файл w / make -r class02;
  • построить все с / makeили make all;
  • соберите и запустите все с / make -r(предположим, что все они содержат какой-то определенный тип утверждений, и вы просто хотите проверить их все)
Чиро Коста
источник
6

это выглядит

команда args перезаписать переменную окружения

Makefile

send:
    echo $(MESSAGE1) $(MESSAGE2)

Пример запуска

$ MESSAGE1=YES MESSAGE2=NG  make send MESSAGE2=OK
echo YES OK
YES OK
YumaInaura
источник
5

Если вы создадите файл с именем Makefile и добавите переменную наподобие этого $ (unittest), то вы сможете использовать эту переменную внутри Makefile даже с подстановочными знаками

пример :

make unittest=*

Я использую BOOST_TEST и, задав подстановочный знак для параметра --run_test = $ (unittest), я смогу использовать регулярное выражение для фильтрации теста, который я хочу запустить в своем Makefile.

Serup
источник
4
export ROOT_DIR=<path/value>

Затем используйте переменную $(ROOT_DIR)в Makefile.

parasrish
источник