Сделать цель перед использованием в вызове $(shell)

У меня есть проект, который можно настроить через scenario.xml файл. Проект содержит небольшой инструмент для извлечения информации из этого XML-файла (tools/xmlq), который скомпилирован из исходного файла переменного тока. Make-файлы используют этот инструмент, чтобы влиять на сборку, присваивая ее выходные данные различным переменным make, таким как

SOME_VAR := $(shell tools/xmlq some_query)

Проблема с этим подходом заключается в том, что на чистой сборке, tools/xmlq не существует и SOME_VAR не будет содержать ожидаемое значение.

Мой вопрос: есть ли способ обеспечить сборку tools/xmlq перед $(shell ...) вызовы, которые используют это, выполняются? Если нет: какие обходные пути можно использовать, чтобы избежать проблемы?


Некоторые возможные обходные пути, о которых я думал до сих пор:

  1. Используйте файлы вместо переменных.

    Это означает, что такая конструкция

    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 в качестве предпосылки больше.

  2. Просто позвони 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
Другие вопросы по тегам