2017-06-04 28 views
0

让我们想象一下,我有一个不产生基于文件系统的一些其他文件的文件,但一些外部命令的输出可能会或可能不会改变。我可以在makefile中表达这个概念,并且只有在内容实际改变时才运行相关目标。生成文件重新编译只有当它的依赖实际上改变

具体的,我有一个文件date.h其中有当前的日期,小时和分钟(而不是秒),这是由规则产生这样的:

echo "#define DATE" '"' $$(date '+%D-%H:%M') '"' > date.h 

默认的“应用”目标依赖在date.h和整个Makefile文件看起来像:

app: date.h 
    echo "Building app" 
    touch app 

date.h: FORCE 
    echo "#define DATE" '"' $$(date '+%D-%H:%M') '"' > date.h 

FORCE: 

现在FORCE目标造成date.h要重建每一次,这将导致app永远是过时的,并得到重修。另一方面,如果我不包含FORCE目标,那么date.h只有在不存在的情况下才会被重建(例如,在清理之后或初始克隆项目之后),但不会在之后再次重建。

我想要的只是如果date.h的内容实际上被echo更改了 - 也就是说,当分钟发生变化时,但不是其他情况。有没有办法告诉make只考虑date.h如果其实际字节在磁盘上发生更改,而不是按时间戳或另一种方式来实现此效果,则会发生更改?

回复日期到一个临时文件,然后有条件地更新date.h基于比较他们的内容跨过我的脑海,但我不知道这是否是一个合理的方法。

+1

这最后一句听起来像一个合理的办法给我。你必须每次执行'echo',Make看看文件修改时间,而不是内容,所以如果你想使用Make,我认为你必须这样做。 – Beta

+2

通常的方法就像你描述的一样。生成文件作为临时文件,检查是否更改,如果是这样,用临时文件替换目标。海湾合作委员会为此目的有一个“如果改变”的脚本。 –

+0

我可能表明,具有类似于在一个字符串/文件/编译时间的日变化项目是在其本身的错误。您应该改用版本标签。无论什么时候改变,版本标签都会改变。噗!突然间,这变成了一个非问题,你的Makefile可以小而性感,没有你现在正在思考的扭曲。 – Jens

回答

2

你的建议在最后一段这样做是有条件改造的目标只有一个特定的依赖实际上已经改变,而不仅仅是如果依赖的时间戳已经改变了通常的方式。在生成特定依赖关系的规则中,将其生成为临时文件,检查其内容是否已更改,如果是,则用临时文件替换规则的目标。值得注意的是,只要我能记得,海湾合作委员会在其制作文件中一直这样做。它生成源代码和头文件,如表和模式识别器,当它们的依赖关系之一时它们通常不会改变。停止生成这些生成文件的依赖项的目标不会被重建,这会对构建时间产生很大影响。

因此,对于你的makefile例如,你可以这样做:

date.h: FORCE 
     echo "#define DATE" '"' $$(date '+%D-%H:%M') '"' > date.h.tmp 
     if test -r date.h;            \ 
     then               \ 
       cmp date.h.tmp date.h || mv -f date.h.tmp date.h;  \ 
     else               \ 
       mv date.h.tmp date.h;         \ 
     fi 

您可能还需要在使用中包括GCC源move-if-change shell脚本来看看。

0

我找到了另一种方式,如何解决这个问题。这个想法是这样的:你检查一个临时文件,它是用日期和时间值保存的。所以,第一次,你得到一个像tmp/YYMMDDHHMM这样的文件。当你再次运行你Makefile时,检查它是否存在。如果是的话,不要创建一个新的/不要更新date.h。一分钟后,如果您运行Makefile再次,新的文件tmp/YYMMDDHHMM生成等date.h更新:

TMP_DIR := tmp 
RUN_OR_NOT := $(shell date '+%y%m%d%H%M') 

all: ${TMP_DIR}/date.h 

tmp_dir: 
     mkdir -p ${TMP_DIR} 

${TMP_DIR}/${RUN_OR_NOT}: tmp_dir 
     if [ ! -f "${TMP_DIR}/${RUN_OR_NOT}" ]; then \ 
       echo "" > ${TMP_DIR}/${RUN_OR_NOT}; \ 
     fi; 

${TMP_DIR}/date.h: ${TMP_DIR}/${RUN_OR_NOT} 
     # create date.h 
     @echo "Run date.h target, which creates date.h" 
     touch ${TMP_DIR}/date.h 

.PHONY: all special 
相关问题