I've got the following Makefile
(GNU Make 3.81):
CWD:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
all:
pwd
cd "$(CWD)/.."
pwd
cd ".."
pwd
Here is the output:
$ make
pwd
/Users/kenorb/temp/foo
cd "/Users/kenorb/temp/foo/.."
pwd
/Users/kenorb/temp/foo
cd ".."
pwd
/Users/kenorb/temp/foo
It seems that cd
'ing to parent directory via ..
doesn't take any effect.
How do I change the current working directory to a parent directory relatively to Makefile
file?
This issue has to do with the fact that each line of a rule's recipe is executed in a dedicated shell instance (i.e.: a new process). So, running cd
in one line, won't have any effect for a command in another line, because these commands are executed by different processes.
Changing the working directory for a recipe
You can either use .ONESHELL
(GNU Make 3.82 or later) to run all the recipe's lines in a single and the same shell instance:
CWD:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
.ONESHELL:
all:
pwd
cd "$(CWD)/.."
pwd
cd ".."
pwd
or just keep all the commands in a single line:
CWD:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
all:
pwd; cd "$(CWD)/.."; pwd; cd ".."; pwd
The change of the working directory takes effect only inside that recipe.
Note that changing the current working directory inside the makefile for the shell that invoked make
is not possible, since that's a process' property, and the running make
instance that will execute cd
is another (sub)process. Therefore, it will only change the working directory of that subprocess.
That is the same reason you cannot change the working directory of a shell by executing a script without sourcing it: because the script runs in a new shell instance (i.e.: a subprocess).