Как заставить GNU / сделать так, чтобы прекратить разыменование символических ссылок на каталоги - PullRequest
11 голосов
/ 05 декабря 2011

Руководство по GNU / Make §5.7 гласит следующее:

5.7 Рекурсивное использование make

Рекурсивное использование make-средств с использованием make в качестве команды в make-файле.Этот метод полезен, когда вам нужны отдельные make-файлы для различных подсистем, составляющих большую систему.Например, предположим, что у вас есть подкаталог 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 путь к каталогу, если он является символической ссылкой, всегда отменяется, поэтому нет способа получить «логическое» (как в pwd -L) имя каталога.Рассмотрим следующий пример.Имея следующий каталог Makefile в /tmp/b, который является символической ссылкой на каталог /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'
$ 

AsВы можете видеть, что pwd -P и $(CURDIR) всегда показывают разыменованную символическую ссылку.Но pwd -L работает только при смене каталога перед запуском make, что доказывает, что опция -C для GNU / Make всегда отменяет ссылку на путь к каталогу без веской причины.Я пытался найти какое-либо объяснение этого поведения в документации, но не смог.Также я не могу найти обходной путь для этой проблемы, не меняя каталог с помощью 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 () man page ничего об этом не упоминает, но естьобратите внимание на это в документации Borland Builder (! sic), здесь .Поэтому мне интересно, что bash делает в этом отношении.

1 Ответ

8 голосов
/ 06 декабря 2011

С помощью ephemient я смог понять это.Таким образом, происходит несколько вещей:

  1. Linux не поддерживает установку текущего рабочего каталога в символическую ссылку.chdir () всегда устанавливает его в настоящий каталог.
  2. Существует переменная PWD, представляющая текущий рабочий каталог, по соглашению.
  3. Некоторые функции / системные вызовы honor PWD переменная, а некоторые нет.
  4. Bash поддерживает «поддельный» путь, построенный с использованием символических имен, и соответственно устанавливает переменную PWD.

Это объясняет поведение gmake.Когда gmake вызывается sh, PWD обновляется до выполнения gmake процесса.Таким образом, PWD установлен на «символический» путь, и функции, выполняющие его, продолжают работать нормально.В противном случае gmake вызывает chdir (), который меняет рабочий каталог и устанавливает PWD без хитростей sh.Таким образом, все функции, включая те, которые поддерживают PWD, начинают возвращать «реальный» путь.

В целом, я бы сказал, что в зависимости от символического имени пути это плохая идея, и вещи могут легко развалиться.Например, потому что getcwd () системный вызов не заботится о PWD.Вызов cd перед запуском make работает как краткосрочное решение.

...