Введение

NixOS — отличный дистрибутив для разработки, но сборка Android AOSP/LineageOS требует особого подхода из-за его нетривиальной файловой системы. В отличие от обычных Linux-дистрибутивов, в NixOS нельзя просто установить зависимости глобально через пакетный менеджер — здесь на помощь приходит buildFHSEnv, создающий FHS-совместимое окружение.

Этот материал основан на реальном shell.nix, использовавшемся для сборки LineageOS, и адаптирован для LineageOS 23.2 (Android 16).

Предварительные требования

  • NixOS с настроенным nixpkgs (желательно unstable или nixos-unstable)
  • Минимум 16 ГБ ОЗУ (рекомендуется 32 ГБ)
  • Минимум 200 ГБ свободного места на диске
  • Желание читать логи сборки :)

FHS-окружение для сборки

LineageOS ожидает стандартную FHS-структуру файловой системы. В NixOS это решается через buildFHSEnv — утилиту, создающую изолированное chrub-окружение с привычной структурой каталогов.

Основной shell.nix

{ pkgs ? import <nixpkgs> { } }:

let
  fhs = pkgs.buildFHSEnv {
    name = "android-env";
    targetPkgs =
      pkgs: with pkgs; [
        # Инструментарий Android
        android-tools

        # Библиотеки, необходимые для сборки
        libxcrypt-legacy   # libcrypt.so.1
        freetype           # libfreetype.so.6
        fontconfig         # java NPE: "sun.awt.FontConfiguration.head" is null
        yaml-cpp           # необходима для некоторых ядер

        # Инструменты сборки
        bc                 # калькулятор для ядра
        binutils           # ассемблер, компоновщик
        bison              # генератор парсеров
        ccache             # кэш компиляции (ускоряет повторные сборки)
        curl               # загрузка исходников
        flex               # лексический анализатор
        gcc                # компилятор C/C++
        git                # система контроля версий
        git-repo           # управление несколькими git-репозиториями Android
        git-lfs            # поддержка больших файлов
        gnumake            # система сборки make
        gnupg              # верификация подписей
        gperf              # генератор хеш-функций
        imagemagick        # обработка изображений (сплеш-скрины)
        jdk17              # Java Development Kit (LineageOS 23 требует JDK 17)
        elfutils           # работа с ELF-файлами
        libxml2            # XML-парсер
        libxslt            # XSLT-трансформации
        lz4                # сжатие LZ4
        lzop               # сжатие LZO
        m4                 # макропроцессор
        nettools           # сетевые утилиты (hostname, ifconfig)
        openssl.dev        # криптография
        perl               # скриптовый язык
        pngcrush           # оптимизация PNG
        procps             # утилиты /proc (ps, vmstat)
        python3            # Python 3
        rsync              # синхронизация файлов
        schedtool          # управление планировщиком процессов
        SDL                # Simple DirectMedia Layer
        squashfsTools      # работа с squashfs-образами
        unzip              # распаковка архивов
        util-linux         # системные утилиты
        xml2               # конвертер XML в плоский текст
        zip                # упаковка архивов
      ];

    multiPkgs =
      pkgs: with pkgs; [
        # 32-битные библиотеки (необходимы для некоторых бинарных инструментов)
        zlib               # сжатие
        ncurses5           # терминальный интерфейс
        libcxx             # библиотека C++
        readline           # редактирование командной строки

        # Системные библиотеки
        libgcc             # crtbeginS.o — объектные файлы рантайма
        iconv              # преобразование кодировок
        iconv.dev          # sys/types.h
      ];

    profile = ''
      export ALLOW_NINJA_ENV=true
      export USE_CCACHE=1
      export CCACHE_EXEC=/usr/bin/ccache
      export ANDROID_JAVA_HOME=${pkgs.jdk17.home}
      # Распаковка больших архивов требует временной директории
      export TMPDIR=/tmp
      export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${pkgs.ncurses5}/lib
    '';
  };
in
pkgs.stdenv.mkDerivation {
  name = "android-env-shell";
  nativeBuildInputs = [ fhs ];
  shellHook = "exec android-env";
}

Важно: Для LineageOS 23.2 (Android 16) требуется JDK 17 или новее. В примере выше используется jdk17.

Запуск окружения

# Чистое FHS-окружение (рекомендуется)
nix-shell --pure

# Обычное окружение (могут быть конфликты с пакетами хоста)
nix-shell

Ключевой флаг --pure изолирует окружение от переменных и пакетов хост-системы, что значительно снижает вероятность ошибок.

Особенности NixOS

Ядро и 32-битная эмуляция

NixOS с hardened-ядром отключает 32-битную эмуляцию (IA32_EMULATION), из-за чего некоторые бинарные инструменты Android SDK падают с ошибкой “Exec format error”. Решения:

  1. Использовать стандартное ядро NixOS (не hardened)
  2. Включить IA32_EMULATION в конфиге ядра

В configuration.nix:

boot.kernelPackages = pkgs.linuxPackages;  # вместо linuxPackages_hardened

Репозиторий исходников

Инициализация репозитория LineageOS 23:

repo init -u https://github.com/LineageOS/android.git -b lineage-23.2
repo sync -c -j$(nproc)

Совет: git-repo включён в FHS-окружение. Если repo недоступен, установить отдельно: nix-shell -p git-repo.

Настройка ccache

Для ускорения повторных сборок включите ccache:

export USE_CCACHE=1
export CCACHE_EXEC=/usr/bin/ccache
ccache -M 50G  # максимум 50 ГБ кэша

Эти переменные уже экспортируются в profile shell.nix.

TMPDIR

При распаковке больших архивов (например, vendor-img) временная директория может переполниться. Явно укажите TMPDIR:

export TMPDIR=/tmp
# или на отдельный раздел:
export TMPDIR=/mnt/fast-ssd/tmp

Процесс сборки

После входа в FHS-окружение:

# Применить пачи для устройства
source build/envsetup.sh

# Выбрать целевое устройство (например, Google Pixel 8 — shusky)
breakfast shusky

# Запустить сборку
croot && brunch shusky

Типичные ошибки и их решения

Ошибка Причина Решение
/usr/bin/env: bad interpreter: No such file or directory Отсутствуют 32-битные библиотеки Добавить multiPkgs в shell.nix
fatal error: sys/types.h: No such file or directory Нет заголовочных файлов Добавить iconv.dev в multiPkgs
sun.awt.FontConfiguration.head is null Нет шрифтов Java Установить fontconfig в targetPkgs
libcrypt.so.1: cannot open shared object file Устаревшая библиотека crypt Добавить libxcrypt-legacy
Execution permission denied / Exec format error Отключена 32-битная эмуляция Сменить ядро на обычное

Заключение

Сборка LineageOS в NixOS — вполне реальная задача. Главное преимущество — воспроизводимость окружения: сборка на другой машине с тем же shell.nix пройдёт идентично.

Ключевые моменты:

  • Всегда использовать nix-shell --pure
  • Не забывать про multiPkgs для 32-битных библиотек
  • Для LineageOS 23.2 нужен JDK 17+
  • Стандартное ядро NixOS дружелюбнее к Android-инструментарию

Собранная прошивка — out/target/product/<устройство>/lineage-*.zip.

Удачной сборки!