在规则执行时定义 make 变量

发布于 2024-08-14 18:53:07 字数 368 浏览 7 评论 0原文

在我的 GNUmakefile 中,我希望有一个使用临时目录的规则。例如:

out.tar: TMP := $(shell mktemp -d)
        echo hi $(TMP)/hi.txt
        tar -C $(TMP) cf $@ .
        rm -rf $(TMP)

如所写,上述规则在规则被解析时创建临时目录。这意味着,即使我不总是创建 out.tar,也会创建许多临时目录。我想避免我的 /tmp 到处都是未使用的临时目录。

有没有办法使变量仅在规则触发时定义,而不是在定义时定义?

我的主要想法是将 mktemp 和 tar 转储到 shell 脚本中,但这看起来有点难看。

In my GNUmakefile, I would like to have a rule that uses a temporary directory. For example:

out.tar: TMP := $(shell mktemp -d)
        echo hi $(TMP)/hi.txt
        tar -C $(TMP) cf $@ .
        rm -rf $(TMP)

As written, the above rule creates the temporary directory at the time that the rule is parsed. This means that, even I don't make out.tar all the time, many temporary directories get created. I would like to avoid my /tmp being littered with unused temporary directories.

Is there a way to cause the variable to only be defined when the rule is fired, as opposed to whenever it is defined?

My main thought is to dump the mktemp and tar into a shell script but that seems somewhat unsightly.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

蹲墙角沉默 2024-08-21 18:53:07

在您的示例中,每当评估 out.tar规则时,都会设置 TMP 变量(并创建临时目录)。为了仅在实际触发 out.tar 时创建目录,您需要将目录创建移至以下步骤:

out.tar : 
    $(eval TMP := $(shell mktemp -d))
    @echo hi $(TMP)/hi.txt
    tar -C $(TMP) cf $@ .
    rm -rf $(TMP)

eval 函数计算字符串,就好像它是手动输入到 makefile 中一样。在本例中,它将 TMP 变量设置为 shell 函数调用的结果。

编辑(响应评论):

要创建一个唯一的变量,您可以执行以下操作:

out.tar : 
    $(eval $@_TMP := $(shell mktemp -d))
    @echo hi $($@_TMP)/hi.txt
    tar -C $($@_TMP) cf $@ .
    rm -rf $($@_TMP)

这会将目标名称(在本例中为 out.tar)添加到变量中,生成一个名为 out.tar_TMP 的变量。希望这足以防止冲突。

In your example, the TMP variable is set (and the temporary directory created) whenever the rules for out.tar are evaluated. In order to create the directory only when out.tar is actually fired, you need to move the directory creation down into the steps:

out.tar : 
    $(eval TMP := $(shell mktemp -d))
    @echo hi $(TMP)/hi.txt
    tar -C $(TMP) cf $@ .
    rm -rf $(TMP)

The eval function evaluates a string as if it had been typed into the makefile manually. In this case, it sets the TMP variable to the result of the shell function call.

edit (in response to comments):

To create a unique variable, you could do the following:

out.tar : 
    $(eval $@_TMP := $(shell mktemp -d))
    @echo hi $($@_TMP)/hi.txt
    tar -C $($@_TMP) cf $@ .
    rm -rf $($@_TMP)

This would prepend the name of the target (out.tar, in this case) to the variable, producing a variable with the name out.tar_TMP. Hopefully, that is enough to prevent conflicts.

故笙诉离歌 2024-08-21 18:53:07

一种相对简单的方法是将整个序列编写为 shell 脚本。

out.tar:
   set -e ;\
   TMP=$(mktemp -d) ;\
   echo hi $TMP/hi.txt ;\
   tar -C $TMP cf $@ . ;\
   rm -rf $TMP ;\

我在这里整合了一些相关提示:Makefile 中的多行 bash 命令

A relatively easy way of doing this is to write the entire sequence as a shell script.

out.tar:
   set -e ;\
   TMP=$(mktemp -d) ;\
   echo hi $TMP/hi.txt ;\
   tar -C $TMP cf $@ . ;\
   rm -rf $TMP ;\

I have consolidated some related tips here: Multi-line bash commands in makefile

征棹 2024-08-21 18:53:07

另一种可能性是在规则触发时使用单独的行来设置 Make 变量。

例如,这是一个包含两条规则的 makefile。如果规则触发,它会创建一个临时目录并将 TMP 设置为临时目录名称。

PHONY = ruleA ruleB display

all: ruleA

ruleA: TMP = $(shell mktemp -d testruleA_XXXX)
ruleA: display

ruleB: TMP = $(shell mktemp -d testruleB_XXXX)
ruleB: display

display:
    echo ${TMP}

运行代码会产生预期的结果:

$ ls
Makefile
$ make ruleB
echo testruleB_Y4Ow
testruleB_Y4Ow
$ ls
Makefile  testruleB_Y4Ow

Another possibility is to use separate lines to set up Make variables when a rule fires.

For example, here is a makefile with two rules. If a rule fires, it creates a temp dir and sets TMP to the temp dir name.

PHONY = ruleA ruleB display

all: ruleA

ruleA: TMP = $(shell mktemp -d testruleA_XXXX)
ruleA: display

ruleB: TMP = $(shell mktemp -d testruleB_XXXX)
ruleB: display

display:
    echo ${TMP}

Running the code produces the expected result:

$ ls
Makefile
$ make ruleB
echo testruleB_Y4Ow
testruleB_Y4Ow
$ ls
Makefile  testruleB_Y4Ow
剑心龙吟 2024-08-21 18:53:07

我不喜欢“不”的答案,但是……不。

make 的变量是全局的,应该在 makefile 的“解析”阶段而不是执行阶段进行评估。

在这种情况下,只要该变量是单个目标的本地变量,请按照 @nobar 的答案 并将其设为 shell 变量。

其他 make 实现也认为特定于目标的变量是有害的: katiMozilla pymake。因此,目标可以以不同的方式构建,具体取决于它是独立构建还是作为具有特定于目标的变量的父目标的依赖项。 而且你不会知道它是哪条路,因为你不知道已经构建了什么。

I dislike "Don't" answers, but... don't.

make's variables are global and are supposed to be evaluated during makefile's "parsing" stage, not during execution stage.

In this case, as long as the variable local to a single target, follow @nobar's answer and make it a shell variable.

Target-specific variables, too, are considered harmful by other make implementations: kati, Mozilla pymake. Because of them, a target can be built differently depending on if it's built standalone, or as a dependency of a parent target with a target-specific variable. And you won't know which way it was, because you don't know what is already built.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文