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
本篇文章所編譯的 CyanogenMod 版本為 CM9 ,實際上相對應的 Android 版本 即為 Android 4.0 (ICS) ,因為 HTC 在 Android 4.0 與 4.2 上面的 HBOOT 有差 異,你必須將你的 HBOOT 降版,才能夠將 CM9 裝到你的手機,並成功開機。
若你的 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
遇到 _FORTIFY_SOURCE 這樣的問題
如果你有遇到如以下的錯誤訊息
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 開始 來研究整個移植的步驟,此篇文章僅紀錄這整個流程。