Building LineageOS 17.1 on ArchLinux

This 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

System considerations

In my experience, the following system specifications are a bare minimum for an enjoyable development experience:

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:

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.

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

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.