Warning, /graphics/krita/README.packagers.md is written in an unsupported language. File is not indexed.

0001 Notes on packaging Krita with G’MIC
0002 ==================================
0003 
0004 Krita 3 and later are compatible with G’MIC, an open-source digital
0005 image processing framework. This support is provided by G’MIC-Qt, a
0006 Qt-based frontend for G’MIC. Since its inception, G’MIC-Qt was shipped
0007 as a standalone, externally built executable that is an optional,
0008 runtime dependency of Krita.
0009 
0010 Krita 5 changes the way G’MIC-Qt is consumed. In order to support CentOS
0011 and macOS, G’MIC-Qt has been converted into a dynamically loadable
0012 library that is a dependent of Krita.
0013 
0014 This file reviews these changes, and how to package Krita accordingly.
0015 
0016 Rationale
0017 ---------
0018 
0019 We have chosen to ship G’MIC-Qt as a library because of two longstanding
0020 bugs.
0021 
0022 The Krita host for G’MIC-Qt relies on `QSharedMemory`, i.e. a shared
0023 memory segment, on wich a pipe is instantiated to pass messages to and
0024 from the host app. Firstly, this approach made opening two simultaneous
0025 G’MIC-Qt instances (each paired to its own Krita instance) impossible
0026 [^1]. Secondly, it also forbade using G’MIC-Qt with Krita on CentOS, as
0027 well as macOS, because the former doesn’t support `QSharedMemory` [^2],
0028 and the latter has a meager 4KB as the maximum shared segment size.
0029 While there’s no workaround (to our knowledge) in CentOS, the only
0030 workaround for macOS is to manipulate the maximum segment size via
0031 `sysctl` [^3], which was already difficult pre-Mojave [^4] and now, due
0032 to the significant security measures of recent macOS versions, is
0033 nothing short of a sysadmin task [^5].
0034 
0035 There were two approaches. One was to move to a `mmap`-d file, which is
0036 unpredictable to sync due to each canvas’s differing space requirements.
0037 The easiest, and the one we chose, was to move to a tighter coupled
0038 memory model– a dynamically loadable plugin, as shown in my proposal PR
0039 [^6]. This was rejected by the G’MIC developers because of the
0040 possibility of crashing the host app due to a G’MIC internal bug
0041 [^7][^8]. This decision was later enacted as part of G’MIC contributing
0042 policies [^9].
0043 
0044 How did you fix it?
0045 -------------------
0046 
0047 Due to the above, the only path forward was to fork G’MIC, which we did
0048 in Krita MR !581 [^10].
0049 
0050 From a source code point of view, our fork is based on top of the latest
0051 version’s tarball. Each tarball’s contents are committed to the `main`
0052 branch of the `amyspark/gmic` GitHub repository [^11]. For every covered
0053 release, there is a branch that in turn overlays our own plugin
0054 implementation, along with additional fixes that ensure that G’MIC-Qt
0055 doesn’t attempt to overwrite the internal state of the host application;
0056 namely, `QCoreApplication` settings, widget styles, and the installed
0057 translators.
0058 
0059 From a technical point of view, this library interfaces with Krita
0060 through a new, purpose specific library, `kisqmicinterface`. This
0061 library contains nothing more than the previous iteration of the
0062 communications system, but now exported through namesake APIs [^12].
0063 
0064 In short, we have reversed the dependency flow; while in Krita v4 and
0065 earlier G’MIC-Qt was a runtime dependency, in v5, it’s G’MIC-Qt that
0066 depends on Krita as a build *and* runtime dependency.
0067 
0068 Getting the source code
0069 -----------------------
0070 
0071 The patched version’s tarballs are GPG signed and available at the
0072 Releases section of the GitHub repository [^13]. Alternatively, the
0073 tarballs (though not the signatures) are also mirrored at our
0074 dependencies stash at files.kde.org [^14]. The tarballs are signed with
0075 the GPG key which is available at my GitHub profile. Its fingerprint is
0076 `4894424D2412FEE5176732A3FC00108CFD9DBF1E`.
0077 
0078 Building Krita’s G’MIC-Qt library
0079 ---------------------------------
0080 
0081 After building Krita with your standard process, the CMake install
0082 process should have put `kisqmicinterface.so` in your `lib` folder:
0083 
0084     [2022-01-09T16:21:32.589Z] -- Installing: /home/appimage/appimage-workspace/krita.appdir/usr/lib/x86_64-linux-gnu/libkritaqmicinterface.so.18.0.0
0085     [2022-01-09T16:21:32.589Z] -- Installing: /home/appimage/appimage-workspace/krita.appdir/usr/lib/x86_64-linux-gnu/libkritaqmicinterface.so.18
0086     [2022-01-09T16:21:32.589Z] -- Set runtime path of "/home/appimage/appimage-workspace/krita.appdir/usr/lib/x86_64-linux-gnu/libkritaqmicinterface.so.18.0.0" to "/home/appimage/appimage-workspace/krita.appdir/usr/lib/x86_64-linux-gnu:/home/appimage/appimage-workspace/deps/usr/lib:/home/appimage/appimage-workspace/deps/usr/lib/x86_64-linux-gnu"
0087     [2022-01-09T16:21:32.589Z] -- Installing: /home/appimage/appimage-workspace/krita.appdir/usr/lib/x86_64-linux-gnu/libkritaqmicinterface.so
0088 
0089 It should also install these headers, as illustrated below:
0090 
0091 -   `kis_qmic_plugin_interface.h` exports a G’MIC-alike `launch` entry
0092     point that the plugin will implement
0093 -   `kis_qmic_interface.h` implements the G’MIC request-response APIs
0094 -   `kritaqmicinterface_export.h` is the CMake auto-generated export
0095     decoration header
0096 
0097 <!-- -->
0098 
0099     [2022-01-09T16:21:32.589Z] -- Installing: /home/appimage/appimage-workspace/krita.appdir/usr/include/kis_qmic_interface.h
0100     [2022-01-09T16:21:32.589Z] -- Installing: /home/appimage/appimage-workspace/krita.appdir/usr/include/kis_qmic_plugin_interface.h
0101     [2022-01-09T16:21:32.589Z] -- Installing: /home/appimage/appimage-workspace/krita.appdir/usr/include/kritaqmicinterface_export.h
0102 
0103 The three headers, along with the `libkritaqmicinterface.a` archive
0104 library (if building for Windows under MinGW), comprise a `krita-gmic-dev`
0105 package that’ll be a build dependency of the new G’MIC-Qt plugin.
0106 Please note that `libkritaqmicinterface.so` is consumed
0107 by Krita and MUST NOT be placed inside this dev package.
0108 
0109 Now, download the G’MIC-Qt tarball from one of the sources listed
0110 previously, and unpack it to an isolated directory. Then, you can build
0111 it with these lines (adjust them as described):
0112 
0113     mkdir build
0114     cmake -S ./gmic-$<the tarball's G'MIC version>-patched/gmic-qt \
0115           -B ./build \
0116           -DCMAKE_PREFIX_PATH=$<installation prefix of krita-gmic-dev> \
0117           -DCMAKE_INSTALL_PREFIX=$<installation prefix of krita itself> \ 
0118           -DENABLE_SYSTEM_GMIC=$<false if you don't want to use your system's G'MIC> \
0119           -DGMIC_QT_HOST=krita-plugin
0120     cmake --build . --config $<your desired build type> --target install
0121 
0122 The changes from a standard G’MIC build are:
0123 
0124 -   the new `GMIC_QT_HOST` value, `krita-plugin`
0125 -   the requirement for the `krita-gmic-dev` package to be available in
0126     `CMAKE_PREFIX_PATH`
0127 
0128 This process is illustrated in any of our official build scripts for
0129 Windows [^15] and for macOS/Linux [^16]. You can also check the
0130 `3rdparty_plugins` section of our source tree [^17] to see what other
0131 hardening we apply to the build.
0132 
0133 ------------------------------------------------------------------------
0134 
0135 [^1]: Bug \#44 on c-koi/gmic-qt: “CentOS7: Krita 4.0.4 + gmic\_krita\_qt
0136     2.3.0/2.2.3 - QSharedMemory::attach”.
0137     <https://github.com/c-koi/gmic-qt/issues/44>
0138 
0139 [^2]: Bug 424514 on krita: “Guaranteed crash when opening 2 G’MIC-qt”.
0140     <https://bugs.kde.org/show_bug.cgi?id=424514>
0141 
0142 [^3]: <https://www.ssec.wisc.edu/mcidas/doc/users_guide/2017.1/SharedMemory.html>
0143 
0144 [^4]: e.g. <https://stackoverflow.com/questions/2017004/setting-shmmax-etc-values-on-mac-os-x-10-6-for-postgresql>
0145 
0146 [^5]: See <https://developer.apple.com/forums/thread/669625> for an
0147     approach applicable after `com.apple.rootless` was fully enforced.
0148 
0149 [^6]: <https://github.com/c-koi/gmic-qt/pull/102>
0150 
0151 [^7]: <https://github.com/c-koi/gmic-qt/pull/102>
0152 
0153 [^8]: Note that this was already possible, simply by crashing G’MIC the
0154     host app would deadlock, waiting forever for a response.
0155 
0156 [^9]: <https://github.com/c-koi/gmic-qt/blob/master/NEW_HOST_HOWTO.md>
0157 
0158 [^10]: <https://invent.kde.org/graphics/krita/-/merge_requests/581>
0159 
0160 [^11]: <https://github.com/amyspark/gmic>
0161 
0162 [^12]: An older version of what’s
0163     <https://github.com/c-koi/gmic-qt/blob/master/src/Host/GmicQtHost.h>
0164     nowadays.
0165 
0166 [^13]: <https://github.com/amyspark/gmic/releases>
0167 
0168 [^14]: <https://files.kde.org/krita/build/dependencies/>
0169 
0170 [^15]: <https://invent.kde.org/graphics/krita/-/tree/master/build-tools/windows>
0171 
0172 [^16]: <https://invent.kde.org/graphics/krita/-/blob/master/packaging>
0173 
0174 [^17]: <https://invent.kde.org/graphics/krita/-/tree/master/3rdparty_plugins>