使用c和cpp文件进行NMake推理规则

时间:2017-07-10 01:45:39

标签: nmake

我有一个包含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,但我想知道是否有人知道如何调用这两个规则。

2 个答案:

答案 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通配符。

那,如果目标有多个(推理)规则,那么就只能合理地应用一个规则来创建/更新它。

现在,从干净状态开始的构建逻辑为以下(简体)

  1. 需要构建$(binPath),让我们看看它所依赖的...

  2. *.obj,所以让我们靠近一下吧……

  3. 与任何现有文件都不匹配;检查我们是否可以某种方式构建它...

  4. 很酷,一个推论规则说.obj可以从.c (或.cpp构建,这并不重要,首先找到哪个,顺便说一句,顺便说一句,不是.SUFFIXES的顺序,而是makefile中规则的顺序在这里很重要) ...

  5. 因此,请执行规则中的编译器,以根据其匹配的源(即不可扩展的文字*.obj)创建*.c

    cl /c /Fo($outdir) *.c

  6. 很好,*.obj现在已经准备好,可以继续进行链接...

  7. 好的,最终目标是,并且(即使现在对于未定义的外部设备来说链接可能会失败)这就是我们所能做的,所以让我们称之为“一天”。

注意,替代规则从未出现过!

现在,对于更新,假设不存在损坏(不完整)的目标,但是上面构建的目标文件存在,甚至还有一些更新,对某些.c.cpp文件:

  1. 需要构建缺少的$(binPath),让我们看看它所依赖的...

  2. 再次有*.obj,它现在可以匹配现有文件,所以让我们(一个接一个)检查它们是否需要更新...

  3. 然后,再次使用相同的推理规则(以哪个为准;一个项目只能有一个,我们坚持使用.c)匹配所讨论的.obj目标,因此请检查更改在相应的.c来源中...

  4. 找到了它们,因此“运行编译器”,但是这次NMAKE足够聪明,只能通过$<宏提供更新的C源代码:

    cl /c /Fo($outdir) some.c other.c

    (注意:它甚至足够聪明(显然是在VS 2019中),即使不是明确的批处理规则,它也可以默认使用batch-mode。)

  5. 好的,*.obj现在又是最新的,请继续进行链接...

  6. 最终目标,和以前一样,结束工作,庆祝! (现在,为了下面的其余示例,让我们假定链接已成功。)

再次:从来没有/不需要任何其他规则。

现在,奇怪的是,您甚至可以开始一个接一个地删除.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}}通配符,因为知道我们开始添加源代码的那一刻将变得不完整-即实际上是希望通配符支持!;))