Question

J'utilise un code similaire à ce qui suit dans 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)

Si je l'utiliser dans un répertoire sans espace, dire space-test, il fonctionne très bien:

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

Cependant, si je l'utilise dans un répertoire avec des espaces, par exemple space test, puis $(notdir) fait la mauvaise chose:

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

Qu'est-ce qui se passe ici est que $(notdir) interprète /tmp/space test/foo comme deux fois (à savoir, space et foo) chemins et renvoie la "partie de fichier" de . La partie étrange est que TARGET est correctement échappé; en quelque sorte, à l'intérieur ou à l'intérieur de la règle $(notdir), les évasions backslash sont ignorées.

Qu'est-ce que je fais mal ici?

Était-ce utile?

La solution

La fonction $(notdir) dans GNU Make a une liste d'arguments, séparés par des espaces. Certaines fonctions prennent en charge les espaces s'échappant avec \\, mais $(notdir) n'est pas un d'entre eux.

Cela devrait fonctionner:

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

$(TARGET):
    touch '$(call notdirx,$@)'

Ceci définit une version « espace sûr » de notdir appelé notdirx. Il est assez simple: s? tourne d'abord tous les espaces à des points d'interrogation (en espérant qu'ils ne peuvent pas être présents dans les noms de fichiers), et ?s reconvertit. Entre nous pouvons appeler en toute sécurité la fonction notdir d'origine.

Pour un excellent résumé sur GNU Make et espaces dans les noms de fichiers, voir GNU Make rencontre les noms de fichiers avec des espaces dans les .

Autres conseils

En supposant que vous avez un shell Unix, vous pouvez débourser:

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

Une stratégie similaire pourrait appliquer à d'autres fonctions. Rappelez-vous les guillemets autour de la variable qui contient le texte infecté par des espaces que vous voulez traiter comme un seul argument. Cela permettra également de vous protéger d'autres caractères spéciaux (sauf pour les guillemets!). Voici un exemple à double backslash échapper à tous les espaces dans le résultat d'un glob générique:

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

Windows est de mettre entre parenthèses dans les noms de répertoire maintenant aussi. C:\Program Files (x86)\ Il est pas encore clair pour moi quelles sont les implications de ce lors de l'utilisation make

Ceci est juste un coup de feu dans l'obscurité:

TOP='"/home/chris/src/tests/make/space test"'
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top