【问题标题】:Set a variable from within a rule从规则中设置变量
【发布时间】:2014-07-24 01:25:33
【问题描述】:

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

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

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

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

编辑:这是一个可以更轻松地演示问题的 Makefile:

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 开始之前。我正在寻找一种在运行make clean 后立即获得第二个make bar 调用输出的方法。

【问题讨论】:

  • 如果你使用一个常规的宏(有一个新的名字,EXFLAGS),比如EXFLAGS = $(patsubst %,-pa %,$(wildcard $(PWD)/deps/*/ebin)),然后在命令行中列出$(EXFLAGS),我觉得宏在使用的时候应该被求值,所以patsubst 不应该在目录被填充之后出现。至少,这是一个理论……

标签: makefile


【解决方案1】:

我相信使用包含的 makefile 的类似以下内容会起作用。 未经测试,但我相信这些方面的东西会做你想要的。假设您每次尝试构建时都想运行 rebar。

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-main 规则体中并执行 globbing/etc。在外壳中。

或者,您可以使用eval 强制评估我相信的构建主规则中的 patsubst(我必须对其进行测试以确保时间正确地与 GNU 至少如何制作提升在规则体中制作指令)。

上面这个版本的简单测试用例想法对我有用:

-include inc.mk

$(warning A:$A)

bar:
        @echo $A

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

force: ;

编辑了两个示例 makefile 以在包含的 makefile 上包含强制规则,以强制 make 每次都构建包含的文件。没有它(并且没有花哨的自动依赖生成/检测),make 只会第一次构建包含的文件,然后再也不会触及它。我相信,以始终尝试建立它为代价的部队将避免这个问题。

话虽如此,对于这种情况,MadScientist's answer 可能是更好的选择。

【讨论】:

  • 不,这似乎是在上述行之前执行wildcard 替换,因此生成的文件缺少我想要的值。
  • 哦,是在评估 patsubst 吗?哎呀,是的,你需要逃避它,所以它最终 in paflags.mk 文件。编辑。
  • 写出要包含的文件很简洁,但它只会让我回到开始的地方。第一次运行(文件不存在)包含文件丢失,因此EFLAGS 不完整。在后续运行中,包含文件始终保存来自先前运行的数据。
  • 当 make 找不到包含文件时,它会创建它并重新启动。重新启动后,文件应该已经存在,尝试重新创建(这应该不会导致任何更改),并且在尝试评估包含文件内容时文件应该存在。这没有发生吗?你能告诉我发生了什么吗($(info)make -d 可能)?
  • 如果你做对了,这个方法(包括自动重建)也会起作用。如果您确实需要在build-main 规则之外定义该变量,那就太好了。但是,如果您只是在那个地方需要它,那么使用 shell 来计算它是最直接的。
【解决方案2】:

最简单的解决方案是使用 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)

【讨论】:

  • 其他答案尝试是如此接近,但 gmake 坚持在做任何工作之前评估所有变量,所以我相信你是对的,我需要在 shell 中做。跨度>
  • 为什么 echo glob 而不是一个裸露的 glob?
  • 是的,Etan 好点。那里有点脑残。已修复,谢谢!
猜你喜欢
  • 2021-09-09
  • 1970-01-01
  • 2023-03-04
  • 1970-01-01
  • 2022-01-05
  • 2011-05-06
  • 2016-04-28
  • 2019-10-24
  • 1970-01-01
相关资源
最近更新 更多