Rust Packaging Guidelines
This document details best practices for packaging Rust crates.
Note that the rust2rpm tool,
available as a Fedora package or at https://pagure.io/fedora-rust/rust2rpm,
automates many of these steps.
It is advisable to try rust2rpm $crate
first
before attempting to write a specfile by hand.
This document is applicable only for Fedora Rawhide. Stable releases do not contain any crates. However, this document can be used to build modules with Rust applications (with crates filtered out). |
Naming
Rust crates MUST be named rust-$crate
.
The crates are expected to be from crates.io.
Rust applications that aren’t from crates.io MUST follow the main guidelines for package names.
At this time, Rust libraries MUST be from crates.io, as this enforces a certain standard in how they are packaged and built.
Dependencies
Packages MUST have BuildRequires: rust-packaging
.
Automatic Dependency Generation
rust-packaging
automatically creates Requires/Provides
based on %{cargo_registry}/*/Cargo.toml
files.
The Provides generator creates:
-
crate($name) = $version
for base package (rust-$name-devel
) -
crate($name/$feature) = $version
for feature subpackages (rust-$name+$feature-devel
)
The automatic requirement generator takes this into account and creates the appropriate rich dependencies to ensure that the code works.
For example:
syn = { version = "0.15", features = ["visit", "extra-traits"] }
becomes
(crate(syn/default) >= 0.15.0 with crate(syn/default) < 0.16.0) (crate(syn/extra-traits) >= 0.15.0 with crate(syn/extra-traits) < 0.16.0) (crate(syn/visit) >= 0.15.0 with crate(syn/visit) < 0.16.0)
BuildRequires
Packagers MUST specify all BuildRequires according to the definition in Cargo.toml, for example:
[dependencies] atty = "0.2.2" [build-dependencies] clap = "2.24.1"
should become
BuildRequires: (crate(atty/default) >= 0.2.2 with crate(atty/default) < 0.3.0) BuildRequires: (crate(clap/default) >= 2.24.1 with crate(clap/default) < 3.0.0)
Versions
-
Packagers SHOULD use latest version of dependent crates.
-
Packagers SHOULD patch crates to use the latest version of dependent crates to reduce maintenance burden.
-
When doing so, packagers SHOULD forward these upstream so that the upstream software is fixed to support the latest versions of their dependencies.
Others
Packagers MUST run %cargo_prep
to prepare configuration for further cargo invocations
(sets up RUSTFLAGS and all other stuff).
Exclude unnecessary files
-
Packagers SHOULD exclude files which are not used by anything (things like
appveyor.yml
and CI scripts). -
Packagers SHOULD use exclude field in Cargo.toml instead of using
%exclude
-
Packagers SHOULD forward such patches to upstream
Example:
--- csv-1.0.1/Cargo.toml 1970-01-01T01:00:00+01:00
+++ csv-1.0.1/Cargo.toml 2018-09-25T07:14:47.639840+02:00
@@ -22,6 +22,7 @@
categories = ["encoding", "parser-implementations"]
license = "Unlicense/MIT"
repository = "https://github.com/BurntSushi/rust-csv"
+exclude = ["/.travis.yml", "/appveyor.yml", "/ci/*", "/scripts/*"]
[profile.bench]
debug = true
Nightly, Other Platforms, etc. crates
Packagers MUST NOT package crates which do not work with the distribution. That is, if the crate depends on nightly-only features or works only for non-Linux platforms, the crate is not suitable for inclusion in Fedora.
If the crate can be made usable, packagers MUST patch packages which use such dependencies, for example:
--- memmap-0.7.0/Cargo.toml 1970-01-01T00:00:00+00:00
+++ memmap-0.7.0/Cargo.toml 2019-03-18T19:59:43.683403+00:00
@@ -23,9 +23,6 @@
version = "0.3"
[target."cfg(unix)".dependencies.libc]
version = "0.2"
-[target."cfg(windows)".dependencies.winapi]
-version = "0.3"
-features = ["basetsd", "handleapi", "memoryapi", "minwindef", "std", "sysinfoapi"]
[badges.appveyor]
repository = "danburkert/mmap"
Such patches SHOULD be forwarded upstream.
Examples
Library
Rust library packages are packaged as source-only packages, as we do not build dynamic link libraries at this time due to the lack of a stabilized ABI for Rust.
# Generated by rust2rpm
%bcond_without check
%global debug_package %{nil}
%global crate serde
Name: rust-%{crate}
Version: 1.0.89
Release: 1%{?dist}
Summary: Generic serialization/deserialization framework
# Upstream license specification: MIT/Apache-2.0
License: MIT or ASL 2.0
URL: https://crates.io/crates/serde
Source: %{crates_source}
ExclusiveArch: %{rust_arches}
BuildRequires: rust-packaging
%if %{with check}
BuildRequires: (crate(serde_derive/default) >= 1.0.0 with crate(serde_derive/default) < 2.0.0)
%endif
%global _description \
A generic serialization/deserialization framework.
%description %{_description}
%package devel
Summary: %{summary}
BuildArch: noarch
%description devel %{_description}
This package contains library source intended for building other packages
which use "%{crate}" crate.
%files devel
%license LICENSE-MIT LICENSE-APACHE
%doc README.md crates-io.md
%{cargo_registry}/%{crate}-%{version}/
%package -n %{name}+default-devel
Summary: %{summary}
BuildArch: noarch
%description -n %{name}+default-devel %{_description}
This package contains library source intended for building other packages
which use "default" feature of "%{crate}" crate.
%files -n %{name}+default-devel
%ghost %{cargo_registry}/%{crate}-%{version}/Cargo.toml
%package -n %{name}+alloc-devel
Summary: %{summary}
BuildArch: noarch
%description -n %{name}+alloc-devel %{_description}
This package contains library source intended for building other packages
which use "alloc" feature of "%{crate}" crate.
%files -n %{name}+alloc-devel
%ghost %{cargo_registry}/%{crate}-%{version}/Cargo.toml
%package -n %{name}+derive-devel
Summary: %{summary}
BuildArch: noarch
%description -n %{name}+derive-devel %{_description}
This package contains library source intended for building other packages
which use "derive" feature of "%{crate}" crate.
%files -n %{name}+derive-devel
%ghost %{cargo_registry}/%{crate}-%{version}/Cargo.toml
%package -n %{name}+rc-devel
Summary: %{summary}
BuildArch: noarch
%description -n %{name}+rc-devel %{_description}
This package contains library source intended for building other packages
which use "rc" feature of "%{crate}" crate.
%files -n %{name}+rc-devel
%ghost %{cargo_registry}/%{crate}-%{version}/Cargo.toml
%package -n %{name}+serde_derive-devel
Summary: %{summary}
BuildArch: noarch
%description -n %{name}+serde_derive-devel %{_description}
This package contains library source intended for building other packages
which use "serde_derive" feature of "%{crate}" crate.
%files -n %{name}+serde_derive-devel
%ghost %{cargo_registry}/%{crate}-%{version}/Cargo.toml
%package -n %{name}+std-devel
Summary: %{summary}
BuildArch: noarch
%description -n %{name}+std-devel %{_description}
This package contains library source intended for building other packages
which use "std" feature of "%{crate}" crate.
%files -n %{name}+std-devel
%ghost %{cargo_registry}/%{crate}-%{version}/Cargo.toml
%package -n %{name}+unstable-devel
Summary: %{summary}
BuildArch: noarch
%description -n %{name}+unstable-devel %{_description}
This package contains library source intended for building other packages
which use "unstable" feature of "%{crate}" crate.
%files -n %{name}+unstable-devel
%ghost %{cargo_registry}/%{crate}-%{version}/Cargo.toml
%prep
%autosetup -n %{crate}-%{version_no_tilde} -p1
%cargo_prep
%build
%cargo_build
%install
%cargo_install
%if %{with check}
%check
%cargo_test
%endif
%changelog
* Mon Mar 18 20:55:02 CET 2019 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 1.0.89-1
- Initial package
Binary
Application packages are compiled into binaries, with the application name used as the package name for the output binary package.
# Generated by rust2rpm
%bcond_without check
%global crate ripgrep
Name: rust-%{crate}
Version: 0.10.0
Release: 1%{?dist}
Summary: Line oriented search tool using Rust's regex library
# Upstream license specification: Unlicense OR MIT
License: Unlicense or MIT
URL: https://crates.io/crates/ripgrep
Source: %{crates_source}
# Initial patched metadata
# * No windows
# * No simd
# * Use jit_if_available, https://github.com/BurntSushi/ripgrep/commit/eb18da04506b959c0251099eae83e16d22ce8bcb
Patch0: ripgrep-fix-metadata.diff
# Really use jit_if_available
Patch0001: 0001-pcre2-use-jit_if_available.patch
ExclusiveArch: %{rust_arches}
BuildRequires: rust-packaging
BuildRequires: (crate(clap/suggestions) >= 2.32.0 with crate(clap/suggestions) < 3.0.0)
BuildRequires: (crate(grep/default) >= 0.2.3 with crate(grep/default) < 0.3.0)
BuildRequires: (crate(grep/pcre2) >= 0.2.3 with crate(grep/pcre2) < 0.3.0)
BuildRequires: (crate(ignore/default) >= 0.4.4 with crate(ignore/default) < 0.5.0)
BuildRequires: (crate(lazy_static/default) >= 1.1.0 with crate(lazy_static/default) < 2.0.0)
BuildRequires: (crate(log/default) >= 0.4.5 with crate(log/default) < 0.5.0)
BuildRequires: (crate(num_cpus/default) >= 1.8.0 with crate(num_cpus/default) < 2.0.0)
BuildRequires: (crate(regex/default) >= 1.0.5 with crate(regex/default) < 2.0.0)
BuildRequires: (crate(serde_json/default) >= 1.0.23 with crate(serde_json/default) < 2.0.0)
BuildRequires: (crate(termcolor/default) >= 1.0.3 with crate(termcolor/default) < 2.0.0)
%if %{with check}
BuildRequires: (crate(serde/default) >= 1.0.77 with crate(serde/default) < 2.0.0)
BuildRequires: (crate(serde_derive/default) >= 1.0.77 with crate(serde_derive/default) < 2.0.0)
%endif
BuildRequires: %{_bindir}/a2x
%global _description \
Line oriented search tool using Rust's regex library.\
Combines the raw performance of grep with the usability of the silver searcher.
%description %{_description}
%package -n %{crate}
Summary: %{summary}
%description -n %{crate} %{_description}
%files -n %{crate}
%license LICENSE-MIT UNLICENSE COPYING
%doc README.md CHANGELOG.md
%{_bindir}/rg
%{_mandir}/man1/rg.1*
%dir %{_datadir}/bash-completion
%dir %{_datadir}/bash-completion/completions
%{_datadir}/bash-completion/completions/rg.bash
%dir %{_datadir}/fish
%dir %{_datadir}/fish/vendor_functions.d
%{_datadir}/fish/vendor_functions.d/rg.fish
%dir %{_datadir}/zsh
%dir %{_datadir}/zsh/site-functions
%{_datadir}/zsh/site-functions/_rg
%prep
%autosetup -n %{crate}-%{version_no_tilde} -p1
%cargo_prep
%build
%cargo_build -a
%install
%cargo_install -a
%{__install} -Dpm0644 -t %{buildroot}%{_mandir}/man1 \
target/release/build/%{crate}-*/out/rg.1
%{__install} -Dpm0644 -t %{buildroot}%{_datadir}/bash-completion/completions \
target/release/build/%{crate}-*/out/rg.bash
%{__install} -Dpm0644 -t %{buildroot}%{_datadir}/fish/vendor_functions.d \
target/release/build/%{crate}-*/out/rg.fish
%{__install} -Dpm0644 -t %{buildroot}%{_datadir}/zsh/site-functions \
complete/_rg
%if %{with check}
%check
%cargo_test -a
%endif
%changelog
* Mon Mar 18 21:02:51 CET 2019 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 0.10.0-1
- Initial package
Library + Binary
# Generated by rust2rpm
%bcond_without check
%global crate yubibomb
Name: rust-%{crate}
Version: 0.2.0
Release: 1%{?dist}
Summary: Rust command line tool that prints out a 6-digit random number
# Upstream license specification: GPL-3.0
License: GPLv3
URL: https://crates.io/crates/yubibomb
Source: %{crates_source}
# Initial patched metadata
# * Bump regex to 1, https://gitlab.com/bowlofeggs/yubibomb/commit/301cb10cd056cd33c4736b87aaad333f77c6c252
Patch0: yubibomb-fix-metadata.diff
ExclusiveArch: %{rust_arches}
BuildRequires: rust-packaging
BuildRequires: (crate(rand/default) >= 0.4.0 with crate(rand/default) < 0.5.0)
%if %{with check}
BuildRequires: (crate(regex/default) >= 1.0.0 with crate(regex/default) < 2.0.0)
%endif
%global _description \
Don't you love when you accidentally tap your Yubikey when you have your IRC\
client in focus and you send 987947 into Freenode? Want to be able to have that\
experience without having to reach all the way over to your laptop's USB port?\
Now you can!
%description %{_description}
%package -n %{crate}
Summary: %{summary}
%description -n %{crate} %{_description}
%files -n %{crate}
%license LICENSE
%doc README.md
%{_bindir}/yubibomb
%package devel
Summary: %{summary}
BuildArch: noarch
%description devel %{_description}
This package contains library source intended for building other packages
which use "%{crate}" crate.
%files devel
%license LICENSE
%doc README.md
%{cargo_registry}/%{crate}-%{version}/
%package -n %{name}+default-devel
Summary: %{summary}
BuildArch: noarch
%description -n %{name}+default-devel %{_description}
This package contains library source intended for building other packages
which use "default" feature of "%{crate}" crate.
%files -n %{name}+default-devel
%ghost %{cargo_registry}/%{crate}-%{version}/Cargo.toml
%prep
%autosetup -n %{crate}-%{version_no_tilde} -p1
%cargo_prep
%build
%cargo_build
%install
%cargo_install
%if %{with check}
%check
%cargo_test
%endif
%changelog
* Mon Mar 18 21:09:53 CET 2019 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 0.2.0-1
- Initial package