Reputation: 6665
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?
Upvotes: 330
Views: 515810
Reputation: 1414
For in-source builds where the build directory is the same as the source directory, the $(CURDIR) built-in variable can be used. It is the the current working directory (of the shell that invoked the Makefile), 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
Beware that this does not work for out-of-tree builds, e.g. if someone creates a build subdirectory and runs make -f ../Makefile
. Please see the top answer for a complete solution that always works, regardless of the build location.
Upvotes: 79
Reputation: 11
To determine the makefile's location you will need some directives that are executed in the shell script. Note that this line must execute before you import any other makefiles.
ROOT_DIR := $(shell dirname $(shell readlink -f $(firstword $(MAKEFILE_LIST))))
The above does the following
MAKEFILE_LIST
for the firstword, which is the file name of the makefile.The above commands take place in two shells. This is because we are using the output of two shell commands where one becomes the input of the other. If we remove one shell
directive it doesn't seem to work.
The firstword
part is actually calling a function defined in make, so it is not resolved in a subshell.
The :=
operator is used to ensure it is resolved immediately instead of when the variable is read.
Upvotes: 0
Reputation: 3370
For GNU make >= 3.81, which was introduced in 2006
ROOT_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
MAKEFILE_LIST
changes as include files come in and out of scope. The last item is the current file.
lastword
plucks the last item (Makefile name, relative to pwd
)
realpath
is built-in to make
, and resolves to a canonical path from filesystem root
dir
trims off the filename, leaving just the directory.
Note: The resulting ROOT_DIR
will include the trailing path separator (e.g. '/' on nix or '\' on Windows)
Upvotes: 40
Reputation: 5993
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
Upvotes: 204
Reputation: 888
use {}
instead of ()
cur_dir=${shell pwd}
parent_dir=${shell dirname ${shell pwd}}}
Upvotes: 2
Reputation: 561
As far as I'm aware this is the only answer here that works correctly with spaces:
space:=
space+=
CURRENT_PATH := $(subst $(lastword $(notdir $(MAKEFILE_LIST))),,$(subst $(space),\$(space),$(shell realpath '$(strip $(MAKEFILE_LIST))')))
It essentially works by escaping space characters by substituting ' '
for '\ '
which allows Make to parse it correctly, and then it removes the filename of the makefile in MAKEFILE_LIST
by doing another substitution so you're left with the directory that makefile is in. Not exactly the most compact thing in the world but it does work.
You'll end up with something like this where all the spaces are escaped:
$(info CURRENT_PATH = $(CURRENT_PATH))
CURRENT_PATH = /mnt/c/Users/foobar/gDrive/P\ roje\ cts/we\ b/sitecompiler/
Upvotes: 1
Reputation: 1539
One line in the Makefile should be enough:
DIR := $(notdir $(CURDIR))
Upvotes: -3
Reputation: 103
Solution found here : https://sourceforge.net/p/ipt-netflow/bugs-requests-patches/53/
The solution is : $(CURDIR)
You can use it like that :
CUR_DIR = $(CURDIR)
## Start :
start:
cd $(CUR_DIR)/path_to_folder
Upvotes: -1
Reputation: 166259
Here is one-liner to get absolute path to your Makefile
file using shell syntax:
SHELL := /bin/bash
CWD := $(shell cd -P -- '$(shell dirname -- "$0")' && pwd -P)
And here is version without shell based on @0xff answer:
CWD := $(abspath $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))))
Test it by printing it, like:
cwd:
@echo $(CWD)
Upvotes: 1
Reputation: 5675
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))
.
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 runcd /; make -f /home/username/project/Makefile
, thecurrent_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))))
Upvotes: 427
Reputation: 70289
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.
Upvotes: 11
Reputation: 113
update 2018/03/05 finnaly I use this:
shellPath=`echo $PWD/``echo ${0%/*}`
# process absolute path
shellPath1=`echo $PWD/`
shellPath2=`echo ${0%/*}`
if [ ${shellPath2:0:1} == '/' ] ; then
shellPath=${shellPath2}
fi
It can be executed correct in relative path or absolute path. Executed correct invoked by crontab. Executed correct in other shell.
show example, a.sh print self path.
[root@izbp1a7wyzv7b5hitowq2yz /]# more /root/test/a.sh
shellPath=`echo $PWD/``echo ${0%/*}`
# process absolute path
shellPath1=`echo $PWD/`
shellPath2=`echo ${0%/*}`
if [ ${shellPath2:0:1} == '/' ] ; then
shellPath=${shellPath2}
fi
echo $shellPath
[root@izbp1a7wyzv7b5hitowq2yz /]# more /root/b.sh
shellPath=`echo $PWD/``echo ${0%/*}`
# process absolute path
shellPath1=`echo $PWD/`
shellPath2=`echo ${0%/*}`
if [ ${shellPath2:0:1} == '/' ] ; then
shellPath=${shellPath2}
fi
$shellPath/test/a.sh
[root@izbp1a7wyzv7b5hitowq2yz /]# ~/b.sh
/root/test
[root@izbp1a7wyzv7b5hitowq2yz /]# /root/b.sh
/root/test
[root@izbp1a7wyzv7b5hitowq2yz /]# cd ~
[root@izbp1a7wyzv7b5hitowq2yz ~]# ./b.sh
/root/./test
[root@izbp1a7wyzv7b5hitowq2yz ~]# test/a.sh
/root/test
[root@izbp1a7wyzv7b5hitowq2yz ~]# cd test
[root@izbp1a7wyzv7b5hitowq2yz test]# ./a.sh
/root/test/.
[root@izbp1a7wyzv7b5hitowq2yz test]# cd /
[root@izbp1a7wyzv7b5hitowq2yz /]# /root/test/a.sh
/root/test
[root@izbp1a7wyzv7b5hitowq2yz /]#
old: I use this:
MAKEFILE_PATH := $(PWD)/$({0%/*})
It can show correct if executed in other shell and other directory.
Upvotes: -2
Reputation: 4152
Example for your reference, as below:
The folder structure might be as:
Where there are two Makefiles, each as below;
sample/Makefile
test/Makefile
Now, let us see the content of the Makefiles.
sample/Makefile
export ROOT_DIR=${PWD}
all:
echo ${ROOT_DIR}
$(MAKE) -C test
test/Makefile
all:
echo ${ROOT_DIR}
echo "make test ends here !"
Now, execute the sample/Makefile, as;
cd sample
make
OUTPUT:
echo /home/symphony/sample
/home/symphony/sample
make -C test
make[1]: Entering directory `/home/symphony/sample/test'
echo /home/symphony/sample
/home/symphony/sample
echo "make test ends here !"
make test ends here !
make[1]: Leaving directory `/home/symphony/sample/test'
Explanation, would be that the parent/home directory can be stored in the environment-flag, and can be exported, so that it can be used in all the sub-directory makefiles.
Upvotes: 0
Reputation: 4005
I tried many of these answers, but on my AIX system with gnu make 3.80 I needed to do some things old school.
Turns out that lastword
, abspath
and realpath
were not added until 3.81. :(
mkfile_path := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
mkfile_dir:=$(shell cd $(shell dirname $(mkfile_path)); pwd)
current_dir:=$(notdir $(mkfile_dir))
As others have said, not the most elegant as it invokes a shell twice, and it still has the spaces issues.
But as I don't have any spaces in my paths, it works for me regardless of how I started make
:
All give me wherever
for current_dir
and the absolute path to wherever
for mkfile_dir
.
Upvotes: 8