$(PWD) or $(shell pwd)

Though working with Makefile for quite a long time, I think I would never get a deeper insight into the fact beneath the “$(PWD)” and “$(shell pwd)” until an interesting problem was met just hours ago. And here is what happened:

Different behavors in make and sudo make

I got a Makefile, with some lines like this.

1
2
3
4
TOPDIR=$(PWD)
CONFIG_FILE=$(TOPDIR)/config.mk

include $(CONFIG_FILE)

I typed make as usual, it went well. But when I ran sudo make, the result really perplexed me.

1
2
3
$ sudo make
Makefile:4: /config.mk: No such file or directory
make: *** No rule to make target `/config.mk'. Stop.

I replaced TOPDIR=$(PWD) with TOPDIR=$(shell pwd), then it went right again. So I realized that something went wrong with “$(PWD)”, though I was not quite clear about the root reason. So more further experiments were made.

PWD, from shell environment

By printing make’s internal datebase using make -p, I found the following lines in the command’s output. So PWD is actually an environment variable used by Makefile, but a internal variable or function of Makefile.

1
2
# environment
PWD = /Users/jerome/

Hmm, the root user doesn’t have a environment variable named PWD. I thought I have got the answer, but it did not take very long to realize that I was wrong.

1
2
3
4
5
6
7
$ sudo echo $(PWD)
/Users/jerome/
$ sudo -s
$ echo $(PWD)
/Users/jerome
$ export | grep -w PWD
declare -x PWD="/Users/jerome/"

A clean environment for sudo‘s child process

Yes, as you can see, when we are root, we do have PWD in our environment. Of course, when I ran make as root, but sudo make, it went quit well. So, the sudo must be the ringleader!

So here’s the truth: When we invoke a command via sudo, sudo will fork another process to perform the command. And for some security reasons or of other aspects, not all the environments of the current process will be inheritted. The following example will demonstrate this point:

1
2
3
4
$ printenv | grep PWD
PWD=/Users/jerome
$ sudo printenv | grep PWD
$

Working across

By reading the manual of sudo, I found at least 2 methods are avaliable to walk across this issue. Method 1 is using -E option, which I think is the easiest one:

1
2
$ sudo -E printenv | grep PWD
PWD=/Users/jerome

And method 2 is modifying /etc/sudoers, the config file for sudo. More details could be found by man sudoers.