简体   繁体   English

如何才能将我的大型程序链接起来?

[英]How can I get my very large program to link?

Our next product has grown too large to link on a machine running 32-bit Windows. 我们的下一个产品已经变得太大,无法在运行32位Windows的计算机上进行链接。 The sum total of all the lib files exceeds 2Gb and can only be linked on a 64-bit Windows machine. 所有lib文件的总和超过2Gb,只能在64位Windows机器上链接。 Eventually we will exceed that boundary, since our software tends to grow rather than contract and we are using a 32-bit linker (MS Visual Studio 2005): we expect to hit trouble when our lib size total exceeds 3Gb. 最终我们将超越这个边界,因为我们的软件往往增长而不是契约,我们使用的是32位链接器(MS Visual Studio 2005):当我们的lib总大小超过3Gb时,我们预计会遇到麻烦。

How can I reduce the size of the .lib files, or the .obj files without trimming code? 如何在不修剪代码的情况下减小.lib文件或.obj文件的大小? For example, we use a lot of templates: is there any way of reducing their footprint? 例如,我们使用了很多模板:有没有办法减少它们的占用空间? Is there any way of finding out what's causing the bloat from examining the .lib/.obj files? 有没有办法找出导致膨胀检查.lib / .obj文件的原因? Can this be automated rather than inspected by eye? 这可以自动化而不是通过眼睛检查吗? 2.5Gb is a lot of text to peer through and compare. 2.5Gb是很多文本要比较和比较。

External constraints prevent us from shipping as anything other than a single .exe, so a DLL solution is not available. 外部约束阻止我们将其作为单个.exe以外的任何内容发布,因此DLL解决方案不可用。

I had once been working on a project with several MLoC. 我曾经参与过一个有几个MLoC的项目。 While ours would still link on a 32bit machine, link times where abysmal and became a major problem, because developers were reduced to only get a dozen edit-compile-test cycles done per workday. 虽然我们仍然会在32位机器上链接,但链接时间非常糟糕并且成为一个主要问题,因为开发人员只能在每个工作日完成十几个编辑 - 编译 - 测试周期。 (Compile times were handled pretty well by doing distributed compilation.) (通过分布式编译很好地处理了编译时间。)

We switched to dynamic linking. 我们切换到动态链接。 That increased startup time, but this could be managed by delay-loading of DLLs. 这增加了启动时间,但这可以通过延迟加载DLL来管理。

First, of course, make sure you compile with the 'Optimize for Size' option. 首先,当然,请确保使用“Optimize for Size”选项进行编译。 If you do that, I wouldn't expect inlining, at least, to contribute significantly to the code size. 如果你这样做,我不希望至少内联对代码大小做出重大贡献。 The compiler makes a tradeoff for every inlining candidate regarding how much (if at all) it'd increase code size, compared to the performance boost it'd give. 编译器对每个内联候选者进行权衡,以确定与增加代码大小相比有多少(如果有的话)增加代码大小。 And if you're optimizing for size, the compiler won't risk bloating the code much. 如果你正在优化大小,编译器不会冒很大的代价。 (Note that inlining very small functions can actually decrease code size) (请注意,内联非常小的函数实际上可以减少代码大小)

Second, have you considered unity builds ? 第二,你考虑过团结建设吗? That'd pretty much eliminate the linker entirely, and with only one translation unit, there'd be much less duplicate work and hopefully, a smaller memory footprint. 这几乎完全消除了链接器,并且只有一个转换单元,重复工作要少得多,希望内存占用更少。

