跳至正文

Yen-Chin, Lee

關於 Emacs、Clojure、Linux 與開發工具的筆記。

coldnew's blog
本頁目錄

編譯 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")

© 2012–2026 Yen-Chin, LeeRSSPowered by Astro