GNU/Make manual §5.7 гласит следующее:
5.7 Рекурсивное использование make
Рекурсивное использование make означает использование make в качестве команды в make файле. Этот метод полезен, когда вам нужны отдельные make файлы для различных подсистем, которые составляют более крупную систему. Например, предположим, что у вас есть subdirectory subdir, у которого есть свой собственный make файл, и вы хотите, чтобы содержащийся в make файле каталог запускал make в подкаталоге. Вы можете сделать это, написав это:
subsystem: cd subdir && $(MAKE) or, equivalently, this (see Summary of Options): subsystem: $(MAKE) -C subdir
Итак, в основном это означает, что cd subdir && $(MAKE)
совпадает с $(MAKE) -C subdir
.
Однако оказывается, что это не эквивалент. При использовании -C
путь к каталогу, если он является символической ссылкой, всегда -C
, поэтому нет способа получить "логический" (как в pwd -L
) имя каталога. Рассмотрим следующий пример. Имея следующий Makefile
в каталоге /tmp/b
, который является символической /tmp/a/
каталог /tmp/a/
:
foo:
@echo PWDL=$(shell pwd -L)
@echo PWDP=$(shell pwd -P)
@echo CURDIR=$(CURDIR)
Теперь пусть invoke 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
, что доказывает, что опция -C
для GNU/Make всегда делает ее -C
ссылки на путь к каталогу, без уважительной причины. Я пытался найти какое-либо объяснение этого поведения в документации, но не смог. Я также не могу придумать обходной путь для этой проблемы, не меняя директорию с использованием cd
перед запуском make
(или с очень плохими крючками через LD_PRELOAD
).
Вопрос в том, кто-нибудь еще сталкивался с этой проблемой раньше, имеет объяснение или обходное решение? Благодарю!
ОБНОВИТЬ:
Пытаясь разобраться в этом, я загрузил исходный код для 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
$
Кажется, что либо libc
либо Linux играют на меня трюки, которые мне на самом деле не нравились раньше. И вдобавок к этому, bash s
cd 'работает как-то иначе.
Как ни странно, Linux chdir()
человек страницы ничего об этом не говорится, но есть записка о нем в Borland Builder (! SIC) документации, здесь. Так интересно, что bash
делает в этой связи.