可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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?
回答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 any for Makefiles invoked from any directory:
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
current_dir := $(notdir $(patsubst %/,%,$(dir $(mkfile_path))))
回答2:
As taken from here;
ROOT_DIR:=$(shell dirname $(realpath $(lastword $(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
回答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
回答4:
THIS_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
回答5:
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
:
- make -f ../wherever/makefile
- make -C ../wherever
- make -C ~/wherever
- cd ../wherever; make
All give me wherever
for current_dir
and the absolute path to wherever
for mkfile_dir
.
回答6:
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.
回答7:
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.
回答8:
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)
回答9:
If the make variable contain the Relative path is ROOT_DIR
ROOT_DIR := ../../../
Them to get the absolute path just use below method.
ROOT_DIR := $(abspath $(ROOT_DIR))
Its work fine in GNUMake...
回答10:
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.