RPM/Rust

Материал из ALT Linux Wiki
< RPM

Быстрая сборка Rust-пакета

Вендоринг

Вендоринг — сохранение внешних зависимостей (крейтов) вместе с исходным пакетом (в отличии от помещения их в отдельные пакеты и использования BuildRequires).

В директории программы на Rust:

$ cargo vendor
$ find vendor -name '*.a' -delete
$ sed -Ei 's!,"[^"]+\.a":"[^"]+"!!g' $(find vendor -name .cargo-checksum.json)
$ git add -A -f vendor Cargo.lock
$ git commit -m "cargo vendor"
  • cargo vendor - поместит все зависимости в диру vendor/. Желательно, чтоб она была пустая.
  • find - удалит бинарные библиотеки из виндовых зависимостей (winapi*). См. более полный и правильный пример в полезных советах.
  • sed - удалит упоминания checksum из файлов типа .cargo-checksum.json удалённых бинарных библиотек.
  • git add -f - чтобы избежать возможных проблем с .gitignore.

Spec-файл: без использования специализированных макросов

BuildRequires: rust-cargo

В секции %prep после %setup[1]:

mkdir -p .cargo
cat >> .cargo/config.toml <<EOF
[source.crates-io]
replace-with = "vendored-sources"

[source.vendored-sources]
directory = "vendor"

[term]
verbose = true
quiet = false

[install]
root = "%buildroot%_prefix"

[build]
rustflags = ["-Copt-level=3", "-Cdebuginfo=1"]

[profile.release]
strip = false
EOF
  • эта конструкция подключит завендореные исходники, настроит опции сборки и инсталляции.

В %build:

cargo build %_smp_mflags --offline --release

В %install (если пакет не библиотека, а бинарник):

cargo install %_smp_mflags --offline --no-track --path .

В %check, если нужен:

cargo test %_smp_mflags --release --no-fail-fast

Spec-файл: с макросами из rpm-macros-rust

BuildRequires(pre): rpm-macros-rust
BuildRequires: rpm-build-rust

В секции %prep после %setup:

%rust_prep

В случае, если команда cargo vendor указала на дополнительные источники rust-крейтов, например:

To use vendored sources, add this to your .cargo/config.toml for this project:

[source.crates-io]
replace-with = "vendored-sources"

[source."git+https://github.com/influxdata/arrow-datafusion.git?rev=1c10b8b635831e87cb043a1e3fa8eb89be430d54"]
git = "https://github.com/influxdata/arrow-datafusion.git"
rev = "1c10b8b635831e87cb043a1e3fa8eb89be430d54"
replace-with = "vendored-sources"

[source.vendored-sources]
directory = "vendor"

Дополните секцию %prep после %rust_prep:

cat >> .cargo/config.toml <<EOF
[source."git+https://github.com/influxdata/arrow-datafusion.git?rev=1c10b8b635831e87cb043a1e3fa8eb89be430d54"]
git = "https://github.com/influxdata/arrow-datafusion.git"
rev = "1c10b8b635831e87cb043a1e3fa8eb89be430d54"
replace-with = "vendored-sources"
EOF

Секции %build, %install и %check:

%build
%rust_build 
%install
%rust_install
%check
%rust_test
Внимание! Использование переменной среды RUSTFLAGS, которая по умолчанию инициализируется в макросах %rust_build и %rust_test, отменяет любые установки rustflags через файл .cargo/config.toml.

При использовании макроcов %rust_build и %rust_test из-за невозможности установить rustflags через файл .cargo/config.toml в секциях %build и %check необходимо, например, переопределить переменную среды:

export RUSTFLAGS="*ваши флаги*"

Или нужно задать rustflags, например, так[1]:

%build
%rust_build -- --config 'build.rustflags = ["--html-in-header", "header.html"]'
%check
%rust_test -- --config 'build.rustflags = ["--html-in-header", "header.html"]'

Также данный макрос жёстко задаёт параметр -Cdebuginfo=2. Если вам нужно понизить уровень debuginfo до 1, то придётся использовать суровые меры, вроде:

