月度归档:2012年12月

CentOS 64 位机器安装配置 Jenkins 集成编译 Android 项目

之前一直想在公司搭建一个集成编译的环境,一直没能成行,这次终于着手去做了,发现之前的 Hudson 已经演变成了如今的 Jenkins,关于 Oracle 跟各个开源社区以及其他厂商的一些关于商标的纷争真的很有意思,我觉得未来有可能的话,真的可以专门写一些关于这个话题的东西。具体可以参考 wikipedia 上的 介绍

因为 Jenkins 是基于 Java Servlet 实现的,所以需要依赖于某个 Servlet Container 来运行,我选择的是 Apache Tomcat。Tomcat 也是基于 Java 实现的,那么开始第一步吧。

第一步 安装 SDK

自行下载 JDK,安装配置环境变量,如下:
[bash light=”true”]
export JAVA_HOME=/usr/local/jdk1.6.0_29
export PATH=$JAVA_HOME/bin:$PATH
export CLASS_PATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:.
[/bash]

第二步 安装配置 Tomcat

下载 tomcat 安装包,直接解压,配置环境变量:
[bash light=”true”]
export CATALINA_HOME=/root/apache-tomcat-7.0.33
[/bash]
在 CentOS 的/etc/sysconfig/iptables 配置文件中加入规则:

通过$CATALINA_HOME/bin/startup.sh 启动 tomcat,找个浏览器试试能否访问,http://your_centos_server_ip:8080

确认 tomcat 能正常访问之后,开始第三步

第三步 安装配置 Jenkins

Jenkins 的主页 下载 Jenkins 的 war 文件,将该文件拷贝至$CATALINA_HOME/webapps 目录下,tomcat 会自动将 war 文件解压并部署,找个浏览器试试能否访问这个地址 http://your_centos_server_ip:8080/jenkins,如果可以的话那么 Jenkins 就算是部署好了。

第四步 配置 Android SDK 和 NDK 环境

这一步可能会稍微多一些,可以参考我的这篇文章,CentOS 64 位机器配置 Android SDK 和 NDK 环境

第五步 创建一个 Jenkins 的 Job

完全按照 Jenkins 的提示和帮助一步步进行下午,非常简单。

  1. 给 Project 设置名称
  2. 配置获取最新代码的方式,Jenkins 目前自带了 CVS 和 SVN 的插件,如果你的代码是通过 git 来管理的,只需要安装一个 git 的插件即可,Jenkins 有非常丰富的插件,Jenkins => Manage Jenkins => Manage Plugins,进入插件管理页面,打开 Available 的 Tab 页面,在 Filter 中输入 git,然后找到 Jenkins GIT plugin,勾选前面的复选框,之后点击页面下方的 Download now and install after restart,让它自己安装然后重启吧,重启之后就可以配置通过 git 来获取代码了
  3. 设置编译触发器规则,应该是完全和 Linux cron 的规则一致,可以 google 之。
  4. 配置如何编译方法,在服务器上我们肯定是脱离 ADT 环境的,通常我们会使用 Ant 来进行编译,自行下载并配置 Ant 的环境变量,确保 ant 命令可以正常使用
  5. 先通过 android 命令更新当前需要编译的项目,确保 ant 能找到正确的 sdk 路径和其他的配置,需要编译 release 包的话,可以在 project.properties 中配置好用于签名的 keystore 文件,具体可以参考 这篇文章 ,然后在 Jenkins 中配置 shell 中输入 android update project -p $WORKSPACE -n 工程名 -t 编译目标
  6. 配置 Ant 编译目标为 release
  7. 点击 Save 之后,回到 Job 的首页面,点击 Build Now,开始编译吧。可以通过查看 Console Output 来看所有编译的输出信息,有错就一一排查吧。

CentOS 64 位机器配置 Android SDK 和 NDK 环境

做个小备忘。

因为工作上的一些需要,需要在 CentOS 64 位机器上搭建一个编译 Android 项目的环境,Android SDK 的环境还比较好搭建,直接下载 android-sdk 包即可,下载页面链接在这里 http://developer.android.com/sdk/index.html, 我下载的是 sdk only 包,体积比较小不包含 ADT 包(在服务器上用不着这些东西),因为是在服务器上,所以是木有任何桌面环境的,也就木有桌面浏览器啦。用 wget 或者 curl 下载即可。下载成功后,解压,可是目前目录下面只有 tools 目录,没有 platform-tools 目录,这个目录下的东西可不少哦,神马 aapt、dx 等等非常重要的工具都可是在这个里头哦,通常我们都是直接通过 android 命令就可以启动 Android SDK Manager 的界面管理工具,通过勾选不同平台就可以选择性地更新哪个版本的 sdk 了。服务器上木有 swt 环境啊(Android SDK Manager 是基于 SWT 实现的),肿么办捏?程序员做的东西肯定是有命令行界面的嘛。come 你的 on,google 一下吧,结果在 这里 ,万能的 google,程序员的福音 stackoverflow 上已经有人解决了该问题。大体就是通过

