Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
210 changes: 149 additions & 61 deletions docs/packaging-guidelines/buildsystems/rust.md
Original file line number Diff line number Diff line change
@@ -1,119 +1,207 @@
---
id: buildsystemrust
title: Rust
description: This document explains how to use the declarative build system, rustand rustcrates, when packaging for openRuyi.
description: This document explains how to use the rust and rustcrates declarative build systems when packaging for openRuyi.
slug: /guide/packaging-guidelines/BuildSystems/rust
---

# Rust

This document explains how to use the `rust` and `rustcrates` declarative build systems when packaging for openRuyi.

In general, for Rust library packages, most of the packaging content can be generated by automation tools, with little or no manual work required.
The `rust` and `rustcrates` build systems are intended for different package types:

* Use **`rust`** for Rust applications, command-line tools, or other packages that need to run Cargo build and test workflows.
* Use **`rustcrates`** for Rust crate provider packages, which install crate source code and generate crate feature subpackage metadata.

For Rust crate provider generation, dependency closure handling, compatibility naming, and TakoPack workflows, please refer to the Rust packaging guide. This document only describes the behavior of the build system macros.

## Dependencies

To use the `rust` or `rustcrates` build system, add the following `BuildRequires`:
To use the `rust` or `rustcrates` build system, packages normally need:

```specfile
BuildRequires: rust
BuildRequires: rust-rpm-macros
```

## Required macros
If the package depends on other Rust crates, declare them through `crate(...)` capabilities, for example:

For packages built with the `rustcrates` build system, you should define the following macros near the top of the spec file:
```specfile
BuildRequires: crate(clap-4/default) >= 4.5.0
BuildRequires: crate(serde-1/default) >= 1.0.0
```

```spec
# Original crate name from Cargo.toml.
# Keep this unchanged for reference and debugging.
# In most other places, underscores are normalized to hyphens.
%global crate_name anes
## Choosing the build system

# Full upstream version string from crates.io.
# This must be the complete version, even when it contains extra suffixes.
%global full_version 0.1.6
### `rust`

The `rust` build system is used for Rust application packages. A minimal example:

```specfile
BuildSystem: rust
```

If you need to pass arguments to the Cargo build or test workflow, use `BuildOption(build)` and `BuildOption(check)`:

```specfile
BuildSystem: rust

BuildOption(build): --no-default-features --features "foo,bar" -p example-cli
BuildOption(check): --no-default-features --features "foo,bar" -p example-cli
```

### `rustcrates`

The `rustcrates` build system is used for Rust crate provider packages. A typical example:

# Compatibility package name used in Provides/Requires and folder naming.
# The spec file directory name should also match this value.
```specfile
%global crate_name anes
%global full_version 0.1.6
%global pkgname anes-0.1

Name: rust-%{pkgname}
Version: 0.1.6
BuildSystem: rustcrates
```

In most cases:
Where:

- `crate_name` is the original crate name from `Cargo.toml`.
- `full_version` is the exact upstream crate version.
- `pkgname` is the compatibility name used for dependency resolution.
* `crate_name` is the crate name from upstream `Cargo.toml`;
* `full_version` is the full upstream crate version;
* `pkgname` is the compatibility name used by the provider package.

For crates with stricter compatibility rules, `pkgname` may need to include a more specific version segment. For example:
These macros normally do not need to be changed manually. If a manual change is necessary, please explain it in the commit and pull request.

```spec
%global crate_name toml
%global full_version 0.9.11+spec-1.1.0
%global pkgname toml-0.9.11
For detailed compatibility naming rules, please refer to the Rust packaging guide.

Name: rust-%{pkgname}
Version: 0.9.11
## Prep phase

### `rust`

The prep phase of the `rust` build system performs the default source setup and configures Cargo to use the system registry.

Its core behavior is equivalent to:

```specfile
%autosetup -C -p1 ...
%rust_setup_registry
```

If you change `pkgname`, make sure all related dependency declarations are updated accordingly, for example:
If you need to add a small command before or after the default prep phase, use the section extension mechanism provided by the declarative build system:

```specfile
%prep -p
echo "run before default Rust prep"
```

