This is largely based on a presentation I gave a couple of weeks ago. If you are too lazy to read, go watch it instead 😉
For 20 years KDE has been building free software for the world. As part of this endeavor, we created a collection of libraries to assist in high-quality C++ software development as well as building highly integrated graphic applications on any operating system. We call them the KDE Frameworks.
With the recent advance of software bundling systems such as Snapcraft and Flatpak, KDE software maintainers are however a bit on the spot. As our software is building on such a vast collection of frameworks and supporting technology, the individual size of a distributable application can be quite abysmal.
When we tried to package our calculator KCalc as a snap bundle, we found that even a relatively simple application like this, makes for a good 70 MiB snap to be in a working state (most of this is the graphical stack required by our underlying C++ framework, Qt).
Since then a lot of effort was put into devising a system that would allow us to more efficiently deal with this. We now have a reasonably suitable solution on the table.
The KDE Frameworks 5 content snap.
A content snap is a special bundle meant to be mounted into other bundles for the purpose of sharing its content. This allows us to share a common core of libraries and other content across all applications, making the individual applications just as big as they need to be. KCalc is only 312 KiB without translations.
The best thing is that beside some boilerplate definitions, the snapcraft.yaml file defining how to snap the application is like a regular snapcraft file.
Let’s look at how this works by example of KAlgebra, a calculator and mathematical function plotter:
Any snapcraft.yaml has some global attributes we’ll want to set for the snap
name: kalgebra version: 16.08.2 summary: ((TBD)) description: ((TBD)) confinement: strict grade: devel
We’ll want to define an application as well. This essentially allows snapd to expose and invoke our application properly. For the purpose of content sharing we will use a special start wrapper called kf5-launch
that allows us to use the content shared Qt and KDE Frameworks. Except for the actual application/binary name this is fairly boilerplate stuff you can use for pretty much all KDE applications.
apps: kalgebra: command: kf5-launch kalgebra plugs: - kde-frameworks-5-plug # content share itself - home # give us a dir in the user home - x11 # we run with xcb Qt platform for now - opengl # Qt/QML uses opengl - network # gethotnewstuff needs network IO - network-bind # gethotnewstuff needs network IO - unity7 # notifications - pulseaudio # sound notifications
To access the KDE Frameworks 5 content share we’ll then want to define a plug our application can use to access the content. This is always the same for all applications.
plugs: kde-frameworks-5-plug: interface: content content: kde-frameworks-5-all default-provider: kde-frameworks-5 target: kf5
Once we got all that out of the way we can move on to actually defining the parts that make up our snap. For the most part parts are build instructions for the application and its dependencies. With content shares there are two boilerplate parts you want to define.
The development tarball is essentially a fully built kde frameworks tree including development headers and cmake configs. The tarball is packed by the same tech that builds the actual content share, so this allows you to build against the correct versions of the latest share.
kde-frameworks-5-dev: plugin: dump snap: [-*] source: http://build.neon.kde.org/job/kde-frameworks-5-release_amd64.snap/lastSuccessfulBuild/artifact/kde-frameworks-5-dev_amd64.tar.xz
The environment rigging provide the kf5-launch script we previously saw in the application’s definition, we’ll use it to execute the application within a suitable environment. It also gives us the directory for the content share mount point.
kde-frameworks-5-env: plugin: dump snap: [kf5-launch, kf5] source: http://github.com/apachelogger/kf5-snap-env.git
Lastly, we’ll need the actual application part, which simply instructs that it will need the dev part to be staged first and then builds the tarball with boilerplate cmake config flags.
kalgebra: after: [kde-frameworks-5-dev] plugin: cmake source: http://download.kde.org/stable/applications/16.08.2/src/kalgebra-16.08.2.tar.xz configflags: - "-DKDE_INSTALL_USE_QT_SYS_PATHS=ON" - "-DCMAKE_INSTALL_PREFIX=/usr" - "-DCMAKE_BUILD_TYPE=Release" - "-DENABLE_TESTING=OFF" - "-DBUILD_TESTING=OFF" - "-DKDE_SKIP_TEST_SETTINGS=ON"
Putting it all together we get a fairly standard snapcraft.yaml with some additional boilerplate definitions to wire it up with the content share. Please note that the content share is using KDE neon’s Qt and KDE Frameworks builds, so, if you want to try this and need additional build-packages
or stage-packages
to build a part you’ll want to make sure that KDE neon’s User Edition archive is present in the build environments sources.list deb http://archive.neon.kde.org/user xenial main
. This is going to get a more accessible centralized solution for all of KDE soonâ„¢.
name: kalgebra version: 16.08.2 summary: ((TBD)) description: ((TBD)) confinement: strict grade: devel apps: kalgebra: command: kf5-launch kalgebra plugs: - kde-frameworks-5-plug # content share itself - home # give us a dir in the user home - x11 # we run with xcb Qt platform for now - opengl # Qt/QML uses opengl - network # gethotnewstuff needs network IO - network-bind # gethotnewstuff needs network IO - unity7 # notifications - pulseaudio # sound notifications plugs: kde-frameworks-5-plug: interface: content content: kde-frameworks-5-all default-provider: kde-frameworks-5 target: kf5 parts: kde-frameworks-5-dev: plugin: dump snap: [-*] source: http://build.neon.kde.org/job/kde-frameworks-5-release_amd64.snap/lastSuccessfulBuild/artifact/kde-frameworks-5-dev_amd64.tar.xz kde-frameworks-5-env: plugin: dump snap: [kf5-launch, kf5] source: http://github.com/apachelogger/kf5-snap-env.git kalgebra: after: [kde-frameworks-5-dev] plugin: cmake source: http://download.kde.org/stable/applications/16.08.2/src/kalgebra-16.08.2.tar.xz configflags: - "-DKDE_INSTALL_USE_QT_SYS_PATHS=ON" - "-DCMAKE_INSTALL_PREFIX=/usr" - "-DCMAKE_BUILD_TYPE=Release" - "-DENABLE_TESTING=OFF" - "-DBUILD_TESTING=OFF" - "-DKDE_SKIP_TEST_SETTINGS=ON"
Now to install this we’ll need the content snap itself. Here is the content snap. To install it a command like sudo snap install --force-dangerous kde-frameworks-5_*_amd64.snap
should get you going. Once that is done one can install the kalgebra snap. If you are a KDE developer and want to publish your snap on the store get in touch with me so we can get you set up.
The kde-frameworks-5 content snap is also available in the edge channel of the Ubuntu store. You can try the games kblocks and ktuberling like so:
sudo snap install --edge kde-frameworks-5 sudo snap install --edge --devmode kblocks sudo snap install --edge --devmode ktuberling
If you want to be part of making the world a better place, or would like a KDE-themed postcard, please consider donating a penny or two to KDE
Thank you for this great tutorial. Does the snapped application look the same on for example KDE Neon as the native package? When I snapped http://www.qownnotes.org/ (Qt, C++) the user interface didn’t match the Breeze user interface I am using under KDE Neon at all.
Yes. You’ll have to do something like stage-packages:[plasma-integration,breeze,breeze-icons]. Do note that breeze actually pulls in qt4 due to how the deb had to be made to ensure theme alignment across Qt versions, so manually building breeze as a part is probably the better way to deal with it. Also you’ll only need breeze-icons if you actually load them through QIcon.fromTheme, if you access them through qrc or manual lookup you of course don’t need the icon package.
Depending on whether or not you want KDE file dialogs and the likes you probably don’t even need plasma-integration. If you only want the widget style you only snap breeze and manually set it via QApplication.setStyle in your application.
The problem is that since the confined snap can’t read which style is used outside the confinement, much less load the necessary Qt plugins for the QStyle and QPlatformTheme, it will pick whatever Qt can find inside the snap. By default that would be the fusion theme. By snapping plasma-integration and breeze Qt will pick the plasma theme plugin which in turn will load the breeze style.
Thank you for your explanation! I think users of the QOwnNotes snap might not be very happy if the snap pulls down Plasma, Gnome, Unity or another desktop environment (because it’s the same problem everywhere) just to make the user-interface match the actual user-interface of the host. 🙂
I’d agree. Even if you packed all the styles, the most you can hope for is the “default” appearance of the system. If the user had configured a custom theme the snap would still not know about it. It’s one of the great problems of confined application and right now I doubt there ever will be a compelling solution to the problem. You can’t just load any plugin due to ABI compatibility concerns, yet not doing so pretty much precludes any sort of meaningful desktop integration as far as theming is concerned,
I guess it would be great if snapd would support theme-styling for some desktop environments out of the box. ^_^
Thanks Harald, great job! Can you please make a KF5 Snap for KF5 v5.29 as the current KF5 (up to 5.28) has a bug that prevents KNewStuff from working within KStars.
Sure. Once 5.29 is actually released on Saturday 😉
Thank you very very much for your hard work. The whole KDE community & devs are awesome.
Is this process still considered current? I’m currently working on snapping up Krita.
Mostly. I’ve only packed the boilerplate away into a custom parts file.
https://community.kde.org/Neon/Snap#Building
here’s a fairly current example file
https://packaging.neon.kde.org/applications/kblocks.git/tree/snapcraft.yaml?h=Neon/unstable