Makefile и имена на изчислени променливи

Получих следния Makefile с няколко компилатора и бих искал да ги извикам в цикъл чрез променливата cc:

cc_x64=x86_64-linux-gnu-gcc
cc_mips=mips-linux-gnu-gcc

all:
    for arch in "x64" "mips" ; do\
    cc="cc_$$arch";\
    $($(cc)) some_file -o some_bin

Чрез $($(cc)) се опитвам да заменя $(cc) с cc_xxx и на свой ред да го заменя с действителната команда, която се опитвам да изпълня. Това се нарича име на изчислена променлива в документацията на GNU Make: https://www.gnu.org/software/make/manual/html_node/Computed-Names.html

По някаква причина не мога да накарам това да работи. какво ми липсва ?


person Kereoz    schedule 12.09.2014    source източник


Отговори (3)


Не можете да пресичате черупката/да правите граници по този начин. Вие се опитвате, в контекста на обвивката, да създадете и оцените make променлива в движение. Това не може да работи.

Трябва или да свършите цялата работа в make или в shell. Експортирайте тези make променливи в обвивката и след това нещо подобно трябва да работи:

all:
    for arch in x64 mips; do\
     cc=cc_$$arch;\
     ${!cc} some_file -o some_bin.$$arch;\
    done

Но вероятно би било по-добре да направите това по по-идиоматичен начин.

Което би изглеждало по-скоро така (нетествано):

all: $(addprefix some_file.,x86 mips)

some_file.%: some_file
        $(cc_$(*)) $^ -o $@
person Etan Reisner    schedule 12.09.2014
comment
Същият проблем тук: $(cc_$(*)) се замества с празен низ, въпреки че cc_$(*) всъщност се оценява като например cc_x86. - person Kereoz; 13.09.2014
comment
Каква версия на марката? В бърз тест $(cc_$(*)) работи тук за шаблонно правило. Също така x86 не беше в списъка ви с примерна архитектура, така че ако няма променлива cc_x86 make, която очевидно няма да работи правилно (или по-точно, ще работи напълно правилно и ще ви даде празен низ). - person Etan Reisner; 14.09.2014
comment
(x86 беше само пример). Вие сте прав обаче, след двойна проверка, че работи тук за правило за шаблон, току-що обърках нещо в предишния си тест, моето лошо. Благодаря ти ! - person Kereoz; 15.09.2014

Ако се почувствах длъжен да използвам цикъл, бих го направил така:

COMPS = x86_64-linux-gnu-gcc mips-linux-gnu-gcc

all:
    for comp in $(COMPS); do\
  $$comp some_file -o some_bin; \
  done
person Beta    schedule 13.09.2014
comment
Добре, това е друг начин да го направя, но тук ми е интересно да разбера защо изчислените имена на променливи не работят в този конкретен случай, не търся алтернативни решения. Благодаря все пак за предложението. - person Kereoz; 15.09.2014

Вашият въпрос е "Какво ми липсва?" Отговорът е, че не осъзнавате, че Makefile работи по различен начин от shell скрипт. Опитвате се да поставите shell скрипт в Makefile. Това е като да се опитваш да сложиш седло на крава. И вие, и кравата ще сте недоволни от резултата.

Начинът, по който се опитвате да го направите, не ви трябва Make. Просто използвайте shell скрипта, който имате там под "all:" и забравете за Make. Защо се опитвате да сложите седло на крава?

Ако искате да научите как да използвате Make, тогава, моля, прочетете по-внимателно ръководството за Make и особено проучете дадените там примери. Тогава ще разберете разликата между shell скриптове и Makefiles и всичко ще бъде по-ясно.

Ще ви покажа как да правите това, което искате, по правилния начин, по който Makefiles са проектирани да работят. Но моля, проучете ръководството по-внимателно.

RESULTS := $(addprefix some_bin., x86_64 mips)

.PHONY: all
all: $(RESULTS)
$(RESULTS): some_file Makefile
    $(patsubst .%,%-linux-gnu-gcc,$(suffix $@)) $< -o $@
person Mark Galeck    schedule 13.09.2014