GCC的等效选项是MS的/bigobj

48
我们在IT技术方面大量使用了boost::serialization和模板。一切看起来都很顺利。
然而,在Windows构建中出现了问题。似乎会导致目标文件过大。我们正在使用带有g++ 4.7.0的MinGW/Msys。
c:/mingw/bin/../lib/gcc/mingw32/4.7.0/../../../../mingw32/bin/as.exe: CMakeFiles/source.dir/sourcecode.cpp.obj: too many sections (33396)
C:\Users\username\AppData\Local\Temp\ccnAocvD.s: Assembler messages:
C:\Users\username\AppData\Local\Temp\ccnAocvD.s: Fatal error: can't write CMakeFiles/source.dir/sourcecode.cpp.obj: File too big

谷歌大师公开了这条归档信息,http://sourceforge.net/mailarchive/forum.php?thread_name=CA%2Bsc5mkLvj%3DW9w2%3DsY%3Dc_N%3DEwnsQuPDEX%3DiBcbsbxS3CuE_5Bg%40mail.gmail.com&forum_name=mingw-users

其中提到另一个人遇到了几乎相同的问题。它指出了 Visual Studio 的 /bigobj 选项,该选项似乎可以满足我们的需求。然而,我们无法转向 Visual Studio。

有人建议在汇编选项中添加 --hash-size。但这并没有起到帮助作用。

如果我没记错的话,问题在于对象文件中最多只能有 2^16 个条目。实际上,根据错误消息,我敢说这是一个有符号的 2^16 条目,但这只是小事。Visual Studio 的 /bigobj 选项将把它更改为 2^32。邮件列表的结果不知道 GCC 的等效选项。进一步的谷歌搜索似乎与此无关。

在这一点上,我们将不得不重构我们的代码(呃)。但我仍然担心,在使用大量模板时,我们可能会一次又一次地遇到这个问题(我们已经在三个源文件中遇到了这个问题)。

因此,我的问题是:是否有 GCC 等效于 Microsoft 的 /bigobj 选项?是否有第三个选项我还没有找到?


4
我很乐意。我需要学习目前正在使用的文件对象格式。我需要想出一种新的格式。听起来是个很棒的个人项目。不幸的是,我的雇主不想承担这种责任。 :) - inetknght
另一个可能性是目标文件突破了2GB的限制或类似的限制。你有多确定它是导出符号的数量?一些谷歌搜索表明,gcc在2^16处没有硬性限制...你看过http://mingw-w64.sourceforge.net/吗? - Yakk - Adam Nevraumont
1
@Yakk,巧妙地使用ProcessMonitor,当g++运行汇编器时,可以发现中间汇编文件(错误消息中的ccnAocvD.s)大小约为60MiB。然后它会创建对象文件(假设是为了确保可以打开它)。几秒钟后,它退出并在控制台上显示错误消息。我认为这几秒钟是处理汇编文件并确定符号过多所需的时间。邮件列表中提到了2GiB障碍。我想确定这不是罪魁祸首。 - inetknght
如果你看这里,我们有人在测试gcc是否对该值有硬限制:http://gcc.gnu.org/ml/gcc-patches/2007-05/msg02104.html -- 但那是在'07年。你可以考虑弄清楚如何使用当前的编译器运行这些测试,这可能会确定哪个限制是问题所在。 - Yakk - Adam Nevraumont
那看起来可能很有趣。谢谢! - inetknght
参见 https://svn.boost.org/trac/boost/ticket/8786,显然有一些宏可以帮助减小大小或某些奇怪的东西... - rogerdpack
5个回答

55

解决方法是在编译步骤中添加选项-Wa,-mbig-obj(如果你的GCC版本支持该选项)。您可能只需要在编译步骤中使用它,而不是链接步骤。

如果您的编译器不支持该选项,则应考虑使用mingw-w64和MSYS2


1
我打算接受这个答案。我早已转移到了不同的项目、不同的团队、不同的雇主,而且自那以后我就没有遇到过这个问题,这就是为什么我之前没有接受它的原因。然而,我注意到很多人来投票支持它,所以显然即使六年后它仍然是一个活跃的问题。 - inetknght
1
没有帮我解决从MSYS2安装MinGW64的问题(文件太大)。 - Sergey Kolesnik
2
我认为-mbig-obj只能解决“太多节”错误。如果您没有看到该错误,但是您确实看到“文件过大”错误,则我的猜测是您要创建的文件对于您的文件系统来说太大了,但我还没有深入研究这个问题。我会检查您正在使用的文件系统(例如NTFS,FAT32)及其限制。 - David Grayson

