不停地疯

Work as a hacker, hack as a artist.

高通编译环境一键安装包

| Comments

之前一直都在Marvell平台上开发Android,Marvell平台的CP只Release二进制文件,所以开发过程中一般只需要修改并编译AP端的代码就可以了。最近一个月,由于项目需要,开始转到开发高通平台的Android。初步接触下来,高通平台和Marvell平台有很大不同。最显著一点就是,Marvell平台中是AP启动起来后再挂CP跑;而高通平台则是先启动CP1,然后CP初始化AP并加载程序运行。另一方面,高通的CP相比AP有更大的控制权限,像对GPIO,PMIC的控制等都是CP进行控制,AP端如果需要对这些资源进行操作,则必须先由CP程序分配相应权限给AP才可以。AP和CP的交互则使用共享内存的方式进行同步。

高通这种架构特点注定了OEM商需要同时修改AP和CP的代码,所以高通的软件包在Release的时候是分为AP包和MP1包的。AP包中包括Android,Kernel,AP端的bootloader lk等;而MP包中则包括AMSS,qcsbl,oemsbl等。AP包的编译环境一般都架设在Linux下,使用Android的官方搭建方法就可以搞定。而MP包属于高通的特有产物,需要按照高通的搭建文档来进行,使用RVCT编译器,python以及perl环境。实际搭建下来,MP包的编译环境极为繁琐,从头摸索搭建,没有3、4天是不可能完成的。即便有人之前搭建过,文档工具都准备好的情况下,搭建一个可用的环境也至少需要4个小时。为了方便以后开发人员更加方便快捷的搭建开发环境,我花了2个周末的时间,搭建调试并打包制作了高通编译环境的一键安装包。

该一键安装包分为Windows版和Linux版。是的,你没有看错,还有Linux版本的编译环境!用过的人都懂的,Linux版的编译环境比Windows编译环境的效率高的不是一点两点2。不过有一点需要强调: 我制作的编译包中,RVCT的版本不是高通官方建议的版本 。高通官方文档中说,编译环境需要RVCT 2.2 593版本。而我制作的编译包中RVCT版本分别是Windows 2.2 616,Linux 2.2 686版本。修正版本号比高通官方建议的高,但是高通官方对于高版本的编译环境是否可用没有明确的答复,只是说没有测试过3。我个人简单测试过,分别使用593版本的RVCT,616版本RVCT和686版本RVCT编译同一套代码,对编译出来的bin文件进行比较,发现除了日期和签名部分有不同外,其余部分都是相同的。另外,这三种编译器编译出来的文件分别刷到手机上,也都可以正常运行。但是, 即便如此我也还是不能保证编译环境是完全没有问题的 。所以,对于要求比较高的朋友,可以在研发中使用我的环境,正式发布版本的时候使用高通官方建议的593版本进行编译。

最后放出下载地址(由于CSDN只有60M的上传权限,所以只有Linux环境了,并且需要5个资源分。国外下载地址没有任何限制):

国内下载:

Linux编译环境

国外下载:

Linux编译环境 Windows编译环境

Footnotes:

1 高通平台中将CP称为MP,本质是一样的。

2 相同配置的机器至少有5:1的效率,windows上编译需要50分钟的代码,Linux上只需要10分钟。

3 根据高通文档的编写时间点以及国企一贯保守的工作习惯上来推断,我猜测高版本应该是没有问题的,因为文档写作之初RVCT 616版本的补丁还没有发布,只是高通方面没人更新。所以,流传到现在就是只能使用593版本的RVCT了。当然这只是我本人的推断。

优化使用Orgmode发布Octopress的方法

| Comments

前几天翻译了一篇来自Tom Alexander的文章 ,文中介绍了如何通过修改Rakefile文件以及添加相应的Emacs设置,来使通过Org-mode发布Octopress博客成为可能。该方法很好用,特别是使用作者自己修改的el脚本可以非常方便的将Org文件输出为octopress的文章。但是,原文作者的方法也有一点缺憾,那就是必须手动移动新建的Org文件到相应的目录下;而且在使用 rake new_post[""] 命令新建文档后必须手动编辑新建的文件,少了那么一点点便捷。为此,我又通过网络查找了一些资料,最后找到了这里 。 受到这篇文章的启发,我尝试修改了工程中的 Rakefile 文件,最后成功地让一切都自动化起来。具体方法如下:

  • 修改Rakefile中关于org文档目录以及新建post文件的扩展名。同时新增一个编辑器的变量
