Wespal now has unit tests
While working on Wespal 0.4.0 I ran into many regressions, some of them caused by code refactoring, others by behavioural changes I didn’t entirely foresee, including a particularly annoying one involving the XCF plugin and embedded colour profiles that took me about three nights to have an eureka moment about.
My future self is gonna be thankful some day that I finally added a CI workflow and test suite to Wespal, built and run on Linux, macOS, and Windows for each push via GitHub Actions, so I can promptly find out if I accidentally break some of the more crucial components, or cause the whole thing to stop compilling on particular platform because of a missed #ifdef
or unusual typedef
difference. Or, you know, because while I require Qt 6.4 as a minimum, my development environment actually uses Qt 6.4, so one day I may slip up and add code that does not compile against the 6.4 API.
Now if only I could have CI coverage for the static Windows builds as well...
The neglected child
Currently, I provide two binary builds of Wespal:
Output | Arch | Qt version | Compiler | Linkage | |
---|---|---|---|---|---|
Windows | wespal.exe | x86_64 | 6.6.3 | Mingw-w64 (GCC 11.2) | Static (monolithic .exe) |
macOS | wespal.app | Universal x86_64 + aarch64 | 6.6.3 | Xcode 15.3 (Apple Clang 15) | Dynamic (app bundle) |
Years ago, I decided to provide Wespal for Windows as a statically-linked executable, the reason being that providing a portable binary without an installer resulted in an unwieldy-looking folder with multiple opaque DLLs sitting next to the .exe
. Of course, normally people shouldn’t need to touch the contents of the folder, but people may double click on the .zip
and lookat its contents and then drag them somewhere else instead of using the Extract option from the context menu. And if they don’t make sure to drag all the files, then...
The code execution cannot proceed because Qt6Core.dll was not found. Reinstalling the program may fix this problem.
-clicks OK-
The code execution cannot proceed because Qt6Widgets.dll was not found. Reinstalling the program may fix this problem.
-clicks OK again-
The code execution cannot proceed because Qt6Gui.dll was not found. Reinstalling the program may fix this problem.
-clicks OK a third time-
The code execution cannot proceed because libgcc_s_seh-1.dll was not found. Reinstalling the program may fix this problem.
I especially love the scary-sounding names. libgcc_s_seh-1.dll
, really?
(It’s in reference to Mingw GCC’s support for Win32 Structured Exception Handling, but we are all programmers here, come on.)
I didn’t want to build and ship a Windows installer either, because Wespal is a very, very small app at the end of the day, and nobody likes running installers. In all honesty, Apple’s bundle system is kind of the superior alternative here.
It’s also annoying that this version of Qt also requires some of the DLLs to be deployed in additional subfolders. At least I cannot seem to remember if Qt 5 also required this — maybe it did.
And thus, in order to avoid risking accidental breakage due to people not copying/moving the entire contents of the folder properly, I build my own highly-trimmed-down version of Qt 6, statically, and link Wespal to it. This sounds simple in principle, but in reality I had to codify my build recipe into a script (utils/build-qt-windows-static.cmd
) because of the sheer amount of environment setup and custom configuration required:
set qtsrcdir=C:\Qt\6.6.3\Srcset mingwpath=C:\Qt\Tools\mingw1120_64\binset cmakepath=C:\Qt\Tools\CMake_64\binset ninjapath=C:\Qt\Tools\Ninjarem [...]set PATH=%ninjapath%;%cmakepath%;%mingwpath%;%PATH%rem [...]call %qtsrcdir%\configure -prefix %distdir% -release -optimize-size -static -static-runtime -submodules qtbase,qtimageformats -no-feature-network -no-feature-sql -no-feature-printer -no-feature-printsupport -no-feature-androiddeployqt -no-feature-qdbus -no-feature-concurrent -no-feature-testlib -no-feature-xml -no-feature-qmake -gui -widgets -no-opengl -no-gif -no-tiff -no-dbus
Alas, building Qt takes a decidedly large amount of time even though I disabled basically all components that Wespal does not use directly or indirectly. It’s not something I have to do often anyway, but I can’t imagine doing that on GitHub Actions without self-hosting a runner, which would require me to rent additional hosting and purchase a Windows Server license... no, thanks.
Theoretically, there shouldn’t be any behavioural differences between my static Qt build and the official Mingw DLLs that the GH Actions workflow is using, of course. If anything I’m more likely to hit a build or link-time error at some point because of Wespal gaining a new dependency I didn’t plan for in advance, and then I will just have to rebuild my static Qt.
What about Linux?
Seems like these days Flatpak is all the rage when it comes to distributing Linux software without relying on actual Linux distributions to package your stuff themselves. However, because for the past two years I’ve been using Windows for work and macOS on my Macbook as my daily driver, I largely ignore how to use Flatpak. Not to mention that just a few years ago, I had some negative experiences with it as a user due to it not being designed to account for people having Internet download caps in 2020. Why should I need to download the Gnome desktop environment libraries for Flatpak’s own containers when I already have them installed system-wide?
For the time being, I will just keep recommending to people that they build from source like I already do for testing on Fedora 39 and Debian 12 (bookworm). It’s easier than spending too much energy on a platform I don’t really use anymore outside of testing and triaging desktop apps and hosting Internet-facing servers.