[Archived] WineSnap: Creating snaps for Windows applications

:warning: This information is outdated. Please see the sommelier-core project for an up-to-date guide on how to snap Windows applications.

archived text

Have an awesome Windows application that you want to use on Linux? And it works in Wine? Awesome, let’s create a snap for it!

This thread puts all the info about creating Wine snaps in one place. There’s a bunch of people doing cool stuff with Wine in snaps, so let’s gather what we learned here to make it easier. This is currently mostly a collection of useful info but if you want to create a full-on tutorial, go ahead! If you post it here, I can include it.

Honorable mention to Winepak, a similar initiative making it easy to put a Windows application inside a Flatpak.

Contents

  • Why do I need a snap? I can use Wine!
  • How do I create a WineSnap?
    • Tips and tricks
  • What are the components of a WineSnap?
    • Installing Wine
    • Installing and running the application with sommelier and winetricks
      • Figuring out what dependencies and config are needed
  • Showing loading screens and menus with yad
  • How can we make WineSnapping easier?

(Anyone has any idea how I can create a table of contents with hyperlinks?)

Why do I need a snap? I can use Wine!

Some advantages of using Wine in a snap vs using it directly on your machine:

  • Easy to install. No more messing around tweaking Wine, installing dependencies, and Windows libraries. Just a few clicks and the application is installed.
  • Available in the Ubuntu Software store. While PlayOnLinux and Lutris also offer easy installation of Windows applications, each of these applications has a separate store. Having to search through multiple stores to find a game depending on whether it’s a native Linux application, it runs on Wine or another emulator is a hassle. It’s easier to have a single place for all applications so users get the habit of searching the software store when they want to install an application.
  • Sandboxed. Windows applications running in Wine normally have full access to your operating system, so when an application crashes, does stupid things, or is infected, it can mess up your operating system. Snaps only have limited access to your host operating system so your computer is a lot better protected from buggy Windows applications and buggy Wine.
  • All dependencies included. Snaps contain all the dependencies that an application needs, so you don’t have to install additional libraries or mess with your system in order to install a single application.
  • Snap once, run anywhere*, anytime**. Once an application is snapped, you can install it on a large number of Linux distributions and it will keep working for a very long time. It should be noted, however, that *not all distributions are supported as well as Ubuntu and ** snapd might change in a backward-incompatible way in the distant future.

How do I create a WineSnap?

Roughly speaking, there are two kinds of Wine snaps. Either the snap includes the application preinstalled, or the snap downloads and installs the application and dependencies during the first run. Preinstalled snaps have a better user experience, but know that it might not be legal to distribute the application or the libraries it depends on.

These are some examples of good, working snaps. I recommend you start from one of these examples, clone/fork the repo and change the code to install the application you want.

The SteamForWindows snap has a list of things to do when you create a new snap based on it. Below is a thorough explanation of all the components of a WineSnap and what you should consider when creating one.

Tips and Tricks

  • Use SNAPCRAFT_CONTAINER_BUILDS=1 snapcraft. This builds your snap inside a 16.04 container just like cleanbuild, but it doesn’t throw away the container. It reuses the container for all next builds so that you get the isolation of a container, but the speed of a local build. Other commands like SNAPCRAFT_CONTAINER_BUILDS=1 snapcraft clean <part> clean that part inside the container.
  • Use set -e in your bash scripts to show debugging output.
  • Use snap remove <name> to remove all data including the Wine namespace if you want to simulate a clean install of a snap.

What are the components of a WineSnap?

This part explains all the components of a WineSnap, how everything works, and all the things that I tripped over, so you can refer back to this info when you’re creating your snap.

Installing Wine

The first thing we need is Wine itself installed in the snap. Because 64-bit wine is very buggy, we’re using 32-bit wine, even though most computers run 64-bit Linux.

The snapcraft.yaml file describes how wine is installed.

  • The enable-i386 part makes it possible to include 32-bit packages in a snap
  • wine downloads and installs your preferred wine version directly from the packages provided by winehq itself.
  • wine-runtime includes all the dependencies of wine.

You can specify a specific wine version by changing the variables in the override-build section of the wine part.

      WINE_REL="wine-staging"
      WINE_ARCH="i386"
      WINE_VER="3.10.0"

Note that all the stage-packages end with :i386. This tells apt to install the 32-bit version of the library instead of the 64-bit version of the library. This is because 32-bit programs like the 32-bit version of wine can only use 32-bit libraries. Check out Debian’s multiarch howto for more information about how to install and use 32-bit libraries in a 64-bit Debian-based distribution.

Since we’re only using 32-bit libraries, the snap can run on both 32-bit and 64-bit systems. However, it needs to be built on 64-bit. (I don’t know why. If you do, please let me know.)

architectures:
  - build-on: amd64
    run-on: [amd64, i386]

This is also the reason why we can’t use the snapcraft-desktop-helpers since those are 64-bit only. https://github.com/ubuntu/snapcraft-desktop-helpers/issues/126

Installing and running the application with sommelier and winetricks

Sommelier is a helper script in scripts/sommelier to install and start applications inside of wine in a snap. It originally comes from the SteamForWindows snap. The script has some modularity and customization built-in but you’ll probably have to change some parts of the script. If you’re interested in making sommelier more modular so all wine snaps can use the same script, go ahead and let us know your progress.

Sommelier first sets up loads and loads of environment variables to make both Wine and yad work inside of the snap. At the end of the script, it either installs the application or starts it if it’s already installed.

