This page deals specifically with building platform packages without the help of the Sailfish IDE. See the Application Development overview to learn how to build packages with the help of the Sailfish IDE.
- 1 Building Packages
- 2 Building Binaries Locally
- 3 Packaging formats
- 4 Changelog generation
Packages may either be built locally (using
sfdk, the CLI frontend to the Sailfish SDK), or remotely (using the Sailfish OBS). Building locally has the advantage of being quick, simple, and low-latency. Building remotely has the advantage that build dependencies and other packaging requirements are enforced more strictly.
Building Packages Remotely
Packages may be built using the Open Build Service instance. This requires the user to create a home project, and then create a package under that project, with the appropriate
_service file to specify how the project should be built and packaged. Once the build has been triggered, OBS will attempt to pull in the required dependencies and build the package.
See the page about deploying packages for information on how to install the package once built.
Building Packages Locally
Once the user has installed the Sailfish SDK, they can build packages locally for the target architecture using the tool called
sfdk. This tool provides a number of sub-commands wrapping around ScratchBox2 (
rpmbuild in a way which makes it simple to build packages from source repositories, given an RPM specification (.spec) file.
sfdk tool can be found in the
bin subdirectory of the Sailfish SDK installation directory. Further code examples assume the tool is available on
PATH or by other means simply as
Start by choosing the build target. List the available build tools.
$ sfdk tools list SailfishOS-18.104.22.168 sdk-provided ├─SailfishOS-22.214.171.124-armv7hl sdk-provided └─SailfishOS-126.96.36.199-i486 sdk-provided SailfishOS-188.8.131.52 sdk-provided,latest ├── SailfishOS-184.108.40.206-aarch64 sdk-provided,latest ├── SailfishOS-220.127.116.11-armv7hl sdk-provided,latest └── SailfishOS-18.104.22.168-i486 sdk-provided,latest
Each build target lets you build software for a specific operating system version running on a specific hardware. Each target is listed under one tooling supporting the given OS version.
Pick the latest aarch64 target.
$ sfdk config --push target SailfishOS-22.214.171.124-aarch64
Enter a project directory and perform an all-in-one build procedure using the
build command. If you don't have an existing project available, you can create one as in the following example.
$ mkdir my-app && cd my-app $ sfdk init --type qtquick2-app $ sfdk build
After successful build the resulting RPM package(s) can be found under the
$ ls ./RPMS my-app-0-1.aarch64.rpm
.rpm files may be installed to the device or the build target as described in the page on deploying packages.
sfdk --help-building for more information on building packages or jump directory to an all-in-one guide with
Installing Missing Dependencies
In some cases, the developer will have to add or enable repositories within their build target, if the
sfdk tools complains that a dependency cannot be installed. This can be done by issuing maintenance commands under the build target with the help of the
tools exec command:
sfdk tools exec <name> [<command> [<arg>...]]
Use the command
ssu ar <repo_name> <repo_url>
to add repositories, and
ssu er <repo_name>
to enable repositories, and then
zypper ref -f
to update the installable package information.
ssu lr may be used to list known repositories, and
ssu rr <repo_name> will remove a repository.
# enter the build target ~ $ sfdk tools exec SailfishOS-126.96.36.199-aarch64 # add a repository [SailfishOS-188.8.131.52-aarch64] ~ # ssu ar my-repo https://repo... # reload the package list [SailfishOS-184.108.40.206-aarch64] ~ # zypper ref -f
To determine which repository provides a given package, a contributor should use the search feature of the Sailfish OBS instance, at https://build.sailfishos.org/search
It should be noted that device or hardware-platform-specific packages (especially those needed to build hybris-related packages) are best installed into a separate SDK target, to avoid complications. See Clean Builds below to learn how to achieve that conveniently without explicitly installing separate SDK targets.
It is possible to avoid polluting build targets with build time dependencies of a particular package by using
sfdk with its
snapshot configuration option active. With this option the build target is not used directly. Instead a snapshot is taken and the build is done using the snapshot of the build target.
Consider enabling the
$ sfdk config --global --push snapshot
Should you need to customize the snapshot, like by adding custom repositories, consider using the
pre-pull-build-requires hook for that purpose.
sfdk --help-building for more details.
Building Binaries Locally
In some cases, you will not want to build an entire package (.rpm) to install, but instead want to build a single binary from a simple (most likely Qt-based) project. This can be handy, for example, during testing or prototyping.
In this case, you simply need to build the project from within a build-shell. For example, to build a simple Qt-based project (called "test", located under ~/test/ of the host) the following steps could be taken:
~ $ cd ~/test && sfdk build-shell qmake && sfdk build-shell make
The resulting binary can be copied to the device with
scp and executed directly.
There are different repository formatting guidelines for automated building and packaging for Sailfish OS, depending on the relationship between that repository and its upstream origin and state.
tar_git packaging structure
A special OBS service called 'tar_git' can automatically package sources from a specifically formatted git repository along with any referenced git submodules into a suitable tar archive to be built on OBS. This format is relatively simple and as long as one follows some basic instructions tools like
sfdk work nicely and if
sfdk works then it is quite likely that also the package builds fine after integrating as part of the release process. This process can be triggered automatically on OBS when a new git tag is created, using Webhooks.
Some basic things to remember: the rpm .spec files are located in
rpm/*.spec. As described below. the changelog is generated from git commit messages, so there is no need to include a changelog section in the spec file nor a separate .changes file, unless pre-git historical changelog entries need to be included. These can be included in
rpm/*.changes files. All other files in
rpm/ directory must be marked either with SourceX: or PatchX:. Package version is determined from the latest suitable Git tag. The Version: and Release: tags in the .spec file are ignored – setting them to "0" and "1" respectively is the preferred convention.
Packaging should aim to preserve upstream git history whenever possible to allow for easier synchronization of upstream changes. Bearing this in mind, there are several possibilities for packaging, depending on whether there is an upstream repository and the number of modifications of it required for the Sailfish OS version.
tar_git package source code location in git
When a package has no upstream, i.e. is a package maintained as part of Sailfish OS, the sources are usually located solely within a single git repository alongside the rpm directory, either in the root of the git tree or src dir or something similar depending a bit on the package. Example of such package is for example the lipstick display manager at https://github.com/sailfishos/lipstick/
Otherwise, the package should contain a link to its upstream repository as a git submodule, named the same as the package Name: in .spec file, or simply as upstream. Please use https format for git submodule url. This makes sure that submodule cloning works for all users. Third-party repositories should be mirrored on https://github.com/sailfishos-mirror and referenced there, to avoid future build errors due to upstream moves or removal. New repository mirrors can be requested on IRC.
If the package has upstream somewhere else and there are no heavy modification needed for the sources, the sources are usually built directly from the git submodule. Small modifications and backported commits from later versions can be included as patches stored as
rpm/*.patch. Locally, those patches can be applied with
sfdk apply to the submodule or as part of the whole prepare phase using
sfdk prepare. They can be unapplied with
sfdk apply -R. PackageKit is an example of such package at https://github.com/sailfishos/PackageKit
There is a proposal to use a long-lived topic branch instead of patches, which mirrors the upstream repository directly rather than using a submodule. See Git_Packaging_-_Upstream_Git_with_Long-Lived_Topic_Branch_Approach.
If there are many modifications to the upstream that are not accepted as a part of the upstream (at least yet), then they may be stored in a separate tree from the upstream submodule. In such cases the submodule should be called upstream and the modified copy of the upstream should be a separate directory named after the package name from the .spec file. Synchronization with newer upstream releases is done using
git subtree. An example of such a package is 'connman' at https://github.com/sailfishos/connman
This is an obsolete format and that generally should not be used any more. Any packages using this should be converted to tar_git format whenever the opportunity arises. These use no smart packaging system, instead storing the .spec file, tarball and any patches directly in the root of the git tree. One situation where this might be preferable is if there is no upstream version control and only source tar downloads are available, in which case that archive may be used without modification. An example of such packaging is ncurses, found at https://github.com/sailfishos/ncurses .
Such 'dumb' packages do not compile with the
sfdk build as the packages done with tar_git format. Sometimes it is both necessary and sufficient to unpack and enter the source directory, then tell
sfdk where the .spec file is located:
git clone email@example.com:sailfishos/ncurses.git cd ncurses tar xf ncurses-6.1.tar.gz && cd ncurses-6.1 sfdk --specfile ../ncurses.spec build
As a fallback method,
rpmbuild can be invoked manually under the build shell:
git clone https://xyz/example-dumb-package.git cd example-dumb-package sfdk build-shell rpmbuild --define "_topdir $PWD" --define "_sourcedir $PWD" -bb *.spec
Note that when using
rpmbuild manually, you need to also manually install possible build time dependencies, where
sfdk build does that automatically.
Changelogs are generated from git commits (or from annotated tags in case on forgets the message from the commit) in tar_git packaged packages. This allows change logs to be generated automatically, and for the commit history to contain meaningful back-links to the bug reports which led to the change being made.
Basically how it works is that each line that has the
[ ] is added to the changelog of the package and rest of the lines from the commit message are ignored:
[SHORT] Long description that shall reflect the work done. Bug-ref JB#xxxx [key] Summary. Contributes to xyz#123 [packaging] Updated Y to version X. Fixes xyz#124
sfdk --help-building inside the SDK to learn how to generate changelogs when building a package locally
This line does not need to be the first line in the git commit message and there can be multiple lines within one git commit message.
The SHORT description is any descriptive word like "backend" or "UI" or "bluetooth". Long description describes the change in plain English and shall contain a reference to a bug.
There are couple of ways to refer bugs in the git commit messages
|Contributes to xyz#123||Means that this change contributes to the referred bug number, but does not fully fix it yet. This kind of lines are usually used when the required fixes to one bug are needed across multiple packages or for example the fix improves the issue, but there might still be some corner case that it might be reproduced.|
|Fixes xyz#124||Means that this change fixes the bug.|
Currently known and accepted bug tags for the above xyz are:
|MER||Bugs referring to old Mer infrastructure. (Obsolete)|
|NEMO||Bugs referring to old Nemo infrastructure. (Obsolete)|
|JB||For bugs in internal Jolla Bugzilla|
|TJC||To reference issues listed in together|
These lines are picked to the changelog based on tags, meaning that between two tags all the lines that are following the format are picked up and added to the changelog.