这个命令来查看有哪些 sdk 可以更新,你可以可以通过

来查看其他的一些选项,例如通过

来查看所有的可用的(包括 Android 认为已经过时的,例如 2.3.3 之类的各个 android 版本的 SDK,而且会将名字给你写出来哦),例如:

id: 61 or “extra-android-support”
Type: Extra
Desc: Android Support Library, revision 11
By Android
Install path: extras/android/support

这个指的是就是 Android 的 suppor-library,其他的各个名称也很直观啦,这些名字可以用的地方呢就是我们在使用
android update -u
命令进行 SDK 更新的时候可以通过设置 filter 来选择我们需要安装哪些包,例如下面这个命令:
android update sdk -u –filter extra-google-google_play_services
执行之后,就会选择 Google Play Service 这个包来下载更新,同理其他的都素一样的啦。例如通过
android update sdk -u –filter platform-tool
会自动下载 platform-tools 目录,你要是加上 platform,使用
android update sdk -u –filter platform-tool,platform
就会下载所有版本的 platform 文件,其他的命令自己一个个尝试就好了。等下载完成之后,配置 PATH 变量吧
export ANDROID_SDK_HOME=/root/android-sdk-linux
export PATH=$ANDROID_SDK_HOME/tools:$ANDROID_SDK_HOME/platform-tools:$PATH
配置完 SDK,那么开始配置 NDK 吧,毕竟很多时候我们在开发的过程中还是很有可能会使用到 NDK 的,那么开始吧,先下载 NDK 包吧,下载页面在 这里 ,选择对应平台下载链接下载吧,下载成功后解压缩之后,配置环境变量吧:
export ANDROID_NDK_HOME=/root/android-ndk-r8c
export PATH=$ANDROID_NDK_HOME:$PATH
配置好环境变量,加载一下环境变量,然后开始测试一下能否编译吧,cd 到 samples/hello-jni/jni 目录下,直接执行 ndk-build 命令,提示错误
./../../ndk-build: /root/android-ndk-r8c/prebuilt/linux-x86/bin/make: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory
提示缺少某个依赖文件,Google 之后得知,通过命令
yum install glibc.i686
装上 glibc 库即可,再次尝试 ndk-build,依然提示错误
/root/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/as: error while loading shared libraries: libz.so.1: cannot open shared object file: No such file or directory
提示缺少 zlib 库文件依赖文件,Google 之后得知,通过命令
yum install zlib.i686
装上 zlib 库文件之后,继续 ndk-build,这次能顺利编译出 so 文件了,也成功将文件拷贝到对应的 libs/armeabi 目录下了,可以有这么一个警告信息:
/root/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-strip: /lib/libz.so.1: no version information available (required by /root/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-strip)
大体的意思就时因为/lib 目录下的 libz.so.1 版本信息不对,导致 arm-linux-androideabi-strip 命令无法正常执行,这个会带来神马问题捏?我们来看看吧。其实就是/root/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/下的 arm-linux-androideabi-strip 命令没有办法执行呗,那么这个命令是用来干嘛的,直接运行一下看看 usage:
Usage: /root/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-strip <option(s)> in-file(s)
Removes symbols and sections from files
大体的意思就是通过这个命令可以将我们编译出来的 so 文件中的一些不必要的符号和片段给移除掉,可以让这个二进制文件更紧凑一些,运行效率会高一些?这个我真不知道,因为自己对于编译和链接这一块儿懂得真是太少了所以也就没有什么发言权啦。闲话少说,既然看到有问题,当然这个 so 肯定是可以用的(因为 ndk-build 并没有出错,而且还将 so 文件 install 到 libs 下对应的 armeabi 目录下了,我想 Android 开发团队肯定不会坑爹地将一个可能出错的编译输出文件 install 到该目录下的,所以说这个问题应该不大,肯定可以正常运行),只是看到这个警告信息让我非常的不爽,或者移除了这些符号和片段会让你的二进制文件运行起来更爽,或者可以让别人无法通过反编你的 so 来查看你调用了什么函数之类的,具体原因不明,反正我就是不爽,我要让这个警告信息给我消失。怎么办呢?

