RFC-014b: Система сборки и бинарное распространение
Данный RFC является под-RFC документа RFC-014: Дизайн системы управления пакетами.
Резюме
Определение механизма сборки системы управления пакетами YaoXiang: декларативная конфигурация сборки, стратегии сборки (cargo/cmake/custom/none), распространение предкомпилированных бинарных файлов, проверка системных зависимостей.
Мотивация
Некоторые пакеты содержат только код .yx и не требуют сборки. Другие требуют компиляции FFI-привязок (вызов Cargo, CMake и т.д.). Необходим унифицированный механизм, позволяющий авторам пакетов объявлять требования к сборке, чтобы менеджер пакетов автоматически их обрабатывал.
Текущие проблемы
- Нет объявления конфигурации сборки (отсутствует секция
[build]вyaoxiang.toml) - Нет механизма распространения предкомпилированных бинарных файлов
- Сборка FFI-пакетов полностью зависит от ручных действий пользователя
- Нет проверки системных зависимостей
Предложение
Основной дизайн: декларативная сборка + приоритет предкомпиляции
Авторы пакетов объявляют требования к сборке в yaoxiang.toml, менеджер пакетов автоматически принимает решения на основе этих объявлений.
Стратегии сборки
enum BuildStrategy {
None, // Чистый .yx пакет, сборка не требуется
Cargo, // Вызов cargo build, чтение конфигурации [build.cargo]
Cmake, // Вызов cmake
Custom, // Выполнение скрипта build.yx
}Примечание: вариант Precompiled удалён. Наличие [binaries] автоматически активирует поведение приоритета предкомпиляции без явного объявления стратегии.
Объявления сборки в yaoxiang.toml
[package]
name = "native-foo"
version = "1.0.0"
[build]
strategy = "cargo" # Стратегия сборки
headers = ["include/sqlite3.h"] # Опционально: C заголовочные файлы для автоматической обработки yx-bindgen
[build.cargo]
features = ["ffi"] # cargo build --features ffi
target = "release" # cargo build --release
[build.requirements]
cargo = ">= 1.70" # Инструменты, необходимые для сборки
cmake = ">= 3.20"
[build.platforms] # Переопределения для конкретных платформ
"x86_64-unknown-linux-gnu" = { cargo-features = ["linux-ffi"] }
"x86_64-pc-windows-msvc" = { cargo-features = ["win-ffi"] }
"aarch64-apple-darwin" = { cargo-features = ["mac-ffi"] }Дерево решений установки
yaoxiang install foo
│
├─ 1. Есть ли в [binaries] запись для текущей платформы?
│ → Да: скачать, проверить SHA-256, установить напрямую (пропустить сборку)
│ → Нет: продолжить
│
├─ 2. Скачать исходный архив
│
├─ 3. Есть ли значения в [build].headers?
│ → Да: автоматически запустить yx-bindgen для генерации файлов привязок
│
├─ 4. Прочитать [build].strategy
│ → "none": установить напрямую
│ → "cargo": прочитать конфигурацию [build.cargo], собрать команду cargo build
│ → "cmake": вызвать cmake
│ → "custom": выполнить скрипт build.yx
│
└─ 5. Установить в vendor/Приоритет предкомпиляции, исходный код как запасной вариант. Наличие [binaries] автоматически активирует проверку предкомпилированных файлов без явного объявления стратегии.
Подробности стратегии cargo
Когда strategy = "cargo", читается конфигурация [build.cargo] для сборки команды:
[build]
strategy = "cargo"
[build.cargo]
features = ["ffi"] # → cargo build --features ffi
target = "release" # → cargo build --release
[build.platforms] # Переопределения для платформ
"x86_64-unknown-linux-gnu" = { cargo-features = ["linux-ffi"] }
"x86_64-pc-windows-msvc" = { cargo-features = ["win-ffi"] }
"aarch64-apple-darwin" = { cargo-features = ["mac-ffi"] }Фактически выполняемые команды:
# Базовый вариант
cargo build --release --features ffi
# С переопределениями для платформы (пример для linux)
cargo build --release --features ffi,linux-ffiОбъявление предкомпилированных бинарных файлов
# yaoxiang.toml
[binaries]
"x86_64-unknown-linux-gnu" = { url = "releases/download/v1.0.0/foo-linux-x86_64.tar.gz", sha256 = "abc123" }
"x86_64-pc-windows-msvc" = { url = "https://example.com/foo-win-x86_64.tar.gz", sha256 = "def456" }
"aarch64-apple-darwin" = { url = "releases/download/v1.0.0/foo-macos-aarch64.tar.gz", sha256 = "ghi789" }Формат URL: Поддерживаются абсолютные URL и относительные пути. Относительные пути указываются относительно адреса репозитория пакета (URL GitHub репозитория или корневого URL Registry).
Условия пропуска сборки:
- В
[binaries]есть запись для текущей платформы - Проверка SHA-256 прошла успешно
- Скачивание прошло успешно
Все три условия выполнены → пропустить сборку. Иначе → fallback на сборку из исходного кода.
Скрипт сборки build.yx
Выполняется когда strategy = "custom".
Модель выполнения (минимальная спецификация):
- Скрипт — обычный код
.yxс полным доступом кstd - Рабочая директория: корневая директория пакета (
vendor/<pkg>-<ver>/) - Успех: код завершения 0
- Неудача: ненулевой код завершения, установка прерывается
- Менеджер пакетов не ограничивает поведение скрипта, только проверяет код завершения
# build.yx — скрипт сборки пакета
use std.os
use std.io
fn main() {
let platform = os.platform()
let arch = os.arch()
if os.file_exists("Cargo.toml") {
io.println("Building native extension via Cargo...")
let result = os.exec("cargo build --release")
if result.exit_code != 0 {
io.println("Build failed!")
os.exit(1)
}
}
io.println("Build complete!")
}Проверка системных зависимостей
Перед установкой автоматически проверяются все [build.requirements], при невыполнении требований выдаётся ошибка:
Error: Build requirement not satisfied
cargo >= 1.70 required, but cargo is not installed
Install: https://rustup.rsИнтеграция yx-bindgen (поле headers)
[build].headers объявляет C заголовочные файлы для обработки yx-bindgen. Система сборки автоматически запускает yx-bindgen для генерации .yx файлов привязок.
[build]
strategy = "cargo"
headers = ["include/sqlite3.h", "include/json.h"]Процесс сборки:
1. Есть ли предкомпиляция в [binaries]?→ Пропустить всю сборку
2. Есть ли значения в [build].headers?→ yx-bindgen автоматически генерирует привязки
3. Выполнить [build].strategy (cargo/cmake/custom)
4. Установитьyx-bindgen парсит сигнатуры функций и определения типов из C заголовочных файлов (.h), автоматически генерирует объявления привязок .yx. Пользователю не нужно запускать вручную — система сборки автоматически обрабатывает при обнаружении конфигурации headers.
Связь с RFC-026: RFC-026 определяет семантику yx-bindgen на уровне языка (синтаксис native("symbol"), тип unsafe). RFC-014b определяет способ его интеграции в процесс сборки (конфигурация headers). Оба документа дополняют друг друга.
Интеграция с Cargo Workspace
Если пакет содержит FFI код, можно одновременно определить Cargo workspace:
my-package/
├── yaoxiang.toml # Конфигурация пакета YaoXiang
├── Cargo.toml # Cargo workspace (FFI часть)
├── src/
│ └── lib.yx # Код YaoXiang
└── native/
├── Cargo.toml # FFI код на Rust
└── src/
└── lib.rsyaoxiang build автоматически обнаруживает и вызывает cargo build для компиляции нативной части.
Детальный дизайн
Идентификация платформы
Используется формат Rust target triple (arch-vendor-os-env):
| Платформа | Идентификатор |
|---|---|
| Linux x86_64 (glibc) | x86_64-unknown-linux-gnu |
| Linux x86_64 (musl) | x86_64-unknown-linux-musl |
| Linux ARM64 | aarch64-unknown-linux-gnu |
| Windows x86_64 (MSVC) | x86_64-pc-windows-msvc |
| Windows x86_64 (MinGW) | x86_64-pc-windows-gnu |
| macOS ARM64 | aarch64-apple-darwin |
| macOS x86_64 | x86_64-apple-darwin |
Использование Rust target triple вместо упрощённого формата обусловлено следующим:
- Различение разных ABI на одной ОС (gnu vs musl, msvc vs gnu)
- Соответствие экосистеме Rust/Cargo, уменьшение ошибок маппинга
- Будущие расширения не потребуют изменения формата
Структура директорий артефактов сборки
build/
└── native/
├── x86_64-unknown-linux-gnu/
│ └── libfoo.so
├── x86_64-pc-windows-msvc/
│ └── foo.dll
└── aarch64-apple-darwin/
└── libfoo.dylibПолный жизненный цикл предкомпилированного пакета
Разработчик:
1. Пишет код .yx + FFI привязки
2. Объявляет [build] + [binaries] в yaoxiang.toml
3. yaoxiang publish
→ Автоматическая сборка мультиплатформенных бинарных файлов в CI
→ Загрузка исходного кода + предкомпилированных артефактов
Пользователь:
yaoxiang add native-foo
→ Обнаружены предкомпилированные артефакты → Прямое скачивание (секунды)
→ Нет предкомпилированных артефактов → Скачивание исходного кода + сборка (минуты)Компромиссы
Преимущества
- Декларативная конфигурация, пользователю не нужно разбираться в деталях сборки
- Приоритет предкомпиляции, очень быстрая установка
- Поддержка нескольких платформ, автоматический выбор
- Бесшовная интеграция с экосистемой Cargo
Недостатки
- Предкомпилированные артефакты требуют поддержки CI
- Мультиплатформенная сборка усложняет публикацию
- Для скриптов build.yx требуется механизм песочницы
Альтернативные решения
| Решение | Причина отклонения |
|---|---|
| Только распространение исходников | Пользователю нужно устанавливать инструментарий, высокий порог входа |
| Бинарный формат как Python wheel | Слишком сложно, не нужно на раннем этапе экосистемы YaoXiang |
| Без поддержки FFI сборки | Ограничивает возможности расширения языка |
Стратегия реализации
Разделение на этапы
| Этап | Содержание |
|---|---|
| Phase 5a | Парсинг конфигурации [build] + enum BuildStrategy |
| Phase 5b | Проверка системных зависимостей |
| Phase 5c | Интеграция сборки Cargo (чтение [build.cargo], сборка команды) |
| Phase 5d | Скачивание и проверка предкомпилированных бинарных файлов |
| Phase 5e | Выполнение скриптов build.yx |
| Phase 5f | Интеграция yx-bindgen (поле headers) |
Зависимости
- Зависит от RFC-014a (протокол Registry, используется для скачивания предкомпилированных артефактов)
- Зависит от crate
sha2(проверка целостности)
Открытые вопросы
- [ ] Нужна ли изоляция в песочнице для скриптов build.yx?
- [ ] Какое максимальное ограничение размера артефактов сборки?
- [ ] Поддерживается ли кросс-компиляция (сборка Windows артефактов на Linux)?
- [ ] Как обрабатывать несовместимость версий Cargo?
