Makefile 从规则中设置变量

Makefile 从规则中设置变量,makefile,Makefile,我有一个外部工具,可以获取一些源()。我想在钢筋运行后根据目录的内容填写一个变量 EFLAGS += -I$(PWD)/include EFLAGS += -pa $(PWD)/ebin ## $(PWD)/deps/* will only have contents after Rebar runs EFLAGS += $(patsubst %,-pa %,$(wildcard $(PWD)/deps/*/ebin)) build-deps: ./rebar get-deps

我有一个外部工具,可以获取一些源()。我想在钢筋运行后根据目录的内容填写一个变量

EFLAGS += -I$(PWD)/include 
EFLAGS += -pa $(PWD)/ebin
## $(PWD)/deps/* will only have contents after Rebar runs
EFLAGS += $(patsubst %,-pa %,$(wildcard $(PWD)/deps/*/ebin))

build-deps:
    ./rebar get-deps
    ./rebar compile

build-main: build-deps
    erlc $(EFLAGS) $(INFILE)
如果我将其作为两个单独的调用运行,上述功能将按预期工作:

make build-deps
make build-main
但是,如果我只创建
buildmain
,那么
EFLAGS
会在
deps/
目录为空时设置,然后填充目录,然后使用
EFLAGS

在我运行了一些规则之后,是否有一个好方法可以让我只设置
EFLAGS

编辑:下面是一个可以更容易地演示问题的生成文件:

A=$(wildcard test*)

foo:
    touch test1

bar: foo
    @echo $A

clean:
    -rm test*
在这里,“foo”目标代表我对
rebar
的调用,因此想象一下,您不知道我将传递给
touch
的文件。如果你尝试

make clean
make bar
make bar

您将发现
make bar
的两个调用产生不同的结果,因为在第二个调用中
test1
make
开始之前存在。我正在寻找一种方法,在运行
makeclean

之后立即获得第二次
makebar
调用的输出。我相信,使用附带的makefile,类似下面的方法会奏效。 未经测试,但我相信这方面的东西会满足你的要求。假设每次尝试构建时都要运行钢筋

EFLAGS += -I$(PWD)/include 
EFLAGS += -pa $(PWD)/ebin
EFLAGS += $(PADIRS)

-include paflags.mk

build-main:
    erlc $(EFLAGS) $(INFILE)

paflags.mk: force
        ./rebar get-deps
        ./rebar compile
        echo 'PADIRS := $$(patsubst %,-pa %,$$(wildcard $$(PWD)/deps/*/ebin))' > '$@'

force: ;
上面的编辑删除了
paflags.mk
上的
.PHONY
声明,因为这似乎导致make无法执行此技巧工作所需的重新启动

或者,由于没有使用make的任何先决条件测试,您可以将其全部移动到build主规则体中,并在shell中执行globbing/etc

或者,您可以使用
eval
在我相信的构建主规则中强制评估patsubst(我必须测试它,以确保时间安排正确,至少GNU make,提升机在规则体中发出指令)

上面这个简单测试用例的想法对我来说很有用:

-include inc.mk

$(warning A:$A)

bar:
        @echo $A

inc.mk:
        touch test1
        echo 'A=$$(wildcard test*)' > '$@'

force: ;
编辑两个示例makefiles以在包含的makefile上包含强制规则,以强制make每次生成包含的文件。如果没有这一点(并且没有奇特的自动依赖项生成/检测),make将只在第一次构建包含的文件,然后再也不会接触它。我相信,这支部队将以不断努力建设为代价,避免这个问题


也就是说,对于这种情况,可能是更好的选择。

最简单的解决方案是使用shell来计算值,而不是使用make规则。像这样:

EFLAGS += -I$(PWD)/include 
EFLAGS += -pa $(PWD)/ebin
## $(PWD)/deps/* will only have contents after Rebar runs
EFLAGS += $(patsubst %,-pa %,$(wildcard $(PWD)/deps/*/ebin))

build-deps:
        ./rebar get-deps
        ./rebar compile

build-main: build-deps
        for f in $(PWD)/deps/*/ebin; do paflags="$$paflags -pa $$f"; done; \
        erlc $(EFLAGS) $$paflags $(INFILE)

如果使用常规宏(具有新名称,EXFLAGS),例如
EXFLAGS=$(patsubst%,-pa%,$(wildcard$(PWD)/deps/*/ebin))
,然后在命令行上列出
$(EXFLAGS)
,我认为在使用宏时应该对其进行评估,因此
patsubst
应该在填充目录之后才会出现。至少,这是一个理论…不,这似乎在上面几行之前执行了
通配符
替换,因此生成的文件缺少我想要的值。哦,是不是让我们计算
patsubst
?哦,是的,你需要转义它,这样它就会出现在
paflags.mk
文件中。编辑。写一个要包含的文件很简单,但它只是让我回到开始的地方。第一次运行(文件不存在时)包含文件丢失,因此
EFLAGS
不完整。在后续运行中,包含文件始终保存上一次运行的数据。当make找不到包含文件时,它将创建该文件并重新启动。重新启动后,文件应该已经存在,请尝试重新创建(这不会导致任何更改),并且在尝试评估包含文件内容时,文件应该存在。这不是真的吗?你能告诉我发生了什么吗(使用
$(info)
make-d
也许)?如果你做对了,这种方法(包括自动重建)也会起作用。如果您真的需要在
buildmain
规则之外定义该变量,这很好。但是如果你只是在某个地方需要它,那么使用shell来计算它是最简单的。其他的答案都很接近,但是gmake坚持在做任何工作之前评估所有变量,所以我相信你是对的,我需要在shell中做。为什么echo glob而不是一个裸glob?是的,很好。那里有点脑子出毛病了。修好了,谢谢!