What is your approach to packaging Wine applications with Nix derivations?

I am curious about existing approaches to packaging applications that run via Wine within Nix derivations. I have come across the desire to do so a few times over the past couple of years, but never had the time to work out how to achieve this nicely.

While there are quite a few posts discussing specific Wine packages, I thought it might be worth opening a dedicated post where Nix users can share solutions they’ve used, discuss the challenges, and possibly come up with some ideas for a general solution or expression that we could eventually land in nixpkgs itself.

As far as I’m aware there isn’t yet a “standard” or go-to solution for packaging Wine applications - please correct me if I’m wrong!

From what I’ve read there are some challenges in handling the amount of mutability required by some applications, though I’m sure there is probably a function or two that could at least ease the general process.

All that said, I think even just consolidating some examples in one place would be really useful.


Here are some related links I’ve discovered so far:


While I imagine it might not be common to include Wine applications in nixpkgs itself (particularly as they often require having an existing executable, are unfree, or break between different versions of Wine which might be a bit much to ask of maintainers), I can imagine a general wrapWine function or something along those lines would still be a great help for declarative packaging downstream, whether for personal tools, video game archival, that one Windows-only program your job requires, etc.

11 Likes

Hi o/

I am the author of wrapWine (aka lucasew).

Most windows apps (to not say all) doesn’t work running from a read only place (nix-store) so my idea was to generate everything on first run.

wrapWine generate a script that on the first run initialize a wine prefix with the passed wine version, install all the tricks in the list with winetricks and can run custom setup and run scripts.

For the generated script if you setup the REPL environment variable it starts a bash shell inside the prefix context. This is useful AF for troubleshooting.

And yea. I got a few games working nicely using this approach. If the prefix is f up you just delete it (it’s a folder inside ~/.wine-nix and it will generate on next run.

I already (like I said) run a few repacked games, TORA and 7-zip.

It’s working pretty nice and I think it’s the simplest approach for this problem, more elegant and simple than use something like PlayOnLinux and I can run my software from any folder.

Some games crash if you don’t launch them chdired on their folders.

I am looking to upstream this to nixpkgs but I am a bit low in time. Also I made a wrapper script to launch borderless chrome-like windows. It’s useful to have more screen use but without hiding the polybar.

8 Likes

I’m unsure how well this will play out with Anticheat support that is coming to linux.

1 Like

The approach I’m using is based on wrapWine. It’s a script which creates a Wine bottle and installs a Wine-compatible application, but it uses a Docker-like layered filesystem approach to create something like a Nix store, but in the user’s home directory.

It makes Windows application management more Nix-like, with support for installing multiple versions and rolling back. Just like any other Nix package. You can read more about it here: https://github.com/emmanuelrosa/erosanix/tree/master/pkgs/mkwindowsapp

Some example packages include:

10 Likes

Great approaches!

Even though it’s not packaging, I’d like to present my approach. As a developer I often use nix-shells to handle complex development environments, where I need the tools but don’t install the “main thing”. Even though the reason here would be a bit different, the approach is very handy with wine too. For each game I have a folder with shell.nix, Makefile and the setup file (or similar). shell.nix creates environment with the correct wine version and Makefile handles installing and running the game (including entering the nix-shell). WINEPREFIX is set to a folder within that folder. To avoid rebuilding wine after GC, I use the secret attribute inputDerivation to set the wine build as a garbage root.

3 Likes

I tried doing something similiar myself, except with the read-only layers created by nix, and in the nix store, and the read/write layer in .config. I ended up encountering issues with both overlayfs and unionfs, which made me drop it. I’ll look into how mkWindowsApp works, and see about reworking my version based on it.

I’ve been working on a solution for this as well. It’s quite messy, but I got something working now. I mainly use it to manage Windows-only VST-plugins via yabridge in a reproducible way. It’s still very much work in progress but available here: GitHub - polygon/audio.nix at yabridgemgr_dev

The flake contains a test VM that you can build and play around with.

To build the wineprefix, I spin up a Xvfb to simulate the presence of a DISPLAY, because wine really wants to have one. I also emulate the most needed components of a user $HOME because wine really wants to have one.

Instead of storing the prefix directly into the Nix-store (which removes all the write-permissions, which wine REALLY wants to have), I put everything into a squashfs image and put that into the Nix store. This preserves the permissions, even though the files are not really writeable since the whole FS is read-only.

While mounting to the user-home, I first mount the squashfs with squashfuse and then use fuse-overlayfs to add a writeable layer (because wine REALLY REALLY wants its prefix to be writeable) and to do the UID/GID mapping to the final user (because wine ABSOLUTELY AND WITHOUT COMPROMISE wants the prefix to be owned by the user running wine).

While this does work, there’s some rough edges. The writeable overlay is nice since the Window applications can do what Windows appliations do and store information and settings in the registry, and put files all over the place. However, things will start to fail if you update the prefix and don’t clear out the overlay. But clearing out the overlay might reset all your settings. It’s an issue I haven’t really found a solution for. However, things are working for my use-case so currently not too inclined to drive this much further without a good approach to this issue.

3 Likes