Oct 4th, 2021
by makeworld
Packaging a Python project into a standalone executable is often a struggle. Thankfully we have tools like PyInstaller to make this easier. Recently I ran into another struggle of my own, which was that it seemed impossible to “cross-compile” with PyInstaller. That is to say, run PyInstaller on one OS, and have it generate an executable for another. It was hinted at that Linux → Windows was possible using Wine, but I couldn’t find any guides on it.
Eventually, I got it working, so here is that guide. Hope this helps! This guide might also work on macOS, but I have not tested it.
Thanks to Noah Broyles for the script that helped me figure this all out.
First off, I was only able to use Python 3.8. I tried with 3.9, but I was not able to install it
under WINE. If you are able to, feel free to use that, and change references to 38
in this post
to 39
. I was also using PyInstaller 4.5.1, but other versions should work fine.
The first step is to install WINE for your Linux system. WINE is a compatibility layer that allows
the running of Windows software on non-Windows systems. You can install WINE easily enough from
your distro’s package manager. I am using wine-6.16
, but most likely your distro’s version will
work fine.
Next, download the Python 3.8 Windows installer. You can download that directly from the official
Python Software Foundation here. With
it downloaded, you can run wine python-3.8.9.exe
to begin the installation. WINE may prompt you
to install something like .NET or Mono, you should click Yes and let it install.
You should not use the default installation, follow these steps:
C:\\Python38
Using the C:\\Python38
path helps keep things standard for this blog post.
Now Python 3.8 should be successfully installed in WINE. You can check this by running
wine C:/Python38/python.exe --version
, which will run Windows Python through WINE. Amazing!
Next we’ll need to upgrade pip, to make sure things will install fine. Run
wine C:/Python38/python.exe -m pip install --upgrade pip
. WINE might spit out a lot of warnings
about libgnutls
or something or other, but as long as Pip doesn’t report any errors it’s fine.
Now if your project has any dependencies, you should export them into the standard Python
requirements.txt
file. You can then install them into your WINE Python with this command:
wine C:/Python38/python.exe -m pip install -r requirements.txt
If you’re using a superior dependency manager like Poetry, you should be able to install and use that in WINE, although I haven’t tested that.
In any case, you’ll need PyInstaller to be installed, so run this command if PyInstaller wasn’t in
requirements.txt
already:
wine C:/Python38/python.exe -m pip install pyinstaller
Now you can run PyInstaller and an EXE will be built! Just run
wine C:/Python38/Scripts/pyinstaller.exe ...
and replace ...
with whatever arguments you used
to build a Linux executable.
Enjoy!