Crate Configuration

Cargo Features to Control Building

The pyembed crate has a set of build-mode-* Cargo feature flags to control how build artifacts are created and consumed.

The features are described in the following sections.


This is the default build mode. It is enabled by default.

This build mode uses default Python linking behavior and feature detection as implemented by the cpython and python3-sys crates. It will attempt to find a python in PATH or from the PYTHON_SYS_EXECUTABLE environment variable and dynamically link against it.

This is the default mode for convenience, as it enables the pyembed crate to build in the most environments. However, the built binaries will have a dependency against a foreign libpython and likely aren’t suitable for distribution.

pyembed has a dependency on Python 3.8+. If an older Python is detected, it can result in build errors, including unresolved symbol errors.


A pyoxidizer executable will be run to generate build artifacts.

The path to this executable can be defined via the PYOXIDIZER_EXE environment variable. Otherwise PATH will be used.

At build time, pyoxidizer run-build-script will be run. A PyOxidizer configuration file will be discovered using PyOxidizer’s heuristics for doing so. OUT_DIR will be set if running from cargo, so a pyoxidizer.bzl next to the main Rust project being built should be found and used.

pyoxidizer run-build-script will resolve the default build script target by default. To override which target should be resolved, specify the target name via the PYOXIDIZER_BUILD_TARGET environment variable. e.g.:

$ PYOXIDIZER_BUILD_TARGET=build-artifacts cargo build


This mode tells the build script to reuse artifacts that were already built. (Perhaps you called pyoxidizer build or pyoxidizer run-build-script outside the context of a normal cargo build.)

In this mode, the build script will look for artifacts in the directory specified by PYOXIDIZER_ARTIFACT_DIR if set, falling back to OUT_DIR. See Build Artifacts for documentation on the required artifacts.


Do not attempt to invoke pyoxidizer or find artifacts it would have built. It is possible to build the pyembed crate in this mode if the rust-cpython and python3-sys crates can find a Python interpreter. But, the pyembed crate may not be usable or work in the way you want it to.

This mode is intended to be used for performing quick testing on the pyembed crate. It is quite possible that linking errors will occur in this mode unless you take additional actions to point Cargo at appropriate libraries.

Build Artifacts

When using build-mode-prebuilt-artifacts or build-mode-pyoxidizer-exe, the pyembed crate consumes special artifacts as part of its build process to provide the embedded Python interpreter. These artifacts are typically generated by PyOxidizer. However, there is nothing stopping anyone from producing equivalent artifacts via other means and having pyembed consume them.

The way this mode works is the build script is pointed at a directory containing artifacts. The only required artifact is a cargo_metadata.txt file. This file contains lines which will be printed to stdout by the crate build script. These lines typically contain cargo: lines, which influence Cargo’s configuration for the crate.

The cargo: lines must define a pre-built pythonXY library to link against. That library name is literally pythonXY and XY is not a placeholder for a version string!

Use cases like PyOxidizer derive a custom library containing Python’s core symbols. The cargo: lines for this use case will look something like the following:


Essentially what PyOxidizer does is compile a custom library containing Python. This will be named pythonXY.lib or pythonXY.dll on Windows and libpythonXY.a or on UNIX platforms. It then lists link library dependencies as needed and registers the generated pythonXY library to be linked from the context of the pyembed crate.

Deriving a custom library containing Python is fairly complex! From the perspective of build-mode-prebuilt-artifacts, all that is strictly needed is for the cargo_metadata.txt to define how to link against a pythonXY library. It is even possible to alias pythonXY to an existing Python library already on your system (this is effectively what build-mode-default does). So a minimal cargo_metadata.txt might look something like this:

cargo:rustc-link-lib=pythonXY:python3.9 cargo:rustc-link-search=native=/path/to/directory/containing/python/library