[英]How to make GNU/Make stop de-referencing symbolic links to directories
GNU/Make manual §5.7 states the following: GNU / Make手册§5.7声明如下:
5.7 Recursive Use of make 5.7递归使用make
Recursive use of make means using make as a command in a makefile. 递归使用make意味着使用make作为makefile中的命令。 This technique is useful when you want separate makefiles for various subsystems that compose a larger system. 当您需要为构成更大系统的各种子系统创建单独的makefile时,此技术非常有用。 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. 例如,假设您有一个子目录subdir,它有自己的makefile,并且您希望包含目录的makefile在子目录上运行make。 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
. 因此,基本上它暗示cd subdir && $(MAKE)
与$(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. 使用-C
选项时,目录路径(如果是符号链接)始终是取消引用的,因此无法获得“逻辑”(如在pwd -L
)目录名称。 Consider the following example. 请考虑以下示例。 Having the following Makefile
in /tmp/b
directory, which is a symlink to /tmp/a/
directory: 在/tmp/b
目录中有以下Makefile
,它是/tmp/a/
目录的符号链接:
foo:
@echo PWDL=$(shell pwd -L)
@echo PWDP=$(shell pwd -P)
@echo CURDIR=$(CURDIR)
Now, let's invoke make
differently: 现在,让我们make
不同方式调用:
$ 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. 如您所见, pwd -P
和$(CURDIR)
始终显示取消引用的符号链接。 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. 但是pwd -L
只有在运行make
之前更改目录时才有效,这证明GNU / Make的-C
选项总是使它取消引用目录路径,这是没有充分理由的。 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
). 在运行make
(或通过LD_PRELOAD
非常糟糕的挂钩)之前,我无法在不使用cd
更改目录的情况下为此问题找到解决方法。
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
. 试图找到它的底部,我已下载make
源代码,并没有找到任何特殊的目录处理,只调用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. 当您处于符号链接目录( /tmp/b
)并尝试将目录更改为相同时,该操作无效,并且当前工作目录继续指向符号链接。
When you call chdir ()
and specify either full or relative path, it de-references it before changing directory. 当您调用chdir ()
并指定完整路径或相对路径时,它会在更改目录之前取消引用它。 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. 因此,看起来libc
或Linux正在玩弄我以前并不真正关心的技巧。 And on top of that, bash s
cd` is working somehow different. 最重要的是,bash s
cd`的工作方式有所不同。
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 . 奇怪的是, Linux的chdir ()
手册页并没有提及任何关于它,但有一张纸条上它在Borland的生成器(!原文如此)的文件, 在这里 。 So I wonder what bash
does in this regard. 所以我想知道bash
在这方面做了什么。
With ephemient 's help I was able to figure this one out. 在epippient的帮助下,我能够把这一点弄清楚。 So there are few things that are going on: 所以很少有事情发生:
chdir ()
always sets it to the real directory. chdir ()
总是将它设置为真实目录。 PWD
that represents a current working directory, by convention. 根据惯例,有一个名为PWD
的变量代表当前工作目录。 PWD
variable and some do not. 一些函数/系统调用会使用PWD
变量,而PWD
一些则不会。 PWD
variable accordingly. Bash维护一个使用符号名称构建的“假”路径,并相应地设置PWD
变量。 It explains gmake
behavior. 它解释了gmake
行为。 When gmake
is invoked by sh
, PWD
is updated before gmake
process is executed. 当sh
调用gmake
,在执行gmake
进程之前更新PWD
。 Thus, PWD
is set to "symbolic" path and functions honoring it continue to work fine. 因此, PWD
被设置为“符号”路径并且功能尊重它继续正常工作。 Otherwise, gmake
calls chdir ()
, which changes working directory and sets PWD
without sh's tricks. 否则, gmake
调用chdir ()
,它会更改工作目录并设置PWD
而不需要使用sh的技巧。 Thus, all functions including those honoring PWD
start to return "real" path. 因此,包括那些尊重PWD
所有功能开始返回“真实”路径。
All in all, I'd say that depending on symbolic path name is a bad idea and things can easily fall apart. 总而言之,我会说取决于符号路径名称是一个坏主意,事情很容易崩溃。 For example, because getcwd ()
system call doesn't care about PWD
. 例如,因为getcwd ()
系统调用不关心PWD
。 Invoking cd
before running make
works as a short term solution though. 在运行make
之前调用cd
可以作为短期解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.