winetricks is used for the installation of dependencies and configuration of the wine environment. Winetricks is a (not-snap-specific) helper script to work around issues in Wine. It can install Windows libraries on demand and it has a number of automatic profiles tailored to certain applications. It’s basically a lightweight command-line version of PlayOnLinux. Winetricks is a single script. You can get the latest version from their Github repo. It’s best not to change Winetricks yourself.

To install additional libraries or configure wine using winetricks, you set the TRICKS environment variable in the apps part of the snapcraft.yaml file.

  • TRICKS is a space-separated list of winetricks commands to execute. These can be library names, application names or <key>=<value> settings. Each will be executed by sommelier during the install phase.
  • DLLOVERRIDES specifies which library the application should use first. The native one (n; provided by Wine), or the builtin one; (b; provided by the application, taken from windows or installed by winetricks). This functionality is the same as setting a DLL override in the winecfg utility. More info
environment:
    WINEPREFIX: "$SNAP_USER_COMMON/.wine"
    DLLOVERRIDES: "mscoree,mshtml=;gdiplus=n,b" # "mscoree,mshtml=" Prevents pop-ups asking to install Wine Mono and Wine Gecko.
    TRICKS: "fontsmooth=rgb gdiplus vcrun2008"
    LC_ALL: "C.UTF-8"

Figuring out what dependencies and config are needed

The SteamForWindows snap and any based on it contain three extra CLI tools useful for debugging and trying out what dependencies are needed.

  • winecfg is a GUI to configure the Windows version, library overrides, graphics, desktop integration, and more.
  • winetricks is winetricks. Running it will run the winetricks command in the wine namespace of the app.
  • wineboot simulates a windows OS reboot.

You can use these tools to get the application installed and running manually, and then update the snap to do all that stuff by default.

To run the tools, prefix them with the name of the snap. For example, the following command will run the Wine config GUI in the namespace of the PhotoScape snap.

photoscape.winecfg

Also take a look if there exists an install script for the application in PlayOnLinux, Lutris, WinePak or other tools.

Showing loading screens and menus with yad

yad is a command-line tool to show menus, loading screens, and other GUI’s. This is an easy way to show a GUI from a bash script. It’s API compatible with Zenity, but it has a lot fewer dependencies and it’s easier to package in a snap. The file in scripts/Zenity is a wrapper for yad to mimic zenity, so applications that use Zenity like winetricks still work in the snap.

Note that there is currently a bug where it takes ~1 minute for the first yad window to appear after a clean install of the snap. I don’t know why this is, I think GTK is rebuilding font caches or something. If anyone knows how to fix this, let me know. A band-aid solution is to create a notification using notify-send right after your application starts to let the user know that it has indeed started and us doing stuff in the background.

yad is very useful to show a loading screen while the application is installing or to show a menu screen to select different game modes for example.

Example yad loading screen

The loading screen in PhotoScape is made with yad.

Loading screen

 install_app | tee /dev/stderr | yad --progress --width 350 --pulsate --text "Installing the application, this might take a few minutes." --title "Installing application" --auto-close

The progress window of yad displays each line on stdin that starts with a # as the text above the loading bar. install_app is a bash function that prints status messages starting with a #. Its output is first duplicated to stderr so that you can still see all the output if you run it from the command-line. This will greatly help debugging. (yad captures all stdin input)

Source

Example yad menu

The menu screen in Command and Conquer: Tiberian Sun is made with yad.

Menu Screen

action=$(yad --width 400 --entry --title "C&C Tiberian Sun" \
    --center \
    --width=400 \
    --button="Install:0" --button="Exit:1" \
    --text "Select Game Version Type:" \
    --entry-text \
    "Full Game (Singleplayer + Multiplayer)" "Multiplayer")
ret=$?

[[ $ret -eq 1 ]] && exit 0

case $action in
    Full*) cmd=$(install_ts) ;;
    Multi*) cmd=$(install_cnc) ;;
    *) exit 1 ;;
esac

eval exec $cmd

Source

More yad examples

Since yad is API compatible with zenity, you can use the docs for both tools.

How can we make WineSnapping easier?

Are there ways we can make it easier to create these snaps?

  • Many of the wine snaps include copy-pasted boilerplate code. It would be useful if we could figure out a way to use more common parts. Would it be possible to create a remote part to install wine and sommelier? Is anyone interested in hacking on this? Winepak has an interesting approach; they have a platform snap that provides wine and they use extensions for different wine versions.
  • The Phoenicis (PlayOnLinux successor) people are trying to create a snap package for it, but they seemed to have hit a brick wall ~december. Anyone with experience with snapping a Java GUI application that can help them out?
  • The Lutris guys have extensive knowledge of Wine and wrapping installers. They’re currently looking into Flatpak, but they’re open for contributions for snap support. This seems interesting both for lutris-in-a-snap and lutris-installing-a-snap. Lutris itself can be a classic snap that calls the snap CLI on the host to install wine games.
8 Likes

What about creating generic wine + winetricks snap or PlayOnLinux/Q4wine snap?

You can then install every windows application of your choice in sandboxed snap environment.

Creating snap for every windows app doesn’t scale.

While i personally totall prefer the one-snap approach (snap confinement prevents whatever evil stuff a windows binary wants to do to your system, most windows apps are not opensource so you will not really know what data it steals and sends around), you can indeed create a wine snap that provides the wine executable via a content interface so other snaps could use it … feel free :wink:

1 Like

@admins Would you mind setting this topic as a wiki?

Done - thanks for asking :slight_smile:

1 Like

Has anyone snapped something with wine using dotnet4 ?

Should use snapcraft --use-lxd in current Snapcraft

Can you snap epic games?