Rakefile Source
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 deploy_dir      = "_deploy"   # deploy directory (for Github pages deployment)
 stash_dir       = "_stash"    # directory to stash posts for speedy generation
 posts_dir       = "_posts"    # directory for blog files
 org_posts_dir   = "org_posts"
 themes_dir      = ".themes"   # directory for blog files
 new_post_ext    = "org"  # default new post file extension when using the new_post task
 new_page_ext    = "markdown"  # default new page file extension when using the new_page task
 server_port     = "4000"      # port for preview server eg. localhost:4000

# open ,使用系统默认编辑器
# open -a Mou,使用Mou打开
# open -a Byword,使用Byword打开
# subl, 使用Sublime Text2打开
editor ="~/bin/em" # Emacs wrapper

我使用我自己编写的emacs wrapper来调用Emacs,为的是让Emacs的启动更快一点(通过server方式)。em的内容如下:

em
1
2
#!/bin/bash
/Applications/Emacs.app/Contents/MacOS/bin/emacsclient -n -a "/Applications/Emacs.app/Contents/MacOS/Emacs" $1 > /dev/null 2>&1 &
如果你也想通过emacsclient来加速Emacs的启动速度,你可能需要在你的 .emacs 文件中添加以下语句:
.emacs
1
2
(require 'edit-server)
(edit-server-start)
当然,你也可以指定 editor 变量为任何你喜欢的编辑器,不过既然都用Org文件发博客了,有什么理由不用Emacs呢?

  • 添加新建 org_posts_dir 目录及相应org文件的语句

task :install, :theme do |t, args| 语句之下,添加新建 org_posts_dir 的语句:

Rakefile Source
1
2
3
4
5
6
7
8
9
  theme = args.theme || 'classic'
  puts "## Copying "+theme+" theme into ./#{source_dir} and ./sass"
  mkdir_p source_dir
  cp_r "#{themes_dir}/#{theme}/source/.", source_dir
  mkdir_p "sass"
  cp_r "#{themes_dir}/#{theme}/sass/.", "sass"
  mkdir_p "#{source_dir}/#{posts_dir}"
  mkdir_p "#{source_dir}/#{org_posts_dir}"
  mkdir_p public_dir

task :new_post, :title do |t, args| 语句之下,添加新建文档目录和新建文章的语句:

Rakefile Source
1
2
3
4
5
6
7
8
9
10
 task :new_post, :title do |t, args|
   raise "### You haven't set anything up yet. First run `rake install` to set up an Octopress theme." unless File.directory?(source_dir)
   mkdir_p "#{source_dir}/#{posts_dir}"
   mkdir_p "#{source_dir}/#{org_posts_dir}"
   args.with_defaults(:title => 'new-post')
   title = args.title
   filename = "#{source_dir}/#{org_posts_dir}/#{Time.now.strftime('%Y-%m-%d')}-#{title.to_url}.#{new_post_ext}"
   if File.exist?(filename)
     abort("rake aborted!") if ask("#{filename} already exists. Do you want to overwrite?", ['y', 'n']) == 'n'
   end

  • 为了在新建文件之后能够立即编辑,我还在 new_post 命令中加入了相应的编辑语句:
Rakefile Source
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
desc "Begin a new post in #{source_dir}/#{org_posts_dir}"
task :new_post, :title do |t, args|
  raise "### You haven't set anything up yet. First run `rake install` to set up an Octopress theme." unless File.directory?(source_dir)
  mkdir_p "#{source_dir}/#{posts_dir}"
  mkdir_p "#{source_dir}/#{org_posts_dir}"
  args.with_defaults(:title => 'new-post')
  title = args.title
  filename = "#{source_dir}/#{org_posts_dir}/#{Time.now.strftime('%Y-%m-%d')}-#{title.to_url}.#{new_post_ext}"
  if File.exist?(filename)
    abort("rake aborted!") if ask("#{filename} already exists. Do you want to overwrite?", ['y', 'n']) == 'n'
  end
  puts "Creating new post: #{filename}"
  open(filename, 'w') do |post|
    post.puts "#+BEGIN_HTML"
    post.puts "---"
    post.puts "layout: post"
    post.puts "title: \"#{title.gsub(/&/,'&')}\""
    post.puts "date: #{Time.now.strftime('%Y-%m-%d %H:%M')}"
    post.puts "comments: true"
    post.puts "categories: "
    post.puts "---"
    post.puts "#+END_HTML"
  end
  if #{editor}
    system "sleep 1; #{editor} #{filename}"
  end
end

new_page 中也添加相同的语句,不过注意,最后 editor 那一段中文件名称变量需要使用 #{file} ,如下:

Rakefile
1
2
3
  if #{editor}
    system "sleep 1; #{editor} #{file}"
  end

  • 最后,为了预览更加方便,在 preview 命令最后添加下面的语句:
Rakefile Source
1
2
   system "sleep 2; open http://localhost:#{server_port}/"
   [jekyllPid, compassPid, rackupPid].each { |pid| Process.wait(pid) }

好了,现在我们只需要在控制台上执行 rake new_post["something"] 就会自动在我们设定的 org_posts_dir 目录下新建一份org文档,并且使用我们指定的编辑器打开它。然后随便编辑一点什么,保存并执行 C-c C-e F 或者直接调用Tom Alexander文章中所说的 M-x save-then-publish 命令。最后再在控制台上执行 rake generate&&rake preview 。 Booooom,自动弹出的浏览器上是不是显示出了你刚才编写的文章?非常方便吧?赶快试试!

使用Org-Mode来发布博客

| Comments

原文地址: http://blog.paphus.com/blog/2012/08/01/introducing-octopress-blogging-for-org-mode/

在之前的一篇 文章 中曾介绍过一种从 EmacsOrg-Mode 中导出文章到Octopress的方法,但这种方法使用简单的HTML导出,会失去语法高亮的特性。为此我将方法重新进行了设计,并且得到了一种更好的方法来取代之前不靠谱的方法。

首先,你需要根据 Octopress 的官方说明进行设置。我在Clone好Octopress的代码库后,进入克隆产生的目录并执行以下命令:

1
2
3
4
5
6
7
8
9
  #!/bin/sh
  #
  curl -L https://get.rvm.io | bash -s stable --ruby
  source ~/.rvm/scripts/rvm
  rvm install 1.9.2
  rvm rubygems latest
  gem install bundler
  bundle install
  rake install
像之前介绍的那样,我们需要在 .emacs 中新增一个叫 save-then-publish 的命令。
Save Then Publish source
1
2
3
4
5
  (defun save-then-publish ()
    (interactive)
    (save-buffer)
    (org-save-all-org-buffers)
    (org-publish-current-project))
接下来,我们需要设置Org-mode的工程。以我的配置举例来说,我将Octopress的文章放置在 ~/git/blog/ 目录下。如果你需要将你的文章放在其它什么地方,记得修改下面配置中相应的路径。
Publish Projects source
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  (setq org-publish-project-alist
        '(("blog-org" .  (:base-directory "~/git/blog/source/org_posts/"
                                          :base-extension "org"
                                          :publishing-directory "~/git/blog/source/_posts/"
                                          :sub-superscript ""
                                          :recursive t
                                          :publishing-function org-publish-org-to-octopress
                                          :headline-levels 4
                                          :html-extension "markdown"
                                          :octopress-extension "markdown"
                                          :body-only t))
          ("blog-extra" . (:base-directory "~/git/blog/source/org_posts/"
                                           :publishing-directory "~/git/blog/source/"
                                           :base-extension "css\\|pdf\\|png\\|jpg\\|gif\\|svg"
                                           :publishing-function org-publish-attachment
                                           :recursive t
                                           :author nil
                                           ))
          ("blog" . (:components ("blog-org" "blog-extra")))
          ))
