使用 distcc 构建项目时的链接阶段是在本地完成的,而不是像编译那样发送到其他计算机上完成,是否有任何特殊原因?阅读 distcc 白页并没有给出明确的答案,但我猜测与编译相比,链接目标文件所花费的时间并不是很重要。有什么想法吗?
distcc 的工作方式是在本地预处理输入文件,直到创建单个文件翻译单元。然后该文件通过网络发送并编译。在那个阶段,远程 distcc 服务器只需要一个编译器,甚至不需要项目的头文件。然后,编译的输出被移回客户端并作为目标文件存储在本地。请注意,这意味着不仅链接,而且预处理都是在本地执行的。这种工作划分对于其他构建工具很常见,例如 ccache(始终执行预处理,然后尝试使用先前缓存的结果解析输入,如果成功则返回二进制文件而不重新编译)。
如果要实现分布式链接器,则必须确保网络中的所有主机都具有完全相同的配置,否则必须批量发送操作所需的所有输入。这意味着分布式编译将生成一组目标文件,并且所有这些目标文件都必须通过网络推送,以便远程系统链接并返回链接的文件。请注意,这可能需要引用并存在于链接器路径中但不存在于链接器命令行中的系统库,因此“预链接”必须确定实际需要发送哪些库集。即使可能,这也需要本地系统猜测/计算所有真正的依赖关系并发送它们,这会对网络流量产生很大的影响,并且实际上可能会减慢进程,因为发送的成本可能大于链接的成本 - 如果获取依赖项的成本本身并不像链接那么昂贵。
我目前正在进行的项目有一个超过100M的静态链接可执行文件。静态库的大小各不相同,但如果分布式系统认为最终的可执行文件要远程链接,则可能需要最终可执行文件(模板、内联......所有这些都出现在所有文件中)的网络流量的三到五倍。包含它们的翻译单元,因此网络上会有多个副本)。
链接,几乎按照定义,要求您将所有目标文件放在一处。由于 distcc 将对象文件放在首先调用 distcc 的计算机上,因此本地计算机是执行链接的最佳位置,因为对象已经存在。
此外,一旦您开始将库投入其中,远程链接就会变得特别棘手。如果远程计算机将您的程序链接到其本地版本的库,那么当链接的二进制文件返回到本地计算机时,您就会遇到潜在的问题。
编译可以发送到其他机器的原因是每个源文件都是独立编译的。简而言之,对于每个
.c
输入文件,编译步骤中都会有一个 .o
输出文件。这可以在任意多台不同的机器上完成。
另一方面,链接会收集所有
.o
文件并创建 one 输出二进制文件。那里确实没有什么可以分发的。