How to get current relative directory of your Makefile?

376,514

Solution 1

The shell function.

You can use shell function: current_dir = $(shell pwd). Or shell in combination with notdir, if you need not absolute path: current_dir = $(notdir $(shell pwd)).

Update.

Given solution only works when you are running make from the Makefile's current directory.
As @Flimm noted:

Note that this returns the current working directory, not the parent directory of the Makefile.
For example, if you run cd /; make -f /home/username/project/Makefile, the current_dir variable will be /, not /home/username/project/.

Code below will work for Makefiles invoked from any directory:

mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
current_dir := $(notdir $(patsubst %/,%,$(dir $(mkfile_path))))

Solution 2

As taken from here;

ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))

Shows up as;

$ cd /home/user/

$ make -f test/Makefile 
/home/user/test

$ cd test; make Makefile 
/home/user/test

Hope this helps

Solution 3

If you are using GNU make, $(CURDIR) is actually a built-in variable. It is the location where the Makefile resides the current working directory, which is probably where the Makefile is, but not always.

OUTPUT_PATH = /project1/bin/$(notdir $(CURDIR))

See Appendix A Quick Reference in http://www.gnu.org/software/make/manual/make.html

Solution 4

THIS_DIR := $(dir $(abspath $(firstword $(MAKEFILE_LIST))))

Solution 5

I like the chosen answer, but I think it would be more helpful to actually show it working than explain it.

/tmp/makefile_path_test.sh

#!/bin/bash -eu

# Create a testing dir
temp_dir=/tmp/makefile_path_test
proj_dir=$temp_dir/dir1/dir2/dir3
mkdir -p $proj_dir

# Create the Makefile in $proj_dir
# (Because of this, $proj_dir is what $(path) should evaluate to.)
cat > $proj_dir/Makefile <<'EOF'
path := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
cwd  := $(shell pwd)

all:
    @echo "MAKEFILE_LIST: $(MAKEFILE_LIST)"
    @echo "         path: $(path)"
    @echo "          cwd: $(cwd)"
    @echo ""
EOF

# See/debug each command
set -x

# Test using the Makefile in the current directory
cd $proj_dir
make

# Test passing a Makefile
cd $temp_dir
make -f $proj_dir/Makefile

# Cleanup
rm -rf $temp_dir

Output:

+ cd /tmp/makefile_path_test/dir1/dir2/dir3
+ make
MAKEFILE_LIST:  Makefile
         path: /private/tmp/makefile_path_test/dir1/dir2/dir3
          cwd: /tmp/makefile_path_test/dir1/dir2/dir3

+ cd /tmp/makefile_path_test
+ make -f /tmp/makefile_path_test/dir1/dir2/dir3/Makefile
MAKEFILE_LIST:  /tmp/makefile_path_test/dir1/dir2/dir3/Makefile
         path: /tmp/makefile_path_test/dir1/dir2/dir3
          cwd: /tmp/makefile_path_test

+ rm -rf /tmp/makefile_path_test

NOTE: The function $(patsubst %/,%,[path/goes/here/]) is used to strip the trailing slash.

Share:
376,514

Related videos on Youtube

boltup_im_coding
Author by

boltup_im_coding

#SOreadytohelp

Updated on April 26, 2020

