Makefiles: как получить имя файла для цели правила извне, переносимым способом - PullRequest
2 голосов
/ 08 марта 2010

Мне нужно получить некоторые внешние данные для формирования имени выходного файла в Makefile.

В GNU Make Я могу сделать что-то вроде этого:

NAME=$(shell some_commands)
$(NAME).out: file.in
     compile "$<" -o "$@"

В некоторых других правилах $(NAME).out является обязательным условием, поэтому мне нужно $(NAME).out в качестве цели. Я не могу использовать подстановку + кавычки здесь, поскольку это не интерпретируется оболочкой.

На справочной странице BSD Make я вижу, что в Mac OS X я должен иметь возможность сделать что-то подобное (хотя я еще не смог проверить это):

NAME!=some_commands
$(NAME).out: file.in
     compile "$<" -o "$@"

Есть ли взломать, чтобы делать такие вещи портативным способом?

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

Ответы [ 2 ]

2 голосов
/ 08 марта 2010

Это немного неуклюже, и я не знаю достаточно о различных версиях Make, чтобы знать, действительно ли он переносим, ​​но он может работать и удовлетворяет вашим строгим условиям (без генерации make-файла, без 'include', и все может зависеть от $ (NAME) .out). Если есть только одна цель, которую вы собираетесь сделать из командной строки (скажем, «все»), тогда вы можете написать это так:

ifeq ($(origin NAME), undefined)
all:
    @$(MAKE) -s all NAME=some_commands_using_substituion_and_quotes
else
all: some_preqs_maybe_including_NAME
    do_other_things
endif

Когда вы запускаете Make, NAME не определено, поэтому правило снова запускает Make с определенным NAME, поскольку команда интерпретируется оболочкой. («@» И «-s» предназначены только для того, чтобы сделать его тише.) И если вы попытаетесь сделать другие цели «вручную», у вас будет много проблем, так как $ (NAME) ничего не даст.

2 голосов
/ 08 марта 2010

Я могу предложить несколько трюков. Все они основаны на аутсорсинге выполнения some_commands для тела правила и обеспечении правильного использования их результата.

  1. Это мой любимый. Включите make-файл, который вы создаете самостоятельно, который содержит правило для $(NAME). В начале обработки он будет воссоздан и появится соответствующая цель. Дело в том, что процесс создания этого make-файла выполняется с помощью команд оболочки:

    include aux_makefile
    .PHONY aux_makefile
    aux_makefile:
        NAME=`some_commands` ; ( \
            echo $$NAME.out: file.in ; \
            echo "\t rm aux_makefile" ; \
            echo "\t compile ..."  ) >$@
    
  2. Вариант первого: создайте make-файл оболочки, который сначала записывает вспомогательный make-файл, а затем рекурсивно вызывает исходный make-файл, в него включается вспомогательный make-файл. Специальная цель сборки не требуется.

  3. Сделать фиктивную цель со статическим именем; это будет представлять $(NAME).out. I.e.:

    all: dummy    # Instead of all: $(NAME).out
    dummy: file.in
       NAME=`some_commands`; compile "$<" -o "$$NAME"
       touch $@
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...