J'ai un répertoire contenant plusieurs fichiers, dont certains ont des espaces dans leurs noms:
Test workspace/
Another directory/
file1.ext
file2.ext
demo 2012-03-23.odp
J'utilise la commande $(wildcard)
de GNU sur ce répertoire, puis j'itère le résultat en utilisant $(foreach)
, en imprimant tout. Voici le code:
FOO := $(wildcard *)
$(info FOO = $(FOO))
$(foreach PLACE,$(FOO),$(info PLACE = $(PLACE)))
Voici ce que je m'attendrais à voir imprimé:
Test workspace
Another directory
file1.ext
file2.ext
demo 2012-03-23.odp
Voici ce que j'obtiendrais réellement:
Test
workspace
Another
directory
file1.ext
file2.ext
demo
2012-03-23.odp
Ce dernier ne me sert évidemment à rien. Le documentation for $(wildcard)
flat-out déclare qu'il retourne une "liste de noms séparés par des espaces" mais échoue complètement à reconnaître les énormes problèmes que cela pose. Ni documentation pour $(foreach)
.
Est-il possible de contourner cela? Si c'est le cas, comment? Renommer chaque fichier et répertoire pour supprimer les espaces n'est pas une option.
Le bug # 712 suggère que make ne gère pas les noms avec des espaces. Nulle part, jamais.
J'ai trouvé un article de blog disant qu'il est partiellement implémenté en échappant aux espaces avec \
(\\
Semble être une faute de frappe ou un formatage), mais:
$(wildcard)
.$?
, $^
Et $+
Ainsi que toute variable définie par l'utilisateur. Ce qui à son tour signifie que même si $(wildcard)
correspondra aux fichiers corrects, vous ne pourrez pas interpréter le résultat de toute façon.Ainsi, avec des règles de modèle explicites ou très simples, vous pouvez le faire fonctionner, mais au-delà de cela, vous n'avez pas de chance. Vous devrez chercher un autre système de construction qui prend en charge les espaces. Je ne sais pas si jam / bjam le fait, scons , waf , ant , nant et msbuild tout devrait fonctionner.
GNU Make fait très mal avec les noms de fichiers séparés par des espaces.
Les espaces sont utilisés comme délimiteurs dans la liste Word partout.
Ce billet de blog résume bien la situation, mais ATTENTION: il utilise incorrectement \\ plutôt que\
target: some\ file some\ other\ file
some\ file some\ other\ file:
echo done
Vous pouvez également utiliser des variables, donc cela fonctionnerait également
VAR := some\ file some\ other\ file
target: $(VAR)
$(VAR):
echo done
Seule la fonction wildcard
reconnaît l'échappement, vous ne pouvez donc rien faire de fantaisie sans beaucoup de douleur.
Mais n'oubliez pas que votre Shell utilise également des espaces comme délimiteurs .
Si je voulais changer le echo done
à touch $@
, Je devrais ajouter une barre oblique pour lui échapper pour mon Shell.
VAR := some\ file
target: $(VAR)
$(VAR):
touch $(subst \,\\,$@)
ou, plus probablement, utilisez des guillemets
VAR := some\ file some\ other\ file
target: $(VAR)
$(VAR):
touch '$@'
En fin de compte, si vous voulez éviter beaucoup de douleur, à la fois dans GNU make et dans votre Shell, ne mettez pas d'espaces dans vos noms de fichiers. Si vous le faites, espérons les capacités limitées de Make sera suffisant.
Cette méthode permet également d'utiliser les noms de fichiers répertoriés tels que $?
et les variables utilisateur qui sont des listes de fichiers.
La meilleure façon de gérer les espaces dans Make est de remplacer les espaces par d'autres personnages.
s+ = $(subst \ ,+,$1)
+s = $(subst +,\ ,$1)
$(call s+,foo bar): $(call s+,bar baz) $(call s+,bar\ baz2)
# Will also shows list of dependencies with spaces.
@echo Making $(call +s,$@) from $(call +s,$?)
$(call s+,bar\ baz):
@echo Making $(call +s,$@)
$(call s+,bar\ baz2):
@echo Making $(call +s,$@)
Les sorties
Making bar baz
Making bar baz2
Making foo bar from bar baz bar baz2
Vous pouvez ensuite manipuler en toute sécurité les listes de noms de fichiers en utilisant toutes les fonctions GNU Make. Assurez-vous simplement de supprimer les + avant d'utiliser ces noms dans une règle.
SRCS := a\ b.c c\ d.c e\ f.c
SRCS := $(call s+,$(SRCS))
# Can manipulate list with substituted spaces
OBJS := $(SRCS:.c=.o)
# Rule that has object files as dependencies.
exampleRule:$(call +s,$(OBJS))
# You can now use the list of OBJS (spaces are converted back).
@echo Object files: $(call +s,$(OBJS))
a\ b.o:
# a b.o rule commands go here...
@echo in rule: a b.o
c\ d.o:
e\ f.o:
Les sorties
in rule: a b.o
Object files: a b.o c d.o e f.o
Ces informations proviennent toutes du blog que tout le monde publiait.
La plupart des gens semblent recommander de ne pas utiliser d'espaces dans les chemins ou d'utiliser des chemins Windows 8.3, mais si vous devez utiliser des espaces, les espaces d'échappement et les travaux de substitution.
Si vous êtes prêt à compter un peu plus sur votre Shell, cela donne une liste qui peut contenir des noms avec des espaces très bien:
$(Shell find | sed 's: :\\ :g')
La question d'origine disait que "renommer n'est pas une option", mais de nombreux commentateurs ont souligné que renommer est à peu près la seule façon dont Make peut gérer les espaces. Je suggère une solution intermédiaire: utilisez Make pour renommer temporairement les fichiers, puis renommez-les. Cela vous donne toute la puissance de Make avec des règles implicites et d'autres avantages, mais ne gâche pas votre schéma de nommage de fichiers.
# Make cannot handle spaces in filenames, so temporarily rename them
nospaces:
rename -v 's/ /%20/g' *\ *
# After Make is done, rename files back to having spaces
yesspaces:
rename -v 's/%20/ /g' *%20*
Vous pouvez appeler ces cibles à la main avec make nospaces
et make yesspaces
, ou vous pouvez avoir d'autres cibles en dépend. Par exemple, vous voudrez peut-être avoir une cible "Push" qui s'assure de remettre les espaces dans les noms de fichiers avant de synchroniser les fichiers avec un serveur:
# Put spaces back in filenames before uploading
Push: yesspaces
git Push
[Sidenote: j'ai essayé la réponse qui suggérait d'utiliser +s
et s+
mais cela a rendu mon Makefile plus difficile à lire et à déboguer. Je l'ai abandonné quand il m'a donné un coup de gueule sur les règles implicites comme: %.wav : %.ogg ; oggdec "$<"
.]
D'autres réponses couvrent déjà assez bien le problème. Je viens de faire un exemple pour montrer que le \
- l'échappement fonctionne également pour les dépendances.
$ make --version
GNU Make 4.0
Built for x86_64-pc-linux-gnu
Copyright (C) 1988-2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ sed 's/^ /\t/' >Makefile <<'_EOF_'
X = $(Shell find -name 'x*' -type f | sed 's/ /\\ /g')
all: $(X)
head $(X)
_EOF_
$ touch 'x 1'
$ touch 'x 2'
$ make
head ./x\ 2 ./x\ 1
==> ./x 2 <==
==> ./x 1 <==
$