2009-07-27 10 views
5

que estoy usando un código similar al siguiente en un Makefile:

empty:= 
space:= $(empty) $(empty) 
path_escape = $(subst $(space),\$(space),$(1)) 

TOP=$(call path_escape,$(abspath .)) 
TARGET=$(TOP)/foo 

$(info TOP='$(TOP)') 
$(info TARGET='$(TARGET)') 

all: $(TARGET) 

$(TARGET): 
    touch '$(notdir [email protected])' 

.PHONY: $(TARGET) 

Si utilizo esto en un directorio sin espacios, space-test decir, que funciona bien:

$ make 
TOP='/tmp/space-test' 
TARGET='/tmp/space-test/foo' 
touch 'foo' 

Sin embargo, si lo uso en un directorio con espacios, digo space test, entonces $(notdir) hace las cosas mal:

TOP='/tmp/space\ test' 
TARGET='/tmp/space\ test/foo' 
touch 'space foo' 

Lo que sucede aquí es que $(notdir) interpreta como /tmp/space test/foo dos caminos y devuelve la "parte de archivos" de tanto (es decir, space y foo). La parte extraña de esto es que TARGET está escapado correctamente; de alguna manera, dentro de la regla o dentro de $(notdir), los escapes de la barra invertida se están ignorando.

¿Qué estoy haciendo mal aquí?

Respuesta

9

La función $(notdir) en GNU Make toma una lista de argumentos, separados por espacios. Algunas funciones admiten espacios de escape con \\, pero $(notdir) no es una de ellas.

Esto debería funcionar:

s? = $(subst $(empty) ,?,$1) 
?s = $(subst ?, ,$1) 
notdirx = $(call ?s,$(notdir $(call s?,$1))) 

$(TARGET): 
    touch '$(call notdirx,[email protected])' 

Esto define una versión de "espacio seguro" de notdir llamada notdirx. Es bastante simple: s? primero convierte todos los espacios en signos de interrogación (con la esperanza de que no puedan estar presentes en los nombres de archivo) y ?s convierte de nuevo. Mientras tanto podemos llamar de manera segura a la función original notdir.

Para obtener un resumen excelente sobre GNU Make y espacios en los nombres de archivos, consulte GNU Make meets file names with spaces in them.

+1

Gracias, Ville. Es bastante ridículo que no haya forma de evitar entradas a $ (notdir) excepto a través de este truco (o al menos eso parece). –

+1

Sí. GNU Make realmente podría usar una versión 2 del lenguaje y funciones estándar opcionalmente habilitada (retrocompatible). O tal vez es mejor usar, por ejemplo, SCons o algo con un lenguaje de programación real. –

0

Esto es sólo un tiro en la oscuridad:

TOP='"/home/chris/src/tests/make/space test"' 
+7

Gary, no te odio, estoy lleno de amor. No tomes los votos negativos personalmente, solo indican si una respuesta es correcta y/o útil. En este caso, no, esto no funciona. –

+6

No estamos bajando ** usted **, estamos bajando su ** respuesta **. No te sientas mal por eso. – JesperE

0

Asumiendo que tiene un shell de Unix, usted podría pagar:

notdirx = $(shell basename '$1') 
dirx = $(shell dirname '$1') 

Una estrategia similar podría aplicarse a otras funciones. Solo recuerde las comillas alrededor de la variable que contiene el texto infectado de espacio en blanco que desea tratar como un único argumento. Esto también lo protegerá de otros caracteres especiales (¡excepto las comillas!). He aquí un ejemplo de doble barra invertida escapar ningún espacio en el resultado de un pegote de comodín:

$(shell ls -1 '*.foo' | sed 's/ /\\\\ /g') 

de Windows está poniendo entre paréntesis en los nombres de directorio ahora, también: C:\Program Files (x86)\ Todavía no está claro para mí lo son las implicaciones de esto cuando usando make.

Cuestiones relacionadas