Makefile中的别名目标名称

36

问题:

是否可以为目标对象分配另一个名称或别名,以便可以使用原始目标名称或别名来调用它。

例如,类似于以下内容:

/very/long/path/my_binary: dep_a dep_b dep_c
    # Compile

# Desired command
ALIAS my_binary = /very/long/path/my_binary

# NOTE: Notice the use of 'my_binary' in the dependencies
data1: my_binary datafile
    # Build data file using compiled my_binary

尝试1:.PHONY

我尝试使用.PHONY目标:

.PHONY: my_binary
my_binary: /very/long/path/my_binary

当从命令行调用时,这个功能非常好用:

# Runs rule 'my_binary' and then *only* runs rule '/very/long/path/my_binary'
# if the rule '/very/long/path/my_binary' needs updating.
make my_binary

然而,当别名my_binary被列为依赖项时,这种方法并不奏效:

# *Always* thinks that rule 'data1' needs updating, because it always thinks that
# the .PHONY target 'my_binary' "needs updating". As a result, 'data1' is
# rebuilt every time.
make /very/long/path/my_binary

可能的黑客攻击?

一种可能的黑客攻击方法是使用空目标,如这个问题的答案中建议的那样,但这将需要引入具有与别名对应的虚假文件名称:

my_binary: /very/long/path/my_binary
    touch my_binary

这样会在主目录中创建很多文件!把虚假文件放在子目录中会失去意义,因为别名必须被称为”directory/my_binary”。
3个回答

25

好的,我需要类似的东西。我的输出构件路径很长,但我想要简短的目标名称,并且也容易从 bash-completion 中受益。

以下是我想出来的:

os := [arbitrary long path to an artifact]
platform := [arbitrary long path to a differ artifact]
packer := [common parts of my packer build command]

.PHONY: all
all: $(platform)

.PHONY: platform
platform: $(platform)

$(platform): platform.json  $(os)
    @$(packer) $<

.PHONY: os
os: $(os)

$(os): os.json
    @$(packer) $<

.PHONY: clean
clean:
    rm -fr build/

使用上面的Makefile,您可以这样说:

$ make os
$ make platform

这将成为长工件名称的别名。我使上面的片段相当长,因为重要的是要看到.PHONY别名与真实目标之间的关系。希望这对你有用。

注意:我没有从上面的示例中删除clean目标,因为许多人不将其作为.PHONY目标。但从语义上讲,它应该是这样的。


2
请注意,重要的是让依赖项依赖于实际目标,而不是它们的别名(即$(platform): platform.json $(os)而不是$(platform): platform.json os)。 - Vladimir Panteleev
1
这不就是 OP 在“尝试 1:.PHONY”中描述的完全相同吗? - André Chalella
1
我认为这不是一样的。在我的尝试中,将.PHONY目标想象成仅供最终用户使用的接口,即仅在从shell调用make <target>时使用.PHONY目标。在makefile中描述依赖树时,请始终使用“真实”目标。=> 对最终用户来说很舒适;对编写makefile的开发人员来说有点繁琐。结果:正确的依赖计算;良好的用户体验。 如果您有类似于binary: my-phony-target的东西,则每次调用都会重新构建二进制文件,因为虚拟目标总是过时的,并且可传递性适用。 - frncmx
2
当然,创建可以从命令行使用的“别名”是微不足道的。这非常普遍。但 OP 还想从 makefile 内部使用别名(将其列为先决条件)。在这里,您没有这样做,而是使用完整路径作为前提条件(通过变量)。 - MadScientist
@MadScientist 我不确定你的意思。我的解决方案只是在你的解决方案上添加了一些内容。两个区别是:
  1. 我使用 :=(简单扩展变量)而不是 =(递归变量)
  2. 我添加了一个技巧,使得命令行别名也能使用(不仅仅是在 Makefile 中的速记)
除了上述两点外,该变量可以像你的解决方案一样作为先决条件使用,例如:$(platform): platform.json $(os) 其中 os 是该变量。
- frncmx

19

我认为没有办法让你在Makefile中和命令行中都能使用别名,除非创建临时文件。

为什么不在Makefile中设置变量呢,例如:

my_binary = /very/long/path/my_binary

那么在makefile中的每个地方都使用$(my_binary)?我认为没必要为在makefile内部使用而创建一个真实的别名目标。


可能有些偏题,但如果您选择这个选项,您将如何在循环中调用它?例如 for p in $$($(my_binary) --some-flag); do ...?我似乎无法让它工作。 - Javier García Manzano
你所写的代码是可以工作的。如果它不能正常工作,请创建一个新问题,详细说明你所做的事情、你输入的命令、你得到的输出,并描述输出有什么问题以及你想要得到什么结果。请剪切和粘贴代码,并进行适当的格式化:不要使用图像,也不要改述命令和错误信息。 - MadScientist

5

我有一个类似的需求。我希望我的 Makefile 的用户可以输入以下任何一个来实现同样的结果,这样以下内容就是等效的:

make hit list
make hitlist
make hit_list

我在我的makefile中所做的是以下内容:

hit_list:

        @echo Got here
        <the real recipe goes here>

hit: hit_list
hitlist: hit_list
.PHONY: list
list:
        @echo > /dev/null

接着,我使用任意一个命令 "make hit list"、"make hitlist" 或 "make hit_list" 进行测试时,都得到了相同的结果,正如预期的那样。

因此,如果你的目标之一是具有较长名字的目标,但你采用了这种方法,简单的短名称将具有长名称的目标标识为前提条件,我认为你应该能够说“make short_name”,并实现你所要求的内容。

与你的第一种方法不同的是,这些同义词中没有一个被定义为伪目标(考虑到 "make hit list" 是一个制作两个目标的命令,第二个目标实际上是无操作),因此你所描述的复杂情况不会出现。


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