2011-12-05 11 views
10

GNU/Make Manual §5.7 indica lo siguiente:Cómo hacer que GNU/Haz parada de referencias enlaces simbólicos a los directorios

5,7 Uso recurrente de hacer

El uso recurrente de la marca significa usar como hacer un comando en un archivo MAKE Esta técnica es útil cuando se quieren makefiles separados para varios subsistemas que componen un sistema más grande. Por ejemplo, suponga que tiene subdirectorio subdirectorio que tiene su propio archivo MAKE, y le gustaría contener el archivo MAKE para ejecutar make en el subdirectorio. Puede hacerlo escribiendo esto:

subsystem: 
     cd subdir && $(MAKE) or, equivalently, this (see Summary of Options): 

subsystem: 
     $(MAKE) -C subdir 

Así que, básicamente, implica que cd subdir && $(MAKE) es lo mismo que $(MAKE) -C subdir.

Sin embargo, resulta que no es realmente un equivalente. Al utilizar la opción -C, la ruta del directorio, si es un enlace simbólico, siempre se desreferencia, por lo que no hay forma de obtener el nombre de directorio "lógico" (como en pwd -L). Considera el siguiente ejemplo. Tener la Makefile en /tmp/b siguiente directorio, que es un enlace a /tmp/a/ directorio:

foo: 
    @echo PWDL=$(shell pwd -L) 
    @echo PWDP=$(shell pwd -P) 
    @echo CURDIR=$(CURDIR) 

Ahora, vamos a invocar make diferente:

$ 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' 
$ 

Como se puede ver, pwd -P y $(CURDIR) están mostrando siempre de- enlace simbólico referenciado. Pero pwd -L funciona solo cuando se cambia de directorio antes de ejecutar make, lo que prueba que la opción -C de GNU/Make siempre hace que desinere la ruta del directorio, sin una buena razón. Estaba tratando de encontrar alguna explicación para este comportamiento en la documentación pero no pude. Ni puedo encontrar una solución para este problema sin cambiar el directorio usando cd antes de ejecutar make (o sin ganchos muy malos a través de LD_PRELOAD).

La pregunta es: ¿alguien más se encontró con este problema antes, tiene una explicación o una solución? ¡Gracias!

ACTUALIZACIÓN:

tratando de llegar al fondo del mismo, he descargado el código fuente de make y no encontró ningún proceso especial de directorios, sólo llama a chdir. Así que escribí un pequeño programa para realizar un experimento, y aquí está lo que encontré.

Cuando está en un directorio enlazado (/tmp/b) e intenta cambiar el directorio al mismo, la operación no tiene ningún efecto y el directorio de trabajo actual continúa apuntando al enlace simbólico.

Cuando llame al chdir() y especifique una ruta de acceso completa o relativa, la desreferenciará antes de cambiar el directorio. He aquí una prueba:

$ 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 
$ 

por lo que parece, ya sea libc o Linux está jugando trucos en mí que no me importa antes.Y además de eso, bash s cd` funciona de alguna manera diferente.

Por extraño que parezca, Linux chdir() man page no menciona nada al respecto, pero hay una nota en la documentación de Borland Builder (! Sic), here. Entonces me pregunto qué hace bash en este sentido.

+1

Este es el comportamiento que esperaría de hacer, en realidad. El directorio "lógico" es puramente una invención del caparazón, que hace un trabajo extra para mantener la ilusión. – ephemient

+0

@ephemient: Pensé que estaba haciendo algo así, pero curiosamente, al hacer 'cd' e invocar un proceso que llama a' getcwd() ',' getcwd() 'devuelve una ruta al enlace simbólico, y no al directorio real. Intenté llamar a 'chdir()' con la ruta completa al enlace simbólico y no puedo obtener el mismo efecto. Me pregunto qué está pasando exactamente. –

+0

'bash' almacena en caché el directorio de trabajo en' $ PWD'. 'cd' en shell actualizaciones' $ PWD'. 'pwd' en shell devuelve' $ PWD' si coincide con el directorio de trabajo real. Cuando usa 'cd && $ (MAKE)', la variable se establece para la invocación recursiva; cuando usas '$ (MAKE) -C', no lo es, y' pwd' vuelve a la ruta física no guardada en la memoria caché. – ephemient

Respuesta

7

Con la ayuda de ephemient pude resolver esto. Entonces, hay algunas cosas que están sucediendo:

  1. Linux no admite tener el directorio de trabajo actual configurado en un enlace simbólico. chdir() siempre lo establece en el directorio real.
  2. Hay una variable llamada PWD que representa un directorio de trabajo actual, por convención.
  3. Algunas de las funciones/llamadas al sistema hacen honor a la variable PWD y otras no.
  4. Bash mantiene una ruta "falsa" construida utilizando nombres simbólicos y establece PWD variable en consecuencia.

Comenta gmake comportamiento. Cuando gmake es invocado por sh, PWD se actualiza antes de que se ejecute el proceso gmake. Por lo tanto, PWD se establece en la ruta "simbólica" y las funciones que la cumplen continúan funcionando bien. De lo contrario, gmake llama al chdir(), que cambia el directorio de trabajo y establece PWD sin trucos de sh. Por lo tanto, todas las funciones, incluidas las que hacen honor a PWD, comienzan a devolver la ruta "real".

En general, yo diría que dependiendo del nombre de la ruta simbólica es una mala idea y las cosas pueden desmoronarse fácilmente. Por ejemplo, porque la llamada al sistema getcwd() no se preocupa por PWD. Invocar cd antes de ejecutar make funciona como una solución a corto plazo sin embargo.

Cuestiones relacionadas