Building LineageOS 17.1 on ArchLinux
April 13th, 2020This post serves as a log of some of the hoops I had to jump through in order to get LineageOS 17.1 to build on ArchLinux, as a reminder to myself in case I need to do this again in the future. As a result, it is rather brief and incomplete. Consider filling in the gaps with the official build documentation from the LineageOS Wiki.
This guide assumes working knowledge of ArchLinux and Android development, but makes an effort to link to relevant reading.
Prerequisites
Packages
Required for build
- repo
- lineageos-devel
- multilib-devel
- base-devel
- ttf-dejavu (Fun fact: It’s used to generate the PNG image for the LOS recovery splash screen)
- lib32-ncurses5-compat-libs
- …
Recommended
- android-tools (platform-tools)
- android-udev (udev rules for Android ADB)
System considerations
In my experience, the following system specifications are a bare minimum for an enjoyable development experience:
- A 64-bit multiscalar processor from this decade
- 200GB of solid state storage
- '’At least’’ 16 GB of RAM, at the bare minimum 8 GB with some tweaks
- A relatively cool climate and a nearby window to vent heat
Making it work
There are a number of optimizations which can be performed to ‘'’make it work’’’ despite not having the best computer or internet connection:
Reduce simultaneous jobs
For repo sync
or brunch
consider using fewer simultaneous
jobs (via the -j
flag). This has the effect of:
- Using less memory at once
- Using less network bandwidth at once (for repo)
- Using less compute resources at once
- Making your build take proportionally longer
Build components individually
For systems with less than 16 GB of RAM, there are some parts of the build which will OOM (I’m looking at you, metalava). These components can be selectively built individually, to reduce the number of tasks your computer is processing at once (see the top of &pre(build/envsetup.sh); for make commands).
Use swap and zswap
You should probably use swap on relatively fast storage in order to handle sudden spikes in memory usage.
This includes enabling zswap. Many build steps allocate large heaps or spawn many JVMs which fill all your resident memory. Memory compression is surprisingly effective at handling these bad actors. Without sufficient RAM and swap/zswap disabled, you will probably OOM while generating documentation with metalava.
Caching
For multiple builds, consider enabling ccache with or without compression to reduce build time for subsequent builds.
export USE_CCACHE=1
export CCACHE_COMPRESS=1
ccache -M 20G
Build
Acquiring sources and binaries
Run the following repo commands to download the sources from a hodgepodge of repositories scattered across the internet.
repo init -u https://github.com/LineageOS/android.git -b lineage-17.1
repo sync
Consider using fewer simultaneous jobs if you have a poor internet connection.
repo sync -j1 -c
Make sure you keep the -c
flag, which tells repo to only download the
current branch. Otherwise, you will have a bad time.
Proprietary blobs
You will need proprietary blobs from your device vendor. These can be extracted from a working device, ripped from an image, or obtained via unofficial means.
If you end up getting blobs from a repository, consider adding them to your local manifests. This will make synchronization of your blobs work with repo.
For example, my .repo/local_manifests/roomservice.xml
looks like
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<project path="device/essential/mata" remote="github" name="LineageOS/android_device_essential_mata" />
<project path="kernel/essential/msm8998" remote="github" name="LineageOS/android_kernel_essential_msm8998" />
<project path="vendor/essential" remote="github" name="TheMuppets/proprietary_vendor_essential" />
</manifest>
Device specific sources
To get vendor and device trees for your specific device, you will need to have breakfast. This will fail if your proprietary blobs are missing.
source build/envsetup.sh
breakfast <DEVICE_CODENAME>
Building
Run the following commands to create an unsigned build:
croot
brunch <DEVICE_CODENAME>
Signed builds can be created via a different process, which I will not get into detail.
Your build artifacts will be in the &pre($OUT); directory.
Troubleshooting
Something will probably break while you are trying to build. Here’s what broke for me, and how I tried to fix it.
Various symptoms related to out-of-memory conditions
- Process is randomly terminated while building
[ 97% 99068/101261] //frameworks/base:system-api-stubs-docs Metalava [common]
It was probably killed by the OOM killer. Watch your available memory and process oom scores while building. Consider using the memory techniques mentioned above. If all else fails, try tweaking various environment variables to try to lower memory usage (e.g. Java heap size, cache sizes etc.)
ERROR: Failed to run command '['simg2img', '/tmp/targetfiles-oa64tct3/IMAGES/system.img', '/tmp/targetfiles-oa64tct3/IMAGES/unsparse_system.img']' (exit code 255):
Failed to read sparse file
- platform_build/build_image uses /tmp to unsparse image files. On most systems, /tmp is backed by RAM, with a maximum size of half the available RAM. The random file used by the tool is generated with &pre(mktemp);, so use the &pre(TMPDIR); envvar to set it to somewhere else.
error: vendor/lineage/build/soong/Android.bp:30:8: module "generated_kernel_includes": cmd: unknown variable '$(PATH_OVERRIDE_SOONG)'
Have you ever found an article in a foreign language (navigate at your own risk) that seems to describe the very issue you are having, with no response. Well I have.