Comments

  • boltup_im_coding
    boltup_im_coding about 4 years

    I have a several Makefiles in app specific directories like this:

    /project1/apps/app_typeA/Makefile
    /project1/apps/app_typeB/Makefile
    /project1/apps/app_typeC/Makefile
    

    Each Makefile includes a .inc file in this path one level up:

    /project1/apps/app_rules.inc
    

    Inside app_rules.inc I'm setting the destination of where I want the binaries to be placed when built. I want all binaries to be in their respective app_type path:

    /project1/bin/app_typeA/
    

    I tried using $(CURDIR), like this:

    OUTPUT_PATH = /project1/bin/$(CURDIR)
    

    but instead I got the binaries buried in the entire path name like this: (notice the redundancy)

    /project1/bin/projects/users/bob/project1/apps/app_typeA
    

    What can I do to get the "current directory" of execution so that I can know just the app_typeX in order to put the binaries in their respective types folder?

  • boltup_im_coding
    boltup_im_coding almost 11 years
    That does not work. It is the same problem. pwd prints the full path name, I just want the name of the actual current folder I'm in.
  • Nikolai Popov
    Nikolai Popov almost 11 years
    @unexpected62 What about notdir?
  • boltup_im_coding
    boltup_im_coding almost 11 years
    Thanks. I am a make noob. So what's going on here exactly? notdir is removing everything through the last slash in the output of pwd? I saw gnu.org/software/make/manual/html_node/File-Name-Functions.h‌​tml
  • Nikolai Popov
    Nikolai Popov almost 11 years
    Yep, notdir does just that.
  • Tom Gruner
    Tom Gruner over 10 years
    It needs to have the value expanded immediately so the := operator should be used. As in mkfile_path := and current_dir = (otherwise the right side values could be evaluated later when the MAKEFILE_LIST has changed after other Makefiles were included
  • simpleuser
    simpleuser about 10 years
    Note that a similar issue occurs is you use -C to specify the directory in which to make. The $PWD will be the directory you ran gmake from.
  • Simon Peverett
    Simon Peverett about 10 years
    From the GNU Make manual (page 51): " when GNU make starts (after it has processed any -C options) it sets the variable CURDIR to the pathname of the current working directory." Not the location of where the Makefile is located - although, they might be the same.
  • knocte
    knocte about 10 years
    sad thing is that this doesn't work for AutoMake (Makefile.am files) :(
  • Subfuzion
    Subfuzion over 9 years
    Downvoted because the answer is not technically correct, as noted by Simon Peverett in the previous comment.
  • Serge Roussak
    Serge Roussak over 9 years
    IMHO it would better to use internal make-function dir instead of shell dirname though it gets pathname with trailing / character.
  • sleepycal
    sleepycal over 9 years
    @SergeRoussak Could you perhaps write a seperate answer explaining why? I don't know enough about make to give an informed opinion.
  • Serge Roussak
    Serge Roussak over 9 years
    because of reduction of dependancies on external tools. Ie what if there will alias of dirname command at some system?..
  • mrosales
    mrosales over 9 years
    I know this is an old question but I just ran into and thought this could be useful. This also will not work when there is a space in the relative path of the makefile. Specifically, $(lastword "$(MAKEFILE_LIST)") of a makefile at path "Sub Directory/Makefile" will give you "Directory/Makefile". I dont think there is any way around this since $(MAKEFILE_LIST) with two makefiles gives you a single string "Makefile One Makefile Two, which cannot handle spaces
  • Craig Ringer
    Craig Ringer over 9 years
    ... unless you have spaces in any paths.
  • TrueY
    TrueY about 9 years
    @SimonPeverett: The expression in brackets means the the "current working directory AFTER -C opts applied". Namely $(CURDIR) gives the exactly the same results for "make -C xxx" and "cd xxx; make". Also it removes the trailing /. I tried tied with gmake v3.81. But You are right if make is called as make -f xxx/Makefile.
  • Thorsten Lorenz
    Thorsten Lorenz about 9 years
    This almost worked for me, but DIR had a leading whitespace, so a minor change made work perfectly: DIR:=$(strip $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))))
  • sleepycal
    sleepycal about 9 years
    Thanks @ThorstenLorenz, I've edited the answer to reflect this
  • robal
    robal over 8 years
    ... unless you have included some other makefile in previous line
  • fbence
    fbence over 8 years
    @mrosales I am having this same problem. You could get it from shell with ${PWD##*/} , but $(shell ${PWD##*/} ) complains, that *** unterminated call to function shell': missing )'.
  • Brent Bradburn
    Brent Bradburn over 8 years
    To reference the current makefile, the use of $MAKEFILE_LIST must precede any include operations (docs).
  • Brent Bradburn
    Brent Bradburn over 8 years
    Should use quotes -- at least around the argument to dirname -- in case there are spaces in the path.
  • Jesse Chisholm
    Jesse Chisholm over 8 years
    See my variant answer for gnu make version 3.80, which doesn't have lastword, realpath or abspath.
  • Zsigmond Lőrinczy
    Zsigmond Lőrinczy over 8 years
    I, for one, have compiled gnu-make-3.82 on aix (5-6-7) without problems.
  • Jesse Chisholm
    Jesse Chisholm over 8 years
    Yes, by 3.81 the needed functions for the earlier solutions were implemented. My answer is for older systems with 3.80 or earlier. Sadly, at work I am not allowed to add or upgrade tools to the AIX system. :(
  • Jesse Chisholm
    Jesse Chisholm over 8 years
    This gets the current working directory, not the makefile's home directory.
  • parasrish
    parasrish over 8 years
    These are the lines in the Makefile. Now, as the Makefile command executes, this will get the path at which the Makefile is. I understand "makefile home directory" is refering to the same, i.e. the directory-path in which Makefile is executing.
  • parasrish
    parasrish over 8 years
    @Jesse Chisholm please revisit. I have explained with usage.
  • ntc2
    ntc2 almost 8 years
    The := (vs plain =) is important if you have any include statements, since otherwise the included makefiles will come after the current makefile.
  • Keith M
    Keith M over 7 years
    "It can show correct if executed if other shell and other directory" doesn't make sense in English. Can you try explaining again?
  • zhukunqian
    zhukunqian over 7 years
    sorry for my poor english
  • Keith M
    Keith M over 7 years
    Thanks for the edit, I see you meant IN now. Can you explain what this does before I try it? I'm not sure how to use it. Like what do you mean by "other shell"
  • Mark K Cowan
    Mark K Cowan over 7 years
    CURDIR works for me where PWD did not. I did mkdir -p a/s/d then in each folder had a makefile which printed PWD and CURDIR before +$(MAKE) <subdir>.
  • fbence
    fbence over 6 years
    these don't seem to work if there is a space in the path
  • Bruno Bronosky
    Bruno Bronosky about 6 years
    I have created an answer that demonstrates this. stackoverflow.com/a/49740268/117471
  • sherrellbc
    sherrellbc about 6 years
    @robal Yep. That is what I just encountered. This works great if you only have two Makefiles (the main one plus an included one).
  • CMCDragonkai
    CMCDragonkai about 6 years
    The updated methods doesn't work if there are spaces in the path to the Makefile. It's the dir that fails if there are spaces. That should be mentioned in the answer along with any possible workarounds.
  • CaTx
    CaTx almost 6 years
    That current_dir doesn't work for me. $(PWD) does and it's much simpler.
  • villapx
    villapx over 5 years
    @mrosales @fbence GNU make, in general, doesn't really handle paths that have spaces in them. Something as simple as SRCS variable with all your source file names in it no longer works if a single file has a space in its name.
  • EMon
    EMon over 5 years
    Critical Importance! The second example above needs the := assignment operator or else some very weird and angry things can happen with complex makefiles (trust me)
  • Johan Boulé
    Johan Boulé about 5 years
    First one is a repeated error and doesn't work for out-of-tree-builds.
  • Johan Boulé
    Johan Boulé about 5 years
    This answer has so many wrong things it can't possibly be fixed. I suggest a simple removal.
  • Johan Boulé
    Johan Boulé about 5 years
    A repeated error: it doesn't work for out-of-tree-builds. Also, your gnome terminal provides a simple way to copy text: just select it. The rumor has Imgur is brankrupt.
  • kkm
    kkm about 5 years
    @SergeRoussak: dirname (and its cousin basename) are POSIX. I agree, "what if your system does not have dirname?" is a valid question, but so is "what if your system does not have make?" :-) Also, AFAIK, $(realpath ) is a relatively recent, and GNU-make specific. So here is more dependency on tools for ya. But your $(dir ) suggestion is a good one!
  • Sean
    Sean almost 5 years
    Welcome to Stack Overflow. Can you add more detail to your answer? The question states that $(CURDIR) was already tried unsuccessfully.
  • Sz.
    Sz. almost 5 years
    WARNING, quick-googlers: This is not the directory, where the makefile is, but the current working directory (where make was launched in). It is, indeed, what OP really wanted, but the question title is bogus, so the question itself is inconsistent. So, this is a correct answer to an incorrect question. ;)
  • Stéphane Gourichon
    Stéphane Gourichon almost 5 years
    current_dir is not what I expected. mkfile_dir := $(dir $(mkfile_path)) is what I expected: full path to the makefile directory.
  • Richard Kiefer
    Richard Kiefer over 4 years
    Note that you need to enforce immediate variable expansion using the := operator. Otherwise, you get funky behavior.
  • Victor Sergienko
    Victor Sergienko over 4 years
    "solution only works when you are running make from the Makefile's current directory" is a mild way to say "not really working". I would put the latest piece at the top of the answer.
  • UpAndAdam
    UpAndAdam over 4 years
    This is flat out wrong and a redundant wrong answer
  • UpAndAdam
    UpAndAdam over 4 years
    @CMCDragonkai except that answer is abysmally wrong... any answer of PWD is wrong. And if you are going to be that incorrect use the built in CURDIR instead.
  • carbolymer
    carbolymer over 4 years
    does not work - if you're including other files from Makefile - this will return the path of the last included file!
  • Guss
    Guss almost 4 years
    This works well for me (haven't tested spaces in dirs, but I don't expect to encounter this). The main issue I had with this code is that $(dir) retains the last path separator. Adding $(realpath) before it solves that problem.
  • Mike Maxwell
    Mike Maxwell over 3 years
    @carbolmyer: I use included makefiles extensively. I think that by using $(firstword...) instead of $(lastword...), this can be made to work, assuming the makefile you want is the first one you read. But I won't claim that this works in every situation. In particular, it would not work to find the directory for an intermediate 'include'd makefile. So the statement in my case is current_dir=$(dir $(abspath $(firstword $(MAKEFILE_LIST)))) It is a little surprising that make doesn't have a built-in variable for the full path of the current makefile.
  • devatherock
    devatherock over 3 years
    Changing mkfile_path to mkfile_path := $(lastword $(abspath $(MAKEFILE_LIST))) works for me when the directory path contains spaces
  • user503582
    user503582 over 2 years
    This should be the correct answer. No need to reinvent the wheel. Make does it for you ootb.