Build 在Makefile中,如果另一个目标已过期,是否可能有一个目标已过期?

Build 在Makefile中,如果另一个目标已过期,是否可能有一个目标已过期?,build,makefile,gnu-make,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

我想写一条如下的规则:

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.out
make
将始终将
foo.out
视为过期

有没有办法写出这样的规则

编辑:解释我为什么不无条件地接触foo.out:

我和瓦拉一起工作。Vala编译过程如下所示:

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
  • 对于每个
    .vala
    文件,生成一个
    .vapi
    文件(类似于头文件)
  • 对于每个
    .vala
    文件,生成一个
    .c
    文件(这需要将单个
    .vala
    文件和每个
    .vapi
    文件提供给编译器)
  • 继续典型的
    .c->.o->executable/library
    过程
  • 对于步骤#1和#2,如果
    .vapi
    /
    .c
    文件的内容已更改,则Vala编译器仅更新该文件。这是为了防止不必要的
    .c->.o
    重新编译

    在makefile中:

    • 如果自上次vala编译器重新生成
      .vapi
      文件(不是上次修改
      .vapi
      文件)以来,
      .vapi
      文件已更改,则
      .vapi
      文件已过期
    • 如果自上次vala编译器重新生成
      .c
      文件(不是上次修改
      .c
      文件)以来,
      .c
      文件或任何
      .vapi
      文件已更改,则
      .c
      文件已过期

    请检查以下各项是否适用于您:

    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
    的时间戳。从手册页:


    以下内容似乎与您对
    .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
    % 
    

    这行得通吗?

    有一种技术大致相当于您在Kernighan&Pike(1984)中希望使用的技术,与Yacc语法一起使用

    Yacc源文件可能是
    grammar.y
    。Yacc的默认输出文件是
    y.tab.c
    y.tab.h
    。其他文件(尤其是词法分析器)依赖于头文件,但是头文件并不经常改变,即使语法(操作)的C代码改变了头文件。因此,确保词法分析器使用的头只有在Yacc生成的头不同时才被更改是明智的。处理这个问题的方法是让词法分析器包括
    x.tab.h
    (而不是
    y.tab.h
    ),并且仅当存在差异时,才在旧的
    x.tab.h
    上复制一个新的
    y.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
    filename.c
    ,以及需要
    filename.Vala
    中的代码服务的其他Vala源文件将自动包括
    filename.vapi


    你说:

    在makefile中:

    • 如果自上次vala编译器重新生成
      .vapi
      文件(不是上次修改
      .vapi
      文件)以来,
      .vapi
      文件已更改,则
      .vapi
      文件已过期
    • 如果自上次vala编译器重新生成
      .c
      文件(不是上次修改
      .c
      文件)以来,
      .c
      文件或任何
      .vapi
      文件已更改,则
      .c
      文件已过期
    第一条规则就是正常的源/对象关系:

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

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

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

    file1.c:  file2.vapi file3.vapi file4.vapi ...
    

    我最终解决了这个问题,添加了一个顶层规则,确保戳记始终处于待办状态,并为实际输出文件添加了空规则:

    all: %.out.stamp
    
    %.out: ;
    

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

    在第二个示例中:为什么不无条件地触摸
    foo.out
    (或者,至少,如果没有发生错误)?实际上,我在我的一个项目中面临类似的问题。目前我只接受它,但我肯定希望看到一个解决方案。
    valac
    的关键行为是:运行
    $(valac)--fast vapi=foo.vapi foo.vala
    可能不会更改
    foo.vapi
    的修改日期
    $(VALAC)-C foo.vala--使用fast vapi=*。vapi
    可能不会更改
    foo.C
    的修改日期。所以
    foo.vapi
    /
    foo.c
    永远过时。啊,我可能又误解了。如果问题是“可能不会更改修改日期,而且应该更改”,那么一个有用的模式可能是
    $(VALAC)--fast vapi=$@$<&&touch$@
    ,这将确保编译成功后,$@(=foo.vapi)会更新。但也许你已经试过了。这对你来说不起作用