Linux 如何使GNU/make stop取消引用指向目录的符号链接
GNU/Make手册§5.7规定如下: 5.7循环使用make 递归使用make意味着在makefile中使用make作为命令。 当您希望为不同的应用程序创建单独的makefile时,此技术非常有用 组成更大系统的子系统。例如,假设您有 一个子目录subdr,它有自己的makefile,您希望 要在子目录上运行make的包含目录的makefile。 您可以这样做:Linux 如何使GNU/make stop取消引用指向目录的符号链接,linux,makefile,build-process,symlink,gnu-make,Linux,Makefile,Build Process,Symlink,Gnu Make,GNU/Make手册§5.7规定如下: 5.7循环使用make 递归使用make意味着在makefile中使用make作为命令。 当您希望为不同的应用程序创建单独的makefile时,此技术非常有用 组成更大系统的子系统。例如,假设您有 一个子目录subdr,它有自己的makefile,您希望 要在子目录上运行make的包含目录的makefile。 您可以这样做: subsystem: cd subdir && $(MAKE) or, equivalently
subsystem:
cd subdir && $(MAKE) or, equivalently, this (see Summary of Options):
subsystem:
$(MAKE) -C subdir
因此,它基本上意味着cd subdir&&$(MAKE)
与$(MAKE)-C subdir
相同
然而,事实证明,这并不是一个真正的等价物。使用-C
选项时,目录路径(如果是符号链接)总是被取消引用,因此无法获取“逻辑”(如pwd-L
)目录名。考虑下面的例子。在/tmp/b
目录中具有以下Makefile
,它是指向/tmp/a/
目录的符号链接:
foo:
@echo PWDL=$(shell pwd -L)
@echo PWDP=$(shell pwd -P)
@echo CURDIR=$(CURDIR)
现在,让我们以不同的方式调用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'
$
如您所见,pwd-p
和$(CURDIR)
始终显示取消引用的符号链接。但是pwd-L
仅在运行make
之前更改目录时才起作用,这证明了GNU/make的-C
选项总是使其取消引用目录路径,这是没有充分理由的。我试图在文档中找到这种行为的任何解释,但无法找到。在运行make
(或通过LD\u PRELOAD
)之前,如果不使用cd
更改目录,我都无法想出解决此问题的方法
问题是——以前有没有其他人遇到过这个问题,有没有解释或解决方法?谢谢
更新:
为了弄清真相,我下载了make
的源代码,没有找到任何目录的特殊处理,只调用了chdir
。所以我写了一个小程序来进行一个实验,下面是我的发现
当您在符号链接目录(/tmp/b
)中并试图将目录更改为相同目录时,该操作无效,当前工作目录继续指向符号链接
当您调用chdir()
并指定完整路径或相对路径时,它会在更改目录之前取消引用该路径。这是一个证明:
$ 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
$
$cat cd.cpp
#包括
#包括
int main()
{
chdir(“/tmp/b/”);
printf(“当前目录:%s\n”,
获取当前目录名称();/*请原谅我的内存泄漏*/
}
$gcc-o测试。/cd.cpp
$pwd
/tmp/b
美元/测试
当前目录:/tmp/b
$cd/
美元/桶/测试
当前目录:/tmp/a
$cd/
$/tmp/b/测试
当前目录:/tmp/a
$
所以,看起来不是libc就是Linux在捉弄我,我以前根本不在乎。最重要的是,bashs
cd`的工作方式有所不同
奇怪的是,没有提到任何关于它的内容,但是在Borland Builder(!sic)文档中有一个关于它的注释。因此,我想知道bash在这方面做了什么。在他的帮助下,我能够理解这一点。因此,发生的事情很少:
chdir()
始终将其设置为实际目录PWD
的变量表示当前工作目录PWD
,有些则不调用PWD
变量gmake
被sh
调用时,PWD
在执行gmake
过程之前更新。因此,PWD
被设置为“符号”路径,表示该路径的函数继续正常工作。否则,gmake
调用chdir()
,这将更改工作目录并设置PWD
,而不使用sh的技巧。因此,所有函数,包括那些遵守PWD
的函数,都开始返回“真实”路径
总而言之,我想说的是,依赖于符号路径名是一个坏主意,事情很容易就会分崩离析。例如,因为
getcwd()
系统调用不关心PWD
。不过,在运行make
之前调用cd
可以作为短期解决方案。实际上,这是我期望make的行为。“逻辑”目录纯粹是shell的发明,它做了额外的工作来维持这种错觉。@ephemient:我以为它在做类似的事情,但奇怪的是,当执行cd
并调用调用getcwd()
的进程时,getcwd()
返回一个指向符号链接的路径,而不是真正的目录。我尝试使用symlink的完整路径调用chdir()
,但无法获得相同的效果。我想知道到底发生了什么。bash
将工作目录缓存在$PWD
中<代码>光盘在shell中更新$PWD
<如果shell中的code>pwd与实际工作目录匹配,则返回$pwd
。使用cd&&$(MAKE)
时,将为递归调用设置变量;当您使用$(MAKE)-C时,它不是,并且pwd
会返回到未缓存的物理路径。@ephemient:整个过程会一直工作到。。。。我要草拟一个关于这件事的小答案。一团糟。顺便说一句:Glibc的get\u current\u dir\u name
检查getenv(“PWD”)
<但是,code>make
和bash
只需使用getcwd
。显然,这些都是具体实现的细节。