在 makefile 中调用 bash 命令 [英] Invoking bash commands in makefile

查看:113
本文介绍了在 makefile 中调用 bash 命令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

makefile 内,我试图检查fileA是否比fileB更新得最近.使用之前的一些帖子(此)作为参考,我想出这是为了将自上次文件修改以来的时间存储为变量:

Inside of a makefile, I'm trying to check if fileA was modified more recently than fileB. Using a few prior posts (this and this) as references, I've come up with this as an attempt to store the time since last file modification as a variable:

(我希望这是在 make 配方之外的函数中,但一次只能执行一个步骤.)

(I'd rather this be in a function outside of a make recipe, but one step at a time.)

    .PHONY: all clean

    all      : (stuff happens here)

    radio    :
              BASE_MOD_TIME="$( expr $(date +%s) - $(date +%s -r src/radio_interface/profile_init.c) )"
              @echo "$(BASE_MOD_TIME)"

我认为我应该将 expr 命令的输出分配给变量 BASE_MOD_TIME ,但是输出是:

I thought that I would be assigning the output of the expr command to a variable, BASE_MOD_TIME, but the output is:

    bash-4.1$
    BASE_MOD_TIME=""
    echo ""

我在这里做错了什么?保存 ls -l <​​/code>输出的简单尝试也没有这样的效果.

What am I doing wrong here? Simple attempts to save the output of ls -l also didn't work like this.

推荐答案

使变量通常是全局变量,并且通常不会在配方中设置make变量.配方只是外壳程序要执行的命令的列表,因此在配方中看起来像变量分配的就是外壳程序变量分配.

Make variables are normally global, and you don't normally set make variables in a recipe. A recipe is simply a list of commands to be executed by a shell, and so what looks like a variable assignment in a recipe is a shell variable assignment.

但是, make 配方中的每一行都在其自己的shell子进程中运行.因此,一行中设置的变量在另一行中不可见;他们不是持久的.这使得在配方中设置外壳变量的用处不大.[注1]

However, each line in a make recipe is run in its own shell subprocess. So a variable set in one line won't be visible in another line; they are not persistent. That makes setting shell variables in recipes less useful. [Note 1]

但是您可以在行的末尾使用反斜杠转义,将配方的多行组合到单个shell命令中,并记住用分号终止各个命令(或者更好的是,将它们与&& ),因为不会将反斜杠转义的换行符传递给shell.另外,不要忘记转义 $ 字符,这样它们将被传递到外壳,而不是被 make 解释.

But you can combine multiple lines of a recipe into a single shell command using the backslash escape at the end of the line, and remembering to terminate the individual commands with semicolons (or, better, link them with &&), because the backslash-escaped newline will not be passed to the shell. Also, don't forget to escape the $ characters so they will be passed to the shell, rather than being interpreted by make.

因此您可以执行以下操作:

So you could do the following:

radio:
    @BASE_MOD_TIME="$$( expr $$(date +%s) - $$(date +%s -r src/radio_interface/profile_init.c) )"; \
    echo "$$BASE_MOD_TIME"; \
    # More commands in the same subprocess

但是,如果有多个命令,那将变得很尴尬,更好的解决方案通常是编写一个Shell脚本并从配方中调用它(尽管这意味着Makefile不再是独立的.)

But that gets quite awkward if there are more than a couple of commands, and a better solution is usually to write a shell script and invoke it from the recipe (although that means that the Makefile is no longer self-contained.)

Gnu make提供了两种在配方中设置make变量的方法:

Gnu make provides two ways to set make variables in a recipe:

您可以通过添加类似于以下内容的行来创建特定于目标的变量(并非完全位于目标本地):

You can create a target-specific variable (which is not exactly local to the target) by adding a line like:

target: var := value

要通过shell命令设置变量,请使用 shell 函数:

To set the variable from a shell command, use the shell function:

target: var := $(shell ....)

此变量将在目标配方中以及由目标触发的所有依赖项中可用.请注意,一个依赖项仅被评估一次,因此,如果它可以由另一个目标触发,则依赖于 make 解析的顺序,特定于目标的变量在该依赖项中可能可用或可能不可用.依赖性.

This variable will be available in the target recipe and all dependencies triggered by the target. Note that a dependency is only evaluated once, so if it could be triggered by a different target, the target-specific variable might or might not be available in the dependency, depending on the order in which make resolves dependencies.

由于总是延迟配方的扩展,因此可以在配方内使用 eval 函数来延迟make变量的分配. eval 函数可以很好地放置在配方中的任何位置,因为它的值是空字符串.但是, eval 进行变量分配会使变量分配成为全局变量.它在整个Makefile中都是可见的,但在其他配方中的值将再次取决于make评估配方的顺序,而该顺序不一定是可预测的.

Since the expansion of recipes is always deferred, you can use the eval function inside a recipe to defer the assignment of a make variable. The eval function can be placed pretty well anywhere in a recipe because its value is the empty string. However, evaling a variable assignment makes the variable assignment global; it will be visible throughout the makefile, but its value in other recipes will depend, again, on the order in which make evaluates recipes, which is not necessarily predictable.

例如:

radio:
    $(eval var = $(shell ...))


注意:

  1. 您可以使用 .ONESHELL:伪目标更改此行为,但这将应用于整个Makefile;无法将单个配方标记为在单个子流程中执行.由于更改行为可能会以意想不到的方式破坏食谱,因此我通常不建议使用此功能.
  1. You can change this behaviour using the .ONESHELL: pseudo-target, but that will apply to the entire Makefile; there is no way to mark a single recipe as being executed in a single subprocess. Since changing the behaviour can break recipes in unexpected ways, I don't usually recommend this feature.

这篇关于在 makefile 中调用 bash 命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