10
错误信息 "%B: too many sections (%d)" 来自于位于 bfd/coffcode.h 的函数 coff_compute_section_file_positions()。当输出的 .obj 文件(采用 COFF 格式)包含超过 32766 个段落时,就会产生此错误。如果你想使用 Windows 的 PE/COFF 对象格式,那么至少目前无法避免这种错误;因为 COFF 文件在文件头部分只使用两个字节来记录“NumberOfSections”。

不清楚为什么 GNU 汇编器 as 把段落数量上限设定为 32768 减 2,而不是 65536 减 1(第 0 段被保留);但无论如何,如果你大量使用模板并且编译器通过 COMDAT 段来实现模板,那么这个上限可能还不够。
正如你已经注意到的那样,向 Microsoft 的编译器传递 /bigobj 选项可以使它输出具有多达 231 个段的混乱 COFF 格式,这应该足够了。“大目标文件”格式虽然未经正式文档说明,但似乎也没有任何非正式文档(博客文章等)描述这个选项,所以在没有 MSVC 的副本可以为 /bigobj 编写规范的情况下,它不太可能进入 GNU 工具集。
在我看来,如果你正在尝试制作 Windows 构建,则应该咬紧牙关使用 MSVC。除了 Microsoft 之外,没有人特别有动力去浪费时间来处理 PE/COFF 格式。

这里有很好的信息!确实,我们大量使用模板。我不确定COMDAT部分是什么,但我们在mingw32上使用gcc。我同意我们应该使用MSVC,但不幸的是管理层并不这样认为。他们订阅了“一个代码库,一个编译器,多个平台”的理念。因此,一个可行的解决方案的问题仍然存在。目前,我们的解决方法是将CPP文件拆分成多个文件以呈现单独的编译单元。但是,正如您所想象的那样,这不是最理想的。 - inetknght

5
我在使用MinGW-w64编译Poco库时遇到了同样的问题,结果是一个实现文件的调试对象太大了。
如你之前所提到的,你可以将cpp文件分割并编译,但当你面对别人的源代码时,你不能这样做而不会破坏什么。
作为解决方案,你可以开启编译器优化:从-O1开始到-O3,每个步骤都会生成较小的目标文件,这可能会解决问题,在我的情况下确实如此。是的,对于调试构建,这可能是不希望的,你也可以尝试 -Og

4

谢谢更新。我没有使用mingw64,只用了mingw(例如32位),因为我还需要编译32位的程序,所以想确保不会意外地编译64位的内容。 - inetknght
2
@inetknght:MinGW-w64项目提供32位和64位编译器。该项目的名称是这样命名的,因为原始的MinGW项目只提供32位编译器,而MinGW-w64的目标是生产64位编译器。 - Francis Gagné
3
我已经使用MinGW-w64测试了这个新选项,它有效。你需要在gcc命令中加入-Wa,-mbig-obj来开启大型对象(-Wa的意思是将此选项传递给汇编程序)。请注意不改变原意并使翻译更易懂。 - Francis Gagné

0

正如一些人已经指出的那样,如果在出现Fatal error: can't close xxx.obj: file too big错误之后引发了错误,则-Wa,-mbig-obj将无法起作用。

解决方法是通过添加-Os(根据this link的最小代码大小),重新编译有问题的行(使用make VERBOSE=1查找), 但是另一个-O选项也可能有效。

总结:

C:/msys64/mingw64/bin/c++.exe [...] -Wa,-mbig-obj -c D:/Dev/a_installer/llvm-project/llvm/lib/Passes/PassBuilder.cpp # -> file too big error
C:/msys64/mingw64/bin/c++.exe -Os [...] -Wa,-mbig-obj -c D:/Dev/a_installer/llvm-project/llvm/lib/Passes/PassBuilder.cpp # -> compilation ok

或者,如果您不确定优化是否会改变代码的行为,您可以在CMake中全局设置标志以适用于所有文件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接