```spec
BuildRequires: crate(toml-0.9.11)
```specfile
%prep -a
echo "run after default Rust prep"
```

Also ensure that the spec file directory name matches `pkgname`.
If you fully override `%prep`, make sure to preserve the Cargo system registry configuration. Otherwise, the following Cargo build may not be able to use the crate dependencies provided by the system.

## When manual adjustments are needed
### `rustcrates`

Most Rust library packages can be generated automatically and require little or no manual editing. Manual changes are usually only needed in the following situations:
The prep phase of the `rustcrates` build system only performs the default source setup.

1. **Overly strict dependency constraints**
Some crates pin dependency versions too tightly in `Cargo.toml`. In such cases, you may need to patch the crate to relax the version constraints.
2. **Broken upstream compatibility behavior**
If a crate does not follow compatibility conventions reliably, you may need to adjust `pkgname` to use a more specific version string.
3. **Obviously incorrect generated spec files**
If the generated spec is clearly unreasonable, compare it with existing well-packaged Rust crates and fix it manually.
If you need to add a small command before or after the default prep phase, you can also use the section extension mechanism provided by the declarative build system.

## Source preparation
## Build phase

When using `rust` or `rustcrates`, you normally do **not** need to unpack sources manually or apply patches by hand.
### `rust`

If additional preparation is required, use `%prep -a` where possible. This is preferred because the default `%prep` logic also prepares Cargo to use the system registry.
The build phase of the `rust` build system performs a Rust release build.

If you must fully override `%prep` when use `rust` buildsystem, make sure to preserve the Cargo registry configuration. A typical replacement looks like this:
Use `BuildOption(build)` to pass arguments to the build phase:

```spec
%prep -a
mkdir -p ~/.cargo
cat > ~/.cargo/config.toml <<EOF
[source.crates-io]
replace-with = "system-registry"
[source.system-registry]
directory = "/usr/share/cargo/registry"
EOF
rm -rf Cargo.lock
```specfile
BuildOption(build): --no-default-features --features "foo,bar"
```

## Packaging library-only crates
These arguments are passed to the Cargo build workflow inside the build system.

For most library-only crate packages, the `rustcrates` build system already provides the necessary installation and test behavior. In many cases, no custom `%build`, `%install`, or `%check` sections are needed.
### `rustcrates`

This is the usual choice for packaging Rust libraries.
The build phase of the `rustcrates` build system does not run Cargo build. Instead, it runs a dynamic specpart generation script and generates the corresponding `%files` fragments for crate provider feature subpackages.

## Notes on build behavior
Therefore, do not override this phase.

At present, the Rust build system wraps the common `cargo build --release` workflow. If your package needs additional build steps or different Cargo commands, override `%build` or extend it with `%build -a`.
## Install phase

For `rustcrates`, library packages often need require less customization customisation than application packages.
### `rust`

The `rust` build system currently has no default install action.

If a Rust application needs to install binaries, documentation, or additional files, write or extend `%install` according to the package's actual needs.

For example, to install a built binary:

```specfile
%install
install -Dm0755 target/release/example-cli %{buildroot}%{_bindir}/example-cli
```

### `rustcrates`

The install phase of the `rustcrates` build system installs the crate source code.

Its core behavior is equivalent to:

```specfile
%rust_install_crate
```

This macro installs the current crate source to the system location and generates `.cargo-checksum.json`.

Therefore, Rust crate provider packages usually do not need a hand-written `%install` section. If you really need to add steps before or after the default install logic, use `%install -p` or `%install -a`.

## Check phase

### `rust`

The `rust` build system provides a default test phase. It runs the Cargo test workflow.

Use `BuildOption(check)` to pass arguments to the test phase:

```specfile
BuildOption(check): --no-default-features --features "foo,bar"
```

If upstream tests require network access, unavailable optional dependencies, a specific runtime environment, or are otherwise unsuitable for the build environment, override or disable `%check` according to the package policy.

### `rustcrates`

The `rustcrates` build system currently has no default test phase.

In other words, crate provider packages using `BuildSystem: rustcrates` do not run Cargo test by default. If additional validation is needed, manually override this phase and write the required test logic.

## Notes

* `rust` is used for Rust application packages. It is not used to generate crate provider packages.
* `rustcrates` is used for Rust crate provider packages. It is not used to build Rust applications.
* If a Python package contains a Rust extension, it should usually still use a Python-related build system, such as `BuildSystem: pyproject`.
* If a package has non-standard build steps, use the generic declarative build system extension mechanisms: `%prep -p/-a`, `%build -p/-a`, `%install -p/-a`, and `%check -p/-a`.

## Build system macro files

The macro files for the two Rust build systems are:
Rust-related build system macro files are usually located at:

```text
/usr/lib/rpm/macros.d/macros.buildsystem.rust
/usr/lib/rpm/macros.d/macros.buildsystem.rustcrates
/usr/lib/rpm/macros.d/macros.rust
```

Where:

* `/usr/lib/rpm/macros.d/macros.buildsystem.rust`
* `macros.buildsystem.rust` defines the prep, build, install, and check phase behavior for `BuildSystem: rust`;
* `macros.buildsystem.rustcrates` defines the prep, build, install, and check phase behavior for `BuildSystem: rustcrates`;
* `macros.rust` provides lower-level macros related to Rust registry setup, build, test, and crate installation.

* `/usr/lib/rpm/macros.d/macros.buildsystem.rustcrates`
If you have questions about the exact behavior of these build systems, you are also welcome to check the source code:

```text
https://github.com/openRuyi-Project/rust-rpm-macros
```
Loading