Makefile生成器创建两个文件

Makefile生成器创建两个文件,makefile,Makefile,我有一个生成器程序,可以创建两个版本文件,比如ver.h和ver.cpp。我的最终构建目标取决于这两个文件,构建这两个文件的规则是一个程序。如果我这样做: build : ver.h ver.cpp ver.h ver.cpp : ./gen/version/program 然后,一个并行构建可以运行两次程序,这虽然不坏,但也太过分了。我想我可以让他们都依靠一个虚假的目标: ver.h ver.cpp : do-version-impl do-version-impl: .

我有一个生成器程序,可以创建两个版本文件,比如
ver.h
ver.cpp
。我的最终构建目标取决于这两个文件,构建这两个文件的规则是一个程序。如果我这样做:

build : ver.h ver.cpp

ver.h ver.cpp :
    ./gen/version/program
然后,一个并行构建可以运行两次
程序
,这虽然不坏,但也太过分了。我想我可以让他们都依靠一个虚假的目标:

ver.h ver.cpp : do-version-impl

do-version-impl:
    ./gen/version/program

.PHONY : do-version-impl
这是最好的方法吗?这听起来有点滑稽,不得不引入一个虚假的规则来做这件事

具体见最后一段:

10.5.1模式规则介绍

模式规则不需要任何包含“%”的先决条件,实际上也不需要任何先决条件。这样的规则实际上是一个通用通配符。它提供了一种生成与目标模式匹配的任何文件的方法。见最后手段

模式规则可能有多个目标。与普通规则不同的是,这并不像许多具有相同先决条件和配方的不同规则那样起作用。如果模式规则有多个目标,make知道规则的配方负责生成所有目标。配方只执行一次以生成所有目标。当搜索与目标匹配的模式规则时,除了与需要规则的目标匹配的规则之外,其他规则的目标模式是偶然的:只需担心为当前有问题的文件提供配方和先决条件。但是,当运行此文件的配方时,其他目标会被标记为自己已更新

所以你可以用这样的东西:

v%r.h v%r.cpp:
        ./gen/version/program
ver.h: ver.cpp ;
ver.cpp: Makefile
    ./gen/version/program

我相信你需要奇特的模式来考虑模式匹配(我不相信它会匹配<代码> %>代码>一个空字符串,如<代码> VE%.h VE%.CPP需要)。(我目前在手册中找不到这方面的参考。)

使用虚假目标作为先决条件是个坏主意<代码>程序将运行,即使存在
ver.*
文件,这是一个误报错误

更微妙的是,GNUMake只保证更新其文件时间戳,如果该文件是带有配方的规则的目标。因此,在这里,即使总是运行
程序
,但是依赖于
ver.*
文件的任何东西都可能根本不会得到更新

在我看来,最好不要为每个目标编造不自然的模式,而是要明确:

您正在生成一个“主”文件,即
ver.cpp
。使用“无操作”配方
可以放在同一行上,如下所示:

v%r.h v%r.cpp:
        ./gen/version/program
ver.h: ver.cpp ;
ver.cpp: Makefile
    ./gen/version/program
此方法从您编写的内容开始,但添加了非常重要的

如果您没有“主”文件的自然候选,那么我认为最好使用“哨兵”:


同样,此方法与您的一种方法类似,但非常重要的是,它不使用虚假文件,而是使用真实文件

您是对的,空字符串不起作用,我必须执行类似于
ve%.hve%.cpp
的操作。你认为这样做更好吗?还是我刚想到的其他事情。。。拥有
ver.h:ver.cpp
和构建
ver.cpp
的规则是程序吗?@Barry真的不确定。也许这样做更好,但我不确定分段路线是否有任何问题(但我必须仔细考虑才能说服自己)。@EtanReisner我不得不批评这个答案。隐式规则是针对自然模式的,而不是仅仅为了避免显式目标而构建的模式。如果在构建过程中碰巧出现了另一个文件
verbose.h
,该怎么办。@MarkGaleck您的后两个答案(其中一个是OP在他的评论中建议的,我犹豫了一下,因为我还没有完全解释清楚)很可能比这个黑客更好。这主要是在这里介绍这个想法,而不是给它真正的验证。GNUMake支持这一点是很好的,但它确实有缺点。我想最近有人在邮件列表中对此提出了更明确的语法。@EtanReisner是的,但没有
哪一个是最关键的版本%:Makefile
是否阻止生成运行两次?其他的解决方案确实如此,而且很可能比我的解决方案更可取。分号的作用是什么,而不是在
ver.h:ver.cpp
行和
ver.cpp:Makefile
one之间什么都没有?@EtanReisner是的,这与您引用的关于模式规则的参数相同,默认行为是运行配方一次,然后重新获取其他配方的时间戳targets@Barry分号是“无操作”配方。这是必要的,以确保Make重新获取目标的时间戳。我在上面的回答中写到了这一点。为什么你会认为
ver.h
ver.cpp
都是由
ver.%
同时制作的?为什么不运行两次呢?与构建
foo.o
bar.o
时对
%.o
所做的相同?(例如,不同的目标取决于
版本h
版本cpp
,并使用
-j
运行)