export CARGO_ENCODED_RUSTFLAGS=-Cdebuginfo=1 (переменную среды наивысшего порядка, которая, правда, отменяет установки более низкого порядка, например, из RUSTFLAGS и ниже)
Примечание: В блоке %check важно продублировать настройки конфигурации из блока %build для корректности прохождения тестов.


Полезные советы

Очистка от бинарных артефактов (мы всё-таки собираем из исходников)

Вручную

$ find vendor/ \( -name '*.a' -o -name '*.lib' -o -name '*.dll' -o -name '*.obj' \) -delete
$ sed -Ei 's!,"[^"]+\.(a|lib|dll|obj)":"[^"]+"!!g' $(find vendor -name .cargo-checksum.json)

Такая чистка часто ломает rustix, что решается включением use-libc feature (например добавлением при сборке к rustflags --cfg=rustix_use_libc) или включением cc feature — пример как это выглядит в Cargo.toml:

[dependencies]
rustix = { features = ["cc"] }

Или с помощью опции --config[1]:

cargo build %_smp_mflags --offline --release -- --config 'build.rustflags = ["--cfg=rustix_use_libc"]'

С использованием cargo-vendor-filterer

cargo-vendor-filterer - инструмент для более глубокой очистки каталога vendor/. Например, с его помощью вы можете:

  • Оставить только зависимости для указанных платформ (чтобы отфильтровать зависимости специфические для Windows или MacOS)
$ cargo vendor-filterer \
    --platform=x86_64-unknown-linux-gnu \
    --platform=i686-unknown-linux-gnu \
    --platform=aarch64-unknown-linux-gnu \
    --platform=loongarch64-unknown-linux-gnu \
    --platform=riscv64gc-unknown-linux-gnu
  • Удалить тесты и/или примеры из зависимостей с использованием синтаксиса CRATENAME#PATH:
$ cargo vendor-filterer --exclude-crate-path '*#tests' --exclude-crate-path '*#examples'
Примечание: Синтаксис: CRATENAME - имя крэйта (может содержать wildcards)

PATH - относительный путь к файлу, каталогу или символической ссылке (может содержать wildcards)


  • Оставить только необходимый тип зависимостей [2] [3]:
    • all (normal + build + dev)
    • normal
    • build
    • dev
    • no-normal (build + dev)
    • no-build (normal + dev)
    • no-dev (normal + build)
$ cargo vendor-filterer --keep-dep-kinds no-dev

Подробнее о возможностях смотрите в документации.

В пакете cargo-vendor-filterer кроме самой программы также содержится скрипт-обертка cargo-vendor-alt, который устанавливает некоторые флаги по умолчанию (например, указаны поддерживаемые в репозитории архитектуры) для удобства.

$ cargo-vendor-alt <дополнительные опции>

Решение проблем с windows/unix кодировкой текстовых файлов

$ grep -sq -w 'text' .gitattributes && echo '* -text' > vendor/.gitattributes

Оптимизации сборки пакетов[4]

  • Часто cargo install начинает пересобирать исходники, поэтому лучше делать обычный install
install -Dp target/release/%name -t %buildroot%_bindir
  • Сборка упала на 32-битных архитектурах с LLVM ERROR: out of memory Allocation failed

Возможно, апстрим включил излишнюю оптимизацию в Cargo.toml. Её можно перекрыть в создаваемом выше .cargo/config.toml (в зависимости от того, что было включено), например:

cat >> .cargo/config.toml <<EOF
[profile.release]
lto = "thin"
codegen-units = 16
EOF

Другие вспомогательные утилиты для сборки пакетов

В etersoft-build-utils предусмотрена автоматизация обновления в git-репозитории пакетов rust, требуемых для сборки[5].

Примеры пакетов на Rust

  • influxdb3
  • hyperfine
  • b3sum
  • bugstalker (обратите внимание на макрос %rust_install, где имя бинарника при установке не совпадает с названием проекта).

Ссылки

  1. 1,0 1,1 1,2 [1] - The Cargo Book, Configuration
  2. [2] - The Cargo Book, cargo-tree
  3. [3] - The Cargo Book, Specifying Dependencies
  4. [4] - The Rust Performance Book
  5. [5] - ALT Linux Wiki, Etersoft-build-utils