Distribution Considerations for Windows

This document describes some of the considerations when you want to install/run a PyOxidizer-built application on a separate Windows machine from the one that built it.

Important

The restrictions in this document regard the run-time / target environment that a binary will run on: they do not describe the environment used to build that binary. In many cases, a binary built on Windows 10 or Windows Server 2019 will work fine on earlier operating system versions.

Readers may also find the Microsoft documentation on deployment considerations for Windows binaries a useful resource to supplement this document with more generic considerations.

Operating System Requirements

The default Python distributions used by PyOxidizer require Windows 8 or Windows 2012 or newer.

The official Python 3.8 Windows distributions available on www.python.org support Windows 7. PyOxidizer has chosen to drop support for Windows 7 to simplify support.

In addition to the restrictions imposed by the Python distribution in use, Rust may impose its own restrictions. However, Rust has historically produced binaries that work on Windows 8 and Windows 2012, so this likely is not an issue.

General Runtime / DLL Dependencies

The default Python distributions used by PyOxidizer require the Microsoft Visual C++ Redistributable and Universal CRT (UCRT).

The standalone_dynamic distributions (the default distribution flavor) have a run-time dependency on various 3rd party DLLs used by extensions (OpenSSL, SQLite3, etc). However, these 3rd party DLLs are part of the Python distribution and PyOxidizer should automatically install them if they are required.

All other DLL dependencies required by the default Python distributions should be core Windows operating system components and always available, even in a freshly installed Windows machine.

Application Specific Dependencies

When adding custom behavior to your application, PyOxidizer makes some effort to ensure additional dependencies (beyond the operating system, Python distribution, and Microsoft runtimes) are met. However, there are limitations to this.

When installing custom Python packages, PyOxidizer attempts to identify and install compiled Python extensions and .dll dependencies distributed with that package. See Packaging Files Instead of In-Memory Resources for more. However, there are corner cases and occasional bugs that may prevent this from working correctly.

To ensure are DLL dependencies are properly captured, it is recommend to inspect your binaries for references to missing DLLs before distributing them. The Dependency Walker tool can be used for this. pyoxidizer analyze may also provide useful information.

In many cases, installing a missing DLL is a matter of installing the DLL next to your application/binary by treating the DLL as an additional file from the Starlark configuration. See Packaging Files Instead of In-Memory Resources for more.

When possible, it is recommended to test your application in a freshly installed Windows environment to ensure it works. Please note that many Windows virtual machines already contain additional software and may not reflect real world deployment targets.

Managing the Visual C++ Redistributable Requirement

Binaries built with PyOxidizer often have a run-time dependency on the Microsoft Visual C++ Redistributable. These are DLLs with filenames like vcruntime140.dll and vcruntime140_1.dll.

Important

The Visual C++ Redistributable is not a core Windows operating system component and any distributed Windows application must take measures to ensure the Visual C++ Redistributable is available on the remote machine or the application may fail to run with a missing DLL error.

See Microsoft’s Redistributing Visual C++ Files documentation for the canonical source on distribution requirements.

PyOxidizer has built-in features to make satisfying these requirements turnkey. Read the sections below for details of each.

Installing the Visual C++ Redistributable as Part of Your Application Installer

PyOxidizer can produce Windows .exe application installers that embed a copy of the Microsoft Visual C++ Redistributable installer (files named vc_redist<arch>.exe) and automatically run this installer during application install.

The way this works is PyOxidizer contains a reference to the URL and SHA-256 of these vc_redist<arch>.exe installers. When your application installer is built, these files are downloaded from Microsoft’s servers and embedded in the new meta-installer. At install time, these embedded installers are executed automatically (if they need to be) and the Visual C++ files are installed at the system level, where they are available to any application.

If a newer version of the Visual C++ Redistributable files are already present, the installer should no-op instead of downgrading what’s already installed.

The following Starlark functionality can be used to bundle the Visual C++ Redistributable installer as part of your application installer:

Installing the Visual C++ Redistributable Files Locally Next to Your Binary

Another method of installing the Visual C++ Redistributable files is to distribute copies of the DLLs next to the binary that loads them. e.g. if you produce a myapp.exe, there will be a vcruntime140[_1].dll in the same directory as myapp.exe. Since Windows attempts to load DLLs next to the executable, if the DLLs are present, this should just work.

PyOxidizer supports automatically finding and copying the required DLLs in this manner. The Starlark setting controlling this behavior is PythonExecutable.windows_runtime_dlls_mode.

This setting effectively instructs the PythonExecutable building code to materialize extra files next to the binary. The Visual C++ files are treated just like any other supplementary files (like Python resources). This means that Visual C++ files will be materialized on the filesystem when running pyoxidizer build, pyoxidizer run. The files will also be present in file lists when using Starlark methods like PythonExecutable.to_file_manifest() or PythonExecutable.to_wix_msi_builder().

This local files mode relies on locating DLLs on the local system. It does so using vswhere.exe to locate a Visual Studio installation containing the Microsoft.VisualCPP.Redist.<version>.Latest component (<version> is 14 for vcruntime140.dll). This should just work if you have Visual Studio 2017 or 2019 installed with support for building C/C++ applications. If the files cannot be found, run the Visual Studio Installer, Modify your installation, go to Individual Components, search for redistributable, and make sure all items are checked.

Important

It is possible to include a copy of the Visual C++ Redistributable in both your application installer and as files local to the built binary. This behavior is redundant and will likely result in the local files being used.

When including the Visual C++ Redistributable installer as part of your deployment solution, it is recommended to set PythonExecutable.windows_runtime_dlls_mode to "never" to prevent them from being redundantly installed.

Managing the Universal CRT (UCRT) Requirement

Binaries built with PyOxidizer may have a run-time dependency on the Universal C Runtime (UCRT).

The UCRT is a Windows operating system component and is always present in installations of Windows 10, Windows Server 2016, and newer. Combined with PyOxidizer’s Windows version requirements, this means you don’t need to worry about the UCRT unless you are targeting Windows 8 or Windows Server 2012.

PyOxidizer does not currently support automatically materializing the UCRT. See https://docs.microsoft.com/en-us/cpp/windows/universal-crt-deployment for instructions on deploying the UCRT with your application.

We are receptive to adding a feature to support more turnkey UCRT management if there is interest in it.