30

How to get the name of the makefile in the makefile?

Thanks.

Note:

I would need that because I would like my makefile to call itself, but the makefile is not called Makefile, so I'd like to write something like this:

target:
    $(MAKE) -f $(MAKEFILENAME) other_target
Jens
  • 69,818
  • 15
  • 125
  • 179
hcs42
  • 13,376
  • 6
  • 41
  • 36

6 Answers6

16
location = $(CURDIR)/$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
WHERE_ART_THOU := $(location)
$(warning $(WHERE_ART_THOU))

I also believe this is GNU make-specific, but I'm not too sure.

Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
Michael Foukarakis
  • 39,737
  • 6
  • 87
  • 123
  • 4
    This solution does not work if you check makefile name after you've included another makefile! (copy-pasted comment) – P Shved Sep 09 '09 at 14:57
  • "This solution does not work if you check makefile name after you've included another makefile!" This is not a big problem. I can write the first two line of this code in the beginning of my Makefile, which sets the WHERE_ART_THOU variable correctly. Then I can use that variable anywhere in the Makefile, it will contain the name of my Makefile correctly. – hcs42 Sep 11 '09 at 10:10
  • 7
    But for included makefiles you'll have to use different names: `WHERE_ART_THOU` for one makefile, `WHERE_ART_THOU_2` for another etc. I aimed on introducing one name for all makefiles that works not only when used at the top of a one. – P Shved Sep 11 '09 at 10:28
  • You are right, Pavel. And _now_ I understand your solution :) – hcs42 Sep 11 '09 at 11:14
12

(Should you have any questions, refer to amazingly written GNU make manual. But remember, that, just like Makefile, this manual should be read completely before putting the concepts into practice).

I couldn't figure out how it is done easily. As far as I understand, you'll have to do some manual job.

Later I will describe how it could be done and show scripts that introduce current_makefile variable. But I would like to stress an important concept at the first place.

You should understand that if we had some kind of variable current_makefile, that expands to the current makefile name, then it will have to change during the process of reading makefiles. That means that it should be used withinin "immediate" expansion context -- i.e. within commands that are executed during reading the makefile. Most commands, however, are executed after makefiles are read. Therefore, some commands will print the correct value smoothly, while in certain places, where "deferred" expansion is used, it will always expand to the root makefile name.

If you would want to use this variable within rule text, for example, you'll have to do tricks, because rule text always has deferred expansion. So, if your have the rule

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

it will always print the name of the root makefile. Instead, to force immediate expansion, you will have to create another variable with makefile-specific name (i.e. names of such variables should be different in each makefile):

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

or use eval:.

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

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

If you want to use the name of current makefile for debug purpose only, consider special debugging functions, like warning or info:.

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

These functions use "immediate" expansion and will print the correct value.


How to define such a $(current_makefile)?

You have to manually maintain stack of makefile inclusions. When you include a makefile, its name is placed to the top of the stack; when you return from included makefile to the outer one, the topmost name is popped out of stack. This is achieved by inserting special calls to the beginning and the end of makefile:

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

Now define the functions at the beginning of your root makefile.

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

If you're sure your make is new enough (version 3.81+), replace lastword call with builtin function:.

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

Is it useful?

Totally useless. An only use that might be useful here is to make 100 makefiles that are symlinks to one makefile, the rules in these makefiles depending on their names. But it can be achieved within one makefile and foreach-eval technique described in the manual. So my post was a complete waste of time, though I had some fun :-)

P Shved
  • 96,026
  • 17
  • 121
  • 165
11

This returns the name of the first Makefile called, i.e. the one at the bottom of the call stack:

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

When used in non-cross-recursive situations (e.g. for makedepend), it is just the name of the current makefile.

Narcolessico
  • 1,921
  • 3
  • 19
  • 19
3

I wanted to do something similar (for echoing the contents of the Makefile) for when I use Make for managing simple repetitive tasks. I came across this page and found it was exactly what I was after and really useful for my limited understanding of make.

My result after reading this page:

    # 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`
Keith M
  • 853
  • 10
  • 28
CoffeeMonster
  • 2,160
  • 4
  • 20
  • 34
0

G'day,

If you make a copy of your original makefile, say makefile_test, and then enter the command:

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

That will evaluate the makefile and your make environment but not execute any of the commands. Looking through the output file for references to makefile_test will show you what is set in make's environment and where that value is being set.

N.B. This can generate a lot of info! And don't add the -d (debug) switch which will generate tons of additional output about make's decision process but minimal additional info about make's env.

HTH

Rob Wells
  • 36,220
  • 13
  • 81
  • 146
0

The solutions here addresses 1) POSIX make with 2) Invoked, non included, makefile in 3) A Unix alike platform.

What the OP asked for:

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

The targets depends on the makefile, kind of bloated:

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;

Can be a bit simplified if make is invoked only for all targets.

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

With the previous approach is trivial to implement a solution for included makefiles based in grep and a unique pattern contained in the makefile.

I never answer when I feel the question got a proper solution.

Walter Waldo
  • 129
  • 2
  • 2
  • Amazing general answer, though somewhat opaque. Perhaps a high level breakdown as to why this works and to aid understanding? – Jay M Apr 05 '23 at 14:54