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, либо в оболочке. Экспортируйте эти переменные 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 не было в вашем списке примеров архитектуры, поэтому, если нет переменной make cc_x86, она явно не будет работать правильно (или, точнее, она будет работать совершенно правильно и даст вам пустую строку). - 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 работает иначе, чем сценарий оболочки. Вы пытаетесь поместить сценарий оболочки в Makefile. Это все равно, что пытаться оседлать корову. И вы, и корова будете недовольны результатом.

То, как вы пытаетесь это сделать, вам не нужно делать. Просто используйте сценарий оболочки, который у вас есть в разделе «все:», и забудьте о Make. Зачем пытаться надеть седло на корову?

Если вы хотите узнать, как использовать Make, то, пожалуйста, прочитайте более внимательно руководство Make и особенно изучите приведенные там примеры. Тогда вы поймете разницу между шелл-скриптами и Makefile'ами, и все станет понятнее.

Я покажу вам, как делать то, что вы хотите, тем способом, для которого созданы файлы Makefile. Но, пожалуйста, внимательно изучите инструкцию.

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