肯定先 google 啦,google 了很多,看了一些文档,大体得出结论是这个 libz.so.1 的版本比较低,而 android 这个命令可能比较新,依赖的库的版本比当前我的机器上/lib 目录下的 libz.so.1 的版本要高,好吧,那就去下载源码自己编译吧。可以到这个 zlib 的官方页面 上的这个 下载地址(WTF,竟然需要翻墙)。下载后解压之后,cd 到 zlib 目录下,三步走
./configure
make
make install
整个过程很顺利,编译后的文件都被放到/usr/local/lib 下了,这个可以通过编译安装输出看出来
[root@helihua zlib-1.2.7]# make install
cp libz.a /usr/local/lib
chmod 644 /usr/local/lib/libz.a
cp libz.so.1.2.7 /usr/local/lib
chmod 755 /usr/local/lib/libz.so.1.2.7
cp zlib.3 /usr/local/share/man/man3
chmod 644 /usr/local/share/man/man3/zlib.3
cp zlib.pc /usr/local/lib/pkgconfig
chmod 644 /usr/local/lib/pkgconfig/zlib.pc
cp zlib.h zconf.h /usr/local/include
chmod 644 /usr/local/include/zlib.h /usr/local/include/zconf.h
然后将/lib/libz.so.1 文件先备份一下,将/usr/local/lib 目录下的 libz.so.1 链接到/lib 目录下,因为 arm-linux-androideabi-strip 这个命令链接的路径中依赖的/lib 目录下的 libz.so.1,当然我们也可以通过修改 LD_CLASSPATH 的方式来让 arm-linux-androideabi-strip 这个命令加载/usr/local/lib 目录下的 libz.so.1 文件,可惜我现在不想这么麻烦,因为我现在也不知道具体做法,我懒得去 Google 了,我的方法是直接将该文件链接到/lib 目录下,替换系统原有的 libz.so.1
mv /lib/libz.so.1 /lib/libz.so.1_backup
ln -s /usr/local/lib/libz.so.1 /lib/libz.so.1
但是童鞋们啊,这还是不够滴,因为现在的系统捏是尼玛 64 位滴,而该死的 Android 都是基于 32 开发的,它依赖的是 32 位的 libz,你现在执行 ndk-build 不出意外的话,你会碰到这个错误信息:
[root@helihua jni]# ../../../ndk-build
Gdbserver : [arm-linux-androideabi-4.6] libs/armeabi/gdbserver
Gdbsetup : libs/armeabi/gdb.setup
Install : libhello-jni.so => libs/armeabi/libhello-jni.so
/root/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-strip: error while loading shared libraries: libz.so.1: wrong ELF class: ELFCLASS64
make: *** [/root/android-ndk-r8c/samples/hello-jni/libs/armeabi/libhello-jni.so] Error 127
make: *** Deleting file `/root/android-ndk-r8c/samples/hello-jni/libs/armeabi/libhello-jni.so’
唉,那么就只好开始编译 32 位的咯,怎么编呢,还是 Google 吧,程序员福音 stackoverflow 上又有对应的问题,在 这里 ,通过
export CFLAGS=-m32
指定当前编译目标平台位 32 位滴,直接在 bash 下使用该命令只会在当前 bash 会话期间有效,不会影响到其他 bash 会话和下次你重新登录 bash 时的编译环境设置,非常有用,我们只需要在这次编译 libz 时才需要如此,正中下怀啊。果断重复上面的三步走啊:
./configure
make
make install
这次执行./configure 就不会那么顺利了,会出现这样一个错误:
./configure
Checking for gcc…
.
.
.
Looking for a four-byte integer type… Not found.
如果这个时候你选择继续 make 的话,显然会出错滴,错误如下:
/usr/include/gnu/stubs.h:7:27: error: gnu/stubs-32.h: No such file or directory
通过该命令:
yum install glibc-devel.i386
安装对应的开发环境,重新执行上面的三步,
成功后再重复设置/lib 目录的操作:
mv /lib/libz.so.1 /lib/libz.so.1_backup
ln -s /usr/local/lib/libz.so.1 /lib/libz.so.1
然后再尝试执行 ndk-build 命令,这次就不再提示任何警告和信息了,输出干净多了:
Gdbserver : [arm-linux-androideabi-4.6] libs/armeabi/gdbserver
Gdbsetup : libs/armeabi/gdb.setup
Install : libhello-jni.so => libs/armeabi/libhello-jni.so
回过头来再想想,为什么会出现这些问题呢?
前两个问题是因为 Android NDK 中的某些命令依赖于系统的一些库,没有直接安装就好了,这个没有过多讨论的余地,后面那个出现版本不一致导致的警告信息,我个人的理解是这样的,因为我们直接使用的都是 Android NDK prebuild 的命令,而这些命令可能在 Google 的编译服务器上依赖的是更高版本的库,所以导致在我们的环境中会出现版本不一致的问题。因为 NDK 中带着源码,我倒是觉得可以通过在自己的机器上编译一个 NDK 出来,应该就可以解决这个问题,当然前提是 NDK 的源码中没有引用到更高版本的一些头文件,另外编译源码可能需要我们安装很多的开发环境(就是很多的库和头文件),点到为止,有机会可以一试。