Utilizzando Make $ (dir) o $ (notDIR) su un percorso con spazi
Domanda
Sto utilizzando il codice simile al seguente in 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 $@)'
.PHONY: $(TARGET)
Se io uso questo in una directory senza spazi, diciamo space-test
, funziona benissimo:
$ make
TOP='/tmp/space-test'
TARGET='/tmp/space-test/foo'
touch 'foo'
Tuttavia, se lo uso in una directory con gli spazi, dire space test
, quindi $(notdir)
fa la cosa sbagliata:
TOP='/tmp/space\ test'
TARGET='/tmp/space\ test/foo'
touch 'space foo'
Quello che sta succedendo qui è che $(notdir)
interpreta /tmp/space test/foo
come due percorsi e restituisce la "parte del file" di sia (vale a dire, space
e foo
). La parte strana di questo è che TARGET
sia correttamente sfuggito; in qualche modo, all'interno della regola o $(notdir)
all'interno, le fughe backslash vengono ignorati.
Che cosa sto facendo male qui?
Soluzione
La funzione $(notdir)
in GNU Make prende una lista di argomenti, separati da spazi. Alcune funzioni supportano spazi fuga con \\
, ma $(notdir)
non è uno di loro.
Questo dovrebbe funzionare:
s? = $(subst $(empty) ,?,$1)
?s = $(subst ?, ,$1)
notdirx = $(call ?s,$(notdir $(call s?,$1)))
$(TARGET):
touch '$(call notdirx,$@)'
Questo definisce una versione "spazio-safe" di notdir
chiamato notdirx
. E 'abbastanza semplice: s?
trasforma prima tutti gli spazi in punti interrogativi (sperando che non possono essere presenti nei nomi di file), e ?s
converte indietro. Tra possiamo tranquillamente chiamare la funzione notdir
originale.
Per un riassunto eccellente su GNU Make e gli spazi nei nomi dei file, vedere GNU make incontra i nomi di file con spazi tra loro .
Altri suggerimenti
Supponendo di avere una shell Unix, si potrebbe sborsare:
notdirx = $(shell basename '$1')
dirx = $(shell dirname '$1')
Una strategia simile potrebbe applicarsi ad altre funzioni. Basta ricordare le virgolette intorno alla variabile che contiene il testo da spazi infetti che si vuole trattare come un unico argomento. Questo vi proteggerà anche da altri caratteri speciali (ad eccezione di virgolette!). Ecco un esempio di doppio backslash sfuggire eventuali spazi nel risultato di un glob wildcard:
$(shell ls -1 '*.foo' | sed 's/ /\\\\ /g')
di Windows sta mettendo in parentesi i nomi delle directory ora, anche:. C:\Program Files (x86)\
Non è ancora chiaro per me quali sono le implicazioni di questo quando si utilizza make
Questo è solo un salto nel buio:
TOP='"/home/chris/src/tests/make/space test"'