我有一个包含c和cpp文件的项目,我一直在使用NMake构建。我的问题是,如果我有两个推理规则,每个文件类型一个,
{$(dirSrc)}.c{$(dirObj)}.obj:
cl /nologo /c /EHsc /Fo$(dirObj)\ $<
{$(dirSrc)}.cpp{$(dirObj)}.obj:
cl /nologo /c /EHsc /Fo$(dirObj)\ $<
$(binPath): $(dirObj)\*.obj
link /nologo /dll /out:$(binPath) $(dirObj)\*.obj
只有c文件被编译,大概是因为.c扩展名是.SUFFIXES列表中的第一个。
我当然可以简单地将c文件的扩展名更改为cpp,但我想知道是否有人知道如何调用这两个规则。
答案 0 :(得分:0)
好吧,回答我自己的问题,我能想到的最好的方法是编译到2个不同的目录,然后在运行链接器时指向两者。
{$(dirSrc)}.c{$(dirObj)\c}.obj:
cl /nologo /c /EHsc /Fo$(dirObj)\c\ $<
{$(dirSrc)}.cpp{$(dirObj)\cpp}.obj:
cl /nologo /c /EHsc /Fo$(dirObj)\cpp\ $<
$(binPath): $(dirObj)\c\*.obj $(dirObj)\cpp\*.obj
link /nologo /dll /out:$(binPath) $(dirObj)\c\*.obj $(dirObj)\cpp\*.obj
答案 1 :(得分:0)
(作为同一船上其他船的参考)问题是*.obj
通配符。
那,如果目标有多个(推理)规则,那么就只能合理地应用一个规则来创建/更新它。
现在,从干净状态开始的构建逻辑为以下(简体):
需要构建$(binPath)
,让我们看看它所依赖的...
有*.obj
,所以让我们靠近一下吧……
与任何现有文件都不匹配;检查我们是否可以某种方式构建它...
很酷,一个推论规则说.obj
可以从.c
(或.cpp
构建,这并不重要,首先找到哪个,顺便说一句,顺便说一句,不是.SUFFIXES
的顺序,而是makefile中规则的顺序在这里很重要) ...
因此,请执行规则中的编译器,以根据其匹配的源(即不可扩展的文字*.obj
)创建*.c
:
→cl /c /Fo($outdir) *.c
很好,*.obj
现在已经准备好,可以继续进行链接...
好的,最终目标是,并且(即使现在对于未定义的外部设备来说链接可能会失败)这就是我们所能做的,所以让我们称之为“一天”。
注意,替代规则从未出现过!
现在,对于更新,假设不存在损坏(不完整)的目标,但是上面构建的目标文件存在,甚至还有一些更新,对某些.c
和.cpp
文件:
需要构建缺少的$(binPath)
,让我们看看它所依赖的...
再次有*.obj
,它现在可以匹配现有文件,所以让我们(一个接一个)检查它们是否需要更新...
然后,再次使用相同的推理规则(以哪个为准;一个项目只能有一个,我们坚持使用.c
)匹配所讨论的.obj
目标,因此请检查更改在相应的.c
来源中...
找到了它们,因此“运行编译器”,但是这次NMAKE足够聪明,只能通过$<
宏提供更新的C源代码:
→cl /c /Fo($outdir) some.c other.c
(注意:它甚至足够聪明(显然是在VS 2019中),即使不是明确的批处理规则,它也可以默认使用batch-mode。)
好的,*.obj
现在又是最新的,请继续进行链接...
最终目标,和以前一样,结束工作,庆祝! (现在,为了下面的其余示例,让我们假定链接已成功。)
再次:从来没有/不需要任何其他规则。
现在,奇怪的是,您甚至可以开始一个接一个地删除.obj文件(只要保留一些文件即可),并保持NMAKE不变:
'test.dll' is up-to-date
什么?!为什么不重建失踪者?
你知道吗?让我们删除所有这些文件。...只是为了好玩,将它们替换为一个伪造的文件,方法是从那里(从任何地方)复制一些随机文件,并将其重命名为fake.obj
。
'test.dll' is up-to-date
耶稣!这没有道理!
好的,让我们结束这一点。然后创建一个全新的.c
文件。那肯定会触发重建!
'test.dll' is up-to-date
没办法! :-o到底是怎么回事?也许然后添加一个新的.cpp
...
'test.dll' is up-to-date
OMG!...真是垃圾!难以置信,这是NMAKE的事情...对吗?
好吧...首先,对于fake.obj
,没有匹配名称的来源,这两个规则都不适用:NMAKE不能“发明”该来源,因此它永远都不会被重建,它只是作为定时炸弹而坐在那里,直到下一个链接回合为止,链接器最终会在其中找到并找到它,从而结束了所有的乐趣。 :)
对于所有其他“异常”:
任何现有的 .obj文件将满足*.obj
(对于lib)的依赖关系,因此,只要有至少一个,NMAKE就会开心,并且永远不会甚至不知道这不是完整的清单!
这就是为什么对项目中添加的任何新.c
或.cpp
都一无所获的原因,因此以这种方式使用通配符会使自己陷入困境。 (这并不意味着构建脚本中没有通配符的任何完全合法的情况,BTW。)
然后(概括),为了重建 missing 对象,NMAKE(就像gmake等一样)必须选择一个获胜者,如果有多个匹配规则,则忽略其余部分
(仅供参考,gmake甚至有专门针对此wildcard pitfall的页面。而且,为减轻风险,与NMAKE不同,它似乎拒绝为{{ 1}}通配符,因为知道我们开始添加源代码的那一刻将变得不完整-即实际上是希望通配符支持!;))