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.

Screenshot of a GitHub Actions job output

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...

Currently, I provide two binary builds of Wespal:

OutputArchQt versionCompilerLinkage
Windowswespal.exex86_646.6.3Mingw-w64
(GCC 11.2)
Static
(monolithic .exe)
macOSwespal.appUniversal
x86_64 + aarch64
6.6.3Xcode 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.

Deployed Wespal files for a Mingw-w64 build

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\Src
set mingwpath=C:\Qt\Tools\mingw1120_64\bin
set cmakepath=C:\Qt\Tools\CMake_64\bin
set ninjapath=C:\Qt\Tools\Ninja
rem [...]
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.

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.