Подстановочный знак %
- это не то, что вы, по-видимому, думаете.В вашем Makefile это почти везде обычный символ, часть имен make переменных.Например, когда вы пишете:
$(RTL_FILES%): $(IP_TAR_FILE%)
, строки между ()
являются именами переменных.И поскольку у вас, вероятно, нет таких переменных, они раскрываются как пустая строка.
Единственным исключением является правило print-%
, где оно правильно используется для формирования правила шаблона.По той же причине все ваши использования автоматической переменной $*
, вероятно, неверны: она всегда расширяется как пустая строка.Более того, ваш вопрос является неполным, потому что вы не объясняете, какие переменные RTL_FILES
, IP_TAR_FILE
, FILES
, TAR_FILE
... *.
В любом случае, если вы хотите " untarфайл, если содержащиеся в нем файлы не были извлечены", существует несколько возможностей.Далее предполагается, что вы используете GNU make и что ваш ../a_files.tgz
тарбол расширяется как:
a_files
├── a
└── b
└── b
Также предполагается, что у вас нет имен файлов или каталогов с пробелами, табуляциями, специальными символами ...
Простое решение
Начнем с простого решения, в котором вы хотите разархивировать ../a_files.tgz
тогда и только тогда, когда каталог ../a_files
не существует.В противном случае вы считаете, что тарбол уже извлечен.
.PHONY: all
all: | ../a_files
../a_files:
tar -C .. -xvf ../a_files.tgz
Обратите внимание на обязательное условие только для заказа цели all
, введенное |
.Он говорит, что имеет значение только наличие предпосылки, а не время ее последнего изменения.В большинстве случаев это необходимо, когда предпосылками являются каталоги.
Демонстрация:
$ make
tar -C .. -xvf ../a_files.tgz
a_files/
a_files/b/
a_files/b/b
a_files/a
$ make
make: Nothing to be done for 'all'.
Более сложное (но более мощное) решение
Но что, если вы не хотитесчитать существование a_files
эквивалентным " все файлы были извлечены "?Например, что если вы хотите, чтобы ваш Makefile был устойчивым к случайному удалению некоторых файлов?
Приведенное выше « simple solution » не восстанавливается, пока существует каталог ../a_files
даже если его полное содержимое было удалено:
$ rm -rf ../a_files/*
$ make
make: Nothing to be done for 'all'.
Таким образом, хорошим решением будет рассмотреть полный список извлеченных файлов, а не только их родительский каталог.Если кого-то не хватает, вы бы разобрались снова, иначе нет.Но все немного сложнее, потому что нам нужно:
Получить список файлов.Вы можете жестко связать список в вашем Makefile, но это не очень удобно.Этот список также можно вычислить автоматически, посмотрев на tarball (tar -tf <tarball>
), благодаря функции GNU make shell
:
LIST := $(shell tar -tf ../a_files.tgz)
Скажите make, что все эти файлысоздан с одним выполнением рецепта tar
.Это не так просто, потому что естественный стиль создания заключается в том, что одно выполнение рецепта создает один файл.И если мы просто объявим, что тарбол является обязательным условием для всех извлеченных файлов:
FILES := $(addprefix ../,$(LIST))
$(FILES): ../a_files.tgz
tar -C .. -xvf $<
make может решить запустить столько рецептов tar
, сколько есть файлов для извлечения.Это не то, что мы хотим.К счастью, шаблонные правила с несколькими целями являются исключением, и мы можем это использовать.Сложность в том, что мы должны заменить хотя бы один общий символ на %
во всех словах $(FILES)
.Давайте заменим s
из ../a_files/XXX
:
LIST := $(patsubst a_files/%,%,$(shell tar -tf ../a_files.tgz))
FILES := $(addprefix ../a_files/,$(LIST))
PATTERN := $(addprefix ../a_file%/,$(LIST))
Теперь наши переменные make будут принимать значения:
LIST := b/ b/b a
FILES := ../a_files/b/ ../a_files/b/b ../a_files/a
PATTERN := ../a_file%/b/ ../a_file%/b/b ../a_file%/a
И если мы используем $(PATTERN)
в качестве целиКак правило, make будет учитывать, что все совпадающие цели для любой данной замены %
создаются одним выполнением соответствующего рецепта.
Скажите make, что время последнего измененияфайлы не должны использоваться, чтобы решить, являются ли они современными или нет относительно tarball.Предварительные условия только для заказа, которые мы видели уже в первом решении, - это способ сделать это.
В целом, следующее должно делать то, что мы хотим:
.PHONY: all
LIST := $(patsubst a_files/%,%,$(shell tar -tf ../a_files.tgz))
FILES := $(addprefix ../a_files/,$(LIST))
PATTERN := $(addprefix ../a_file%/,$(LIST))
all: $(FILES)
$(PATTERN): | ../a_files.tgz
tar -C .. -xvf ../a_files.tgz
Демонстрация:
$ make
tar -C .. -xvf ../a_files.tgz
a_files/
a_files/b/
a_files/b/b
a_files/a
$ make
make: Nothing to be done for 'all'.
$ rm ../a_files/a
$ make
tar -C .. -xvf ../a_files.tgz
a_files/
a_files/b/
a_files/b/b
a_files/a