【问题标题】:Unexpected execution of "all" target in my makefile在我的生成文件中意外执行“所有”目标
【发布时间】:2021-05-03 07:51:13
【问题描述】:

我有一个生成文件,假设为目录中的每个 file.csv 重复执行一次 c 代码 (BootstrapCL.c)。对于每次执行,它应该输入 c 代码(作为 argv) 2 字符串:当前执行中使用的输入 csv 文件的名称,带扩展名和不带扩展名。 这是makefile的内容:

SRCS := $(wildcard *.csv)
BINS := $(SRCS:%.csv=%)

all: ${BINS}

%: BootstrapCL.c
    gcc -Wall BootstrapCL.c  -lm -o BootstrapCL
    ./BootstrapCL $@.csv $@

问题在于,在执行完所有的 csv 文件组之后(我只想执行 ${BINS} 列表中的目标),它还使用“all”目标运行最后一次执行。当然,我的文件夹中没有任何 all.csv 文件;我认为我以错误的方式使用 $@,但我不明白为什么以及如何解决这个问题,知道吗?

【问题讨论】:

    标签: c shell makefile target automatic-variable


    【解决方案1】:

    我对解决方案的看法与 Beta 略有不同:

    SRCS := $(wildcard *.csv)
    BINS := $(SRCS:%.csv=%)
    
    # All rule - requires binaries to be generated. This does not generate anything, therefore it is PHONY
    .PHONY: all
    all: ${BINS}
    
    # Generates the binaries - requires BootstrapCL exe to be generated first
    ${BINS}: BootstrapCL
        ./BootstrapCL $@.csv $@
    
    # Generates BootstrapCL
    BootstrapCL:
        gcc -Wall BootstrapCL.c  -lm -o BootstrapCL
    

    据我所知,您需要编译一次 BootstrapCL.c 以生成 BootstrapCL 可执行文件。然后使用它生成多个二进制文件 - 一个用于 eacn .csv 文件。

    反过来:

    • 您有一个需要 BINS 的 all 目标。
    • 您有一个生成 BIN 的 BINS 目标,但首先需要 BootstrapCL - 这将为每个 .csv 文件运行一次。
    • 您有一个BootstrapCL 目标来生成 BootstrapCL 可执行文件 - 这只会运行一次。

    【讨论】:

    • 为什么 BootstrapCL 目标会以这种方式运行一次?
    • 因为创建 BootstrapCL 的规则已定义 - 所以一旦文件 BootstrapCL 存在,make 将看到它存在并且不会尝试再次创建它(如果时间戳更新则源文件)。这是 makefile 的一个关键特性。
    【解决方案2】:

    问题是您没有allrecipe,以及% 的规则匹配任何东西。 当Make 完成了先决条件时(@ 987654323@),它尝试构建all,寻找适合的配方,并找到%

    有(至少)两种方法可以解决这个问题。快速而肮脏的方法是为all 添加一个(空)配方:

    all: ${BINS}
        @:
    

    在我看来更好的另一种方法是收紧第二条规则:

    BINS := $(SRCS:%.csv=%.phony)
    
    all: ${BINS}
    
    %.phony: BootstrapCL.c
        gcc -Wall BootstrapCL.c  -lm -o BootstrapCL
        ./BootstrapCL $*.csv $*
    

    为了整洁,建议你也加一行:

    .PHONY: $(BINS)
    

    让 Make 知道 .phony 目标不是要构建的真实文件。

    其他一些小的改进是可能的。我会考虑BootstrapCL 以及它是否会生成一个可以用作真正目标的文件。

    【讨论】:

    • 感谢您的回答 Beta;它可以帮助我更好地了解正在发生的事情;现在我只有一个疑问。 “当 Make 完成先决条件 (${BINS}) 后,它会尝试构建所有内容”。但是 all 没有配方,那么为什么要将另一个目标 (${BINS}) 的配方分配给“所有”?
    【解决方案3】:

    % 规则过于笼统,可以捕获所有内容,甚至尝试重建 Makefile 本身。而且它每次都编译BootstrapCL,这似乎没有必要:

    $ make
    gcc -Wall BootstrapCL.c  -lm -o BootstrapCL
    ./BootstrapCL Makefile.csv Makefile
    gcc -Wall BootstrapCL.c  -lm -o BootstrapCL
    ./BootstrapCL foo.csv foo
    gcc -Wall BootstrapCL.c  -lm -o BootstrapCL
    ./BootstrapCL bar.csv bar
    gcc -Wall BootstrapCL.c  -lm -o BootstrapCL
    ./BootstrapCL all.csv all
    

    我会使用模式规则来生成二进制文件,因为这也会在 .csv 文件发生更改时重建二进制文件。我还将BootstrapCL 生成分离到不同的规则,只编译一次,但如果BootstrapCL 发生变化,请将其保留在目标的依赖项列表中以重新生成它们:

    $ cat Makefile
    SRCS := $(wildcard *.csv)
    BINS := $(SRCS:%.csv=%)
    
    all: ${BINS}
    
    BootstrapCL: BootstrapCL.c
            gcc -Wall $< -lm -o $@
    
    %: %.csv BootstrapCL
            ./BootstrapCL $< $@
    

    输出:

    $ make
    gcc -Wall BootstrapCL.c -lm -o BootstrapCL
    ./BootstrapCL foo.csv foo
    ./BootstrapCL bar.csv bar
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-10-04
      • 1970-01-01
      • 2012-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-22
      相关资源
      最近更新 更多