Тулчейн как расширение SDK#

Пример показывает, как добавить в готовый SDK набор инструментов, не пересобирая сам SDK. За основу взят компилятор из репозитория Astra: он приезжает отдельным расширением и монтируется в точку, объявленную в SDK.

Тулчейн при этом живёт своим циклом: его можно обновить или поставить рядом другую версию, не трогая ни SDK, ни собранные на нём приложения. Скачивают его только те, кому он нужен.

Точка расширения в SDK#

Расширение встаёт только туда, где хост объявил точку. Проверить, что точка есть и как она называется:

flatpak info -m org.astra.mainSdk//1.8.6

В выводе нужна секция вида:

[Extension org.astra.Sdk.Extension]
directory=lib/sdk
subdirectories=true
version=1.8.6
add-ld-path=lib
no-autodownload=true

Отсюда берутся три вещи. Каталог монтирования lib/sdk означает, что содержимое окажется в /usr/lib/sdk. Включённое subdirectories разрешает нескольким расширениям встать в подкаталоги одной точки, каждое в свой. Значение version задаёт ветку, с которой расширение обязано совпасть.

Имя расширения должно начинаться с имени точки: ref org.astra.Sdk.Extension.llvm-19 встаёт в подкаталог llvm-19, то есть в /usr/lib/sdk/llvm-19.

Манифест#

version: "1.0"

metadata:
  id: org.astra.Sdk.Extension.llvm-19
  name: "LLVM/Clang 19 SDK Extension"
  version: "1.8.6"
  arch: amd64
  branch: "1.8.6"

extends:
  ref: runtime/org.astra.mainSdk/x86_64/1.8.6
  directory: lib/sdk/llvm-19

buildRuntime:
  id: org.astra.mainSdk
  version: "1.8.6"
  sdk: org.astra.mainSdk

source:
  type: repository
  repository:
    package: clang-19

dependencies:
  force:
    - llvm-19
    - llvm-19-dev
    - clang-19
    - libclang-19-dev
    - libclang-cpp19
    - libllvm19
    - lld-19

layout:
  - { from: usr/lib/llvm-19,          to: "" }
  - { from: usr/lib/x86_64-linux-gnu, to: lib }

files:
  write:
    - path: enable.sh
      executable: true
      content: |
        export PATH="/usr/lib/sdk/llvm-19/bin${PATH:+:${PATH}}"
        export LD_LIBRARY_PATH="/usr/lib/sdk/llvm-19/lib${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
        export CC=/usr/lib/sdk/llvm-19/bin/clang
        export CXX=/usr/lib/sdk/llvm-19/bin/clang++
        export LLVM_CONFIG=/usr/lib/sdk/llvm-19/bin/llvm-config

build:
  sbom: true

export:
  repository: ./repo

Что здесь важно.

Ветка 1.8.6 в metadata.branch совпадает с version точки расширения. Расхождение приведёт к тому, что расширение просто не смонтируется, и никакой ошибки при этом не будет.

Секция buildRuntime задаёт среду, по составу которой отсекается лишнее. Всё, что уже есть в org.astra.mainSdk, в расширение не попадает, и оно не дублирует библиотеки хоста.

Список dependencies.force перечисляет пакеты, которые нужны в расширении несмотря на отсечение. Тулчейн должен быть самодостаточным: он работает из своего каталога, а не из системных путей хоста.

Раскладка уплощает дерево. Пакеты Debian кладут тулчейн в usr/lib/llvm-19, а разделяемые библиотеки в каталог архитектуры. Первое правило поднимает содержимое usr/lib/llvm-19 в корень расширения, второе кладёт библиотеки в lib. После этого bin, lib и include оказываются там, где их ждёт enable.sh.

Файл enable.sh не обязателен, но избавляет от ручной настройки путей: его достаточно подключить в начале сборки.

Сборка#

aft-extension validate llvm.yaml
sudo aft-extension build llvm.yaml

В одном файле можно описать несколько версий тулчейна, разделив документы строкой ---. Они соберутся по очереди и встанут в соседние подкаталоги одной точки.

Проверка#

Расширение ставится отдельно от SDK: точка объявлена с no-autodownload, поэтому само оно не приедет:

sudo flatpak remote-add --if-not-exists --no-gpg-verify local-repo ./repo
sudo flatpak install -y local-repo org.astra.Sdk.Extension.llvm-19//1.8.6

Проверить, что расширение смонтировалось и работает, можно прямо в песочнице SDK:

flatpak run --command=sh runtime/org.astra.mainSdk/x86_64/1.8.6

Внутри:

ls /usr/lib/sdk
. /usr/lib/sdk/llvm-19/enable.sh
clang --version
echo 'int main(){return 0;}' > /tmp/t.c && clang /tmp/t.c -o /tmp/t && /tmp/t

Пустой каталог /usr/lib/sdk означает, что расширение не смонтировалось. Самые частые причины две: ветка расширения не совпадает с version точки, или имя ref не начинается с имени точки.

Использование при сборке приложения#

Расширение SDK подключается на время сборки и в готовое приложение не попадает. Для источника sourcedir подключение делается первой командой сборки:

source:
  type: sourcedir
  sourcedir:
    path: ./src
    buildCommands:
      - . /usr/lib/sdk/llvm-19/enable.sh && cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/app
      - . /usr/lib/sdk/llvm-19/enable.sh && cmake --build build -j
      - cmake --install build