在PSPDFKit,我们继续扩大我们的产品范围,努力添加新功能并改进现有功能,同时处理PDF世界所包含的无数特殊情况。作为一个自然结果,我们有一个不断增长的代码库。更多代码意味着更长的构建时间,没有人喜欢更长的构建时 在这里,我们将向您介绍如何使用优秀的工具distcc
在多台计算机上分配构建,并将构建时间缩短到之前持续时间的一小部分。
串行编译 | 并行编译 |
---|---|
| |
制备
首先,让我提请你注意ccache。我们已经有很多成功使用的ccache
,这是我们写之前在这里。我强烈建议您先阅读该博客文章,因为这篇文章是根据您ccache
在博客文章中描述的设置的假设编写的。这是绝对有可能使用distcc
不ccache
如果你真的需要,但我们不会推荐它。
distcc的
distcc是一个工具,实际上是一组工具,使您能够通过网络在服务器池(包括工作站)中分发C,C ++,Objective-C和Objective-C ++文件的编译。池中构建服务器的唯一真正要求是它们必须安装与您在主计算机上使用的版本相同的编译器版本。他们不需要直接访问您正在构建的源代码甚至系统头文件。将它们视为愚蠢的设备,提供所需的所有输入,其结果是成功编译的单元或错误。
值得指出的是,为了从分发构建中获益,这些构建服务器不必是特别快的机器,也不需要最快的网络连接。当然如果他们这样做那就更好了!您的主计算机可以继续编译,同时等待其他人慢慢编译其他内容。这一切都是并行发生的,所以只要你有足够的文件可以编译就可以获得。如果您的项目只包含几十个文件,则此设置可能不适合您。另一方面,链接必须在本地进行,以便时间在任何构建时间都是下限。你好,阿姆达尔定律!
另外,你可能会遇到一些叫做的东西,pump mode
但是现在可以忽略它。简而言之,pump mode
是一个额外的工具distcc
,可以将编译单元的预处理分发给构建服务器。如果没有pump mode
,则需要在分发之前在主构建机器上完成预处理。请记住,构建服务器不需要对标头或源代码进行文件级访问。但是现在一台典型的机器可以使10或20个构建服务器忙于处理预处理的编译单元。因此,除非您打算设置至少包含那么多服务器的构建服务器场,否则对您没有任何好处。
Xcode中
此前Xcode的4.3,支持distcc
了内置。由于原因不明,Apple决定取消对分布式构建的支持。已经采取了一些措施来填补这一空白。但是,由于Xcode 8引入了代码签名,因此有效地禁止插件,尽管有一些解决方法。尽管如此,可以在不依赖插件或插入Xcode的情况下设置分布式构建。
目前distcc
在处理Xcode构建方面存在一些小问题clang
。因为它distcc
是编译器的前端,clang
并且clang++
它必须采用你传递给它的所有参数clang
并适当地处理它们,例如重写路径等。截至当前版本distcc
,它缺少对几个选项的支持。 Xcode的构建所独有的clang
。幸运的是,distcc
自己修补和构建它并不困难 。我们在这里提供了修补源的副本。
这是设置一切的一种方法。
-
使用安装最新版本
brew install distcc
。(使用自制软件并确保安装了autotools和automake。) -
通过克隆repo并遵循这些构建步骤来构建修补版本。
./autogen.sh
./configure --without-libiberty --disable-Werror
make
通过更换安装二进制文件brew
在/usr/local/Cellar/distcc/
你刚刚建成的人。还有一个类似的叉子供参考 - 很多人都在研究这个问题。
为了确保一切正常,首先只将工作站用作构建服务器。这消除了隐藏任何其他问题的可能的网络问题。一旦您知道distcc
本地工作,您就可以设置其他构建服务器。
确保distcc
它附带的其他二进制文件(distccd
和distccmon-text
)在您的路径中。运行distcc
一次,它将初始化配置文件~/.distcc/
。下一步是创建一个文件~/.distcc/hosts
,我们需要在其中指定构建服务器的地址。现在,只有这个工作站将在构建服务器池中,因此您的文件应该包含这一行。
在终端窗口中,我们现在想要distcc
使用以下命令启动守护程序:我更喜欢地址127.0.0.1
而不是localhost
。如果使用,localhost
您可能会遇到IPv6问题,除非您当然只使用IPv6。
--no-detach
不要从你启动它的shell中分离。这使你能够用ctrl-c
等等结束守护进程。或者,killall -9 distccd
用来杀死所有守护进程。这些开关具有以下用途:
--daemon
听插座。--allow
什么地址范围应该distccd
接受来自的连接。上面的示例允许从192.168.
第二个地址开始的所有地址的连接也允许来自127.0.0.1
我们想要的特定地址的连接。--log-stderr
将日志输出到控制台。--verbose
最初使用它来调试问题,直到您满意它正在工作。
在开始之前distccd
,你应该检查你期望在你的路径的工具which clang
和which as
,例如。
现在我们已经distcc
启动并运行了一个守护进程,让我们测试一下。
在另一个终端上的临时目录中,创建一个包含Hello World主目录的简单c或c ++文件。现在编译它,但将命令distcc
放在clang
:
现在,我们知道我们有一个工作设置,我们需要扩大我们的,我们增加了对小脚本ccache
在博客文章中描述这里打电话distcc
。我更喜欢只distcc
在主机文件存在时调用。如果没有,那么它应该回退到本地编译,但我发现能够通过简单重命名我的~/.distcc/hosts
文件来启用和禁用它是有用的。ccache
检查一个特殊的环境变量CCACHE_PREFIX
,如果它已经设置,那么它会在调用编译器之前放置它所设置的任何内容。在调用之前将以下内容添加到脚本中ccache
:这应该产生一个可执行的二进制文件,另外在守护进程的控制台中你应该看到很多输出。如果它不起作用,您应该从distcc
您尝试编译的位置以及守护程序的输出中获得有用的输出。在您调用的地方,通常会报告任何代码错误和警告distcc
。请注意,我们设置DISTCC_FALLBACK
为0
防止回退到本地编译。即我们强制执行分布式编译,如果它不起作用,它不应该继续。
复制
现在我们应该准备从Xcode构建distcc
!当您第一次设置这一切时,不要忘记清除缓存,ccache -C
否则您只需从缓存中构建,distcc
完全绕过。这显然是可取的,但是现在我们想知道一切是否都能很好地协同工作。如果您决定不使用ccache
,您只需要在呼叫前clang
加上distcc
。
现在你知道你已经distcc
集成到你的构建中了,现在是时候设置一些服务器来加快速度了!
在您的其他计算机上,distcc
如上所述进行安装,不要忘记使用您自己构建的修补程序替换二进制文件。
记下他们的IP地址或地址名称,并将其添加到~/.distcc/hosts
工作站上的文件中。
这是一个示例文件:
默认情况下,Xcode将尝试并行编译足够的文件,以保持您的工作站合理忙碌。它不知道我们现在有这么多的力量。我们需要告诉Xcode它可以启动多少个并行编译作业。通过此配置,我们有4个构建服务器,包括此工作站。但是,我们还需要做一件事让Xcode为所有机器生成足够的工作。
退出Xcode并设置以下默认值。
现在,坐下来,点击Build并感受力量!下次启动Xcode时,它将获取此值。它只在启动时读取它,所以每次更改它都需要重新启动Xcode。我在这里设置为24,每个构建服务器6个。您需要尝试设置以找到最佳设置。一句警告,不要忘记在不使用时取消设置,distcc
否则机器会停止运转。此外,请记住所有服务器上的Xcode版本(实际上是clang版本)必须相同,否则您将获得未定义的行为。
如果您希望监视构建作业的处理位置,可以在终端中使用以下内容:
庆典结合watch
实用程序(brew install watch
),您可以在终端窗口中运行一个漂亮的小监视器。
设置distcc
NDK构建有点复杂。没有必要建立一个补丁版本distcc
,官方发布的工作正常。但是,由于NDK对每个ABI都有不同的工具链,我们正在有效地使用多个版本的编译器,如前所述,这会导致最坏情况下的未定义行为,并且如果它们在编译期间混合,则会在最佳情况下构建错误。也许有一天,NDK将提供一个完全统一的工具链,可以针对所有ABI,但现在情况并非如此。所以我们遇到的问题是:我们如何distcc
为每个ABI使用正确的编译器?Android NDK
我们针对此问题的解决方案是为distccd
我们定位的每个ABI 运行一个单独的守护程序实例。例如,如果您要定位arm64-v8a
,armv7-a
并且x86
您将distcc
在每个构建服务器上启动3个单独的实例。实例1,distccd
在arm64-v8a
其路径中只有工具链的环境中,侦听为该ABI保留的特定端口。实例2,armv7-a
在其路径中具有工具链的环境中,以及它自己的端口。并且,逻辑上,实例3在x86
其路径中具有工具链并且又具有其自己的端口的环境中。
为了使事情易于管理,我发现为我们目标的每个ABI生成一个独立的NDK工具链很有用。NDK附带了一个方便的脚本来为我们这样做。
我们需要为每个ABI生成一个工具链:
复制
首先需要PATH
在启动守护程序之前将正确的编译器和工具带入您的程序。例如,在此位置~/arm-toolchain/arm-linux-androideabi/bin
执行以下操作:接下来,我们想要distccd
为每个ABI 启动一个守护进程,可能首先在一个单独的终端窗口中。这有助于您在需要时诊断任何问题--verbose
。
复制
--no-detach
不要从你启动它的shell中分离。这使你可以用它ctrl-c
等结束守护进程。这些开关具有以下用途:
--daemon
听插座。--allow
什么地址范围应该distccd
接受来自的连接。上面的示例允许从192.168.
第二个地址开始的所有地址的连接也允许来自127.0.0.1
我们想要的特定地址的连接。--log-stderr
将日志输出到控制台。--verbose
最初使用它来调试问题,直到您满意它正在工作。
在开始之前distccd
,你应该检查你期望在你的路径的工具which clang
和which as
,例如。
这里的关键部分是为每个守护进程指定不同端口的最后一个参数。默认端口是3632
这样我之后使用端口以防止意外地为非NDK构建提供守护进程。我曾经使用3633
过armv7-a
,3634
for for for x86
和3635
for arm64-v8a
。
现在我们为每个ABI运行一个守护进程,监听它自己的端口,我们需要能够指导我们的构建分发到正确的实例。
默认情况下,distcc
尝试从位于的文件中读取构建服务器列表~/.distcc/hosts
。我们可以做的是设置一个环境变量,指示distcc
查看该hosts
文件的不同目录。此变量已命名DISTCC_DIR
。
例如,我们可以有三个文件,每个文件包含一个distccd
实例的地址和端口号:
/Users/james/distccconf/Arm7/hosts
含192.168.1.123:3633
/Users/james/distccconf/Arm64/hosts
含有192.168.1.123:3635
/Users/james/distccconf/x86/hosts
含192.168.1.123:3634
请注意,在此示例中,它们都在同一台计算机上侦听不同的端口号。在设置额外的构建服务器时,您只需将每个实例的地址和端口添加到每个文件中。
您的构建环境将与我们的不同,但基本更改应如下所示。
我们使用运行自定义摇篮任务cmake
和ninja
。在启动编译器之前的Gradle任务中,我们设置了两个环境变量。distcc
当前ABI 的特定主机目录的路径,因为我们使用,ccache
我们需要告诉它为编译器添加前缀distcc
。
这应该足以让你在一台机器上构建和运行。在那里取得成功后,添加新的构建服务器,不要忘记确保它们都具有相同版本的NDK。重要提示:我们在通话时不设置这些CMake
。仅在启动make
或ninja
执行编译时。CMake
如果您尝试分发它,那么在尝试测试编译器功能时会窒息。
因为distcc
如果设置不正确,几乎会默默地回退到本地编译,您可能不会注意到您的设置有问题。因此,我建议你也设置DISTCC_FALLBACK
到0
这将停止生成如果失败分发构建任务。至少在您对自己的设置有信心之前。这将有助于您更早地诊断问题。该手册页提供distcc
了可以帮助您的其他几个环境变量的良好文档,例如DISTCC_LOG
。
由于这是一个相对复杂的构建环境,我强烈建议您逐步设置,逐步测试每个部分,以便您知道它的工作原理。
快乐的建筑!