LineageOS-21 编译大战!—— 一个萌新的心路历程 ☆
kira~☆ 本文将同步闪耀于 CSDN & 看雪论坛,请多指教!
0x01 碎碎念 Time~
最近闲得快要长蘑菇了,于是淘来一台二手 LG G8 ThinQ (代号是 alphaplus
哦~),打算让它成为我的新玩具... 啊不,是备用机!然后捏,一个大胆的想法突然降临:何不亲手为它打造一套 LineageOS 呢?
说干就干,冒险的帷幕,就此拉开!(•̀ㅂ•́)و✧
0x02 冒险前的物资准备!
- 大量的时间 & 钢铁般的耐心 (非常重要!说三遍!后面还会再说!)
- Linux 大陆通行证 (强烈推荐物理机,跑起来才够劲!虚拟机什么的... 稍稍有点勉强啦。WSL2 也要小心,特别是 WSL1,那是万万不可的哟~♀️)
- 畅通无阻的网络 (我们需要从 GitHub 召唤 Vendor Blobs 和 Kernel 这些神秘力量!后面会细说。可怜我的校园网只有 7Mb/s,光是拉源码就花了一整天... !)
- 一个足够大的磁盘空间 (咱的口袋是 391.8GB,编译完成后还剩大约 67.1GB,给小伙伴们参考一下~ 至少需要 400GB 才稳妥哦!)
- 强力的 CPU 核心 (我用的是 i7-9750H... 没错,就是那台服役 6 年的老伙计笔记本!编译过程大概跑了一整天... 核心越多越好,像八爪鱼那样!)
- 至少 32GB 的内存 (不开 swap 会直接宕机!亲身经历 T_T... 建议设置 12GB 的 swap 结界,不然真的会死得很惨...)
- 再次强调:大量的时间 & 钢铁般的耐心! (这是成为魔法师... 啊呸,编译大师的必备素质!)
0x03 羁绊的开始!Let's Go!
Step 1: 搭建我们的秘密基地 (环境准备)
首先,得把我们的 Linux 小窝打造成适合编译魔法的环境。需要安装一些神秘的咒语。
本教程基于 Archlinux 魅魔,Ubuntu 小姐姐部分如果有误,请温柔地指出,我会立刻修正哒~ (没有特别标注的话,就是两个系统通用的咒语哦!)
!!!注意注意!!!编译的时候千万不要用 root 大人的权限,会引来不必要的麻烦哦!Σ( ° △ °|||)
For Archlinux 小伙伴:
1 2 3 4 5 6 7 | sudo pacman -Syyu
sudo pacman -S --needed base-devel git jdk17-openjdk python python-pip ccache \
libxml2 ncurses zlib openssl pngcrush schedtool imagemagick \
bc android-tools rsync wget unzip zip p7zip curl \
libxslt lz4 patchelf coreutils findutils gawk grep sed git git-lfs
|
For Ubuntu 小伙伴:
1 2 3 4 | sudo apt update && sudo apt upgrade
sudo apt install bc bison build-essential ccache curl flex g++-multilib gcc-multilib git git-lfs gnupg gperf imagemagick lib32readline-dev lib32z1-dev libdw-dev libelf-dev liblz4-tool lz4 libsdl1.2-dev libssl-dev libxml2 libxml2-utils lzop pngcrush rsync schedtool squashfs-tools xsltproc zip zlib1g-dev libwxgtk3.0-dev lib32ncurses5-dev libncurses5 libncurses5-dev
|
Step 1.5: 召唤 Ccache 酱,开启高速模式!✨
诶嘿嘿~ 想要让之后的编译快到飞起吗?那就快来召唤 Ccache 酱 这位时间魔法师吧!她能记住你编译过的东西,下次再编译同样的内容时,就能瞬间完成,大大缩短等待时间哦!(ノ´ヮ´)ノ*:・゚✧
要召唤 Ccache 酱,你需要咏唱以下咒语:
1 2 | export USE_CCACHE=1
export CCACHE_EXEC= /usr/bin/ccache
|
然后,记得把这两行神秘代码也添加到你的 ~/.bashrc
(或者 ~/.zshrc
,看你用哪个 Shell 啦) 文件里,这样每次打开终端,Ccache 酱就会自动准备好为你加速啦!
接下来,要告诉 Ccache 酱她能使用多少硬盘空间来存放她的编译产物。念这个咒语:
这里的 30G
就代表 Ccache 酱可以征用 30GB 的硬盘空间哦。这个咒语只需要成功咏唱 一次 就好~
Ccache 酱需要多大空间呢?
- 一般来说,给她分配 25GB 到 100GB 的空间,就能让编译速度发生翻天覆地的变化!(举个栗子,原本 1 小时的漫长等待,可能咻的一下就缩短到 20 分钟!)
- 如果你只打算为一个老婆… 啊不,一台设备编译 ROM,那么 25GB-50GB 就足够 Ccache 酱施展拳脚啦。
- 但如果你是个“后宫王”体质,要为好几位内核源码不同的设备后宫编译,那最好给她准备 75GB-100GB 的大 house!
- 不过要注意! 这部分空间会被 Ccache 酱 永久占据 (除非你手动清理或卸载她),所以在决定大小前要好好掂量一下自己的硬盘容量,别不小心撑爆了哟!
还有个小秘技!Ccache 酱的压缩魔法!
你可以选择开启 Ccache 酱的压缩模式!虽然这可能会让她的编译速度稍微慢一丢丢,但好处是能在同样的空间里塞下更多的缓存文件!更省空间了耶!
要开启压缩模式,就念这个咒语 (同样,只需一次):
1 | ccache -o compression= true
|
小贴士: 如果开启了压缩模式,之前设定的缓存大小就可以适当调小一点啦 (比如只为一个设备编译的话,大概 20GB 可能就够用了~)
好啦!有了 Ccache 酱的加持,我们的编译大业就能更加顺畅啦!继续前进!➡️
Step 2: 开辟源码的圣域 (创建源码目录)
就在咱的用户目录下建一个新家吧~
然后,瞬移进去!
Step 3: 获取 repo 酱这个传送门管理员 (设置 repo)
1 2 3 4 5 6 7 8 | mkdir ~ /bin
PATH=~ /bin :$PATH
curl https: //mirrors .tuna.tsinghua.edu.cn /git/git-repo -o ~ /bin/repo
chmod a+x ~ /bin/repo
|
Step 4: 设定传送目标 (配置仓库)
我们选择清华大学的镜像作为主要传送点。(当然 BFSU 镜像在 LineageOS-21.0 时也能成功抵达终点,但 LineageOS-22.1 遇到了 VNDK33 无法召唤的问题,22.2 又遇到了奇怪的编译错误... 可能是版本更新太快,同步还没跟上?)
简单对比一下两大传送门 (截至我上次观察时... 诶~我上次观察是啥时候来着?):
- 清华源 (TUNA): 同步范围超广,但有时感觉拉取速度像是在爬... (不知道现在有没有变快?)
-> 清华酱的 AOSP 代码同步状态展示图 (看起来很大很全!)
-> 清华酱的 LineageOS 代码同步状态展示图 (感觉也不错!)
- 北外源 (BFSU): 速度飞快!但可能因为同步有延迟,偶尔会找不到最新的零件。
-> BFSU 酱的 AOSP 代码同步状态展示图 (明显小很多)
-> BFSU 酱的 LineageOS 代码同步状态展示图 (同样,可能不是最新鲜的)
结论: 清华更稳妥全面,但可能慢;BFSU 快但可能有坑。大家可以根据自己的网络情况和追求选择信仰!(当然,直连官方 GitHub/GoogleSource 的都是真·勇士!这件事实在是泰裤辣!)
这里以 BFSU 源为例 (因为它在我的 LineageOS-21 冒险中成功了嘛):
1 2 3 4 | repo init -u https: //mirrors .bfsu.edu.cn /git/lineageOS/LineageOS/android .git -b lineage-21.0 --git-lfs
|
小小解说:
-u
: 指定那个记录着所有宝藏地点 (manifest 仓库) 的 URL。
-b
: 我们要探索哪个版本的世界线 (分支)。
--git-lfs
: 开启对“大件行李”(Git Large File Storage) 的支持,有些宝藏需要这个才能搬运哦 (具体是哪些嘛... 咱也不知道,咱也不敢问)。
Step 5: 向 Git 大神登记身份 (配置 Git)
第一次进行大规模召唤 (拉取操作) 前,需要先跟 Git 大神报上名号:
1 2 | git config --global user.name "<你的昵称或者名字啦,记得去掉尖括号哦>"
git config --global user.email "<你的邮箱地址,也去掉尖括号哈>"
|
Step 6: 开始伟大的召唤仪式!(拉取源码)
先悄悄修改一下传送契约 .repo/manifests/default.xml
:
把这段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | < remote name = "github"
fetch = "dd9K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1j5`." />
< remote name = "private"
fetch = "ssh://git@github.com" />
< remote name = "aosp"
fetch = "942K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0K9i4u0J5L8%4u0K6i4K6u0W2j5X3k6K6N6g2)9J5k6h3g2V1N6g2)9J5k6h3y4F1i4K6u0r3k6$3W2@1i4K6u0r3b7f1!0e0f1l9`.`."
review = "android-review.googlesource.com"
revision = "refs/tags/android-14.0.0_r67" />
< default revision = "refs/heads/lineage-21.0"
remote = "github"
sync-c = "true"
sync-j = "4" />
|
改成这样 (具体修改可以参考镜像站点的帮助文档):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | < remote name = "github"
fetch = "d7dK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1j5`." />
< remote name = "lineage"
fetch = "62fK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0K9i4u0J5L8%4u0K6i4K6u0W2j5X3k6K6N6g2)9J5k6h3g2V1N6g2)9J5k6h3y4F1i4K6u0r3k6$3W2@1i4K6u0r3L8r3W2F1k6h3q4Y4k6f1!0e0i4K6u0r3"
review = "review.lineageos.org" />
< remote name = "aosp"
fetch = "05dK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0K9i4u0J5L8%4u0K6i4K6u0W2j5X3k6K6N6g2)9J5k6h3g2V1N6g2)9J5k6h3y4F1i4K6u0r3k6$3W2@1i4K6u0r3b7f1!0e0f1l9`.`."
review = "android-review.googlesource.com"
revision = "refs/tags/android-14.0.0_r67" />
< default revision = "refs/heads/lineage-21.0"
remote = "lineage"
sync-c = "true"
sync-j = "12" />
|
然后,启动召唤法阵!
1 | repo sync --no-clone-bundle
|
加 --no-clone-bundle
这个小咒语是为了防止某些调皮的仓库 (比如 Lineage_framework_base
) 在同步时闹别扭,出现 bundle 错误。
召唤途中可能会遇到小波折,不要慌!按下 Ctrl + C
中断仪式,然后重新念咒:
1 | repo sync --no-clone-bundle
|
如果还不行,试试更强硬的姿态:
但有时,会遇到极其可怕的恶性错误:
1 2 3 4 5 6 7 8 | 出现错误:Fetching: 0% (7 /1471 ) 0:05 | 14 jobs | 0:04 LineageOS /android_bionic @ bionic
致命错误:不是 git 仓库: '/mnt/swapdisk/Android/LineageOS/.repo/projects/dalvik.git'
platform /dalvik :
致命错误:不是 git 仓库: '/mnt/swapdisk/Android/LineageOS/.repo/projects/dalvik.git'
platform /dalvik : sleeping 4.0 seconds before retrying
致命错误:不是 git 仓库: '/mnt/swapdisk/Android/LineageOS/.repo/projects/dalvik.git'
error: Cannot fetch platform /dalvik from https: //mirrors .bfsu.edu.cn /git/AOSP/platform/dalvik
... (更多类似的报错) ...
|
这是我在尝试召唤 LineageOS-22.1 时遇到的噩梦...
遇到这种级别的错误,基本就是绝境了... (偷偷用 git clone
塞东西到 .repo/project
里面?想都别想!repo
酱会用小皮鞭严厉惩罚每一个不听话的宝宝;中途更换代码源到 googlesource
或 github
?她同样会惩罚那些三心二意的宝宝,必须对选择的源保持忠贞不渝!)
实在没办法了,可以试试这些最后的挣扎:
强制对问题仓库进行灵魂同步:
1 2 | repo sync --force- sync platform /dalvik
|
物理超度损坏的仓库,然后重新召唤:
1 2 3 4 | rm -rf .repo /projects/platform/dalvik .git
repo sync platform /dalvik
|
如果以上都不行... 终极奥义:删库重来!
然后回到 Step 4,重新配置仓库 (repo init
)。这次... 也许该考虑放弃国内镜像,直接拥抱官方源了 (虽然可能要经历漫长的等待... 大约 200GB 的数据量呢)。
1 | repo init -u https: //github .com /LineageOS/android .git -b lineage-21.0 --git-lfs
|
之后,就是... 泡杯茶,看几集番,或者睡一觉吧... 等待法阵完成它的工作... 直到所有星辰归位... ✨
Step 7: 召唤特定设备的神秘力量 (准备 Vendor Blobs 等)
请务必查清你家设备的代号!可以去官方文档或者XDA这样的论坛找找看。
在 .repo
目录下创建一个叫做 local_manifests
的小文件夹。在里面新建一个文件,名字可以叫 <你的手机厂商>_manifest.xml
(比如 lge_manifest.xml
)。然后,参考下面的模板抄写咒语:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <? xml version = "1.0" encoding = "UTF-8" ?>
< manifest >
< remote name="<随便取个名字,比如 a_cool_repo>" fetch="<仓库地址,一定要对哦!>" revision="<仓库里对应的分支名,比如 lineage-21>" />
< project path="vendor/<手机厂商>/<设备代号>" name="proprietary_vendor_<手机厂商>_<设备代号>" remote="<上面定义的名字>" />
< project path="device/<手机厂商>/<设备代号>" name="android_device_<手机厂商>_<设备代号>" remote="<上面定义的名字>" />
< project path="vendor/<手机厂商>/<处理器代号>-common" name="proprietary_vendor_<手机厂商>_<处理器代号>-common" remote="<上面定义的名字>" />
< project path="device/<手机厂商>/<处理器代号>-common" name="android_device_<手机厂商>_<处理器代号>-common" remote="<上面定义的名字>" />
</ manifest >
|
那么,这些神秘力量的地址在哪里找呢?
很简单!去 GitHub 这个大宝库里搜索关键词,比如:
proprietary_vendor <手机厂商> <设备代号>
android_device <手机厂商> <设备代号>
proprietary_vendor <手机厂商> <处理器代号> common
(建议有)
android_device <手机厂商> <处理器代号> common
(建议有)
很多机型的这些宝贝都可以在 TheMuppets
(木偶大佬!) 的 GitHub 仓库下找到 (但不一定是最新的哦)。想要最新鲜的?直接在 GitHub 搜索框里搜,像这样:

点进搜索结果,找到看起来最靠谱的仓库(数量不多的话也可以依次查看,顺便看看作者有没有其他的库),然后去看看它的 Branches
(分支) 页面:

选择与你的 LineageOS 版本 (比如 lineage-21
) 相对应的那个分支,把仓库地址和分支名填到我们刚才的 .xml
文件里。
保存好 .xml
文件后,再次执行召唤仪式!
1 | repo sync --no-clone-bundle
|
Step 8: 与 Android 酱共进早餐 (最终准备与编译)
现在呢...
呐~ 你吃早餐了吗?要不要和可爱的 Android 酱共进早餐呢?
诶?同意了嘛?那... 把你手机的代号作为用餐券交给 Android 酱吧~
欸嘿,别忘了问 Android 酱的联系方式哦~ (虽然她可能不会直接告诉你)
嗯... 果然,傲娇的 Android 酱没有直接回应... 但没关系,我们可以用刚才的“用餐券”来正式邀请她共进早餐啦!
如果是第一次约 Android 酱吃早餐,她可能会需要从 GitHub 上拉取一些专属于你设备的材料 (device, hardware, kernel 等)。这时候可能需要你的魔法上网工具助力!如果开了代理(全局)还是卡住不动,就按 Ctrl + C
强制取消,然后重新邀请她吃早餐 (多试几次可能就好了)。

早餐过后,就是激动人心的早午餐 (Brunch) 时间!这才是正餐!

接下来,就是漫长而又悲壮的炼成时间... 期间你可能会经历:
- 出现奇怪的编译错误
- 仿佛永无止境的编译时间...
- CPU 君发出的痛苦咆哮
- 内存酱被 Buffer/Cache 填满到几乎窒息
- Swap 结界被无情地挤占
- 硬盘空间以肉眼可见的速度消失 (尤其最后 10%-15%,请务必留足至少 50GB 的空间!)
- 甚至... 电脑直接累晕过去
不过不用太担心!即使编译中途电脑不幸牺牲,直接强制重启后,回到源码目录,重新执行 source build/envsetup.sh
和 brunch <你的设备代号>
,编译大法师会从上次中断的地方继续施法 (有点像断点续传,超神奇!)。

坚持住!胜利的 BGM 终将奏响!—— 编译成功!

我们亲手炼成的 ROM 包就静静地躺在 ./out/target/product/<你的设备代号>/
这个目录下。

好啦!快去把这份带着你心血和汗水的 ROM 刷入你的爱机吧!享受这份亲手创造的喜悦!(≧∇≦)
最后于 22小时前
被OrionisLi编辑
,原因: 修改错误的格式