现在,我们开始修改代码目录中的 Rakefile 文件。打开它找到 Misc Configs 设置部分,参照下面例子分别修改 new_post_extnew_page_ext 的内容并添加 org_posts_dir 项:
Rakefile source
1
2
3
4
5
6
7
8
9
10
11
12
13
  ## -- Misc Configs -- ##

  public_dir      = "public"    # compiled site directory
  source_dir      = "source"    # source file directory
  blog_index_dir  = 'source'    # directory for your blog's index page (if you put your index in source/blog/index.html, set this to 'source/blog')
  deploy_dir      = "_deploy"   # deploy directory (for Github pages deployment)
  stash_dir       = "_stash"    # directory to stash posts for speedy generation
  posts_dir       = "_posts"    # directory for blog files
  org_posts_dir   = "org_posts"
  themes_dir      = ".themes"   # directory for blog files
  new_post_ext    = "org"  # default new post file extension when using the new_post task
  new_page_ext    = "org"  # default new page file extension when using the new_page task
  server_port     = "4000"      # port for preview server eg. localhost:4000
接着修改 Rakefile ,找到下面代码所示的部分并添加 BEGIN_HTMLEND_HTML 。这样,我们新建文章的时候就能自动生成相应的HTML标签了。
Rakefile source
1
2
3
4
5
6
7
8
9
      post.puts "#+BEGIN_HTML"
      post.puts "---"
      post.puts "layout: post"
      post.puts "title: \"#{title.gsub(/&/,'&')}\""
      post.puts "date: #{Time.now.strftime('%Y-%m-%d %H:%M')}"
      post.puts "comments: true"
      post.puts "categories: "
      post.puts "---"
      post.puts "#+END_HTML"
