Makefile"include"的时间为自动生成文件的语句 [英] Timing of Makefile "include" statements for auto-generated files

查看:75
本文介绍了Makefile"include"的时间为自动生成文件的语句的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在此Makefile中...

In this Makefile...

all:    piped.mk
ifeq ($(PIPED),1)
    @echo Output of make is piped
else
    @echo Output of make is NOT piped
endif

piped.mk:
    [ -t 1 ] && PIPED=0 || PIPED=1 ; echo "PIPED=$${PIPED}" > piped.mk

.PHONY: piped.mk all

include piped.mk

...我期望以下内容:

...I would expect the following:

  • 第一个规则all说,它取决于文件piped.mk.
  • 文件piped.mk是通过询问外壳程序终端的标准输出是否为TTY生成的
  • 文件piped.mk在结尾处是include d;因此,从理论上讲,这应该触发make的重制"逻辑(请参见make手册中的3.5节)
  • 为了强制创建piped.mk(,因为它不应该依赖文件,而是调用make的方式),所以它也被标记为.PHONY目标-无论如何,都应该重制它.
  • The first rule, all, says it depends on the file piped.mk.
  • The file piped.mk is generated by asking the shell whether the terminal's stdout is a TTY or not
  • The file piped.mk is included at the end; in theory therefore this should trigger makes "remaking" logic (see section 3.5 in the make manual)
  • To force the creation of piped.mk (since it is not supposed to depend on files, but on the way make was invoked), it is also marked as a .PHONY target - one that should be remade no matter what.

如果这些假设是正确的,我不明白这个结果:

If these assumptions are correct, I don't understand this result:

$ make
[ -t 1 ] && PIPED=0 || PIPED=1 ; echo "PIPED=${PIPED}" > piped.mk
Output of make is NOT piped

$ cat piped.mk 
PIPED=0

$ make | more
[ -t 1 ] && PIPED=0 || PIPED=1 ; echo "PIPED=${PIPED}" > piped.mk
Output of make is NOT piped

$ cat piped.mk 
PIPED=1

似乎文件piped.mk总是按预期进行了重新制作-并且确实包含了预期的信息(是否通过标准输出输出了).但是,Makefile似乎忽略了PIPED的值-它总是报告"NOT Piped";好像piped.mk在重新生成后未重新包含...

It appears that file piped.mk is always remade, as intended - and it indeed contains the intended information (whether the standard output is piped or not). The Makefile however, seems to ignore the value of PIPED - it always reports "NOT piped"; as if piped.mk is not re-included after its regeneration...

更新

传统上,自动生成的Makefile部分的典型示例是C文件依赖项的生成-在这种情况下,我看到的所有示例最终都使用Makefile底部的include.但是,也许这种方法仅适用于生成依赖项,而不适用于Makefile变量的分配...

Traditionally, the prototypical example of automatically generated Makefile parts is the generation of the C file dependencies - in which case all examples I've seen end up using include at the bottom of the Makefile. However, maybe this approach only works for the generation of dependencies, and does not work for the assignment of Makefile variables...

要检查是否是原因,我尝试将include向上移动到顶部...

To check if this was the reason, I attempted to move the include up to the top...

$ cat Makefile
include piped.mk

all: ...

...导致令人讨厌的延迟"效果:

...which caused a nasty "delay" effect:

$ rm -f piped.mk
$ make | more
[ -t 1 ] && PIPED=0 || PIPED=1 ; echo "PIPED=${PIPED}" > piped.mk
Output of make is NOT piped

$ make | more
[ -t 1 ] && PIPED=0 || PIPED=1 ; echo "PIPED=${PIPED}" > piped.mk
Output of make is piped

基本上,会发生包含 -但它是在piped.mk生成之前发生的.因此,它使用PIPED定义的旧"值,而不是执行时仅放置在piped.mk内部的新值.也许只允许重新包含piped.mk才能更新依赖项规则,而不能更新变量定义吗?

Basically, the inclusion does happen - but it happens BEFORE the piped.mk generation. It therefore uses the "old" value of the definition of PIPED, not the new one that was just placed inside piped.mk upon execution. Maybe the re-inclusion of piped.mk is only allowed to update dependency rules and not variable definitions?

所以,我的问题:

是否可以自动生成包含变量定义的Makefile的一部分,并在同一Makefile调用中将其包括在内?

Is it possible to auto-generate a part of a Makefile that contains variable definitions, and include it within the same Makefile invocation?

也就是说,没有单独的$(MAKE)调用-这是我到目前为止找到的唯一使之起作用的方法:

That is, without a separate $(MAKE) invocation - which is the only way I have found so far to make it work:

all:
        @[ -t 1 ] && PIPED=0 || PIPED=1 ; \
            $(MAKE) binary "PIPED=$${PIPED}"

binary:
ifeq ($(PIPED),1)
        @echo Output of make is piped
else
        @echo Output of make is NOT piped
endif

.PHONY: all binary

谢谢您的建议.

推荐答案

首先,非常感谢@Beta的反馈.

First of all, many thanks to @Beta for his feedback.

@Beta建议使用$(shell ...)构造执行[-t 1]检查;但不幸的是,在这种情况下,这无法正常工作.目的是检测Makefile是否在管道执行中得到处理...

@Beta recommended using the $(shell ...) construct to execute the [-t 1] check; but unfortunately this can't work in this case. The intent is to detect whether the Makefile is processed in a piped execution...

$ make | less     # page/search interactively in the build log
$ make | grep ... # Bulk search for stuff in the build log
$ make > log.txt  # Or use the log.txt from within e.g. a LaTEX doc...

...还是不.想想避免在输出中打印颜色代码(这会弄乱在LaTEX文档中按原样重新使用输出,或者使您的寻呼机,grep等混乱).这个构造...

