Получение имени make-файла из make-файла

Как получить имя make-файла в make-файле?

Благодарю.

Замечания:

Мне это нужно, потому что я хотел бы, чтобы мой make-файл вызывался сам, но make-файл не называется Makefile, поэтому я хотел бы написать что-то вроде этого:

target:
    ($MAKE) -f ($MAKEFILENAME) other_target

7 ответов

Решение
location = $(CURDIR)/$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
WHERE_ART_THOU := $(location)
$(warning $(WHERE_ART_THOU))

Я также верю, что это GNU-специфика, но я не слишком уверен.

(Если у вас есть какие-либо вопросы, обратитесь к удивительно написанному руководству по GNU make. Но помните, что, как и Makefile, это руководство следует полностью прочитать, прежде чем применять концепции на практике).

Я не мог понять, как это сделать легко. Насколько я понимаю, вам придется делать какую-то ручную работу.

Позже я опишу, как это можно сделать, и покажу сценарии, которые вводят current_makefile переменная. Но я хотел бы подчеркнуть важную концепцию в первую очередь.

Вы должны понимать, что если бы у нас была какая-то переменная current_makefile, который расширяется до текущего имени файла makefile, тогда его придется изменить в процессе чтения файлов makefile. Это означает, что он должен использоваться в "непосредственном" контексте расширения - то есть в командах, которые выполняются во время чтения make-файла. Однако большинство команд выполняются после чтения make-файлов. Поэтому некоторые команды будут печатать правильное значение плавно, в то время как в определенных местах, где используется "отложенное" расширение, оно всегда будет расширяться до имени корневого make-файла.

Например, если вы захотите использовать эту переменную в тексте правила, вам придется делать трюки, потому что текст правила всегда имеет отложенное расширение. Итак, если у вас есть правило

rule:
        echo In makefile $(current_makefile):
        echo Making target $@

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

this_makefile_unique_name := $(current_makefile)
rule:
        echo In makefile $(current_makefile):
        echo Making target $@

или используйте eval:.

define make_rule
rule:
        echo In makefile $(1):
        echo Making target $$@

$(eval $(call make_rule,$(current_makefile)))

Если вы хотите использовать имя текущего make-файла только для целей отладки, рассмотрите специальные функции отладки, такие как предупреждение или информация:.

$(warning We're in makefile $(current_makefile))

Эти функции используют "немедленное" расширение и выводят правильное значение.


Как определить такой $(current_makefile)?

Вы должны вручную поддерживать стек включений make-файла. Когда вы включаете make-файл, его имя помещается на вершину стека; когда вы возвращаетесь из включенного make-файла во внешний, самое верхнее имя выталкивается из стека. Это достигается путем вставки специальных вызовов в начало и конец make-файла:

# Beginning of makefile
$(eval $(makefile_names_push))
#... makefile text
$(warning $(current_makefile))
#...
$(eval $(makefile_names_pop))
#End of file

Теперь определите функции в начале вашего корневого make-файла.

lastword=$(word $(words $(1)),$(1))

define makefile_names_push
current_makefile := $$(CURDIR)/$$(call lastword,$$(MAKEFILE_LIST))
makefile_stack :=$$(makefile_stack) $$(current_makefile)
endef

define makefile_names_pop
makefile_stack := $$(filter-out $$(current_makefile),$$(makefile_stack))
current_makefile := $$(call lastword,$$(makefile_stack))
endef

Если вы уверены, что ваш бренд достаточно новый (версия 3.81+), замените lastword вызов со встроенной функцией:

#inctead of $$(call lastword,$$(MAKEFILE_LIST))
$$(lastword $$(MAKEFILE_LIST))

Это полезно?

Совершенно бесполезно. Единственное использование, которое может быть здесь полезным, - это сделать 100 make-файлов, которые являются символическими ссылками на один make-файл, правила в этих make-файлах зависят от их имен. Но это может быть достигнуто с помощью одного make-файла и метода foreach-eval, описанного в руководстве. Так что мой пост был пустой тратой времени, хотя я повеселился:-)

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