现在,我们可以使用我修改后的HTML导出插件来生成新的文章了。我修改后的导出插件放置在github上,地址在 https://github.com/craftkiller/orgmode-octopress 。你也可以直接通过 org-octopress.el 1来下载。将下载的文件存放在你emacs的load-path中,并通过 (require 'org-octopress) 命令来加载。因为我的git代码都存放在 ~/git/ 目录下,所以我的Emacs配置是这样的:
.emacs
1
2
  (add-to-list 'load-path "~/git/orgmode-octopress")
  (require 'org-octopress)
终于可以写作了!但是写作之前,你必须像下面示例那样先新增一个org文件并将它移动到org_posts目录下:
1
2
3
4
5
  cd blog
  rake "new_post[title]"
  mv source/_posts/2012-08-01-title.org source/org_posts/
  # I keep my posts in GIT so then I add it to the repo
  git add source/org_posts/2012-08-01-title.org
写完文章后,在Emacs中执行 M-x save-then-publish ,然后你可以到shell中执行 rake gen_deploy. 这样,你的文章就成功的发布到网上了。

我这次改进主要新增了代码模块的语法高亮特性,不过目前它只能支持小写的 begin_src end_src 代码块。 另外,它也支持 :title :url:urltext 选项。如果你想了解他们的用法,可以看看这篇博文的源代码:http://blog.paphus.com/org_posts/2012-08-01-introducing-octopress-blogging-for-org-mode.org 。如果有谁希望帮助改进这个HTML导出插件的话,欢迎在github加入。

最后,你也许需要修改你的 .htaccess 文件来重定向图像请求。我重定向了所有SVG文件的请求到根目录上,这样静态链接就不会在访问图像的时候报错了。你需要将 .htaccess 文件放置在 source 目录下。

.htaccess
1
2
3
4
  Options +FollowSymlinks
  RewriteEngine on
  RewriteBase /
  RewriteRule /([^/]+)\.(svg)$ /$1.$2 [R,L]

Footnotes:

1 译者注:注意,该插件只支持Emacs 24.x。之前就因为Emacs版本原因,一直无法使用。

搭建Linux下的分布式编译系统

| Comments

概述

在公司做手机软件研发已有一年多,前前后后接触过三种手机系统:MStar,MTK和Android。他们有一个共同的特点:代码非常庞大,每种系统都有超过1GB的源代码。如此大量的代码,编译起来是相当缓慢的。实际中,如果使用一台普通四核的机器进行编译的话,将至少需要一个小时才能完成一次完整的编译。长时间的编译等待,对于研发来讲是个极大的浪费。

好在事情没有一路悲剧,因为实际中确有一种方法可以提高代码的编译速度,那就是通过分布式编译工具来加速编译工作。何谓分布式编译?简而言之,就是借网络上其他电脑的空闲CPU给自己使用,从而加速编译工作。一般来讲,通过分布式编译工具可以借到的CPU数量是10至20个,这10到20个借来的CPU足以将编译效率提高300%~400%。像MStar系统如果使用分布式编译的话,完整的编译时间将会缩短到15分钟左右!相比单机一个多小时的编译时间来讲,这是非常大的效率提升!

Windows下的Incredibuild就是一款成熟的常用分布式编译软件,它提供编译协同处理,可以很好的协同网络上的其他计算机获取和利用他们的空余计算能力进行代码编译。开发MStar和MTK时,就是利用Incredibuild实现的分布编译。遗憾的是Android的系统开发将平台换成了Linux,Linux上有没有办法使用分布式编译呢?答案是肯定的。本文就将探讨如何在Linux上搭建及使用分布式编译系统。

分布式编译系统的搭建

分布式编译系统,其实分两部分:编译器程序和分布式编译协同程序,像前面说的Windows下的Incredibuild软件其实就是分布式编译协同软件。编译器部分不用担心,Linux下的编译器种类非常丰富,有商业的也有开源的,一般我们使用开源的GCC系列编译器。而分布式协同软件,我们同样选择开源的distcc。

distcc简介

distcc是一款符合GPL协议开源的分布式编译协同软件,它分为两个部分:distcc-client和distcc-server。distcc-client将代码的编译请求发送到distcc-server上,而distcc-server则会对代码按要求进行编译后回传至请求方,从而完成编译代码的动作。client可以和server装在同一台电脑上,也即是说一台电脑可以利用其他电脑进行分布编译,也可以在空闲的时候为其他电脑提供分布编译服务。下面,我们将着重讲解如何安装,配置和使用distcc。

distcc的安装

distcc的项目主页为:http://code.google.com/p/distcc/, 主页上提供源代码以及安装包的下载。安装包默认提供deb和rpm软件包,分别用来适应Debian系和RedHat系的Linux系统,可以直接安装。如果比较追新和在意个性化定制,也可以下载最新的源代码进行编译后使用。本文采用编译源代码的方法进行安装。 从官网下载最新的 3.1 版的distcc软件包,名称为: distcc-3.1.tar.bz2

假如软件包下载后存放在 ~/Downloads 目录下,使用命令:

1
mkdir -p ~/temp && tar jxvf ~/Downloads/distcc-3.1.tar.bz2 -C ~/temp

将其解压至个人目录中的临时目录: ~/temp 下。然后执行:

1
2
3
4
cd ~/temp
./configure
make
sudo make install

安装时需要输入自己的密码,如果顺利的话,就会看到distcc安装完成了。不过目前这种状态还不能使用,需要对distcc进行配置。

distcc的配置

配置分为两部分,客户端和服务端的配置,主要的配置文件存放在 /etc/distcc 目录下。

服务器端配置

假设当前电脑所在网络IP地址为: 172.16.149.22 ,需要 172.16 网段的电脑都能够访问这台分布编译服务器,那么做如下配置:

修改 /etc/distcc/client.allow ,在最后一行添加

#允许172.16网段的所有电脑连接本服务器
172.16.0.0/16

修改 /etc/distcc/commands.allow.sh ,在 allowed_compilers 段里加入需要访问到的编译器程序。注意这里编译器程序可以使用通配符,但是路径需要使用绝对路径,否则会拒绝访问相应的编译器。此例中配置允许访问存放在 /usr/local/ 目录下gcc的 arm-eabi-4.4.3 交叉编译器,实际配置中需要根据需要做修改。

commands.allow.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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/arm-eabi-4.4.3/bin/*gcc*
  /usr/local/arm-eabi-4.4.3/bin/*g++*
  /usr/local/arm-eabi-4.4.3/bin/*ld*
  /usr/local/arm-eabi-4.4.3/bin/*ar*
  /usr/local/arm-eabi-4.4.3/bin/*as*
"

/usr/local/arm-eabi-4.4.3/bin/ 加入到访问路径中,修改 ~/.bash_profile 文件,添加以下内容:

1
export PATH=/usr/local/arm-eabi-4.4.3/bin/:$PATH

修改 /etc/init.d/distcc ,在

1
EXEC="/usr/bin/distccd"

下面添加一行

1
export PATH=/usr/local/arm-eabi-4.4.0/bin/:$PATH

上述文件都改好保存后,退出到命令行界面,重启distcc服务程序:

1
sudo /etc/init.d/distcc restart
好了,这样一台服务器就算配置完成了。将网络上可以提供编译服务的电脑,全部参照如此配置进行设置。这样就拥有一群可以提供分布编译服务的计算机群了。

客户端配置

相对于服务器端的配置来说,客户端的配置非常简单。只需要修改 /etc/distcc/hosts 文件即可。 修改 /etc/distcc/hosts ,加入配置好的服务器IP即可,一行一个IP地址,如:

172.16.149.45
172.16.149.14
172.16.149.60
172.16.149.20
#本机也加入分布编译服务器群组
localhost

然后定义 CROSS_COMPILE 环境变量,以之前配置的 arm-eabi-gcc 交叉编译器为例,如下定义:

1
export CROSS_COMPILE="distcc arm-eabi-"
至此,distcc的配置全部完成,可以使用了。

验证distcc

在客户端电脑上进入开源代码目录中执行,上执行

1
make clean;make -j4 CC="distcc gcc"
然后在同一台客户机的另一终端上执行:
1
watch distccmon-text
如果看到类似如下信息,则表明distcc安装配置正常。

Every 2.0s: distccmon-text                            Mon Oct 24 15:29:40 2011

  8836  Compile     state.c                                  172.16.149.45[0]
  8808  Connect     climasq.c                                172.16.149.14[2]
  8807  Connect     backoff.c                                172.16.149.60[3]
  8839  Preprocess  strip.c                                  172.16.149.60[0]

如果显示Block之类的信息,请检查对方服务器上的 client.allow 是否正确,同时需要确保服务器上的3632端口没有被防火墙拦住。

使用distcc进行效率对比

本例中使用3台单核2.6G的电脑群组做编译实验,分别对单机编译和分布编译时间进行比较。对比中会分别编译emacs23代码和交叉编译Android的linux内核代码。

编译emacs

下载并解压emacs23代码,目录为: ~/Downloads/emacs-23.3/

首先非分布式编译,使用8个线程。执行

1
2
3
4
cd ~/Downloads/emacs-23.3
./configure
make clean
time make -j8
编译完成后结果为:

real    3m14.220s
user    2m24.740s
sys     0m48.610s

然后使用分布式编译,同样使用8个线程。执行

1
2
3
4
cd ~/Downloads/emacs-23.3
./configure
make clean
time make -j8 CC="distcc gcc"
编译完成后结果为:

real    2m24.330s
user    1m38.630s
sys     0m37.600s

可以看到编译时间减少了50秒,cpu的占用也明显减小了不少。

编译Android的Linux内核

假设Android的Linux内核存目录为: ~/Downloads/Android2.3_kernel_v1.01

同样首先非分布式编译,使用8个线程。由于之前设置过 CROSS_COMPILE 变量,现在单机编译需要重新设置该变量。

1
2
3
4
export CROSS_COMPILE="arm-eabi-"
cd ~/Downloads/Android2.3_kernel_v1.01
make clean
time make -j8
编译完成后结果为:

real    6m32.640s
user    4m22.040s
sys     2m9.160s

然后分布式编译,使用8个线程。执行

1
2
3
4
export CROSS_COMPILE="distcc arm-eabi-"
cd ~/Downloads/Android2.3_kernel_v1.01
make clean
time make -j8
编译完成后结果为:

real    3m42.140s
user    2m10.630s
sys     1m20.240s

可以看到编译时间减少了2分50秒,接近一半的水平了,分布编译的性能提升非常明显。

从以上两个实验可以看出,对于使用纯C程序编写的软件项目,如:Linux内核,distcc提供的分布编译效率非常显著。而对于混合有其他程序语言的项目,如Emacs1,效率提升就不是那么显著了。

Android代码的分布式编译

Android的代码比较特殊,一部分是C程序,而另一部分为JAVA程序。所以分布编译的时候只能对C程序部分生效。同时,Android代码包包含完整的交叉编译工具链,编译时会使用自己代码包中的工具链进行编译,所以我们之前设置的 CROSS_COMPILE 环境变量会失效。好在解决办法也不是没有,做如下修改即可:

修改Android代码目录中的 build/core/combo/select.mk 文件

build/core/combo/select.mk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# (...省略...)
# Now include the combo for this specific target.
include $(BUILD_COMBOS)/$(combo_target)$(combo_os_arch).mk

#使用distcc修改 BEGIN
ifneq ($(USE_DISTCC),)
  distcc := distcc
  ifneq ($(distcc),$(firstword $($(combo_target)CC)))
    ifeq ($(dir $($(combo_target)CC)),./)
      $(combo_target)CC := $(distcc) $($(combo_target)CC)
    else
      $(combo_target)CC := $(distcc) $(abspath $($(combo_target)CC))
    endif
  endif
  ifneq ($(distcc),$(firstword $($(combo_target)CXX)))
    ifeq ($(dir $($(combo_target)CXX)),./)
      $(combo_target)CXX := $(distcc) $($(combo_target)CXX)
    else
      $(combo_target)CXX := $(distcc) $(abspath $($(combo_target)CXX))
    endif
  endif
  distcc =
endif
#使用distcc修改 END

ifneq ($(USE_CCACHE),)
  CCACHE_HOST_TAG := $(HOST_PREBUILT_TAG)
  # If we are cross-compiling Windows binaries on Linux
# (...省略...)
之后,执行
1
2
3
4
5
6
. ./build/envsetup.sh

export USE_CCACHE=1
export USE_DISTCC=1

make -j16
我这里使用6台XEON四核单机组成的集群做出来的结果是:

Android编译结果比较
不开启分布编译开启分布编译第一次开启分布编译第二次
real 37m49.735sreal 34m1.854sreal 31m7.957s
user 107m13.238suser 55m57.950suser 52m28.229s
sys 9m55.805ssys 26m40.228ssys 21m22.468s
可以看出有一定的效率提升,但是非常有限,只有区区8分钟不到的提升。我将其原因归结于以下几个原因:
  1. 磁盘瓶颈。编译过程中需要读写大量中间文件,磁盘的读写速度限制了编译程序的处理能力;
  2. 编译JAVA时不能分布式。如前面所述,Android代码中有一部分时JAVA代码。而JAVA代码在编译的时候是不能应用到distcc的分布式能力的,所以这方面也拖了编译速度的后腿。
  3. 没有根据服务器的CPU处理能力进行任务分发优化。distcc默认是没有任务分发优化的,需要配合使用dmucs程序才能实现。据说配合了dmucs后,性能还能提升30%~50%。不过如何配置使用dmucs就不是本文的主题了,也希望通过我这抛出的“砖”能引出配置dmucs的“玉”来。

总结

总体来讲,使用distcc这个工具可以大幅提高编译代码的效率。但这个工具只能针对C++、ObjC、C等C系列语言生效;而对于像Android这种有一半代码是JAVA的系统来说,联编优势就不那么显著了。尽管如此,distcc带来的200%的编译效率提升,还是值得使用的。

Footnotes:

1 Emacs源码中包含不少的elisp程序,这些elisp程序也在make编译阶段进行编译,从而成为elc文件。

Hello World

| Comments

关于本Blog

自己是一个很懒散的人,从接触电脑开始到现在不下14个年头,但要说自己做过什么,一时间还真难以回答。零星的积累都随我那善变的爱好一去不返了,让人有种虚度光阴的感觉。自己也不是没有做过尝试,开玩网络之初就在MyOpera上建立了自己的Blog,当然内容以个人日记流水账为主,那时真是快乐的单身年代。可是用了一段MyOpera后总觉得界面和功能不禁人意,而此时的Google正如火如荼,于是便赶了潮流在Blogspot上搭建了人生第二个Blog。可惜好景不长,Blogspot在国内越来越难以访问,原因大家懂的。慢慢的,也就淡了。然而随之时间的流逝,也许是老了,总觉得不记录些什么有愧于人生,从而有了再建立一个Blog的想法。当然,建立本Blog还有以下几个原因:

  1. 之前两个博客太过生活化,流水账没有重点。虽说这也是记录博客的一种方式,但是自己想做点改变。
  2. 想把自己工作中的一些经验和生活中的感悟,都点点滴滴的记录下来,希望到老了的时候看到时,不会后悔曾经浪费了生命。
  3. 作为程序员和Emacs追随者,没有不用github和org-mode的理由。加之Emacs又有可以将org-file很好地转换为Octopress Markdown格式的插件,没理由拒绝。

最后以一个程序员最惯用的开场白来向各位打个招呼:Hello World!