Сделать цель перед использованием в вызове $(shell)
У меня есть проект, который можно настроить через scenario.xml
файл. Проект содержит небольшой инструмент для извлечения информации из этого XML-файла (tools/xmlq
), который скомпилирован из исходного файла переменного тока. Make-файлы используют этот инструмент, чтобы влиять на сборку, присваивая ее выходные данные различным переменным make, таким как
SOME_VAR := $(shell tools/xmlq some_query)
Проблема с этим подходом заключается в том, что на чистой сборке, tools/xmlq
не существует и SOME_VAR
не будет содержать ожидаемое значение.
Мой вопрос: есть ли способ обеспечить сборку tools/xmlq
перед $(shell ...)
вызовы, которые используют это, выполняются? Если нет: какие обходные пути можно использовать, чтобы избежать проблемы?
Некоторые возможные обходные пути, о которых я думал до сих пор:
Используйте файлы вместо переменных.
Это означает, что такая конструкция
SOME_VAR := $(shell tools/xmlq some_query) some-target: some-prerequisites some-command $(SOME_VAR) $^
изменится на
some-var.txt: tools/xmlq scenario.xml $< some_query > $@ some-target: some-var.txt some-prerequisites some-command $$(cat $<) $(filter-out $<,$^)
у этого есть то преимущество, что это кажется очень идиоматичным, но имеет большой недостаток, который я не мог использовать, например
$(SOME_VAR).o
в качестве предпосылки больше.Просто позвони
make tools/xmlq
в начале make-файла с$(shell make tools/xmlq)
(Очевидно, должно быть несколько охранников, чтобы избежать бесконечной рекурсии). Недостатком здесь будет то, что файлы Makefile по сути читаются дважды. Однажды построить
tools/xmlq
и один раз для первоначального вызова.
1 ответ
Вам не требуется обходной путь, просто уместно make
логика. Подробно это зависит от того, где находится исходный файл xmlq.c
проживает. Для иллюстрации я предполагаю, что это в tools
:-
SOME_VAR = $(shell tools/xmlq some_query)
some-target: some-prerequisites | tools/xmlq
some-command $(SOME_VAR) $^
tools/xmlq: tools/xmlq.o
$(CC) -o $@ $^ # Or however you build it.
Есть два момента к решению:-
Немедленное назначение
SOME_VAR := $(shell tools/xmlq some_query)
заменяется ленивым назначением
SOME_VAR = $(shell tools/xmlq some_query)
Итак, определение $(shell tools/xmlq some_query)
будет расширен только тогда, когда $(SOME_VAR)
расширяется, т.е. когда рецепт some-command $(SOME_VAR) $^
расширяется, когда make
решает запустить его. Так tools/xmlq
не нужно существовать до этого момента.
Правило
some-target: some-prerequisites | tools/xmlq
марки tools/xmlq
предварительное условие только для заказа some-target
, Который означает, что tools/xmlq
не будет учитываться при определении some-target
должно быть сделано, но если будет установлено, что some-target
должно быть сделано, то tools/xmlq
будет сделано первым. таким образом tools/xmlq
будет существовать раньше make
раскрываться $(SOME_VAR)
,
Демо:
инструменты /xmlq.c
#include <stdio.h>
int main(int argc, char *argv[])
{
int i;
for (i = 1; i < argc; ++i) {
fputs(argv[i],stdout);
}
return 0;
}
а также
Makefile
.PHONY: clean foo World
SOME_VAR = $(shell tools/xmlq Hello)
foo: World | tools/xmlq
echo $(SOME_VAR) $^
tools/xmlq: tools/xmlq.o
$(CC) -o $@ $^
World:;
clean:
rm -fr tools/xmlq.o tools/xmlq
который работает как:
$ make
cc -c -o tools/xmlq.o tools/xmlq.c
cc -o tools/xmlq tools/xmlq.o
echo Hello World
Hello World
И это может быть уменьшено до:
.PHONY: clean foo World
foo: World | tools/xmlq
echo $$(tools/xmlq Hello) $^
tools/xmlq: tools/xmlq.o
$(CC) -o $@ $^
World:;
clean:
rm -fr tools/xmlq.o tools/xmlq