Technical post follows, probably boring to most.

It took me several months of well, being distracted mostly, but I finally made progress on releasing mealplanner. That progress being cross-compiling and bundling the app through docker for the OSes I’m planning to support initially: linux, windows & macos.

Specifically this means I was able to compile a rust app that runs on windows from within a linux environment, and ditto for macos. And it means I was able to create a windows installer in a linux environment and a (pretty shitty) dmg in a linux environment.

Now technically I didn’t actually haaaave to do any of this. Most CI/CD platforms allow running jobs on machines with different OSes. I could’ve, for example, just built the mac bundle on a macos VM on gitlab (I use gitlab because afaik github still works with ICE).

But then if something goes wrong I’m stuck with a problem I can’t reproduce locally, unless I setup a dev environment on both windows and macos and whatever OS I target next. And having to debug a problem on a remote machine that is only active after I create and push a commit is a very special sort of hell that I definitely don’t want to deal with.

Cross-compiling through docker, which is it’s own type hell really, is at least one I can deal w/ locally, without having to wait > 10 mins to see the result of a change.

And also, if I can solve it here once, I can re-use the method & code for every other app I wanna make.

Anyhoo, since I started trying this months ago and only just finished, I actually can’t remember all of the weird little problems I had to solve. So I’m just gonna talk about how the process works for different target OSes.

Just a quick note: mealplanner is a tauri app, and tauri has commands for building and bundling for different platforms, but does not support cross compiling & bundling for non-linux platforms on linux. So I had to do a lot of forking and modifying other peoples’ code.

Building for Linux

This one’s simple. Docker containers run in a linux environment, so compiling the rust app and creating a .deb file (via a tauri command) just worked.

Building for Windows

This one was also pretty easy. People have been cross compiling for windows for a long time (since mingw I guess) and the rust community has been working on it as well. I ended up using https://github.com/cross-rs/cross which contains a set of docker files pre-configured for cross compiling rust/C/C++ code.

The installer is created using makensis. There might have been some issues w/ getting this working, buuuut… I can’t remember at this point.

Building for OS X

This was the real challenge. The only thing that works out of the box is the rust compiler cross compiling to a darwin target. Compiling C/C++ code (required since tauri depends on many native projects) and creating a DMG for distribution is definitely not handled.

Fortunately, enough people have solved enough problems that I was able to string something together and get something that runs on a Mac.

For compiling C/C++ code there’s osxcross which, happily, still works. I think there was just one issue I had where I needed to replace a cp -R command w/ rsync.

For building a DMG file, well, the most obvious solution was to use the hfsprogs package. This lets you (among other things) mount a DMG file, which I would’ve then copied files into. But mounting in docker, even with just a file and not an actual external device, would require running containers in privileged mode, which is a big security risk. (And thus a no-no.)

Again, fortunately for me, there was a solution out there I could use: https://github.com/indygreg/apple-platform-rs. I guess other people also have little interest in maintaining dev environments on multiple platforms. Anyway, this project provides some pure rust implementations of tools used in bundling mac apps. And it actually worked.

Next steps

Now that I can create releases through docker, I need to run those docker containers in gitlab’s CI/CD system, which is the main thing I’ll be trying to find time for next. Once that’s done, I’ll want to do a security review of the pipeline, then find some way to distribute the plated recipe database I created. At that point, people can actually use it, and I can turn my focus to the application itself.

The builds for Windows and Mac are not perfect, though, so eventually I’ll want to make some improvements there as well.

For Windows, building the app using MinGW results in a 50mb installer vs. 15mb when using the MSVC toolchain.

For Mac, the DMG that I’m creating currently uses the FAT32 filesystem which doesn’t allow extended attributes and is created without a .DS_Store file. OS X uses extended attributes on the volume and the .DS_Store contents to configure how Finder displays the DMG when mounted/open. This is usually displayed as two folders: Applications & the .app bundle, w/ the user being told to drag one to the other. What I have now is just mounted as a drive. So there’s no clue to what the user has to do to install the app. Both of these are solvable (probably), but I don’t think anyone’s actually written code to do it, so it’s not something I can look into w/o some free time.