Использование Make $(dir) или $(notdir) на пути с пробелами

Я использую код, подобный следующему в 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)

Если я использую это в каталоге без пробелов, скажем, space-testработает нормально:

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

Однако, если я использую его в каталоге с пробелами, скажем, space test, затем $(notdir) делает неправильную вещь:

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

Что здесь происходит, так это $(notdir) толкует /tmp/space test/foo как два пути и возвращает "файловую часть" обоих (т.е. space а также foo). Странная часть этого в том, что TARGET правильно сбежал; так или иначе, внутри правила или внутри $(notdir)обратные слэши игнорируются.

Что я здесь не так делаю?

3 ответа

Решение

$(notdir) Функция в GNU Make принимает список аргументов, разделенных пробелами. Некоторые функции поддерживают экранирование с \\, но $(notdir) не один из них.

Это должно работать:

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

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

Это определяет "безопасную для космоса" версию notdir называется notdirx, Все довольно просто: s? сначала превращает все пробелы в знаки вопроса (надеясь, что они не могут присутствовать в именах файлов), и ?s обращает обратно. В промежутке мы можем смело назвать оригинал notdir функция.

Чтобы получить отличную сводку по GNU Make и пробелам в именах файлов, см. GNU Make встречает имена файлов с пробелами в них.

Предполагая, что у вас есть оболочка Unix, вы можете выложить:

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

Аналогичная стратегия может применяться к другим функциям. Просто запомните кавычки вокруг переменной, содержащей зараженный пробелами текст, который вы хотите рассматривать как один аргумент. Это также защитит вас от других специальных символов (кроме кавычек!). Вот пример двойной обратной косой черты, экранирующей любые пробелы в результате подстановочного символа:

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

Windows теперь также ставит скобки в именах каталогов: C:\Program Files (x86)\ Мне еще не ясно, каковы последствия этого при использовании make,

Это просто выстрел в темноте:

TOP='"/home/chris/src/tests/make/space test"'
Другие вопросы по тегам