Compile Go CLI programs into Python wheels.
This tool takes a Go module directory, cross-compiles it for multiple platforms, and produces properly-tagged Python wheels that can be installed via pip or pipx to get the Go binary on your PATH.
See Distributing Go binaries like sqlite-scanner through PyPI using go-to-wheel for background on this project.
pip install go-to-wheel
# or
pipx install go-to-wheelRequires Go to be installed and available in your PATH.
Build wheels for all platforms from a Go module:
go-to-wheel path/to/go-moduleThis will create wheels in a ./dist directory for Linux (glibc and musl), macOS (Intel and Apple Silicon), and Windows (amd64 and arm64).
go-to-wheel path/to/go-folder [options]| Option | Description | Default |
|---|---|---|
--name NAME |
Python package name | Directory basename |
--version VERSION |
Package version | 0.1.0 |
--output-dir DIR |
Directory for built wheels | ./dist |
--entry-point NAME |
CLI command name | Same as package name |
--platforms PLATFORMS |
Comma-separated list of targets | All supported platforms |
--go-binary PATH |
Path to Go binary | go |
--description TEXT |
Package description | "Go binary packaged as Python wheel" |
--license LICENSE |
License identifier | None |
--author AUTHOR |
Author name | None |
--author-email EMAIL |
Author email | None |
--url URL |
Project URL | None |
--requires-python VERSION |
Python version requirement | >=3.10 |
--readme PATH |
Path to README markdown file for PyPI long description | None |
--set-version-var VAR |
Go variable to set to --version value via -X ldflag |
None |
--ldflags FLAGS |
Additional Go linker flags (appended to default -s -w) |
None |
Build wheels with a custom package name:
go-to-wheel ./mytool --name my-python-toolBuild for specific platforms only:
go-to-wheel ./mytool --platforms linux-amd64,darwin-arm64Embed the wheel version into the Go binary at compile time (requires a var version in your Go source):
go-to-wheel ./mytool --version 2.0.0 --set-version-var main.versionThis passes -X main.version=2.0.0 to the Go linker, so the compiled binary knows its own version without hardcoding it in the Go source. A typical Go pattern for this:
var version = "dev"
func main() {
if os.Args[1] == "--version" {
fmt.Println(version) // prints "2.0.0" when built with --set-version-var
}
}Pass arbitrary Go linker flags with --ldflags:
go-to-wheel ./mytool --version 2.0.0 \
--ldflags "-X main.version=2.0.0 -X main.commit=abc123"The flags are appended to the default -s -w, so the full linker invocation becomes -ldflags="-s -w -X main.version=2.0.0 -X main.commit=abc123".
Build with full metadata for PyPI:
go-to-wheel ./mytool \
--name mytool-bin \
--version 2.0.0 \
--description "My awesome tool" \
--license MIT \
--author "Jane Doe" \
--author-email "jane@example.com" \
--url "https://github.com/jane/mytool" \
--readme README.md| Platform | Wheel Tag |
|---|---|
linux-amd64 |
manylinux_2_17_x86_64 |
linux-arm64 |
manylinux_2_17_aarch64 |
linux-amd64-musl |
musllinux_1_2_x86_64 |
linux-arm64-musl |
musllinux_1_2_aarch64 |
darwin-amd64 |
macosx_10_9_x86_64 |
darwin-arm64 |
macosx_11_0_arm64 |
windows-amd64 |
win_amd64 |
windows-arm64 |
win_arm64 |
- Cross-compiles the Go binary using
GOOSandGOARCHenvironment variables withCGO_ENABLED=0for static binaries - Creates a Python package with a thin wrapper that
execs the bundled binary - Packages everything into a wheel with the correct platform tag
The resulting wheel can be installed with pip:
pip install ./dist/mytool-1.0.0-py3-none-manylinux_2_17_x86_64.whlOr tested directly with uv:
uv run --with ./dist/mytool-1.0.0-py3-none-manylinux_2_17_x86_64.whl mytool --helpClone the repository:
git clone https://github.com/simonw/go-to-wheel
cd go-to-wheelRun tests:
uv run pytest- maturin - The Rust equivalent that inspired this tool
- pip-binary-factory - Template for packaging pre-built binaries