編譯 CyanogenMod 9 (ICS) 並安裝到 HTC One X 手機
CyanogenMod 是目前最為風行的 Android 第三方改版,原本由 Steve Kondik 創 辦開發,並加入了許多 xda 社群的改版,該團隊也在最近成立了公司 CyanogenMod Inc.
本篇文章以 CyanogenMod 9 (簡稱 CM9) 為主,並使用 HTC One X (Endeavoru) 作為編譯的目標機型。由於目前的 HTC One X 所安裝的 HBOOT 僅 適用於 Android 4.2 以上的版本,若想要依據本篇文章的方式編譯 CM9,你同時 需要將你的 HTC One X 進行 HBOOT 降級的動作。
建立你的開發環境
要能夠編譯 CyanogenMod, 首先要先把開發環境建立好,才能夠在編譯的過程中 順順利利的,以下列出幾個常用的 Linux 建立編譯環境所需要額外安裝的套件。
為了能夠正確編譯你的 CyanogenMod 或是 Android,請使用 64-bit 的 Linux 系統。
- Debian /Ubuntu Linux
sudo apt-get install \
build-essential pkg-config zlib1g-dev libusb-dev libqt4-dev \
autoconf libtool git-core gnupg sun-java6-jdk flex bison \
gperf libsdl-dev libesd0-dev libwxgtk2.6-dev zip curl \
libncurses5-dev ia32-libs lib32z1-dev lib32ncurses5-dev \
gcc-multilib g++-multilib
- Gentoo Linux
emerge -v \
schedtool cmake bison curl git sun-jdk \
gnupg flex bison gperf libsdl squashfs-tools \
ncurses zlib perl-Switch zip unzip wxGTK \
emul-linux-x86-baselibs emul-linux-x86-compat emul-linux-x86-cpplibs
取得 repo 工具
不論你是要編譯 Android、CyanogenMod 或是 Firefox OS、Ubuntu Touch,你都 會需要 repo 這個命令,因此若你沒有這個命令的話,趕快安裝他吧 :)
下面的指令會將 repo 放到 ~/bin 下
curl http://commondatastorage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo
export PATH="${PATH}:~/bin"
取得必須的原始碼
本篇文章所編譯的為 CM9 的版本,相對應的版本為 Android 4.0 (ICS),由於目 前的 HTC One X 幾乎都升級到 Android 4.2 (JB) 的版本,要使用 CM9 你必須知道 如何將 HBOOT 降版,或是將本篇文章編譯的版本改成 CM-10.2。
- 建立編譯用的目錄
cm9並切換進去
mkdir cm9 && cd cm9
- 取得 manifest
repo init -u git://github.com/CyanogenMod/android.git -b cm-9.1.0
- 下載程式碼
repo sync
- 取得預先編譯好的 app
cd vendor/cm && ./get-prebuilts
- 取得 HTC One X kernel 和其他可能需要的原始碼
source build/envsetup.sh
breakfast endeavoru
取得官方提供的二進制檔案
要取得手機裡面特殊的二進制文件有兩種作法,一個是從你的手機裡面取出,另 外一個則是使用別人已經 備份 在網路上的檔案。由於我們這次要編譯的是比 較過時的 CM9,建議使用網路上的檔案,才不會出現 firmware 和 ROM 不批配的狀況。
下載別人整理好的二進制檔案
在 Github 上可以找到一些已經整理好 HTC One X 二進制檔的 repo, 修改
.repo/local_manifest.xml,讓他變成下面這樣
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<project name="CyanogenMod/android_device_htc_endeavoru" path="device/htc/endeavoru" remote="github" revision="ics" />
<project name="coldnew/android_vendor_htc_endeavoru" path="vendor/htc/endeavoru" remote="github" revision="ics" />
</manifest>
接著再使用 repo 命令來取得原始碼
repo sync
- 直接從手機裡面取得二進制檔案
cd device/htc/endeavoru && ./extract-files.sh
編譯 CyanogenMod
要編譯 CyanogenMod,你只需要再下以下命令,並等待你的 ROM 編譯好即可
croot
brunch endeavoru
下載到 HTC One X
若你的 HTC 手機裡面已經將 recovery 更改為 TWRP 或是 CWM 的話,你可以直 接複製編譯好的 ROM 檔案到你的手機裡面,並使用這些 recovery tool 來 安裝新的 image (HBOOT 要先降版本),具體的檔案路徑如下:
out/target/product/endeavoru/cm-9-20131027-UNOFFICIAL-endeavoru.zip
除此之外,你也可以使用 fastboot 命令來燒錄新的 image,以下是操作流程
- 1. 重新開機到 bootloader
adb reboot-bootloader
- 2. 查看是否有找到裝置
fastboot devices
- 3. 燒錄你的新的 image
fastboot flash boot boot.img
fastboot flash system system.img
- 4. 清除 cache 和 user-data
fastboot erase userdata
fastboot erase cache
- 5. 重新啟動你的手機
fastboot reboot
可能會遇到的編譯問題
編譯 Android 的時候,很多時候會冒出一些奇奇怪怪的問題,下面是我編譯 CyanogenMod 9 以及 Android ICS 時,遇到問題以及解決方案的整理。
編譯
doclava時,被告知以下錯誤訊息若你編譯時,遇到 doclava 出現以下錯誤
xternal/doclava/src/com/google/doclava/ClassInfo.java:20: package com.sun.javadoc does not exist
import com.sun.javadoc.ClassDoc;
^
解決的方案:
1. 檢查你使用的 java-vm 是否為
sun-jdk (jdk 6)如果你是使用 openjdk 或是 icedtea,是有可能編譯不過的。
2. 確認你的環境變數
在我的 Gentoo 系統上,我遇到這個編譯問題時,是因為環境變數指向 java-vm 的位置錯誤,因此我修改了環境變數如下
export JAVA_HOME="/usr/lib/jvm/sun-jdk-1.6"
export PATH="${JAVA_HOME}/bin:$PATH"
編譯 llvm 時出錯
若在編譯 llvm 時遇到以下錯誤
external/llvm/include/llvm/ADT/PointerUnion.h:56:10: error: comparison between ‘ enum llvm::PointerLikeTypeTraits<clang::QualifiedTemplateName*>::<anonymous>’ and ‘ enum llvm::PointerLikeTypeTraits<clang::DependentTemplateName*>::<anonymous>’ [-Werror=enum-compare]
external/llvm/include/llvm/ADT/PointerUnion.h:56:10: error: enumeral mismatch in conditional expression: ‘ llvm::PointerLikeTypeTraits<clang::QualifiedTemplateName*>::<anonymous enum>’ vs ‘ llvm::PointerLikeTypeTraits<clang::DependentTemplateName*>::<anonymous enum>’ [-Werror=enum-compare]
這種錯誤可能跟系統的 gcc 參數、配置等有關,比較簡單的解決方案為:
編輯 frameworks/compile/slang/Android.mk 將 -Werror 移除掉並重新 編譯即可。
編譯 dalvik 時出錯
若出現如以下錯誤
dalvik/vm/native/dalvik_system_Zygote.cpp: In function ‘ int setrlimitsFromArray(ArrayObject*)’:
dalvik/vm/native/dalvik_system_Zygote.cpp:199:19: error: aggregate ‘ setrlimitsFromArray(ArrayObject*)::rlimit rlim ’ has incomplete type and cannot be defined
struct rlimit rlim;
^
這個參數似乎也是和系統比較相關,修正方式很簡單,請參考以下 patch
diff --git a/dalvik/vm/native/dalvik_system_Zygote.cpp b/dalvik/vm/native/dalvik_system_Zygote.cpp
--- a/dalvik/vm/native/dalvik_system_Zygote.cpp
+++ b/dalvik/vm/native/dalvik_system_Zygote.cpp
@@ -19,3 +19,4 @@
*/
#include "Dalvik.h"
#include "native/InternalNativePriv.h"
+#include <sys/resource.h>
#include
#if (__GNUC__ == 4 && __GNUC_MINOR__ == 7)
- 執行 make 後出現以下錯誤
build/core/java.mk:20: *** dalvik/dexgen: Invalid LOCAL_SDK_VERSION '4' Choices are: current . Stop.
遇到此種問題的時候,首先先移除你的 prebuilt 資料夾,並重新下載
rm -rf prebuilt
repo sync prebuilt
遇到 _FORTIFYSOURCE 這樣的問題
如果你有遇到如以下的錯誤訊息
error: "_FORTIFY_SOURCE" redefined [-Werror]
按照以下 patch 去修改 build/core/combo/HOST_linux-x86.mk
diff --git a/core/combo/HOST_linux-x86.mk b/core/combo/HOST_linux-x86.mk
index 5ae4972..7df2893 100644
--- a/core/combo/HOST_linux-x86.mk
+++ b/core/combo/HOST_linux-x86.mk
@@ -53,6 +53,6 @@ HOST_GLOBAL_CFLAGS += \
-include $(call select-android-config-h,linux-x86)
# Disable new longjmp in glibc 2.11 and later. See bug 2967937.
-HOST_GLOBAL_CFLAGS += -D_FORTIFY_SOURCE=0
+HOST_GLOBAL_CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0
HOST_NO_UNDEFINED_LDFLAGS := -Wl,--no-undefined
編譯 mesa3d 出錯
如果編譯 mesa3d 下的 linker.cpp 產生如以下的錯誤
external/mesa3d/src/glsl/linker.cpp:623:33: warning: by 『 virtual ir_visitor_status remap_variables(ir_instruction*, gl_shader*, hash_table*)::remap_visitor::visit(ir_dereference_variable*)』 [-Woverloaded-virtual]
external/mesa3d/src/glsl/linker.cpp: In function 『 void assign_varying_locations(gl_shader_program*, gl_shader*, gl_shader*)』:
external/mesa3d/src/glsl/linker.cpp:1394:49: error: expected primary-expression before 『,』 token
external/mesa3d/src/glsl/linker.cpp:1394:50: error: 『 varyings' was not declared in this scope
external/mesa3d/src/glsl/linker.cpp:1394:58: error: 『 offsetof' was not declared in this scope
external/mesa3d/src/glsl/linker.cpp:1395:48: error: expected primary-expression before 『,』 token
external/mesa3d/src/glsl/linker.cpp:1412:47: error: expected primary-expression before 『,』 token
修改 external/mesa3d/src/glsl/linker.cpp 成如下
diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp
index f8b6962..cfdd3d3 100644
--- a/src/glsl/linker.cpp
+++ b/src/glsl/linker.cpp
@@ -67,7 +67,7 @@
#include <cstdio>
#include <cstdarg>
#include <climits>
-
+#include <stddef.h>
#include <pixelflinger2/pixelflinger2_interface.h>
extern "C" {
編譯 oprofile 時出錯
在編譯 oprofile 時,如果遇到以下錯誤
external/oprofile/libpp/format_output.h:94:22: error:reference「counts」cannot be declared「mutable」 [-fpermissive]
修改 external/oprofile/libpp/format_output.h 成如下
diff --git a/libpp/format_output.h b/libpp/format_output.h
index b6c4592..8e527d5 100644
--- a/libpp/format_output.h
+++ b/libpp/format_output.h
@@ -91,7 +91,7 @@ protected:
symbol_entry const & symbol;
sample_entry const & sample;
size_t pclass;
- mutable counts_t & counts;
+ counts_t & counts;
extra_images const & extra;
double diff;
};
編譯 gtest 時出錯
如果遇到以下錯誤
external/gtest/src/../include/gtest/internal/gtest-param-util.h:122:11: error: 「ptrdiff_t」does not name a ty
修改 external/gtest/include/gtest/internal/gtest-param-util.h 成如 下
diff --git a/include/gtest/internal/gtest-param-util.h b/include/gtest/internal/gtest-param-util.h
index 5559ab4..405dc4d 100644
--- a/include/gtest/internal/gtest-param-util.h
+++ b/include/gtest/internal/gtest-param-util.h
@@ -37,6 +37,7 @@
#include <iterator>
#include <utility>
#include <vector>
+#include <cstddef>
#include <gtest/internal/gtest-port.h>
遇到 ParamName 錯誤
如果遇到以下問題
frameworks/compile/slang/slang_rs_export_foreach.cpp:249:23: error: variable 『 ParamName' set but not used [-Werror=unused-but-set-variable]
修改 frameworks/compile/slang/slang_rs_export_foreach.cpp 成如下
diff --git a/slang_rs_export_foreach.cpp b/slang_rs_export_foreach.cpp
index a4025ca..0dbf954 100644
--- a/slang_rs_export_foreach.cpp
+++ b/slang_rs_export_foreach.cpp
@@ -246,7 +246,6 @@ RSExportForEach *RSExportForEach::Create(RSContext *Context,
clang::SourceLocation(),
&Ctx.Idents.get(Id));
- llvm::StringRef ParamName = PVD->getName();
clang::FieldDecl *FD =
clang::FieldDecl::Create(Ctx,
RD,
後記
最近一直在嘗試移植 Firefox OS 給我的 HTC One X 使用,為了能更加了解整 個編譯流程,以及確認我改的 manifest 是否正確,因此我是從 CyanogenMod 開始 來研究整個移植的步驟,此篇文章僅紀錄這整個流程。
參考資料
[1] How To Build CyanogenMod Android for HTC One X ("endeavoru")