在同一个Makefile中,如何从一个recipe更改一个make变量并调用另一个规则?

47

我已经看过了如何从make目标手动调用另一个目标?,但我的问题有些不同;考虑以下示例(注意,stackoverflow.com将制表符改为空格显示;但如果您尝试编辑,制表符将保留在源代码中):

TEXENGINE=pdflatex

pdflatex:
    echo the engine is $(TEXENGINE)

lualatex:
    TEXENGINE=lualatex
    echo Here I want to call the pdflatex rule, to check $(TEXENGINE) there!

这里,如果我运行默认目标(pdflatex),我会得到预期的输出:

$ make pdflatex 
echo the engine is pdflatex
the engine is pdflatex

然而,对于目标lualatex,我想要:

  • make变量TEXENGINE更改为lualatex,然后
  • 调用与pdflatex相同的代码(使用它)。

我该怎么做呢?

显然,在我的lualatex规则中,我甚至没有成功地更改TEXENGINE变量,因为我在尝试时得到了这个提示:

$ make lualatex 
TEXENGINE=lualatex
echo Here I want to call the pdflatex rule, to check pdflatex there!
Here I want to call the pdflatex rule, to check pdflatex there!

...所以我真的想知道在Makefile中是否可能实现这样的功能。


1
首先,如果您正在使用它来检查任意内容,我不会将目标称为 pdflatex。我建议使用类似于 checkEngine 的东西,并将其设置为 .PHONY - Oliver Charlesworth
谢谢,@OliverCharlesworth - 我认为这很好,因为在这种情况下,pdflatex是默认的,所以我只需使用makemake pdflatex即可获得相同的结果(然后可以通过将它们指定为make目标来更改引擎,例如make lualatex)。干杯! - sdaau
1
由你决定 ;) (我会觉得这样相当混乱和不好的做法...)你能否只需执行 make TEXENGINE=whatever,并构建一组通用的目标/规则,使用用户指定的 TEXENGINE 变量? - Oliver Charlesworth
再次感谢@OliverCharlesworth - 我同意这将是不好的做法,特别是对于代码构建;但在这种情况下,这种makefile的增长方式非常有限,所以我敢忽略不良实践,以换取命令行方便:)否则,我已经忘记了在make命令行上使用变量 - 只是在写下面的答案时才想起。干杯! - sdaau
2个回答

76

使用目标特定变量

目标特定变量的另一个特殊功能是: 当你定义一个针对特定目标的变量时,该变量值也适用于此目标的所有前置条件,以及它们的前置条件等(除非这些前置条件使用自己的目标特定变量值覆盖该变量)。

TEXENGINE=pdflatex

pdflatex:
    echo the engine is $(TEXENGINE)

lualatex: TEXENGINE=lualatex
lualatex: pdflatex
    echo Here I want to call the pdflatex rule, to check $(TEXENGINE) there!

输出结果为:

$ make pdflatex
echo the engine is pdflatex
the engine is pdflatex
$ make lualatex
echo the engine is lualatex
the engine is lualatex
echo Here I want to call the pdflatex rule, to check lualatex there!
Here I want to call the pdflatex rule, to check lualatex there!

感谢@JonathanWakely的帮助 - 起初我有些困惑,因为先决条件会在lualatex之前调用pdflatex;但是后来我进行了测试并意识到将lualatex:目标拆分成两个可以避免这个问题 - 这个解决方案也可以在没有递归make调用的情况下工作,这太棒了。还要感谢您对“目标特定变量”的说明。干杯! - sdaau
4
更具体地说,如果在 lualatex 中没有需要做的事情,除了 pdflatex 所做的事情,那么在 lualatex 目标上你就不需要任何配方内容。只需要两个 lualatex: 行就足够了。 - Etan Reisner
你可以定义多个变量吗? - CpILL
2
@CpILL 是的,您可以添加多个“lualatex:foo = bar”行,每个行代表一个额外的变量。(我不确定您是否可以在单行上处理多个变量)。 - chrismo
如果我想从lualatex两次调用pdflatex,每次使用不同的变量,该怎么办? - SOFe
1
@SOFe 这似乎应该是一个新问题,而不是一个评论。你可以让 lualatex 目标依赖于 lualatex1 和 lualatex2 目标,每个目标都使用不同的变量覆盖方式。 - Jonathan Wakely

7

好的,我成功地找到了一种解决方法,但我并不完全理解它,因此更深入的回答将会被欣然接受。对我来说,以下链接非常有帮助:

所以这里是修改后的示例 - 显然,要从一个规则中调用另一个规则(不作为先决条件,而是作为后决条件),我只能递归调用make,同时在其命令行上指定新的变量值:

TEXENGINE=pdflatex

pdflatex:
    echo the engine is $(TEXENGINE)

lualatex:
    echo Here I want to call the pdflatex rule, to check $(TEXENGINE) there!
    $(MAKE) TEXENGINE=lualatex pdflatex

输出结果有点啰嗦,但它是可行的:
$ make lualatex 
echo Here I want to call the pdflatex rule, to check pdflatex there!
Here I want to call the pdflatex rule, to check pdflatex there!
make TEXENGINE=lualatex pdflatex
make[1]: Entering directory `/tmp'
echo the engine is lualatex
the engine is lualatex
make[1]: Leaving directory `/tmp'

......这正是我想要的,纯粹基于命令行交互方式,但我知道这不是最好的解决方案(见下面@JonathanWakely的评论)


4
你的规则在这里的作用是运行另一个make实例并显式地覆盖TEXENGINE变量。在命令行定义的变量优先于环境变量或者 makefile 中定义的变量,因此第二个make运行时会使用被覆盖的值。这种方法的缺点是你需要运行两次make,所以如果它需要大量工作来检查先决条件的状态,那么你需要做两次所有的工作。 - Jonathan Wakely

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接