基于 Distcc 的android分布式编译环境的搭建

时间:2021-02-27 08:53:29
关于Ditscc分布式编译环境的搭建,网上也有不少文章,但是基本上都过时了。所以看了很多文章,走了不少弯路,最后总算梳理清楚了一条正确的环境搭建的步骤,而且可以实现zeroconf。本文不涉及负载均衡的实现。

本文所述环境的搭建是基于Ubuntu 12.04 64bit,android版本是4.1(其他版本估计也一样)。android编译环境的搭建就不再赘述了,请参考尽量参考官方文档https://source.android.com/source/initializing.html

1.Distcc简介

Distcc 是一个将 C、C++等程序的编译任务分发到网络中多个主机的程序。 Distcc的工作原理为: GCC 编译C/C++构建一个execualble分为四个阶段: 预处理:.c 到.i,由cc完成 汇编:.i到.s ,由cc完成 编译:.s到.o,由as完成 链接:.o 到可执行文件,由collect2完成 其中第三阶段是效率瓶颈。distcc是一个编译器驱动器。它在”gcc -c”阶段把预处理输出分发到指定的服务器阵列并收集结果。GNU Make的”-j”并行编译可以利用distcc来加速编译。distcc本身事实上并不参与任何编译过程,而只是一个编译器的前端。为编译器加入分布式特性,并参与部分管理和简单的负载均衡的功能。distcc在本地完成预处理(使用gcc -E,完成头文件、宏的展开),把结果发给集群中的工作主机,由工作主机完成编译(使用gcc -c)并发回编译结果,最后在本地做链接。 基于 Distcc 的android分布式编译环境的搭建 distcc分布式编译程序可以将包含两个部分: distcc:在客户端分发编译任务到编译主机 distccd:编译主机启动distccd守护进程接收编译任务,并返回编译结果。

2.安装Distcc

如果不想走弯路,请不要

sudo apt-get install distcc

也不要在https://code.google.com/p/distcc/downloads/list这里下载安装包。
我通过这两种方式安装后都会在编译主机上产生编译错误,结果几乎所有任务都在本地编译了。这样就没意义了。

我推荐的方法是:

svn checkout http://distcc.googlecode.com/svn/trunk/ distcc-read-only

代码checkout下来自己编译。拿到代码后,要仔细阅读INSTALL文件,里面很详细,胜过任何网上的其他介绍distcc环境搭建的文章,当然android涉及交叉编译,会有所不同。
为了顺利编译处安装包,按照INSTALL文档所述,安装以下依赖:

sudo apt-get install gcc make python python-dev binutils-dev alien libavahi-client-dev

为了编译出deb安装包,要安装alien。
Ubuntu 12.04是支持zeroconf的,可以ps查看下,是有avahi-daemon在运行的,但是为了编译出支持zeroconf的安装包,需要安装libavahi-client-dev依赖。zeroconf是什么东西我就不赘述了。万事具备只差make了,执行以下:

./autogen.sh
./configure --with-avahi
sudo make deb

with-avahi参数表明build出的包支持zeroconf。如果一切顺利,你将在源码的packaging目录下得到build出来的安装包
distcc_3.2rc1-1_amd64 distcc-server_3.2rc1-1_amd64
安装他们:

dpkg -i distcc_3.2rc1-1_amd64 distcc-server_3.2rc1-1_amd64

注意:
为了实现zeroconf,我最初在虚拟机和本机上做实验,按照下文继续配置好后,可以找到主机。相同的环境在另一台电脑上搭建,zeroconf却找不到那台电脑。我使用avahi-discover查看Distributed Compiler下的所有主机,确实是可以看到的。这就说明zeroconf的实现程序avahi是可以找到这个主机的,distcc利用avahi寻找主机,理论上也应该可以找到的。继续追踪/var/log/syslog
文件,看到类似下面这一行

(daemon_proc) Browsing for 'x86_64-unknown-linux-gnu_4.4.3_distcc._tcp'.

也就是说,distcc通过avahi寻找主机的时候,要求主机和gcc的版本都要一致,但是实际上gcc小版本不一致并不会影响编译结果。果断改代码,zeroconf.c文件中:

......
# if (dcc_get_gcc_version(version, sizeof(version)) &&
# dcc_get_gcc_machine(machine, sizeof(machine))) {
#
# dcc_make_dnssd_subtype(stype, sizeof(stype), version, machine);
# } else {
rs_log_warning("Warning, failed to get CC version and machine type.\n");

strncpy(stype, DCC_DNS_SERVICE_TYPE, sizeof(stype));
stype[sizeof(stype)-1] = 0;
# }
......

这样distcc找主机时,参数就是"_distcc._tcp"了。这样修改至少在我这边是OK的

3.配置distcc

涉及到的配置文件主要在"/etc/distcc/"文件夹下
client.allow中内容为

#表明192.168.*的IP都能发给自己编译任务
192.168.0.0/16

拷贝android源码包prebuilts下的编译工具到指定目录:/usr/local/distcc/prebuilts/
修改commands.allow.sh的内容为:

numwords=1
allowed_compilers="
/usr/bin/cc
/usr/bin/c++
/usr/bin/c89
/usr/bin/c99
/usr/bin/gcc
/usr/bin/g++
/usr/bin/*gcc-*
/usr/bin/*g++-*
/usr/local/distcc/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/arm-linux-androideabi*
/usr/local/distcc/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6/bin/i686-linux*
"
......

注意保证新添加的那两行的内容真是存在,否则服务端会发生编译错误。

在"/etc/distcc/"文件夹下
hosts文件的内容为:

localhost
+zeroconf

貌似zeroconf能找到的IP只能匹配一个网段,所以可以自己在文件中继续添加其他IP地址。

在"/etc/init.d/"文件夹下
distcc文件的内容为:

......
OPTIONS="--zeroconf --log-file=/var/log/distccd.log --daemon --stats --job-lifetime=1200"
USER=distcc
PROG="distccd"
PIDFILE=/var/run/$PROG.pid
EXEC="/usr/bin/distccd"
......

"--zeroconf --log-file=/var/log/distccd.log"参数是为了支持zeroconf和log。
最后重新重启distccd

sudo /etc/init.d/distcc reload

以上步骤完成后就基本完成了服务端的配置(客户端也要进行那些配置),客户端要想启动distcc编译,还需要继续以下步骤:

4.android的distcc编译配置

以下只是叙述了android要成功启动distcc编译任务所以要的必备条件,很多改动并不优雅。

首先确保编译前

export PATH=/usr/bin/distcc:$PATH

不建议写到环境变量中

在"build/core/combo"文件夹下
TARGET_linux-arm.mk文件:

......
ifeq ($(strip $(TARGET_TOOLS_PREFIX)),)
TARGET_TOOLCHAIN_ROOT := /usr/local/distcc/prebuilts/gcc/$(HOST_PREBUILT_TAG)/arm/arm-linux-androideabi-4.6
TARGET_TOOLS_PREFIX := $(TARGET_TOOLCHAIN_ROOT)/bin/arm-linux-androideabi-
endif
......

select.mk文件:

......
include $(BUILD_COMBOS)/$(combo_target)$(combo_os_arch).mk

$(combo_target)CC := distcc $($(combo_target)CC)
$(combo_target)CXX := distcc $($(combo_target)CXX)
......

最后启动编译

. ./build/envsetup.sh
lunch
make -jN

即可

5.监视distcc编译任务
distcc自带distccmon-text,可以启动文本化监视

#3秒刷新一次
distccmon-text 3

也可以使用distccmon-gnome启动图形化监视程序

sudo apt-get install distccmon-gnome
distccmon-gnome &

即可