2011-02-01 58 views
0

我们使用Microsoft NMAKE编译大量本机C++和某些英特尔Fortran文件。典型地,生成文件所包含的行如本(对于每个文件):更改较早的makefile系统以利用并行编译

$(LINKPATH)\ olemisc.obj:OLE2 \ olemisc.cpp $(OLEMISC_DEP)
$(CCDEBUG)OLE2 \ olemisc.cpp
$ (GDEPS)OLE2 \ olemisc.cpp

OLEMISC_DEP = \
E:\ OLE2 \ ifaceole.hpp \
E:\ OLE2 \ cpptypes.hpp \

它工作正常,但一次编译一个文件。我们希望利用多核处理器并一次编译多个文件。我希望得到关于实现这一目标的最佳方式的一些建议。这是我到目前为止。

一: GNU化妆可以让你使用例如--jobs = 2选项执行并行作业和正常工作与海湾合作委员会(我们不能使用GCC黯然)。但是微软的NMAKE似乎不支持这种选择。这两个名称程序的兼容性如何,如果我们开始使用GNU MAKE,您是否可以同时运行两个cl.exe进程?我希望他们抱怨PDB(调试)文件被锁定,或者是否有一个新的cl.exe命令行参数可以帮助你解决这个问题?

二: cl.exe时具有/ MP(构建具有多个进程)标志,它可以让你在同一时间编译多个文件是否通过命令行传递在一起,例如:

CL/MP7 a.cpp b.cpp c.cpp d.cpp e.cpp

但是使用这将需要更改生成文件。我们的make文件是由我们自己的程序从其他文件生成的,所以我可以轻松地更改我们在makefile中的内容。但是,如何将来自不同cpp文件的依赖关系结合在makefile中,以便通过一次cl.exe调用将它们一起编译?每个.obj都有一组不同的目标和一组命令来完成它?

或者我更改makefile来不调用cl.exe,而是我们编写的其他一些小的可执行文件,然后将一系列.cpp文件集中在一起,然后将shell传出到cl.exe,传递多个参数?这将工作,似乎可行,但也似乎过于复杂,我不能看到其他人这样做。

我错过了一些明显的东西吗?必须有一个更简单的方法来完成这个?

我们不使用Visual Studio或解决方案文件进行编译,因为文件列表非常广泛,我们在makefile中有一些特殊项目,理论上不希望过度依赖于MS C++等

回答

1

我彻底推荐在Windows上使用GNU make。我倾向于使用cygwin make,因为它创建的环境往往是可移植到类Unix平台(Mac和Linux的一开始)的。使用Microsoft工具链进行编译并行并具有100%准确的依赖关系和CPU使用情况非常有效。你有其他的要求,但。

只要你的nmake问题去了,在手册中查找batch-mode inference rules。基本上,nmake能够一次调用C编译器,一次传递一整个C文件。因此,您可以使用编译器的/MP...类型开关。

内置于编译器中的并行编译?呸!可怕的破碎我说。这里是一个骨架反正:

OBJECTS = a.obj b.obj c.obj 
f.exe: $(OBJECTS) 
    link $** -o [email protected] 

$(OBJECTS): $$(@R).c 

# "The only syntactical difference from the standard inference rule 
# is that the batch-mode inference rule is terminated with a double colon (::)." 
.c.obj:: 
    cl -c /MP4 $< 

编辑

如果每个.obj都有其自己的依赖(可能!),那么你只需添加为单独的依赖性线(即,他们没有任何shell命令附带)。

a.obj: b.h c.h ../include/e.hpp 
b.obj: b.h ../include/e.hpp 
    ∶ 

通常这样的锅炉板由另一工具和!INCLUDE d到主生成文件生成。如果你很聪明,那么你可以在编译时免费生成这些依赖关系。 (如果你走得很远,那么nmake开始在接缝处吱吱作响,你也许应该换成GNU make。)

0

好吧,我今天早上花了一些时间在这个上面工作,并且感谢bobbogo,我得到了它工作。下面是其他任何人的具体细节是谁考虑这个:

旧风格的makefile即一次编译一个文件有吨这样的:

$(LINKPATH)\PS_zlib.obj : zlib\PS_zlib.cpp $(PS_ZLIB_DEP) 
     $(CC) zlib\PS_zlib.cpp 

$(LINKPATH)\ioapi.obj : zlib\minizip\ioapi.c $(IOAPI_DEP) 
     $(CC) zlib\minizip\ioapi.c 

$(LINKPATH)\iowin32.obj : zlib\minizip\iowin32.c $(IOWIN32_DEP) 
     $(CC) zlib\minizip\iowin32.c 

注意,每个文件在一次编译一个。所以现在你想用花哨的Visual Studio 2010/MP开关“/ MP [n]最多使用'n'进程进行编译”来同时编译多个文件。怎么样?你的Makefile需要利用在NMAKE一批推理规则,如下:

$(LINKPATH)\PS_zlib.obj : zlib\PS_zlib.cpp $(PS_ZLIB_DEP) 

$(LINKPATH)\ioapi.obj : zlib\minizip\ioapi.c $(IOAPI_DEP) 

$(LINKPATH)\iowin32.obj : zlib\minizip\iowin32.c $(IOWIN32_DEP) 

#Batch inference rule for extension "cpp" and path "zlib": 
{zlib}.cpp{$(LINKPATH)}.obj:: 
     $(CC) $(CCMP) $< 

#Batch inference rule for extension "c" and path "zlib\minizip": 
{zlib\minizip}.c{$(LINKPATH)}.obj:: 
     $(CC) $(CCMP) $< 

在这种情况下,在其他地方,我们有

CCMP = /MP4 

注意,执行nmake推理批规则不支持通配符或空格在路径中。我在某处发现了一些体面的nmake文档,指出您需要为每个扩展名和源文件位置创建单独的规则,如果这些文件位于不同位置,则不能有一条规则。另外,使用#import的文件不能用/ MP编译。

我们有一个工具可以生成我们的makefile,所以它现在也生成批量推断规则。

但它的工作!编译一个大dll的时间从12分钟降到7分钟!哇噢!

+0

有人给我一个“这很有用”的勾号给你所有的细节吗? * grins * – 2011-03-17 19:48:46

1

需要牢记的一点是:您基本上必须为每个路径和扩展名定义一个批处理规则。但是,如果在两个不同的源目录中有两个具有相同名称的文件并且这些目录具有批处理推理规则,则批处理规则可能不会选择您想要的文件。

基本上,make系统知道它需要制作一个obj文件,只要它找到一个推理规则,它就会使用它。

解决方法是不要有重复的命名文件,如果不能避免,不要使用这些文件的推理或批处理规则。