Terra Guidelines
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 (opens in a new tab) and RFC 8174 (opens in a new tab).
Packagers and maintainers MUST follow the policies and guidelines listed in this document. Everything covered here is one of 3 things:
- Differences from the Fedora Packaging Guidelines (opens in a new tab)
- Changes in addition to the Fedora Packaging Guidelines (opens in a new tab)
- Terra-exclusive guidelines
It is highly recommended to read through the Fedora Packaging Guidelines (opens in a new tab) on langauges/sections not listed here, or for greater detail.
TL;DR
Condensed version of guidelines.
REMEMBER TO BUMP Release: if propose new changes (unless pkg with current release num doesn't exist in repos (opens in a new tab))
No period at end of Summary:, but add period at end of %description.
%changelog only for large changes.
Prefer patching e.g. -p1 at %autosetup over using %autopatch.
Prefer %elifarch over %endif + %ifarch.
Use %pkg_completion for shell completions.
Use %pkg_devel_files, %pkg_libs_files, %pkg_static_files.
See Development and Shared Libraries section.
Install .desktop file to %_appsdir for graphical apps. Guide here. Prefer upstream provided ones over manually generating one. It is RECOMMENDED to use our .desktop file macros for installing and editing .desktop files.
Follow Fedora guidelines for interpreted (ex. Python/Ruby) & dynamically (ex. C/++) compiled langs. Statically compiled lang guidelines follow.
For Rust, use rust2rpm, suffix _online to %cargo_prep, %cargo_license, %cargo_license_summary;
remove %generate_buildrequires section.
If no flags to %cargo_build, remove it,
else add flags to it and replace %cargo_install with %crate_install_bin.
Also %rustup_nightly exists btw, see our macros.
For Go, use go2rpm, rename package name to sensible one,
remove %generate_buildrequires section,
EITHER add %global gomodulesmode GO111MODULE=on OR replace %goprep with %goprep_online.
For Nim, use one of below. Also %nim_c = %nim_build, see our macros.
%prep
%autosetup
%nim_prep
%build
%nim_c src/dive%prep
%autosetup -Sgit
%build
atlas init
atlas rep atlas.lock
%nim_c src/nettoFor Zig, BuildRequires: zig zig-rpm-macros zig-srpm-macros.
If doesn't build with build arguments provided by Fedora %zig_build
(e.g. ReleaseFast required, microarchitectures), try %zig_build_target.
Remember to try e.g. -Dstrip=false. If still no debug info, %global debug_package %{nil}.
If can't dynamically link all deps / no deps to link, %zig_build_target with -s, then -fsys=pkgname for things dyn-linkable.
Terra Packaging Guidelines
Usage of the mold Linker
We encourage the use of mold (opens in a new tab), which can speed up build times, especially in large projects.
You MAY enable it in C/++ projects by adding -fuse-ld=mold in CFLAGS/CXXFLAGS.
The %with_mold flag is enabled by default in anda-srpm-macros. mold is also preinstalled in the builders.
You can disable mold for Rust and Nim by using %bcond_with mold.
Interpreted Languages (Python, Ruby, etc.)
All packages using interpreted languages SHOULD follow the Fedora guidelines. All dependencies must be packaged individually as they are considered runtime dependencies.
Dynamically Compiled Languages (C, C++, Vala)
Dependencies required for runtime MUST be packaged separately.
Statically Compiled Languages
Terra does not strictly follow Fedora's reproducibility requirements, and we do not want large amounts of development libraries for them, packagers SHOULD vendor dependencies on build time.
Terra's Mock sandbox has networking enabled, so builders can download the dependencies directly on build time.
Rust
These are guidelines for packaging projects written in Rust (opens in a new tab).
For the official Rust language documentation, see here (opens in a new tab).
- You SHOULD add (at least!) the following build dependencies to your spec file:
BuildRequires: anda-srpm-macrosBuildRequires: cargo-rpm-macrosBuildRequires: rust-srpm-macros
- You MAY generate the spec file using
rust2rpm. - You SHOULD NOT use the tradtional Fedora
%cargo_prepmacro. Instead, use%cargo_prep_onlinefromanda-srpm-macros. Also, you SHOULD remove the%generate_buildrequiresmacro, as it is useless. - It is RECOMMENDED to use
%cargo_license_onlineand%cargo_license_summary_online, although they are not a strict requirement. - You SHOULD NOT use both
%cargo_buildand%cargo_installin the same spec file as anything that callscargo installmight cause a rebuild due to a cargo bug. You SHOULD only include%cargo_buildor%cargo_install. In most cases, you can just omit%cargo_buildentirely and it will build just fine.
Example:
%prep
%autosetup -n %{crate}-%{version} -p1
%cargo_prep_online
%build
%{cargo_license_online} > LICENSE.dependencies
%install
%cargo_installIn rare cases, you may need to use %cargo_build and %crate_install_bin instead:
%prep
%autosetup -n %{crate}-%{version}
%cargo_prep_online
%build
%{cargo_license_online} > LICENSE.dependencies
%{cargo_build} --locked
%install
# install the binary from target/rpm/%{crate} to %buildroot%_bindir
%crate_install_binIf Rust nightly is required, add the %rustup_nightly macro to %prep.
Check the Rust section on the SRPM page for more information on these macros.
Go
These are guidelines for packaging projects written in Go (opens in a new tab).
For the official Go language documentation, see here (opens in a new tab).
- You SHOULD add (at least!) the following build dependencies to your spec file:
BuildRequires: go-rpm-macrosBuildRequires: go-srpm-macros
- If you use
go2rpm, you SHOULD NOT use the default naming, as an unnecessarily long package name is bad for UX. You MAY put the name generated bygo2rpmin theProvides:field. - You SHOULD remove the
%generate_buildrequiressection, and either add%global gomodulesmode GO111MODULE=onOR use%goprep_onlineinstead of%goprepin the%prepsection.- You SHOULD add
BuildRequires: anda-srpm-macrosto your spec if using%goprep_online.
- You SHOULD add
Nim
These are guidelines for packaging projects written in Nim (opens in a new tab).
For the official Nim language documentation, see here (opens in a new tab).
- You SHOULD add (at least!) the following build dependencies to your spec file:
BuildRequires: anda-srpm-macrosBuildRequires: nim
- You SHOULD use our Nim macros.
In most cases, use nimble to download dependencies in %prep,
then %build with nim, e.g.1:
%prep
%autosetup
%nim_prep
%build
%nim_c src/dive
%install
install -Dm755 src/dive -t %buildroot%_bindirThe use of the atlas (opens in a new tab) package cloner is also recognized, e.g.2:
%prep
%autosetup -Sgit
%build
atlas init
atlas rep atlas.lock
%nim_c src/nettoZig
These are guidelines for packaging projects written in Zig (opens in a new tab).
For the official Zig language documentation, see here (opens in a new tab).
- You SHOULD add (at least!) the following build dependencies to your spec file:
BuildRequires: zigBuildRequires: zig-rpm-macrosBuildRequires: zig-srpm-macros
- When building Zig projects you SHOULD keep in mind that Zig is an optimization centric language and some projects may rely on build arguments different than what the upstream Fedora macros (opens in a new tab) set. For example, many Zig projects rely on
ReleaseFast(or more rarely,ReleaseSmall) builds for runtime optimization. Additionally, some Zig projects only work correctly when built for certain microarchitectures or higher (usually, this isx86_64_v2instead ofbaselinedue to reliance on SIMD). - For these reasons, you SHOULD refer to upstream guidance when packaging Zig projects.
- If any of the scenarios above apply, you MAY use
%zig_build_targetwith appropriate flags instead of%zig_build. You however SHOULD use%zig_buildinstead if none of the above apply.- If using
%zig_build_target, you SHOULD addBuildRequires: anda-srpm-macrosto your spec. - For more information on
%zig_build_target, please see its documentation on our macros page.
- If using
Regardless of build macro in use, they should be used in either the %build or %install section depending on how the project is built (as some can be built directly into root by setting the DESTDIR=%{buildroot} variable).
Example using %zig_build:
%build
%{zig_build} \
-Demit-docsExample using %zig_build_target:
%build
%{zig_build_target -r fast -c x86_64_v2} \
-Demit-docs- Note that
ReleaseFastand especiallyReleaseSmallwill strip some debug info from the binaries. - Some Zig projects have enabled build flags to override this and those SHOULD be used if available (this will usually be
-Dstrip=false). - If they are not, you may need to disable debug packages using the global variable
%global debug_package %{nil}if not enough debug info is preserved to strip.
For projects where dynamic linking of all dependencies is simply not possible (such as the version in the Fedora repos is too new or too old) or that have no dependencies to link, you MAY use %zig_build_target with the -s flag. You SHOULD still dynamically link compatible dependencies by using -fsys=pkgname.
Shell Completions
- SHOULD be a subpackage.
- SHOULD use the
%pkg_completionmacro.
Development and Shared Libraries
You SHOULD try to use the %pkg_devel_files, %pkg_libs_files and %pkg_static_files macros.
Shared library packages SHOULD be suffixed with -libs.
These packages SHOULD NOT contain anything except:
%_libdir/*.so.*
%doc …
%license …Do not confuse the -libs file (*.so.*) with a -devel file (*.so).
Development library packages SHOULD be suffixed with -devel.
These packages SHOULD NOT contain anything except:
%doc …
%license …
%_includedir/*
# ^ source files, depending on the language, could be in other locations
%_libdir/*.so
%_libdir/*.a
%_libdir/pkgconfig/%{name}.pc
# and other development files (.vapi, .typelib, .gir, etc.).JavaScript
These are guidelines for packaging projects written in oe which utilize JavaScript (opens in a new tab).
These guidelines also often cover things written in or which utilize TypeScript (opens in a new tab).
Node Modules
Guidelines for packaging Node modules in Terra.
"Node modules" in this document refers to JavaScript packages run using a JavaScript runtime (usually Node.js), which are hosted on the NPM Registry (opens in a new tab).
"JavaScript modules," however, refers to to JavaScript packages run using a JavaScript runtime which are hosted on either the NPM Registry or the JavaScript Registry (opens in a new tab), the latter of which are also called "modern JavaScript packages." This means Node modules are JavaScript modules, but not the other way around.
NPM only officially uses Node modules. You can use JSR with NPX by using npx jsr, but not through NPM directly. Other package managers of new enough versions support both.
- You SHOULD add (at least!) the following build dependencies to your spec file:
BuildRequires: nodejs(OR the required Node.js version if the default in a given branch of Fedora will not work)- If using an alternate Node.js version be prepared that you may need to patch or otherwise edit some JS executables' shebangs.
BuildRequires: nodejs-npmBuildRequires: nodejs-packaging
- We package them like Arch and other distros, and allow bundled dependencies unlike Fedora. You however MAY use system dependencies instead for modules by removing the installed dependency and symlinking it to the one available in the package repos, but this is likely more work than it is worth.
- You MUST either set
%global npm_name pkgnameor use%npm_prep -n pkgnamewhen packaging Node modules directly. This MUST be defined as the canonical name of the module as listed on the NPM Registry. - You SHOULD use
%npm_licenseto create the license of the bundled dependencies. - You MAY opt instead to follow Fedora's Node.js packaging methods but keep in mind this is very difficult to maintain and may not work on all modules.
Web Applications
These are guidelines for building web applications (opens in a new tab) (hereafter referred to as "webapps"), which refers to apps built using technologies such as Electron or Tauri.
These apps embed parts of browser functionality in order to display web content. One of the most recognizable examples is Discord (opens in a new tab).
The general guidelines for building webapps are:
- Use our JavaScript package manager macros and/or webapp build macros.
- Use appropriate Electron macros for Electron apps.
- Use appropriate Tauri macros for Tauri apps.
- Add the correct JavaScript package manager to your build dependencies.
- Examples:
-
Electron
These are guidelines for packaging Electron (opens in a new tab) apps.
Many Electron projects will default to building distro binary packages (such as RPMs and Debs) and this rarely works well in RPM builds. Packagers should be prepared to patch or otherwise modify the Electron Builder config to rectify this.
- You SHOULD add
%electronmetaand make sure it is in the correct location in the spec file. The other macros for Electron also depend on the information in this being set.- This meta macro automatically handles MANY common issues that can happen with Electron packages including incorrect dependencies due to bundled (or private) shared object (
*.so) libraries (opens in a new tab). - It also pulls all basic build dependencies for Electron apps.
- Like all meta macros, must be placed carefully:
- MUST always come after
Name:is defined and before the first%description. - SHOULD come before the
License:field if using%{electron_license}. - MAY be used under preambles but before
%descriptionif not using%{electron_license}. - For more information on what all this meta macro does, please read its section in our SRPM documentation page.
- MUST always come after
- This meta macro automatically handles MANY common issues that can happen with Electron packages including incorrect dependencies due to bundled (or private) shared object (
- You SHOULD append any additional private (bundled) libraries that the Electron app has that are picked up by RPM AutoReqProv (opens in a new tab) to
%{__requires_excludes}and%{__provides_excludes}using a%globalsimilar to the below examples.%global __requires_excludes %{__requires_excludes}|private_library\\.so%global __provides_excludes %{__provides_excludes}|private_library\\.so
- You MAY use the macro
%{electron_license}which contains the licenses for bundled Electron. You SHOULD double check any additional licenses you should list and make sure any other listed licenses are not duplicated or overlapping.- You can double check what the macro expands to with the command
rpm --eval '%{electron_license}'if you haveanda-srpm-macrosinstalled.
- You can double check what the macro expands to with the command
- You SHOULD use our
%electron_installmacro for installing Electron apps.
Tauri
These are guidelines for packaging Tauri (opens in a new tab) apps.
Tauri builds webapps using Cargo and the system WebKit. For these reasons some of the Rust guidelines also apply to Tauri. Most relevant Cargo macros have been ported into Tauri compatible ones, however it will likely still be helpful to make yourself familiar with the original macros.
It is important to note that unlike the original Cargo macros, Tauri macros only support passing features with the -f flag due to how Tauri works.
- You SHOULD use one of the following in your spec:
BuildRequires: %{tauri_buildrequires}-
<Callout type="warning"> BuildRequires generation only works in Mock. </Callout> - You SHOULD use
%tauri_prepin the%prepsection. - You SHOULD use either a webapp build macro or the
%tauri_buildmacro, however the latter will not work with all Tauri projects. See its entry on our SRPM macros page for more information. - You SHOULD use
%{tauri_cargo_license} > LICENSE.dependenciesin your spec to package the Cargo dependency licenses. - You MAY use the
%tauri_cargo_license_summaryand%tauri_cargo_vendor_manifestmacros in your spec for addition license and Cargo information. - You MAY use the configurable macros for Tauri builds if necessary, but it should rarely be needed.
Miscellaneous
Changelog Entries
You MUST add a Changelog entry when you submit a new package, and you MUST NOT use %autochangelog.
We typically use Initial package/Initial commit, but anything that describes adding the package is fine.
Changing an Existing Package
You SHOULD add a %changelog entry for large changes, such as file renames, new build process, etc.
Small changes like adding build dependencies or adding one-liners to make a build work MAY be omitted from adding a %changelog entry, it is up to you.
Copying a Spec from a Different Repository
When copying/porting/using a spec file from a different repository (SUSE, Mandriva, RPMfusion, Copr, etc.), you MUST preserve any changelogs in the spec, and then add your own changelog entry as Port to Terra.
You MAY specify which repo it has been ported from.
Modifying Changelog Entries
This should not need to be done, the only reasons are if there was a formatting error, date error, or updated name/emails. It is also acceptable to add more to previous changelogs (for example, adding missing emails/version), but there has to be a reason to do this.
Fixing Packages
- If a PR is changing anything user-facing, the
Release:tag SHOULD be bumped. The only exception SHOULD be if you are fixing a package where the current version does not and has never built.- Some (not all!) examples of user-facing fixes requiring a
Release:bump:- Installing a missing file.
- Adding any build or non-build, hard or soft, forward or backward dependencies.
- Changing any user-facing tags (
URL:,License:,Summary:, etc.).
- Some (not all!) examples of user-facing fixes requiring a
- If a package fix PR is fixing/changing anything build-facing, the
Release:tag SHOULD NOT need to be bumped.- Some (not all!) examples changes NOT requiring a
Release:bump:- Fixing a package that failed to build when the
Version:tag is bumped. - Any changes that do not affect the final package.
- Fixing a package that failed to build when the
- Some (not all!) examples changes NOT requiring a
- If you are unsure if a bump is needed, bump it.
- Follow appropriate changelog procedures outlined in the above section.
Patches
- Packages SHOULD apply patches (usually via the
-p*flag) in%autosetup. If this is not possible (typically when%autosetupis not used), you SHOULD use %autopatch.
Providing Your Own .desktop File
If you are packaging a graphical app that doesn't provide its own .desktop file, you SHOULD create one.
Creating the .desktop File
Copy the following template:
[Desktop Entry]
Name=PACKAGE NAME
Exec=PROVIDED_BINARY
Icon=ICON NAME
Type=ApplicationThe Icon tag SHOULD NOT a contain full path, just the name of the icon file.
The Exec tag SHOULD be a full path if the binary placed in /usr/bin is a symlink.
If this is not the case, it is up to you if you want to use the full path or not (it will look in the user's $PATH).
You SHOULD name this file either package-name.desktop or package_app-ID.desktop.
You MAY add more tags, to see all possible tags, read through the freedesktop specification (opens in a new tab).
Installing the .desktop File
To install the .desktop file:
- Add it to your package's folder
- Add it as a
Source:in the .spec file - Install it
- List it in the
%filessection
It is RECOMMENDED to use the %_appsdir macro from Anda SRPM instead of %_datadir/applications/ and to use the %desktop_file_install macro.
With NeoHtop package (opens in a new tab) as the example:
Source1: NeoHtop.desktop
...
%install
%desktop_file_install %{SOURCE1} %{buildroot}%{_appsdir}/NeoHtop.desktop
...
%files
...
%{_appsdir}/NeoHtop.desktopValidating the .desktop File
You MUST validate your .desktop file. To do this, add the following to your spec file:
BuildRequires: desktop-file-utils
...
%check
%desktop_file_validate %{buildroot}%{_appsdir}/NeoHtop.desktop
...Finished Example
NeoHtop.desktop:
[Desktop Entry]
Categories=Utility;
Comment=A cross-platform system monitor
Exec=NeoHtop
Icon=NeoHtop
Name=NeoHtop
Terminal=false
Type=ApplicationAll custom .desktop file portions of a spec file:
Source1: NeoHtop.desktop
...
BuildRequires: desktop-file-utils
%install
...
%desktop_file_install %{SOURCE1}
%check
%desktop_file_validate %{buildroot}%{_appsdir}/NeoHtop.desktop
%files
...
%{_appsdir}/NeoHtop.desktopUsage of Periods in Various Package Fields
You MUST NOT have a period at the end of any Summary: tags, and you SHOULD have a period at the end of all %descriptions.
Usage of %elifarch
To make specs easier to read, you SHOULD use %ifarch followed by %elifarch before %endif in specs where build steps are arch dependent.
Incorrect:
%ifarch x86_64
%define arch %{nil}
%endif
%ifarch aarch64
%define arch arm64-
%endifCorrect:
%ifarch x86_64
%define arch %{nil}
%elifarch aarch64
%define arch arm64-
%endif