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

StackOverflow https://stackoverflow.com/questions/1189781

  •  19-09-2019
  •  | 
  •  

Вопрос

Я использую в 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), обратная косая черта игнорируется.

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

Это было полезно?

Решение

А $(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"'
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top