在Makefile中,如果另一个目标已过期,是否可以让目标过时?

时间:2012-07-18 21:58:46

标签: build makefile gnu-make

我想写一个看起来像这样的规则:

foo.out: (out of date if foo.in is newer than foo.out.stamp)
    # update foo.out if and only if the new foo.out has different contents
    # than the old foo.out (a change to foo.in may or may not change foo.out)
    && touch foo.out.stamp

我不能这样做:

foo.out.stamp: foo.in
    # update foo.out if and only if the new foo.out has different contents
    # than the old foo.out (a change to foo.in may or may not change foo.out)
    && touch foo.out.stamp

foo.out: foo.out.stamp

因为如果foo.in更改,但foo.out.stamp的配方不会更改foo.outmake将始终将foo.out视为过期。

有没有办法写这种规则?

编辑:解释为什么我没有无条件地触摸foo.out

我正在与Vala合作。 Vala编译过程如下所示:

  1. 对于每个.vala文件,生成一个.vapi文件(类似于头文件)。
  2. 对于每个.vala文件,生成一个.c文件(这需要单独的.vala文件和每个 .vapi文件编译器)
  3. 继续典型的.c -> .o -> executable/library流程。
  4. 对于步骤#1和#2,Vala编译器仅在其内容已更改时才更新.vapi / .c文件。这是为了防止不必要的.c -> .o重新编译。

    在makefile中:

    • 如果自上次Vala编译器重新生成.vapi文件后.vala文件发生更改,.vapi文件已过期(不是.vapi的最后一次文件被修改了。)
    • 如果自上次Vala编译器重新生成{{1}后.c任何 .vala文件发生更改,则.vapi文件已过期文件(不是最后一次修改.c文件)。

4 个答案:

答案 0 :(得分:1)

有一种技术大致相当于你想要在Kernighan& Pike 'The UNIX Programming Environment'(1984),与Yacc语法一起使用。

Yacc源文件可能是grammar.y。 Yacc的默认输出文件是y.tab.cy.tab.h。其他文件(特别是词法分析器)依赖于标题,但即使语法的C代码(动作),标题也不会经常改变。因此,只有当Yacc生成的标题不同时才能确保词法分析器使用的标题更改是明智的。解决这个问题的方法是让词法分析器包含x.tab.h(不是y.tab.h),并且只有在有y.tab.h时才复制新的x.tab.h差。

x.tab.h: y.tab.h
   -cmp -s x.tab.h y.tab.h || cp y.tab.h x.tab.h

这在您的上下文中更难应用,因为您似乎无法控制可以以相同方式使用的文件名 - filename.vala文件生成filename.vapi和{{1需要filename.c中代码服务的其他Vala源文件将自动包含filename.vala


你说:

  

在makefile中:

     
      
  • 如果自上次Vala编译器重新生成filename.vapi文件后.vapi文件发生更改,.vala文件已过期(不是.vapi的最后一次文件被修改了。)
  •   
  • 如果自上次Vala编译器重新生成{{1}后.vapi任何 .c文件发生更改,则.vala文件已过期文件(不是最后一次修改.vapi文件)。
  •   

第一条规则就是普通的源/对象关系:

.c

其中(我猜).c选项从Vala源生成标头(%.vapi: %.vala $(VALAC) -h $*.vala )文件,相应的-h选项生成C源({{1文件。

第二条规则也是正常的源/对象关系:

.vapi

这表示如果-c文件比.c文件更新,则会从%.c: %.vala $(VALAC) -c $*.vala 文件重新生成.c文件。 此外,.vala文件取决于它包含的.vala文件:

.c

答案 1 :(得分:0)

请检查以下内容是否适合您:

foo.out.stamp: foo.in
    # if the new foo.out has different contents than the old foo.out
    update foo.out && touch foo.out.stamp
    #else
    touch -r foo.out foo.out.stamp

foo.out: foo.out.stamp

touch的第二次调用会将foo.out.stamp的时间戳更新为foo.out的时间戳。从联机帮助页:

-r, --reference=FILE
      use this file's times instead of current time

答案 2 :(得分:0)

以下内容似乎与您对.vapa.vali文件之间关系的描述相符:

% cat Makefile
VFILES=A B

.PRECIOUS: $(VFILES:=.vapi)

%.vapi: %.vala
    touch $@

%.c: %.vala $(VFILES:=.vapi)
    echo "$^" >$@

%.o: %.c
    touch $@

all: A.o
% ls
A.vala      B.vala      Makefile
% make A.o
touch A.vapi
touch B.vapi
echo "A.vala A.vapi B.vapi" >A.c
touch A.o
rm A.c
% make B.o
echo "B.vala A.vapi B.vapi" >B.c
touch B.o
rm B.c
% touch A.vala
% make B.o    
touch A.vapi
echo "B.vala A.vapi B.vapi" >B.c
touch B.o
rm B.c
% make A.o
echo "A.vala A.vapi B.vapi" >A.c
touch A.o
rm A.c
% ls -lt
total 24
-rw-r--r--  1 norman  wheel    0 19 Jul 00:11 A.o
-rw-r--r--  1 norman  wheel    0 19 Jul 00:11 A.vapi
-rw-r--r--  1 norman  wheel    0 19 Jul 00:11 B.o
-rw-r--r--  1 norman  wheel    6 19 Jul 00:11 A.vala
-rw-r--r--  1 norman  wheel    0 19 Jul 00:10 B.vapi
-rw-r--r--  1 norman  wheel    6 19 Jul 00:10 B.vala
-rw-r--r--  1 norman  wheel  141 19 Jul 00:09 Makefile
% 

这有用吗?

答案 3 :(得分:0)

我最后通过添加一个顶级规则来确保邮票始终可用,并且实际输出文件为空规则,从而解决了这个问题:

all: %.out.stamp

%.out: ;

从技术上讲,这并不是我所做的,因为我不是手工编写Makefile(我正在使用cmake)。在CMake术语中,我添加了一个自定义目标,该目标取决于所有.vapi.stamp.dep(类似于.c.stamp)文件。从.c文件构建可执行文件/库的CMake目标取决于此目标。