gpt4 book ai didi

makefile - 在 makefile 中正确使用 call 函数

转载 作者:行者123 更新时间:2023-12-02 21:58:44 24 4
gpt4 key购买 nike

我正在尝试为具有不同优化级别等的不同软件目录进行编译。我创建了以下 makefile 来执行此操作:

OWNER           = betsy molly fred
DOG = poodle mutt doberman
COLOUR = brown red yellow
ATTR = big small
LEGS = 0 3

#we want every possible combination to be excercised
OUTPUT_STUFF = $(foreach own,$(OWNER),$(foreach dog,$(DOG),$(foreach col,$(COLOUR),$(foreach attr,$(ATTR),$(foreach legs,$(LEGS),new/$(own)/$(dog)/$(col)/$(attr)/$(legs)/dogInfo.txt)))))

.PHONY: all

all: $(OUTPUT_STUFF)

define PROGRAM_template

own = $(1)
dog = $(2)
col = $(3)
attr = $(4)
legs = $(5)

BUILD_DIR = new/$(own)/$(dog)/$(col)/$(attr)/$(legs)

#for each build directory, we are going to put a file in it containing the build dir. string
$$(BUILD_DIR)/dogInfo.txt:
@echo "$$@"
mkdir $$(BUILD_DIR)
@echo "$$(BUILD_DIR)" > $$(BUILD_DIR)/dogInfo.txt
endef

#call the function many times
$(foreach own,$(OWNER),$(foreach dog,$(DOG),$(foreach col,$(COLOUR),$(foreach attr,$(ATTR),$(foreach legs,$(LEGS),$(eval $(call PROGRAM_template,$(own),$(dog),$(col),$(attr),$(legs))))))))

正如您所看到的,这个简单的测试程序循环遍历所有者、狗等的不同组合。最终目标是拥有一个新目录,其中将所有所有者作为目录,并在其中包含所有狗等。底部只是一个包含路径的文件。

当我运行它时,输出是:

new/betsy/poodle/brown/big/0/dogInfo.txt
mkdir new/fred/doberman/yellow/small/3
mkdir: cannot create directory `new/fred/doberman/yellow/small/3': No such file or directory
make: *** [new/betsy/poodle/brown/big/0/dogInfo.txt] Error 1

因此,出于某种原因,目标是好的,但看似完全相同的变量是我循环中的最后一个。从根本上说,我不太明白发生了什么。

Weird foreach + user-defined function behavior in Makefiles似乎回答了,但我不完全明白。在我看来,当调用该函数时,它会用一个 $ 填充所有实例,而转义的实例将变为 $(BUILD_DIR)。然后,它将代码“粘贴”到临时文件,完成所有调用后,它会评估该文件,正常替换变量。

我想到的一个(丑陋的)解决方案是让 BUILD_DIR 变量每次都不同,如下所示:

B_D_$(1)_$(2)_$(3)_$(4)_$(5) = ~~~

最佳答案

亚历克斯是正确的(尽管我认为他的意思是食谱,而不是收据:-))。调试复杂 eval 问题的最佳方法是将 eval 函数替换为对 info 的调用。所以如果你有类似的东西:

$(foreach A,$(STUFF),$(eval $(call func,$A)))

那么你可以将其重写为:

$(foreach A,$(STUFF),$(info $(call func,$A)))

现在 make 将准确地打印出 eval 将要解析的内容。通过查看 makefile 输出,通常很清楚问题出在哪里。在您的情况下,您将在输出中看到类似的内容(省略所有额外的变量设置):

BUILD_DIR = new/betsy/poodle/brown/big/0
$(BUILD_DIR)/dogInfo.txt:
@echo "$$@"
mkdir $(BUILD_DIR)
@echo "$(BUILD_DIR)" > $(BUILD_DIR)/dogInfo.txt

BUILD_DIR = new/betsy/poodle/brown/big/3
$(BUILD_DIR)/dogInfo.txt:
@echo "$$@"
mkdir $(BUILD_DIR)
@echo "$(BUILD_DIR)" > $(BUILD_DIR)/dogInfo.txt

等等。请注意您每次如何设置全局变量BUILD_DIR。在 make 中,变量(一次)只有一个值。当 make 读取 makefile 时,它​​会立即扩展目标和先决条件列表,因此无论 BUILD_DIR 具有当时的值都将用于目标/先决条件,因此这对您有用.

但是当 make 完成读取 makefile 时,BUILD_DIR 的值将始终是您最后设置的值;在本例中new/fred/doberman/yellow/small/3。现在 make 开始调用每个目标的配方,当它这样做时,它将在配方中扩展 BUILD_DIR,因此所有配方都将获得相同的值。

正如 Alex 指出的那样,您应该确保您的配方使用自动变量,例如 $@,这些变量为每个规则正确设置。如果您这样做,您会发现您根本不需要重新定义规则,因为它实际上对所有目标都是相同的配方。如果您注意到这一点,您会发现您一开始就不需要整个评估或调用复杂性。

您所要做的就是计算所有目标的名称,然后编写一条规则:

ALLDOGINFO = $(foreach own,$(OWNER),$(foreach dog,$(DOG),$(foreach col,$(COLOUR),$(foreach attr,$(ATTR),$(foreach legs,$(LEGS),new/$(own)/$(dog)/$(col)/$(attr)/$(legs)/dogInfo.txt)))))

$(ALLDOGINFO):
@echo "$@"
mkdir $(dir $@)
@echo "$(dir $@)" > $@

如果您不需要尾部斜杠,则必须使用 $(patsubst %/,%,$(dir $@)) 代替。

关于makefile - 在 makefile 中正确使用 call 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17866245/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com