Finally, I know Visual Studio (or possibly the Windows SDK) has a 64-bit compiler (that is, a compiler that is itself a 64-bit application, not just a compiler producing 64-bit code). 最后,我知道Visual Studio(或可能是Windows SDK)有一个64位编译器(也就是说,编译器本身就是一个64位应用程序,而不仅仅是一个生成64位代码的编译器)。 Consider using that. 考虑使用它。 (I don't know if there is also a 64-bit linker) (我不知道是否还有一个64位链接器)

I don't know i the linker is built with the LARGEADDRESSAWARE flag set. 我不知道链接器是在LARGEADDRESSAWARE标志设置的情况下构建的。 If so, running it on a 64-bit machine will let the process consume a full 4GB of memory instead of the 2 GB it normally gets. 如果是这样,在64位计算机上运行它将使进程消耗完整的4GB内存,而不是通常获得的2 GB内存。 (if necessary, you can add the flag yourself by modifying the PE header) (如有必要,可以通过修改PE头自己添加标志)

Perhaps limiting the linkage of various symbols could help as well. 也许限制各种符号的联系也可能有所帮助。 If you know that a symbol won't be needed outside of the current translation unit, put it in an anonymous namespace. 如果您知道当前转换单元之外不需要符号,请将其放在匿名命名空间中。 That might allow the compiler to trim down unused symbols before passing everything on to the linker 这可能允许编译器在将所有内容传递给链接器之前减少未使用的符号

Try using the Symbol Sort program to show you where the main bits of bloat are in your code. 尝试使用符号排序程序来显示代码中膨胀的主要位置。 Also just looking at the size of the raw .obj files will give you a reasonable idea of where to target. 另外,只需查看原始.obj文件的大小,您就可以合理地了解目标的位置。

OMFG!!!!! OMFG !!!!! That's huuuuuge! 那是huuuuuge!

Apart from the fact I think it's too big to be rational... can't you use dynamic linking to avoid linking all the mess in compile time and only link in runtime what's necesary (I mean, loading dlls in demand)? 除了我认为它太大而不合理之外......你不能使用动态链接来避免在编译时链接所有混乱,只在运行时链接什么是必要的(我的意思是,需要加载dll)?

Does it need to be one big app? 它需要是一个大应用程序吗?

One option is to split various modules into DLLs and load/unload them as needed. 一种选择是将各种模块拆分为DLL,并根据需要加载/卸载它们。

Alternatively, you might be able to split into several apps and share data using mapped memory, pipes a DBMS or even simple data files. 或者,您可以使用映射内存拆分多个应用程序并共享数据,管理DBMS甚至简单数据文件。

First of all, find out how to measure the size which is used by various features. 首先,了解如何测量各种功能使用的大小。 Don't go ahead and try to play replace template usage or other things because you suspect that it makes a significant difference. 不要继续尝试使用替换模板使用或其他东西,因为您怀疑它会产生重大影响。

Run

dumpbin /HEADERS <somebinary>

to find out which sections in your binary are causing the huge size. 找出二进制文件中哪些部分导致巨大的大小。 Do you have a huge Debug Directory section? 你有一个庞大的调试目录部分吗? Strip symbols then. 然后剥离符号。 Is the Import Address Table large? 导入地址表大吗? Check the table and locate symbols which you don't need (a problem with templates is that symbols of template instantiations tend to be very very large). 检查表并找到您不需要的符号(模板的问题是模板实例化的符号往往非常大)。 Similiar analysis can be done for the Exception Directory, COM Descriptor Directory etc.. 可以对异常目录,COM描述符目录等进行类似的分析。

I do not think there is any single tool that can give you statistics that you want/need. 我认为没有任何一种工具可以为您提供您想要/需要的统计数据。 Using either .map files or the dumpbin utility with /SYMBOLS parameter plus some post-processing of the created log might help you get what you want. 使用带有/SYMBOLS参数的.map文件或dumpbin实用程序以及对创建的日志进行一些后处理可能会帮助您获得所需内容。

If the statistics confirm your suspicion of template bloat, or even without the confirmation, it might be a good idea to do several things with the source: 如果统计数据证实您怀疑模板膨胀,或者甚至没有确认,那么使用源代码执行以下操作可能是个好主意:

  1. Try using explicit instantiations and move template definitions into .cpp files. 尝试使用显式实例化并将模板定义移动到.cpp文件中。 Of course this works only if you have limited and well known set of types/values that you use as arguments to the templates. 当然,只有当您使用有限且众所周知的一组类型/值作为模板的参数时,这才有效。
  2. Add more abstraction and/or indirection. 添加更多抽象和/或间接。 Factor code that does not depend on your template parameters into their own base classes or free functions. 因素代码不依赖于您的模板参数到他们自己的基类或自由函数中。 If you have several template type parameters, see if you cannot split the single class template into several base classes without overlapping template parameters. 如果您有多个模板类型参数,请查看是否无法将单个类模板拆分为多个基类而不重叠模板参数。 (See http://www2.research.att.com/~bs/SCARY.pdf .) (见http://www2.research.att.com/~bs/SCARY.pdf 。)
  3. Try using the pimpl idiom; 尝试使用pimpl成语; avoid instantiating templates in headers if you can, instantiate them only in .cpp files. 如果可以,请避免在头文件中实例化模板,仅在.cpp文件中实例化它们。
  4. Templates are nice but sometimes ordinary classes work as well; 模板很好但有时普通的类也可以工作; eg avoid passing integer constants as non-type template parameters if you can pass them as parameter to ctor. 例如,如果可以将它们作为参数传递给ctor,则避免将整数常量作为非类型模板参数传递。

@hatcat and @jalf: There is indeed a full set of 64bit tools . @hatcat和@jalf:确实有一整套64位工具 For example, you can set an environment variable: 例如,您可以设置环境变量:

set PreferredToolArchitecture=x64

and then run Visual Studio (from de developer console). 然后运行Visual Studio(来自de developer console)。

I am highly skeptical that your actual code is 2GB; 我非常怀疑你的实际代码是2GB; more likely you are compiling a lot of information. 你很可能正在编译大量的信息。 Consider offloading some of that information into a resource file, and embedding it in the executable as a separate step. 考虑将一些信息卸载到资源文件中,并将其作为单独的步骤嵌入可执行文件中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM