GNU/Make manual §5.7 states the following:
5.7 Recursive Use of make
Recursive use of make means using make as a command in a makefile. This technique is useful when you want separate makefiles for various subsystems that compose a larger system. For example, suppose you have a subdirectory subdir which has its own makefile, and you would like the containing directory's makefile to run make on the subdirectory. You can do it by writing this:
subsystem: cd subdir && $(MAKE) or, equivalently, this (see Summary of Options): subsystem: $(MAKE) -C subdir
So, basically it implies that cd subdir && $(MAKE)
is the same as $(MAKE) -C subdir
.
However, it turns out that it is not really an equivalent. When using -C
option, the directory path, if it is a symlink, is always de-referenced, so there is no way to get "logical" (as in pwd -L
) directory name. Consider the following example. Having the following Makefile
in /tmp/b
directory, which is a symlink to /tmp/a/
directory:
foo:
@echo PWDL=$(shell pwd -L)
@echo PWDP=$(shell pwd -P)
@echo CURDIR=$(CURDIR)
Now, let's invoke make
differently:
$ pwd
/tmp
$ (cd b && make foo)
PWDL=/tmp/b
PWDP=/tmp/a
CURDIR=/tmp/a
$ make -C b foo
make: Entering directory `/tmp/a'
PWDL=/tmp/a
PWDP=/tmp/a
CURDIR=/tmp/a
make: Leaving directory `/tmp/a'
$ make --directory=b foo
make: Entering directory `/tmp/a'
PWDL=/tmp/a
PWDP=/tmp/a
CURDIR=/tmp/a
make: Leaving directory `/tmp/a'
$
As you can see, pwd -P
and $(CURDIR)
are always showing de-referenced symbolic link. But pwd -L
works only when changing directory before running make
, which proves that -C
option to GNU/Make always makes it de-reference the directory path, for no good reason. I was trying to find any explanation for this behavior in the documentation but couldn't. Neither I can come up with a workaround for this problem without changing directory using cd
before running make
(or w/o very bad hooks trough LD_PRELOAD
).
The question is - did anyone else run into this problem before, have an explanation or a workaround? Thanks!
UPDATE:
Trying to get to the bottom of it, I have downloaded source code for make
and did not find any special processing of directories, only calls to chdir
. So I wrote a little program to conduct an experiment, and here is what I found.
When you are in a symlinked directory (/tmp/b
) and trying to change directory to the same, the operation has no effect and current working directory continues to point to the symbolic link.
When you call chdir ()
and specify either full or relative path, it de-references it before changing directory. Here is a prove:
$ cat cd.cpp
#include <stdio.h>
#include <unistd.h>
int main ()
{
chdir ("/tmp/b/");
printf ("Current dir: %s\n",
get_current_dir_name ()); /* Forgive my memory leak. */
}
$ gcc -o test ./cd.cpp
$ pwd
/tmp/b
$ ./test
Current dir: /tmp/b
$ cd ../
$ ./b/test
Current dir: /tmp/a
$ cd /
$ /tmp/b/test
Current dir: /tmp/a
$
So it seems like either libc
or Linux is playing tricks on me that I didn't really care about before. And on top of that, bashs
cd` is working somehow different.
Strangely enough, Linux chdir ()
man page doesn't mention anything about it, but there is a note on it in Borland Builder (!sic) documentation, here. So I wonder what bash
does in this regard.
cd
and invoking a process that callsgetcwd ()
,getcwd ()
returns a path to symlink, and not the real directory. I have tried to callchdir ()
with full path to symlink and cannot get the same effect. I am wondering what exactly is going on. – Cubitalbash
caches the working directory in$PWD
.cd
in shell updates$PWD
.pwd
in shell returns$PWD
if it matches the real working directory. When you usecd && $(MAKE)
, the variable is set for the recursive invocation; when you use$(MAKE) -C
, it's not, andpwd
falls back to the uncached physical path. – Darlleenget_current_dir_name
does checkgetenv("PWD")
.make
andbash
just usegetcwd
, however. And obviously, this is all implementation-specific detail. – Darlleenchdir ()
to a symlink, if only there waschdir ()
accepting inode... Anyways, I will keep far far away from "symlinks as cwd" concept in the future. Thanks for your help figuring this out! – Cubital