...or not. Think e.g. of avoiding the printing of color codes in the output (which would mess up re-using the output as-is from within a LaTEX document, or confuse your pager, grep, etc). This construct...

PIPED:=$(shell [ -t 1 ] ... )

...当嵌入在Makefile中时不起作用;因为stdout已经在make内部重定向,以捕获输出并将其分配给变量.

...when embedded in the Makefile doesn't work; because stdout is already redirected inside make, to capture the output and assign it to a variable.

@Beta另外提出了一个建议,这是解决此问题的关键-这与我对.PHONY的使用有关:

@Beta additionally gave another suggestion, which was key to solving this - it was about my use of .PHONY:

...如果该文件为PHONY,则重建包含的文件不会触发重新调用.

...rebuilding an included file doesn't trigger reinvocation if that file is PHONY.

的确,这解释了为什么我会看到重新执行创建piped.mk的规则,但是不会重新包含该文件的原因.因此PIPED变量保持不变.

Indeed, this explained why I would see the re-execution of the rule that created piped.mk, but the file would not be re-included; and therefore the PIPED variable stayed the same.

为避免这种情况,我完全删除了.PHONY规范,并在all规则的末尾添加了一个操作,以删除piped.mk (因此强制下次重新创建make被调用):

To avoid that, I removed the .PHONY spec altogether, and added an action at the end of the all rule, to remove the piped.mk (thus forcing it to be re-created next time make is invoked):

all:    piped.mk
ifeq ($(PIPED),1)
        @echo Output of make is piped because PIPED is ${PIPED}
else
        @echo Output of make is NOT piped because PIPED is ${PIPED}
endif
        @rm -f piped.mk

piped.mk:
        [ -t 1 ] && PIPED=0 || PIPED=1 ; echo "PIPED=$${PIPED}" > piped.mk

-include piped.mk

使用此方法,我看到了以下结果:

Using this, I saw the following result:

$ make
[ -t 1 ] && PIPED=0 || PIPED=1 ; echo "PIPED=${PIPED}" > piped.mk
Output of make is NOT piped because PIPED is 0

好.对于管道...

$ make | more
[ -t 1 ] && PIPED=0 || PIPED=1 ; echo "PIPED=${PIPED}" > piped.mk
Output of make is NOT piped because PIPED is 1

糟糕!显然,重新包含了piped.mk,并且重新评估了PIPED(因为该操作报告了because PIPED is 1)-但令人惊奇的是,执行的规则是ifeq中的错误规则!

Ooops! Clearly piped.mk was re-included, and PIPED was re-evaluated (since the action reported because PIPED is 1) - but the rule that was executed, amazingly, was the wrong one in the ifeq!

ifeq ($(PIPED),1)
        @echo Output of make is piped because PIPED is ${PIPED}
else
        @echo Output of make is NOT piped because PIPED is ${PIPED}
endif

注意:我严重怀疑那里的任何人都期望包含这5行的Makefile能够打印Output of make is NOT piped because PIPED is 1.实际上,我认为这是make中的错误.

Note: I seriously doubt anyone out there would expect that a Makefile with these 5 lines could ever print Output of make is NOT piped because PIPED is 1. In fact, I'd consider this to be a bug in make.

我的最终想法是,也许make不会重新评估在重新包含之前的检查条件-我将include移到了顶部:

My final idea was that maybe make DOES NOT re-evaluate the check conditions that are BEFORE the point where the re-inclusion took place - and I moved the include on top:

-include piped.mk

all:    piped.mk
ifeq ($(PIPED),1)
    @echo Output of make is piped because PIPED is ${PIPED}
else
    @echo Output of make is NOT piped because PIPED is ${PIPED}
endif
    @rm -f piped.mk

piped.mk:
    [ -t 1 ] && PIPED=0 || PIPED=1 ; echo "PIPED=$${PIPED}" > piped.mk

这终于奏效了:

$ make
[ -t 1 ] && PIPED=0 || PIPED=1 ; echo "PIPED=${PIPED}" > piped.mk
Output of make is NOT piped because PIPED is 0

$ make | more
[ -t 1 ] && PIPED=0 || PIPED=1 ; echo "PIPED=${PIPED}" > piped.mk
Output of make is piped because PIPED is 1

因此,总结一下:

  • 切勿将包含的文件放在.PHONY规则中-如果您希望每次都对它们进行重新评估,只需确保在处理结束时将其删除即可.
  • 如果生成的文件包含依赖项(如make手册中描述的".d"文​​件),则可以在末尾将它们包括在内.但是,如果它们包含变量分配,请确保在使用/检查所述变量之前将其包括在内.
  • Never place included files in .PHONY rules - if you want them re-evaluated every time, just make sure to remove them in the end of your processing.
  • If your generated files contain dependencies - like the '.d' files described in the make manual - it is OK to include them at the end. If, however, they contain variable assignments, make sure to include them BEFORE you use/check said variables.

再次感谢@Beta向我指出正确的方向.

Again, many thanks to @Beta for pointing me in the right direction.

更新:

几个月后,我意识到,由于重新评估了该变量(将其从.PHONY中删除后),我还可以避免使用ifeq,而是在shell本身中进行决定:

And a few months later, I realized that since the variable was re-evaluated (after removing it from the .PHONY), I could also avoid using ifeq and instead decide in the shell itself:

all:
    @[ ${PIPED} -eq 1 ] && echo Piped. || echo Not piped.
    @rm -f piped.mk

piped.mk:
    @[ -t 1 ] && PIPED=0 || PIPED=1 ; echo "PIPED=$${PIPED}" > piped.mk

include piped.mk

这篇关于Makefile"include"的时间为自动生成文件的语句的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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