在$(shell)调用中使用目标之前,先创建目标

在$(shell)调用中使用目标之前,先创建目标,shell,gnu-make,Shell,Gnu Make,我有一个可以通过scenario.xml文件配置的项目。该项目包含一个小工具,用于从从c源文件编译的xml文件(tools/xmlq)中提取信息。makefile使用此工具通过将其输出分配给各种make变量来影响构建,如 SOME_VAR := $(shell tools/xmlq some_query) 这种方法的问题在于,在干净的构建中,tools/xmlq不存在,并且某些变量将不包含预期值 我的问题是:是否有某种方法确保在执行使用它的$(shell…调用之前生成tools/xmlq?如果

我有一个可以通过
scenario.xml
文件配置的项目。该项目包含一个小工具,用于从从c源文件编译的xml文件(
tools/xmlq
)中提取信息。makefile使用此工具通过将其输出分配给各种make变量来影响构建,如

SOME_VAR := $(shell tools/xmlq some_query)
这种方法的问题在于,在干净的构建中,
tools/xmlq
不存在,并且
某些变量将不包含预期值

我的问题是:是否有某种方法确保在执行使用它的
$(shell…
调用之前生成
tools/xmlq
?如果不是:我可以使用什么解决方法来避免问题


到目前为止,我已经想到了一些可能的解决办法:

  • 使用文件而不是生成变量

    这意味着

    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.txt:tools/xmlq scenario.xml
    $$@
    一些目标:some-var.txt一些先决条件
    
    有些命令$$(cat$不需要解决方法,只需要适当的
    make
    logic 这取决于源文件
    xmlq.c
    所在的位置 我假设它在
    工具中
    :-

    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工具/xmlq some\u查询)
    只有在
    $(some\u VAR)
    展开,即当配方
    some命令$(some_VAR)$^
    展开时, 当
    make
    决定运行它时。因此
    tools/xmlq
    不需要存在,直到那个时刻

    规则

    some-target: some-prerequisites | tools/xmlq
    
    使
    tools/xmlq
    对于
    某些目标
    。这意味着在确定时将不考虑
    工具/xmlq
    是否应制定
    某些目标
    ,但如果确定应制定
    某些目标
    然后首先生成
    tools/xmlq
    。因此
    tools/xmlq
    将在之前存在
    make
    展开
    $(一些变量)

    演示:

    工具/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;
    }
    
    其运行方式如下:

    $ 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
    

    是否可以选择将一个小的主makefile放在层次结构的顶部,生成所有必要的工具,然后递归调用当前的makefile?这是否意味着您必须定义每个目标两次?一次是在实际构建它的当前makefile中,一次是在主makefile中委托给当前makefile?否,只有两条规则:“全部”规则依赖于xmlq和最终输出文件,并执行“make-f oldmakefile.mk”和xmlq规则,后者构建xmlq本身。下面的答案更好,不需要两个文件。
    .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