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 делает в этой связи.