代码合并包括将整个源代码复制到一个文件中。
例如,它由SQLite完成,以减少编译时间并提高生成的可执行文件的性能。在这里,它产生一个184K行代码的文件。
我的问题不是关于编译时间(已在this question中回答),而是关于可执行文件的效率。
SQLite开发人员说:
除了使SQLite更容易合并到其他项目之外,合并还使其运行得更快。许多编译器能够在代码包含在单个转换单元中时对代码进行额外的优化,例如它在合并中。当我们使用合并来编译SQLite而不是单个源文件时,我们已经测量了5到10%的性能改进。这样做的缺点是额外的优化通常采用函数内联的形式,这往往会使得到的二进制图像的大小变大。
据我所知,这是由interprocedural optimization (IPO)引起的,这是编译器的优化。
GCC开发人员也这样说(感谢@nwp的链接):
编译器根据程序的知识执行优化。一次编译多个文件到单个输出文件模式允许编译器在编译每个文件时使用从所有文件中获取的信息。
但是他们并没有谈到最终的收获。
除了SQLite之外,是否有任何测量结果证实或驳斥了IPO 与合并产生的可执行文件比使用gcc编译时没有合并的IPO 更快的可执行文件?
作为一个附带问题,将代码合并或#include所有.cpp(或.c)文件整合到一个关于此优化的文件中是一回事吗?
答案 0 :(得分:1)
源代码文件的组织不会产生更有效的二进制文件,"从多个源文件中检索的速度可以忽略不计。
版本控制系统将采用任何文件的 deltas ,无论大小如何。
通常,单独编译这些单独的组件以生成包含相关目标代码的二进制库:每次都不重新编译源代码。当一个"应用程序A"使用"库B"然后改变,然后"应用程序A"必须重新链接,但如果库的API没有更改,则无需重新编译。
而且,就库本身而言,如果它由(数百个)单独的源文件组成,则只有在重新链接库之前必须重新编译已更改的文件。 (任何Makefile
都会这样做。)如果源代码是一个巨大的东西,"你每次都必须重新编译所有这些,这可能需要长时间...基本上,浪费时间。
有两种方法可以将库中的对象代码(一旦构建完成后......)合并到可执行文件中:静态链接,动态。< / em>如果使用静态链接,库中的必要部分将被复制到可执行文件中...但不是全部。运行可执行文件时,不必存在库文件。
如果使用动态链接,则整个库存在于单独的文件(例如 .DLL
或.so
)中 必须在运行时出现,但将由同时使用它的每个应用程序共享。
我建议您主要将此视为源代码管理问题,而不是赋予任何技术或运行时优势的东西。 (它不会。)我发现很难看到令人信服的理由这样做。