MAKEFILE_JUSTNAME := $(firstword $(MAKEFILE_LIST))
MAKEFILE_COMPLETE := $(CURDIR)/$(MAKEFILE_JUSTNAME)

Когда используется в нерекурсивных рекурсивных ситуациях (например, для makedepend), это просто имя текущего make-файла.

Быстрая экскурсия в Google предполагает, что у этого сайта есть ответ.

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

Мой результат после прочтения этой страницы:

    # Makefile - 'make' and 'make help' now echo the makefile.
    help:
        cat $(lastword $(MAKEFILE_LIST))
    start:
        sudo -u www /path/to/webapp/myhttpd restart
    stop:
        sudo kill `cat /path/to/webapp/data/httpd.pid`

Решения здесь касаются 1) POSIX make с 2) вызываемым, не включенным makefile в 3) Unix-подобной платформой.

Что попросил ОП:

      target:
    @pid=$$$$; \
    while test `ps -ocomm= $$pid` != make; do \
        pid=`ps -oppid= $$pid`; \
    done; \
    MAKEFILENAME=`ps -oargs= $$pid|sed 's/^.* -f *\([^ ]*\).*$$/\1/'`; \
    test -z "$$MAKEFILENAME" -a -f Makefile && MAKEFILENAME=Makefile; \
    test -z "$$MAKEFILENAME" -a -f makefile && MAKEFILENAME=makefile; \
    export MAKEFILENAME; \
    $(MAKE) -e -f $$MAKEFILENAME other_target

Цели зависят от make-файла, немного раздутого:

      TARGET1_MAKEFILENAME = target1_preamble

all: target1 target2...

target1: $(TARGET1_MAKEFILENAME) other_dependencies...
    @test $(TARGET1_MAKEFILENAME) == target1_preamble && exit 0; \
    built_instructions_for_target1;

target1_preamble:
    @pid=$$$$; \
    while test `ps -ocomm= $$pid` != make; do \
        pid=`ps -oppid= $$pid`; \
    done; \
    MAKEFILENAME=`ps -oargs= $$pid|sed 's/^.* -f *\([^ ]*\).*$$/\1/'`; \
    test -z "$$MAKEFILENAME" -a -f Makefile && MAKEFILENAME=Makefile; \
    test -z "$$MAKEFILENAME" -a -f makefile && MAKEFILENAME=makefile; \
    export MAKEFILENAME; \
    $(MAKE) -e -f $$MAKEFILENAME target1;

Может быть немного упрощено, если make вызывается только для всех целей.

      MAKEFILENAME = invoked_makefile_placeholder

all: target1 target2...

target1: $(MAKEFILENAME) other_dependencies...
    @test $(MAKEFILENAME) == invoked_makefile_placeholder && exit 0; \
    built_instructions_for_target1;

invoked_makefile_placeholder:
    @pid=$$$$; \
    while test `ps -ocomm= $$pid` != make; do \
        pid=`ps -oppid= $$pid`; \
    done; \
    MAKEFILENAME=`ps -oargs= $$pid|sed 's/^.* -f *\([^ ]*\).*$$/\1/'`; \
    test -z "$$MAKEFILENAME" -a -f Makefile && MAKEFILENAME=Makefile; \
    test -z "$$MAKEFILENAME" -a -f makefile && MAKEFILENAME=makefile; \
    export MAKEFILENAME; \
    $(MAKE) -e -f $$MAKEFILENAME

С предыдущим подходом тривиально реализовать решение для включенных make -файлов на основе grepи уникальный шаблон, содержащийся в make-файле.

Я никогда не отвечаю, когда чувствую, что вопрос получил правильное решение.

G'day,

Если вы делаете копию своего исходного make-файла, произнесите makefile_test, а затем введите команду:

make -np -f makefile_test 2>&1 | tee output

Это оценит make-файл и вашу среду make, но не выполнит ни одну из команд. Просмотр выходного файла на наличие ссылок на makefile_test покажет вам, что установлено в среде make и где устанавливается это значение.

NB Это может генерировать много информации! И не добавляйте ключ -d (debug), который будет генерировать тонны дополнительной информации о процессе принятия решения make, но минимальную дополнительную информацию о среде en make.

НТН

Другие вопросы по тегам