sailfishos-open / docker-sailfishos-builder

Docker based Sailfish OS build environment

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Sailfish OS build environment based on Docker

Status: Testing

This is an alternative build environment for Sailfish OS. In contrast to the official SDKs, it doesn't use Scratchbox2 (SB2). Instead, it relies on running either native or through QEMU hardware emulation. When using QEMU emulation, expect very slow compilation speeds when compared to SB2.

This build environment was created to address official SDK limitations encountered while packaging Qt 5.15 for Sailfish OS. You may want to use it if you have a project that is difficult or impossible to compile using the official SDK.

How to use it

Preparations:

  1. Clone this repositiory or clean it if you already cloned it with git clean -dfx
  2. initialize submodule with git submodule update --init

To use this build environment, you have to have clean sources checked out. If your sources have compilation artifacts, those could interfere with the building. As full build process is performed, make sure that the patches used in %prep stage apply.

Until published, Docker builder images have to be generated locally (see below for instructions).

With the builder image ready, go to the folder of your cloned repository root and run (for sailfishos-i486-4.5.0.19 builder image) build command similar to:

sudo docker run --rm -it -v `pwd`:/source \
   sailfishos-i486-4.5.0.19 buildrpm \
     -r https://repo.sailfishos.org/obs/sailfishos:/chum:/testing/4.5.0.19_i486/

In this example, docker container gets access to the sources by its volume mapping your current folder (pwd) to /source inside the container. Container executes buildrpm script inside it (see sources) that handles building RPMs from SPEC in /source/rpm.

There are few options that can be given to buildrpm script:

  • -r REMOTE specify additional repositories for pulling dependencies (can be given multiple times);
  • -s SPEC specify SPEC if there are more than one in rpm subfolder of the sources. Use just a file basename, as in "test.spec";
  • -v VENDOR set vendor for RPM.
  • -p skip generation of source package and use the one in rpm subfolder.

If all goes well, RPMs will be created under subfolder RPMS of the sources.

Note that it is recommended to use --rm to remove container as soon as it is finished. On every build, a clean environment is used and all the dependencies are pulled in again.

Using with sources in archive

In addition to the mode, where the build is performed using checked out sources, it is possible to build packages when the sources are already available in packaged form. For example, Node.js as packaged at OBS. In this case, you have to use option -p and mount volumes separately for /source/rpm and /source/RPMS. Here, /source/rpm should be linked with the host folder that has RPM SPEC, source archive as referenced in SPEC, and all patches. Folder /source/RPMS has to be linked with a host folder that will receive compiled RPMS. If you forget to specify the latter, your compiled RPMS would stay in docker container. It is expected that /source/rpm and /source/RPMS point to different folders on host.

Example command :

sudo docker run --rm -it \
   -v `pwd`/../nodejs18:/source/rpm \
   -v `pwd`:/source/RPMS \
   sailfishos-i486-4.5.0.19 \
   buildrpm -p -v chum \
       -r https://repo.sailfishos.org/obs/sailfishos:/chum:/testing/4.5.0.19_i486/

In this example, Node.js RPMs are built and saved into the current folder (pwd). Corresponding sources are in a folder ../nodejs18. It is also setting vendor to chum and is using one of Chum repositories.

How it works

Inside Docker container, the build is performed in several steps.

First, SPEC file is parsed and all the build requirements are installed.

Second, if sources are in Git repository and -p option was not used, RPM version will be determined based on the latest git tag and its offset from HEAD. Regardless of whether sources are in Git or not, release will be offset by UTC timestamp. Such handling of RPM version and release will ensure the newest builds would have larger version-release pair.

Next, RPM build proceeds in a classical way using rpmbuild, under a dedicated user builder. For that, folders for building are setup under /builder/rpmbuild. It is possible to debug intermediate steps through creation of the volume linking to /builder/rpmbuild in docker container.

Before starting the build, your sources are packed into tar.gz (or bz2, xz, as given in Source0) under /builder/rpmbuild/SOURCES. This step is skipped if -p option was given. In addition, all files from your sources rpm subfolder are copied to /builder/rpmbuild/SOURCES, including all patches.

Then the build proceeds under user builder with rpmbuild. rpmbuild will unpack the sources, apply patches and proceed building your packages. After successful build, RPMs are copied into your source folder under RPMS subfolder. For a feedback, rpmlint is applied as well.

Note that, as a new clean environment is created for every build, it maybe advantageous to debug the build process and reuse the same container in the case of failure. Easiest is just start the container with bash and execute buildrpm already while inside the container. It is possible to apply the steps done by buildrpm manually as well when inside the container.

Limitations

The scripts are not handling many cases in a flexible manner provided by mb2 from official SDK. For example, during packaging, sources are packed and then unpacked which wastes time and allocates storage, until docker container is destroyed. There are probably many other cases where mb2 would be able to handle building better.

Due to the way the builder works, Source0 from RPM SPEC is expected to be in the form %{name}-%{version}.tar.bz2 (.gz and .zx are supported as well).

While we get rid of SB2 bugs, there are possible QEMU issues that can interfere. For example, armv7hl could be hit with issue #6. See issue for problem description. It is recommended then to check whether QEMU distributed by Jolla works better.

How to create builder images

Builder Docker images are very easy to create using makeimage script. Make sure you have QEMU setup working for all architectures that you want to use (see below for QEMU setup, if needed).

Script makeimage takes two arguments: SFOS architecture (i486, aarch64, armv7hl) and SFOS version. Due to issue #1, you would want to run the script as root:

sudo ./makeimage i486 4.5.0.19

This will create locally Docker image sailfishos-i486-4.5.0.19. This image can be used for building your packages.

QEMU setup

You need to setup binfmt for qemu for the architectures you want to use. Follow the instructions for your system

Arch-based

Install package qemu-user-binfmt.

Debian-based

Install package qemu-user-static.

Other

To enable QEMU in systemd based Linux, add qemu-custom.conf in /etc/binfmt.d. Example:

:qemu-aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-aarch64:F
:qemu-arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-arm:F

After that, restart systemd service:

systemctl restart systemd-binfmt

You should see formats registered in /proc:

# cat /proc/sys/fs/binfmt_misc/qemu-aarch64
enabled
interpreter /usr/bin/qemu-aarch64
flags: F
offset 0
magic 7f454c460201010000000000000000000200b700
mask ffffffffffffff00fffffffffffffffffeffffff

See References below for how to test QEMU support using Docker images.

References

About

Docker based Sailfish OS build environment


Languages

Language:Shell 87.9%Language:Dockerfile 12.1%