# https://github.com/simonw/go-to-wheel 项目说明书

生成时间：2026-05-15 08:31:09 UTC

## 目录

- [Introduction](#page-introduction)
- [Installation](#page-installation)
- [Quick Start Guide](#page-quick-start)
- [CLI Options Reference](#page-cli-options)
- [Usage Examples](#page-examples)
- [System Architecture](#page-architecture)
- [Supported Platforms](#page-platforms)
- [Wheel Generation Process](#page-wheel-generation)
- [Development Guide](#page-development-guide)
- [Configuration and Metadata](#page-configuration)

<a id='page-introduction'></a>

## Introduction

### 相关页面

相关主题：[Installation](#page-installation), [Quick Start Guide](#page-quick-start)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/simonw/go-to-wheel/blob/main/README.md)
- [spec.md](https://github.com/simonw/go-to-wheel/blob/main/spec.md)
- [go_to_wheel/__init__.py](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)
</details>

# Introduction

## Overview

`go-to-wheel` is a Python command-line tool that compiles Go CLI programs into Python wheels, enabling Go binaries to be distributed and installed through the Python packaging ecosystem via `pip` or `pipx`. This tool bridges the Go and Python communities by providing a seamless way to package and distribute Go applications to Python developers who are accustomed to installing tools through Python package managers. The project was created to address the gap in the ecosystem—there was no equivalent to Rust's `maturin --bindings bin` for Go, and `go-to-wheel` fills that void by providing a straightforward solution for bundling Go binaries into standard Python wheel packages.

资料来源：[README.md:1-10]()

The tool takes a Go module directory as input, cross-compiles the Go binary for multiple target platforms, and produces properly-tagged Python wheels that can be installed via standard Python package management tools. This approach allows Go developers to leverage the extensive Python packaging infrastructure for distribution, including PyPI hosting, pipx for isolated installations, and standard Python dependency resolution.

资料来源：[spec.md:1-15]()

## Core Functionality

### What go-to-wheel Does

At its core, `go-to-wheel` performs three main operations to transform a Go module into a distributable Python wheel. First, it validates that the input directory is a valid Go module containing a `go.mod` file. Second, it cross-compiles the Go binary for each requested target platform using environment variables `GOOS` and `GOARCH` with `CGO_ENABLED=0` to produce static binaries. Third, it creates a Python package structure with a thin wrapper that executes the bundled binary, then packages everything into a wheel file following PEP 427 conventions.

资料来源：[spec.md:80-95]()

The resulting wheel can be installed with pip, which extracts the bundled Go binary and creates console entry points that make the tool available on the system PATH. This means users can install and run Go-compiled tools exactly as they would any other Python package, without needing to understand that the underlying implementation is written in Go.

资料来源：[README.md:55-65]()

### How It Works

The build process follows a precise sequence of operations to ensure compatibility across all supported platforms. The tool begins by validating the input Go module directory and verifying that Go is installed and accessible. It then iterates through each requested platform, setting the appropriate environment variables and running the Go compiler with flags optimized for static binary production.

```mermaid
graph TD
    A[Start: go-to-wheel] --> B{Validate Go Module}
    B -->|go.mod exists| C[Parse Package Metadata]
    B -->|No go.mod| E[Error: Not a Go module]
    C --> D{For each target platform}
    D --> F[Cross-compile with GOOS/GOARCH]
    F --> G[CGO_ENABLED=0 for static binary]
    G --> H[Generate Python wrapper]
    H --> I[Create wheel structure]
    I --> J[Zip into .whl file]
    J --> D
    D -->|All platforms done| K[Output wheels to ./dist]
    K --> L[Success]
```

资料来源：[spec.md:85-100]()

The cross-compilation step uses `CGO_ENABLED=0` to ensure that the resulting binaries are fully static and have no libc dependencies, which is essential for compatibility across different Linux distributions and container environments. The `-ldflags="-s -w"` flags strip debug information and reduce binary size for more efficient distribution.

资料来源：[README.md:45-50]()

## Supported Platforms

`go-to-wheel` supports a comprehensive range of target platforms across Linux, macOS, and Windows operating systems, covering both x86_64 and ARM architectures. The tool provides different wheel tags depending on whether the target uses glibc (standard Linux) or musl (Alpine Linux and similar distributions).

### Platform Mapping

| Target Platform | GOOS | GOARCH | Wheel Tag |
|-----------------|------|--------|-----------|
| linux-amd64 | linux | amd64 | manylinux_2_17_x86_64 |
| linux-arm64 | linux | arm64 | manylinux_2_17_aarch64 |
| linux-amd64-musl | linux | amd64 | musllinux_1_2_x86_64 |
| linux-arm64-musl | linux | arm64 | musllinux_1_2_aarch64 |
| darwin-amd64 | darwin | amd64 | macosx_10_9_x86_64 |
| darwin-arm64 | darwin | arm64 | macosx_11_0_arm64 |
| windows-amd64 | windows | amd64 | win_amd64 |
| windows-arm64 | windows | arm64 | win_arm64 |

资料来源：[README.md:35-45]()

### Default Platform Behavior

By default, `go-to-wheel` builds wheels for all eight supported platforms, ensuring maximum compatibility for distribution. Users can optionally specify a subset of platforms using the `--platforms` flag with a comma-separated list of target platforms, which is useful when building for specific deployment environments or when cross-compilation toolchains are not available for all targets.

资料来源：[spec.md:40-45]()

## Installation and Requirements

### Prerequisites

The tool itself requires Python 3.10 or later and has no external Python dependencies—it uses only the Python standard library. For building Go binaries, Go 1.16 or later is required due to the use of `go mod` commands.

资料来源：[spec.md:115-120]()

### Installation Methods

`go-to-wheel` can be installed using standard Python package installation tools:

```bash
pip install go-to-wheel
# or
pipx install go-to-wheel
```

资料来源：[README.md:20-25]()

After installation, Go must be available in the system PATH. The tool will automatically detect the Go binary or can be configured to use a specific path via the `--go-binary` option.

## Command Line Interface

### Basic Usage

The simplest usage of `go-to-wheel` requires only a path to the Go module directory:

```bash
go-to-wheel path/to/go-module
```

资料来源：[README.md:30-35]()

This command creates wheels in the `./dist` directory for all supported platforms using default metadata values.

### Command 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 | None |
| `--set-version-var VAR` | Go variable for version via `-X` ldflag | None |
| `--ldflags FLAGS` | Additional Go linker flags | None |

资料来源：[spec.md:25-45]()

## Wheel Structure

Each generated wheel follows PEP 427 format with a specific internal structure that enables proper execution of the bundled Go binary.

### File Structure

```
{package_name}-{version}-py3-none-{platform_tag}.whl
├── {package_name}/
│   ├── __init__.py
│   ├── __main__.py
│   └── bin/
│       └── {binary_name}[.exe]
├── {package_name}-{version}.dist-info/
│   ├── METADATA
│   ├── WHEEL
│   ├── RECORD
│   └── entry_points.txt
```

资料来源：[spec.md:60-70]()

### Python Wrapper Mechanism

The Python wrapper in `__init__.py` provides the execution mechanism for the bundled binary. It uses `os.execvp()` on Unix systems to replace the Python process with the Go binary, ensuring proper signal handling and exit code propagation. On Windows, it uses `subprocess.call()` to achieve similar behavior with proper signal handling.

资料来源：[spec.md:60-90]()

```python
def main():
    """Execute the bundled binary."""
    binary = get_binary_path()
    if sys.platform == "win32":
        # On Windows, use subprocess to properly handle signals
        sys.exit(subprocess.call([binary] + sys.argv[1:]))
    else:
        # On Unix, exec replaces the process
        os.execvp(binary, [binary] + sys.argv[1:])
```

资料来源：[spec.md:75-85]()

### Why Python Wrapper vs .data/scripts

The specification uses a Python wrapper with `console_scripts` entry point rather than placing the binary directly in `.data/scripts/` for several important reasons. First, it provides consistent behavior across all platforms without platform-specific edge cases. Second, it enables better error messages if the binary is missing or incompatible with the system. Third, it offers future flexibility for adding Python-side features such as version checking or update notifications. Fourth, it works seamlessly with `pipx install` for isolated application installations.

资料来源：[spec.md:90-100]()

## Use Cases

### Distributing Go Tools to Python Users

The primary use case for `go-to-wheel` is distributing Go CLI tools to Python developers who prefer to use `pip` or `pipx` for managing command-line tools. This is particularly valuable for tools that have natural appeal to the Python community or tools that need to be installed alongside Python packages as dependencies.

资料来源：[README.md:8-12]()

### PyPI Distribution

Go binaries packaged as wheels can be uploaded to PyPI, making them available through the standard Python package index. This enables distribution to millions of Python developers who can install the tool with a single `pip install` command, without needing to understand Go compilation or maintain separate release artifacts.

### pipx Isolation

Wheels built with `go-to-wheel` work seamlessly with `pipx`, which provides isolated Python environments for command-line tools. Users can install Go-compiled tools in isolation to avoid dependency conflicts:

```bash
pipx install ./dist/mytool-1.0.0-py3-none-manylinux_2_17_x86_64.whl
```

资料来源：[README.md:60-65]()

## Advanced Features

### Version Embedding

Go-to-wheel supports embedding the package version into the Go binary at compile time using Go linker flags. This requires a `var version` declaration in the Go source code. When the `--set-version-var` option is used, the tool automatically passes the value from `--version` to the Go linker via the `-X` flag.

资料来源：[README.md:50-55]()

A typical Go pattern for version embedding:

```go
var version = "dev"

func main() {
    if os.Args[1] == "--version" {
        fmt.Println(version) // prints "2.0.0" when built with --set-version-var
    }
}
```

资料来源：[README.md:50-60]()

### Custom Linker Flags

Additional Go linker flags can be passed using the `--ldflags` option, which are appended to the default `-s -w` flags. This allows for custom version strings, commit hashes, or other build-time information:

```bash
go-to-wheel ./mytool --version 2.0.0 \
  --ldflags "-X main.version=2.0.0 -X main.commit=abc123"
```

资料来源：[README.md:60-65]()

### README Integration

The `--readme` option allows embedding a README markdown file into the wheel's METADATA, which is displayed on the PyPI package page:

```bash
go-to-wheel ./mytool --readme README.md
```

资料来源：[spec.md:42]()

## Development

### Running Tests

The project uses pytest for testing. After cloning the repository, tests can be run with:

```bash
git clone https://github.com/simonw/go-to-wheel
cd go-to-wheel
uv run pytest
```

资料来源：[README.md:70-75]()

### Project Architecture

The tool is implemented as a single Python module (`go_to_wheel/__init__.py`) with no external dependencies. The main components include argument parsing, cross-compilation orchestration, wheel file generation, and metadata file creation. This simple architecture makes the tool easy to understand, maintain, and extend.

## Related Tools

`go-to-wheel` was inspired by similar tools in the Rust ecosystem. The primary inspiration is `maturin`, which provides the same functionality for Rust programs with Python bindings. Additionally, `pip-binary-factory` serves as a template for packaging pre-built binaries.

资料来源：[README.md:75-80]()

| Tool | Language | Repository |
|------|----------|------------|
| go-to-wheel | Go | simonw/go-to-wheel |
| maturin | Rust | PyO3/maturin |
| pip-binary-factory | Template | Bing-su/pip-binary-factory |

## License

`go-to-wheel` is released under the Apache 2.0 license, allowing for both personal and commercial use with minimal restrictions.

资料来源：[README.md:12]()

## Summary

`go-to-wheel` provides a valuable bridge between the Go and Python ecosystems by enabling Go CLI programs to be packaged and distributed as standard Python wheels. With support for eight target platforms, flexible metadata configuration, and seamless integration with pip and pipx, it offers Go developers a straightforward path to reaching Python's extensive user base. The tool's single-file implementation with no external dependencies ensures reliability and ease of installation, making it a practical choice for distributing Go tools to the Python community.

---

<a id='page-installation'></a>

## Installation

### 相关页面

相关主题：[Introduction](#page-introduction), [Development Guide](#page-development-guide)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/simonw/go-to-wheel/blob/main/README.md)
- [spec.md](https://github.com/simonw/go-to-wheel/blob/main/spec.md)
- [go_to_wheel/__init__.py](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)
</details>

# Installation

`go-to-wheel` is a Python tool that compiles Go CLI programs into Python wheels. Installing this tool correctly is the first step to packaging Go binaries for PyPI distribution.

## Prerequisites

Before installing `go-to-wheel`, ensure your environment meets the following requirements:

| Requirement | Version | Description |
|-------------|---------|-------------|
| Python | >= 3.10 | The tool is implemented in Python and requires this version or higher |
| Go | >= 1.16 | Required for building Go modules with `go mod` support |

资料来源：[spec.md](https://github.com/simonw/go-to-wheel/blob/main/spec.md)

### Python Dependencies

`go-to-wheel` has **no external Python dependencies**. The tool uses only Python's standard library for all operations:

- `argparse` - Command-line argument parsing
- `zipfile` - Wheel creation
- `subprocess` - Go compilation execution
- `hashlib` / `base64` - RECORD file hash generation
- `tempfile` / `shutil` - Temporary directory management

资料来源：[go_to_wheel/__init__.py:1-20](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

### Go Installation Verification

To verify Go is installed and accessible:

```bash
go version
```

Ensure `go` is in your system's `PATH` environment variable.

## Installation Methods

### Via pip (Recommended for Users)

```bash
pip install go-to-wheel
```

资料来源：[README.md](https://github.com/simonw/go-to-wheel/blob/main/README.md)

This method installs `go-to-wheel` globally in your Python environment.

### Via pipx (Recommended for CLI Tools)

```bash
pipx install go-to-wheel
```

资料来源：[README.md](https://github.com/simonw/go-to-wheel/blob/main/README.md)

`pipx` is preferred for CLI applications because it:

- Creates an isolated virtual environment for the tool
- Automatically manages PATH shims for the installed command
- Avoids dependency conflicts with other Python packages

## Installation Workflow

```mermaid
graph TD
    A[Choose Installation Method] --> B{pip or pipx?}
    B -->|pip| C[Run pip install go-to-wheel]
    B -->|pipx| D[Run pipx install go-to-wheel]
    C --> E[Download from PyPI]
    D --> E
    E --> F[Install to Python environment]
    F --> G[Create executable entry point]
    G --> H[go-to-wheel ready to use]
```

## Post-Installation Verification

After installation, verify the tool is working:

```bash
go-to-wheel --version
```

Expected output:
```
go-to-wheel v0.1.0
```

资料来源：[go_to_wheel/__init__.py](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

## Usage Requirements

Once installed, you need a Go module to package:

```bash
# Verify you have a Go module
cd path/to/your-go-module
ls go.mod
```

The tool will:
1. Cross-compile the Go binary for multiple platforms
2. Create Python wheels with proper metadata
3. Bundle everything into installable packages

资料来源：[spec.md](https://github.com/simonw/go-to-wheel/blob/main/spec.md)

## Quick Start After Installation

```bash
# Build wheels for all platforms
go-to-wheel path/to/go-module

# Or with custom options
go-to-wheel ./mytool --name my-python-tool --version 1.0.0
```

资料来源：[README.md](https://github.com/simonw/go-to-wheel/blob/main/README.md)

## Troubleshooting

| Issue | Solution |
|-------|----------|
| `go-to-wheel: command not found` | Ensure pip's Scripts directory is in PATH, or use `python -m go_to_wheel` |
| Go not found | Install Go from [go.dev](https://go.dev) and ensure it's in PATH |
| Python version error | Upgrade to Python 3.10 or higher |
| Permission denied | Use `pip install --user` or `pipx install` instead of system-wide install |

---

<a id='page-quick-start'></a>

## Quick Start Guide

### 相关页面

相关主题：[CLI Options Reference](#page-cli-options), [Usage Examples](#page-examples)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/simonw/go-to-wheel/blob/main/README.md)
- [go_to_wheel/__init__.py](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)
- [spec.md](https://github.com/simonw/go-to-wheel/blob/main/spec.md)
</details>

# Quick Start Guide

## Overview

The **Quick Start Guide** provides the fastest path for developers to begin using go-to-wheel to compile Go CLI programs into installable Python wheels. This tool addresses a gap in the Go/Python ecosystem—there is no equivalent to Rust's `maturin --bindings bin` for Go. Go-to-wheel takes a Go module directory, cross-compiles it for multiple platforms, and produces properly-tagged Python wheels installable via `pip` or `pipx`. 资料来源：[README.md:1-10]()

## Prerequisites

Before using go-to-wheel, ensure your environment meets the following requirements:

| Requirement | Version | Notes |
|-------------|---------|-------|
| Python | >= 3.10 | Required for installation and running the tool |
| Go | >= 1.16 | Required for building Go modules 资料来源：[spec.md:145-150]() |
| Go Module | Valid `go.mod` | The source Go project must be a Go module |

Go must be installed and available in your system PATH. No external Python dependencies are required—go-to-wheel uses only the Python standard library. 资料来源：[go_to_wheel/__init__.py:1-15]()

## Installation

Install go-to-wheel using pip or pipx:

```bash
pip install go-to-wheel
# or
pipx install go-to-wheel
```

Verify the installation:

```bash
go-to-wheel --version
```

## Basic Usage

### Minimal Command

Build wheels for all supported platforms using the simplest invocation:

```bash
go-to-wheel path/to/go-module
```

This command will:

1. Cross-compile the Go binary for all default platforms
2. Create a Python package with a thin wrapper
3. Package everything into wheels in `./dist` directory
4. Use the directory name as the package name with version `0.1.0` 资料来源：[README.md:35-50]()

### Build Flow

```mermaid
graph TD
    A[Go Module Directory] --> B[Validate go.mod exists]
    B --> C[Cross-compile Go binary for each platform]
    C --> D[Create Python package structure]
    D --> E[Generate wheel metadata]
    E --> F[Package into .whl file]
    F --> G[Move to output directory]
```

## Command Options

The following table documents all available command-line 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 (e.g., MIT) | 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 | None |
| `--set-version-var VAR` | Go variable to set via `-X` ldflag | None |
| `--ldflags FLAGS` | Additional Go linker flags | None | 资料来源：[README.md:20-35]()

## Supported Platforms

Go-to-wheel supports cross-compilation to the following target platforms:

| Platform Identifier | GOOS | GOARCH | Wheel Tag |
|---------------------|------|--------|-----------|
| `linux-amd64` | linux | amd64 | `manylinux_2_17_x86_64` |
| `linux-arm64` | linux | arm64 | `manylinux_2_17_aarch64` |
| `linux-amd64-musl` | linux | amd64 | `musllinux_1_2_x86_64` |
| `linux-arm64-musl` | linux | arm64 | `musllinux_1_2_aarch64` |
| `darwin-amd64` | darwin | amd64 | `macosx_10_9_x86_64` |
| `darwin-arm64` | darwin | arm64 | `macosx_11_0_arm64` |
| `windows-amd64` | windows | amd64 | `win_amd64` |
| `windows-arm64` | windows | arm64 | `win_arm64` | 资料来源：[go_to_wheel/__init__.py:20-30]()

## Common Use Cases

### Custom Package Name

Build wheels with a custom Python package name:

```bash
go-to-wheel ./mytool --name my-python-tool
```

### Build for Specific Platforms Only

Reduce build time by targeting only required platforms:

```bash
go-to-wheel ./mytool --platforms linux-amd64,darwin-arm64
```

### Embed Version into Go Binary

Pass the version to the Go binary at compile time using linker flags. First, add a version variable to your Go source:

```go
var version = "dev"

func main() {
    if os.Args[1] == "--version" {
        fmt.Println(version)
    }
}
```

Then build with:

```bash
go-to-wheel ./mytool --version 2.0.0 --set-version-var main.version
```

This passes `-X main.version=2.0.0` to the Go linker. The flags are appended to the default `-s -w`, resulting in `-ldflags="-s -w -X main.version=2.0.0"`. 资料来源：[README.md:55-75]()

### Full Metadata for PyPI

Publish to PyPI with complete metadata:

```bash
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
```

### Custom Linker Flags

Pass arbitrary Go linker flags for additional build-time configuration:

```bash
go-to-wheel ./mytool --version 2.0.0 \
  --ldflags "-X main.version=2.0.0 -X main.commit=abc123"
```

## How It Works

The build process consists of four main steps:

```mermaid
graph LR
    A[Cross-compile Go Binary] --> B[Create Python Package]
    B --> C[Generate Metadata Files]
    C --> D[Package into Wheel]
```

### Step 1: Cross-Compilation

For each target platform, go-to-wheel executes:

```bash
GOOS={goos} GOARCH={goarch} CGO_ENABLED=0 go build \
  -ldflags="-s -w" \
  -o {output_path} \
  {go_module_path}
```

Key points:
- `CGO_ENABLED=0` ensures static binaries with no libc dependency issues
- `-ldflags="-s -w"` strips debug information to reduce binary size
- Windows builds automatically receive `.exe` extension 资料来源：[spec.md:100-115]()

### Step 2: Python Package Structure

Each wheel contains a Python wrapper that executes the bundled binary:

```
{package_name}-{version}-py3-none-{platform_tag}.whl
├── {package_name}/
│   ├── __init__.py
│   ├── __main__.py
│   └── bin/
│       └── {binary_name}[.exe]
├── {package_name}-{version}.dist-info/
│   ├── METADATA
│   ├── WHEEL
│   ├── RECORD
│   └── entry_points.txt
```

The `__init__.py` file contains a `main()` function that:
- On Windows: uses `subprocess.call()` for proper signal handling
- On Unix: uses `os.execvp()` to replace the Python process 资料来源：[spec.md:60-95]()

### Step 3: Metadata Generation

Generated METADATA follows PEP 566:

```
Metadata-Version: 2.1
Name: {package_name}
Version: {version}
Summary: {description}
License: {license}
Author: {author}
Author-email: {author_email}
Home-page: {url}
Requires-Python: {requires_python}
```

The WHEEL file follows PEP 427:

```
Wheel-Version: 1.0
Generator: go-to-wheel {version}
Root-Is-Purelib: false
Tag: py3-none-{platform_tag}
```

### Step 4: Entry Points

Console script entry points are defined in `entry_points.txt`:

```
[console_scripts]
{entry_point} = {package_name}:main
```

The tool uses Python wrapper entry points rather than `.data/scripts/` because:
- Consistent behavior across all platforms
- Better error messages if binary is missing
- Future flexibility for Python-side features
- Seamless pipx compatibility 资料来源：[spec.md:95-105]()

## Testing Built Wheels

### Install with pip

```bash
pip install ./dist/mytool-1.0.0-py3-none-manylinux_2_17_x86_64.whl
```

### Test with uv

```bash
uv run --with ./dist/mytool-1.0.0-py3-none-manylinux_2_17_x86_64.whl mytool --help
```

### Run with pipx

```bash
pipx install ./dist/mytool-1.0.0-py3-none-manylinux_2_17_x86_64.whl
```

After installation, the Go binary is available on your PATH through the Python wrapper. 资料来源：[README.md:100-115]()

## Development

To contribute or customize go-to-wheel:

```bash
# Clone the repository
git clone https://github.com/simonw/go-to-wheel
cd go-to-wheel

# Run tests
uv run pytest
```

## Package Name Validation

Package names must follow PEP 503 naming rules:

| Rule | Description |
|------|-------------|
| Allowed characters | Lowercase letters, digits, hyphens, underscores, periods |
| Must start with | Letter or digit |
| Normalization | Hyphens and underscores become hyphens in wheel filename |

The import name (Python package directory) follows PEP 8:
- Hyphens are replaced with underscores
- Example: `my-tool` becomes `my_tool/` directory 资料来源：[spec.md:130-140]()

## Troubleshooting

| Issue | Solution |
|-------|----------|
| "No go.mod file found" | Ensure the path points to a valid Go module directory |
| "Go compilation failed" | Verify Go is installed and the module builds correctly standalone |
| Invalid package name | Follow PEP 503 naming rules (lowercase, alphanumeric with hyphens/underscores) |

## See Also

- [maturin](https://github.com/PyO3/maturin) - The Rust equivalent that inspired this tool
- [pip-binary-factory](https://github.com/Bing-su/pip-binary-factory) - Template for packaging pre-built binaries
- [Distributing Go binaries like sqlite-scanner through PyPI using go-to-wheel](https://simonwillison.net/2026/Feb/4/distributing-go-binaries/) - Background article on this project 资料来源：[README.md:120-130]()

---

<a id='page-cli-options'></a>

## CLI Options Reference

### 相关页面

相关主题：[Quick Start Guide](#page-quick-start), [Configuration and Metadata](#page-configuration)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [go_to_wheel/__init__.py](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)
- [README.md](https://github.com/simonw/go-to-wheel/blob/main/README.md)
- [spec.md](https://github.com/simonw/go-to-wheel/blob/main/spec.md)
</details>

# CLI Options Reference

## Overview

The `go-to-wheel` CLI provides comprehensive options for cross-compiling Go binaries into Python wheels. The command follows the structure:

```bash
go-to-wheel path/to/go-folder [options]
```

All options are passed as space-separated arguments after the path to the Go module directory. 资料来源：[README.md](https://github.com/simonw/go-to-wheel/blob/main/README.md)

## Complete Options Reference

### Core Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `path/to/go-folder` | positional | required | Path to Go module directory containing go.mod |
| `--name NAME` | string | Directory basename | Python package name for the wheel |
| `--version VERSION` | string | `0.1.0` | Package version string |
| `--output-dir DIR` | string | `./dist` | Directory where built wheels are written |
| `--entry-point NAME` | string | Same as package name | CLI command name exposed after installation |
| `--go-binary PATH` | string | `go` | Path to Go binary in PATH |

资料来源：[go_to_wheel/__init__.py:52-85](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

### Metadata Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `--description TEXT` | string | `"Go binary packaged as Python wheel"` | Package summary for PyPI |
| `--license LICENSE` | string | None | SPDX license identifier (e.g., MIT, Apache-2.0) |
| `--author AUTHOR` | string | None | Author name |
| `--author-email EMAIL` | string | None | Author email address |
| `--url URL` | string | None | Project homepage URL |
| `--requires-python VERSION` | string | `>=3.10` | Python version requirement |
| `--readme PATH` | string | None | Path to README.md for PyPI long description |

资料来源：[go_to_wheel/__init__.py:86-115](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

### Build Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `--platforms PLATFORMS` | string | All 8 platforms | Comma-separated list of target platforms |
| `--ldflags FLAGS` | string | None | Additional Go linker flags appended to `-s -w` |
| `--set-version-var VAR` | string | None | Go variable name for version embedding via `-X` |

资料来源：[go_to_wheel/__init__.py:116-128](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

## Supported Platforms

The following platform targets are available for cross-compilation:

| Platform Identifier | GOOS | GOARCH | Wheel Tag |
|-------------------|------|--------|-----------|
| `linux-amd64` | linux | amd64 | manylinux_2_17_x86_64 |
| `linux-arm64` | linux | arm64 | manylinux_2_17_aarch64 |
| `linux-amd64-musl` | linux | amd64 | musllinux_1_2_x86_64 |
| `linux-arm64-musl` | linux | arm64 | musllinux_1_2_aarch64 |
| `darwin-amd64` | darwin | amd64 | macosx_10_9_x86_64 |
| `darwin-arm64` | darwin | arm64 | macosx_11_0_arm64 |
| `windows-amd64` | windows | amd64 | win_amd64 |
| `windows-arm64` | windows | arm64 | win_arm64 |

资料来源：[go_to_wheel/__init__.py:25-35](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

### Platform Selection Syntax

Specify multiple platforms using comma-separated values:

```bash
go-to-wheel ./mytool --platforms linux-amd64,darwin-arm64,windows-amd64
```

## Version Embedding

The `--set-version-var` option enables embedding the package version into the Go binary at compile time. This requires a matching variable in the Go source:

```go
var version = "dev"

func main() {
    if len(os.Args) > 1 && os.Args[1] == "--version" {
        fmt.Println(version)
    }
}
```

Build command with version embedding:

```bash
go-to-wheel ./mytool --version 2.0.0 --set-version-var main.version
```

This passes `-X main.version=2.0.0` to the Go linker. 资料来源：[README.md](https://github.com/simonw/go-to-wheel/blob/main/README.md)

## Advanced Ldflags

The `--ldflags` option appends custom linker flags to the default `-s -w` flags (which strip debug info):

```bash
go-to-wheel ./mytool --ldflags "-X main.commit=abc123 -X main.date=2024-01-15"
```

The combined ldflags become: `-s -w -X main.commit=abc123 -X main.date=2024-01-15`

## Usage Examples

### Minimal Build

```bash
go-to-wheel ./mytool
```

Produces wheels for all 8 platforms using default settings. 资料来源：[README.md](https://github.com/simonw/go-to-wheel/blob/main/README.md)

### Custom Package Name

```bash
go-to-wheel ./mytool --name my-python-tool
```

Creates `my-python-tool-0.1.0-py3-none-*.whl` files.

### PyPI-Ready Build

```bash
go-to-wheel ./mytool \
  --name mytool-bin \
  --version 2.0.0 \
  --description "My awesome CLI tool" \
  --license MIT \
  --author "Jane Doe" \
  --author-email "jane@example.com" \
  --url "https://github.com/jane/mytool" \
  --readme README.md
```

### Platform-Specific Build

```bash
go-to-wheel ./mytool --platforms linux-amd64,darwin-arm64
```

### With Version Embedding

```bash
go-to-wheel ./mytool --version 1.2.3 --set-version-var main.version
```

## Option Processing Flow

```mermaid
graph TD
    A[Parse CLI Arguments] --> B[Validate go_dir exists]
    B --> C{Check go.mod}
    C -->|Valid| D[Set defaults]
    C -->|Invalid| E[Exit with error]
    D --> F[Parse platforms list]
    F --> G[Build ldflags]
    G --> H[Cross-compile for each platform]
    H --> I[Generate Python wheel]
    I --> J[Move to output-dir]
    J --> K[Print summary]
```

## Default Values Behavior

| Option | Default Source | Override Mechanism |
|--------|---------------|-------------------|
| Package name | `go_path.name` (directory basename) | `--name` |
| Version | `"0.1.0"` | `--version` |
| Entry point | Same as package name | `--entry-point` |
| Platforms | `DEFAULT_PLATFORMS` list (all 8) | `--platforms` |
| Go binary | `"go"` from PATH | `--go-binary` |
| Description | `"Go binary packaged as Python wheel"` | `--description` |
| Requires Python | `">=3.10"` | `--requires-python` |

资料来源：[go_to_wheel/__init__.py:175-190](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

## Error Handling

The CLI validates inputs and exits with descriptive errors:

| Error Condition | Exit Behavior |
|-----------------|---------------|
| Go directory not found | `FileNotFoundError: Go directory not found: <path>` |
| No go.mod file | `ValueError: Not a Go module: <path>` |
| Go binary not found | `FileNotFoundError` from subprocess |
| Compilation failure | `RuntimeError: Go compilation failed for <os>/<arch>` |
| No wheels built | `Error: No wheels were built` |

## Return Codes

| Code | Meaning |
|------|---------|
| 0 | Success - wheels built and written to output directory |
| 1 | Error occurred (invalid input, compilation failure, etc.) |

资料来源：[go_to_wheel/__init__.py:130-155](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

---

<a id='page-examples'></a>

## Usage Examples

### 相关页面

相关主题：[Quick Start Guide](#page-quick-start), [Wheel Generation Process](#page-wheel-generation)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/simonw/go-to-wheel/blob/main/README.md)
- [go_to_wheel/__init__.py](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)
- [spec.md](https://github.com/simonw/go-to-wheel/blob/main/spec.md)
</details>

# Usage Examples

This page provides comprehensive usage examples for `go-to-wheel`, demonstrating how to compile Go CLI programs into distributable Python wheels. The examples progress from basic usage to advanced configurations, covering all available command-line options and common use cases.

## Overview

`go-to-wheel` transforms Go binaries into Python packages that can be installed via `pip` or `pipx`. The tool handles cross-compilation for multiple platforms, generates proper Python wheel metadata, and creates installable packages with executable entry points. All examples assume Go is installed and available in the system PATH.

## Basic Usage

The simplest way to build wheels from a Go module is to pass the module directory path:

```bash
go-to-wheel ./mytool
```

This command:

1. Locates the Go module in `./mytool` (requires `go.mod` file)
2. Cross-compiles the binary for all supported platforms
3. Creates wheels in `./dist` directory
4. Uses the directory name as the package name
5. Defaults to version `0.1.0`

The resulting wheels follow the naming convention `{name}-{version}-py3-none-{platform_tag}.whl`.

## Command Line Options

### Option Reference Table

| Option | Description | Default Value |
|--------|-------------|---------------|
| `--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 | None |
| `--set-version-var VAR` | Go variable for `--version` value | None |
| `--ldflags FLAGS` | Additional Go linker flags | None |

资料来源：[go_to_wheel/__init__.py:1-100]()

## Platform Selection

### Build for All Platforms

By default, `go-to-wheel` builds wheels for all supported platforms:

| 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` |

资料来源：[README.md:1-50]()

### Build for Specific Platforms

To build only for specific platforms, use the `--platforms` option with a comma-separated list:

```bash
go-to-wheel ./mytool --platforms linux-amd64,darwin-arm64
```

This produces wheels for only Linux amd64 and macOS ARM64, reducing build time when you don't need all platform variants.

### Using a Custom Go Binary

If Go is not in your PATH or you need a specific version:

```bash
go-to-wheel ./mytool --go-binary /usr/local/go/bin/go
```

## Package Naming

### Custom Package Name

Override the default package name derived from the directory:

```bash
go-to-wheel ./mytool --name my-python-tool
```

This creates wheels named `my-python-tool-{version}-py3-none-{platform_tag}.whl`.

### Custom Entry Point

The CLI command name can differ from the package name:

```bash
go-to-wheel ./mytool --name my-tool-bin --entry-point mytool
```

This creates a package named `my-tool-bin` but installs the command as `mytool`.

## Version Management

### Setting Package Version

```bash
go-to-wheel ./mytool --version 2.0.0
```

### Embedding Version in Go Binary

To embed the version into the Go binary at compile time, define a version variable in your Go source:

```go
var version = "dev"

func main() {
    if os.Args[1] == "--version" {
        fmt.Println(version)
    }
}
```

Then use `--set-version-var` to pass the version via linker flags:

```bash
go-to-wheel ./mytool --version 2.0.0 --set-version-var main.version
```

This passes `-X main.version=2.0.0` to the Go linker. The combined linker flags become `-s -w -X main.version=2.0.0`.

资料来源：[README.md:50-80]()

## Custom Linker Flags

### Using ldflags

Pass arbitrary Go linker flags with `--ldflags`:

```bash
go-to-wheel ./mytool --version 2.0.0 \
  --ldflags "-X main.version=2.0.0 -X main.commit=abc123"
```

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"
```

The `-s` flag strips symbol table, and `-w` removes DWARF debugging information, reducing binary size.

资料来源：[spec.md:50-80]()

## Output Management

### Custom Output Directory

```bash
go-to-wheel ./mytool --output-dir ./wheels
```

### Installing Built Wheels

After building, install wheels with pip:

```bash
pip install ./dist/mytool-1.0.0-py3-none-manylinux_2_17_x86_64.whl
```

Or test directly with uv:

```bash
uv run --with ./dist/mytool-1.0.0-py3-none-manylinux_2_17_x86_64.whl mytool --help
```

## Complete Examples

### Basic Distribution

For internal distribution without PyPI publishing:

```bash
go-to-wheel ./mytool
```

### PyPI-Ready Distribution

Full metadata configuration for PyPI publishing:

```bash
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
```

This generates wheels with complete metadata suitable for publishing to PyPI. The `--readme` option sets the long description from your README file.

资料来源：[README.md:80-120]()

### Development Workflow

Typical development workflow:

```bash
# Build all wheels
go-to-wheel ./mytool --output-dir ./dist

# Test specific wheel
uv run --with ./dist/mytool-0.1.0-py3-none-manylinux_2_17_x86_64.whl mytool --help

# Install locally for testing
pip install ./dist/mytool-0.1.0-py3-none-manylinux_2_17_x86_64.whl

# Uninstall after testing
pip uninstall mytool
```

## Build Process Flow

```mermaid
graph TD
    A[go-to-wheel command] --> B[Validate Go directory]
    B --> C[Check go.mod exists]
    C --> D{For each platform}
    D --> E[Cross-compile with GOOS/GOARCH]
    E --> F[Create Python package structure]
    F --> G[Generate __init__.py and __main__.py]
    G --> H[Generate METADATA and WHEEL files]
    H --> I[Calculate RECORD with SHA256]
    I --> J[Zip into wheel file]
    J --> K{More platforms?}
    K -->|Yes| D
    K -->|No| L[Move wheels to output dir]
    L --> M[Print summary]
```

The build process uses `CGO_ENABLED=0` for static binaries, ensuring compatibility across different Linux distributions without libc dependencies.

资料来源：[spec.md:30-60]()

## Error Handling

Common errors and solutions:

| Error | Cause | Solution |
|-------|-------|----------|
| `Go directory not found` | Invalid path | Verify the directory exists |
| `Not a Go module` | Missing `go.mod` | Ensure directory contains `go.mod` |
| `Go compilation failed` | Build error in Go code | Check Go source for errors |
| `No wheels were built` | Platform validation failed | Verify platform names are correct |

资料来源：[go_to_wheel/__init__.py:150-200]()

## Quick Reference

| Task | Command |
|------|---------|
| Build all wheels | `go-to-wheel ./mytool` |
| Custom name | `go-to-wheel ./mytool --name my-package` |
| Specific version | `go-to-wheel ./mytool --version 1.2.3` |
| Specific platforms | `go-to-wheel ./mytool --platforms linux-amd64,darwin-arm64` |
| With metadata | `go-to-wheel ./mytool --author "Name" --license MIT --readme README.md` |
| Embed version | `go-to-wheel ./mytool --version 1.0 --set-version-var main.version` |

---

<a id='page-architecture'></a>

## System Architecture

### 相关页面

相关主题：[Wheel Generation Process](#page-wheel-generation), [Supported Platforms](#page-platforms)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [go_to_wheel/__init__.py](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)
- [spec.md](https://github.com/simonw/go-to-wheel/blob/main/spec.md)
- [README.md](https://github.com/simonw/go-to-wheel/blob/main/README.md)
</details>

# System Architecture

## Overview

go-to-wheel is a Python CLI tool that bridges the Go and Python packaging ecosystems. It takes a Go module directory, cross-compiles it for multiple target platforms, and packages each binary as a PEP 427-compliant Python wheel with executable entry points. This enables Go binaries to be distributed and installed via `pip` or `pipx`.

资料来源：[spec.md](https://github.com/simonw/go-to-wheel/blob/main/spec.md)

## Architecture Components

The system consists of four primary components working in sequence:

```mermaid
graph TD
    A[Go Module Input] --> B[Input Validation]
    B --> C[Cross-Compilation Engine]
    C --> D[Wheel Builder]
    D --> E[Output Wheels]
    
    B --> B1[Verify go.mod exists]
    B --> B2[Validate package name]
    C --> C1[GOOS/GOARCH env vars]
    C --> C2[CGO_ENABLED=0]
    D --> D1[Generate METADATA]
    D --> D2[Generate WHEEL]
    D --> D3[Generate RECORD]
    D --> D4[Create zip archive]
```

### Component Responsibilities

| Component | Purpose | Key Functions |
|-----------|---------|---------------|
| **CLI Parser** | Parse command-line arguments | `argparse`, argument validation |
| **Input Validator** | Verify Go module structure | Path existence, `go.mod` detection |
| **Cross-Compiler** | Build binaries for target platforms | `subprocess.run()`, env var management |
| **Wheel Builder** | Create PEP 427 compliant wheels | `zipfile`, metadata generation |

资料来源：[go_to_wheel/__init__.py:1-50](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

## Platform Mapping System

The platform mapping system translates human-readable platform names into Go build environment variables and Python wheel tags.

```mermaid
graph LR
    P1["linux-amd64"] --> PM1["PLATFORM_MAPPINGS"]
    P2["darwin-arm64"] --> PM1
    P3["windows-amd64"] --> PM1
    
    PM1 --> G["GOOS/GOARCH"]
    PM1 --> W["Wheel Tag"]
    
    G --> G1["linux/amd64"]
    W --> W1["manylinux_2_17_x86_64"]
```

### Platform Mapping Table

| Platform Name | GOOS | GOARCH | Wheel Tag |
|---------------|------|--------|-----------|
| `linux-amd64` | `linux` | `amd64` | `manylinux_2_17_x86_64` |
| `linux-arm64` | `linux` | `arm64` | `manylinux_2_17_aarch64` |
| `linux-amd64-musl` | `linux` | `amd64` | `musllinux_1_2_x86_64` |
| `linux-arm64-musl` | `linux` | `arm64` | `musllinux_1_2_aarch64` |
| `darwin-amd64` | `darwin` | `amd64` | `macosx_10_9_x86_64` |
| `darwin-arm64` | `darwin` | `arm64` | `macosx_11_0_arm64` |
| `windows-amd64` | `windows` | `amd64` | `win_amd64` |
| `windows-arm64` | `windows` | `arm64` | `win_arm64` |

资料来源：[go_to_wheel/__init__.py:23-32](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

## Build Process Workflow

```mermaid
flowchart TD
    START[Start build_wheels] --> V1{Go directory exists?}
    V1 -->|No| ERROR1[FileNotFoundError]
    V1 -->|Yes| V2{go.mod exists?}
    V2 -->|No| ERROR2[ValueError]
    V2 -->|Yes| PARSE[Parse arguments]
    
    PARSE --> SETUP[Set defaults<br/>name, entry_point,<br/>platforms]
    
    SETUP --> FOR_LOOP[For each platform]
    FOR_LOOP --> CROSS[cross_compile_go]
    
    CROSS --> BUILD[Build wheel structure]
    BUILD --> GEN_INIT[Generate __init__.py]
    BUILD --> GEN_MAIN[Generate __main__.py]
    BUILD --> GEN_META[Generate METADATA]
    BUILD --> GEN_WHEEL[Generate WHEEL]
    BUILD --> GEN_RECORD[Generate RECORD]
    BUILD --> GEN_ENTRY[Generate entry_points.txt]
    
    GEN_INIT --> ZIP[Create wheel.zip]
    GEN_MAIN --> ZIP
    GEN_META --> ZIP
    GEN_WHEEL --> ZIP
    GEN_RECORD --> ZIP
    GEN_ENTRY --> ZIP
    
    ZIP --> NEXT{More platforms?}
    NEXT -->|Yes| FOR_LOOP
    NEXT -->|No| OUTPUT[Move wheels to output_dir]
    OUTPUT --> DONE[Return wheel paths]
```

### Cross-Compilation Details

The cross-compilation step uses Go's built-in cross-compilation support:

```bash
GOOS={goos} GOARCH={goarch} CGO_ENABLED=0 go build \
  -ldflags="-s -w" \
  -o {output_path} \
  {go_module_path}
```

Key compilation flags:
- `CGO_ENABLED=0`: Disables C bindings for static binaries
- `-ldflags="-s -w"`: Strips debug info and symbol tables
- `.exe` extension added automatically on Windows

资料来源：[spec.md](https://github.com/simonw/go-to-wheel/blob/main/spec.md)

## Wheel Structure

Each generated wheel follows the PEP 427 standard structure:

```
{package_name}-{version}-py3-none-{platform_tag}.whl
├── {package_name}/
│   ├── __init__.py
│   ├── __main__.py
│   └── bin/
│       └── {binary_name}[.exe]
├── {package_name}-{version}.dist-info/
│   ├── METADATA
│   ├── WHEEL
│   ├── RECORD
│   └── entry_points.txt
```

资料来源：[spec.md](https://github.com/simonw/go-to-wheel/blob/main/spec.md)

### Generated File Contents

#### `__init__.py`

The wrapper module that locates and executes the bundled binary:

```python
"""Go binary packaged as Python wheel."""

import os
import stat
import subprocess
import sys

__version__ = "{version}"

def get_binary_path():
    """Return the path to the bundled binary."""
    binary = os.path.join(os.path.dirname(__file__), "bin", "{binary_name}")

    # Ensure binary is executable on Unix
    if sys.platform != "win32":
        current_mode = os.stat(binary).st_mode
        if not (current_mode & stat.S_IXUSR):
            os.chmod(binary, current_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
    return binary

def main():
    """Execute the bundled binary."""
    binary = get_binary_path()
    if sys.platform == "win32":
        sys.exit(subprocess.call([binary] + sys.argv[1:]))
    else:
        os.execvp(binary, [binary] + sys.argv[1:])
```

资料来源：[go_to_wheel/__init__.py:75-100](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

#### METADATA (PEP 566)

```
Metadata-Version: 2.1
Name: {package_name}
Version: {version}
Summary: {description}
License: {license}
Author: {author}
Author-email: {author_email}
Home-page: {url}
Requires-Python: {requires_python}
```

#### WHEEL (PEP 427)

```
Wheel-Version: 1.0
Generator: go-to-wheel {go_to_wheel_version}
Root-Is-Purelib: false
Tag: py3-none-{platform_tag}
```

#### RECORD

CSV format with columns: `path,hash,size`

#### entry_points.txt

```
[console_scripts]
{entry_point} = {package_name}:main
```

资料来源：[spec.md](https://github.com/simonw/go-to-wheel/blob/main/spec.md)

## Command-Line Interface

### Options Table

| 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 8 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 | None |
| `--set-version-var VAR` | Go variable for version via `-X` | None |
| `--ldflags FLAGS` | Additional Go linker flags | None |

资料来源：[go_to_wheel/__init__.py:50-130](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

## Data Flow Diagram

```mermaid
flowchart LR
    subgraph Input
        A[Go Module Directory]
        B[CLI Arguments]
    end
    
    subgraph Processing
        C[Input Validation]
        D[Cross-Compilation]
        E[Metadata Generation]
        F[Zip Packaging]
    end
    
    subgraph Output
        G[Python Wheel Files]
        H[dist/ Directory]
    end
    
    A --> C
    B --> C
    C --> D
    D --> E
    E --> F
    F --> G
    G --> H
```

## Key Function Signatures

### `build_wheels()`

```python
def build_wheels(
    go_dir: str,
    *,
    name: str | None = None,
    version: str = "0.1.0",
    output_dir: str = "./dist",
    entry_point: str | None = None,
    platforms: list[str] | None = None,
    go_binary: str = "go",
    description: str = "Go binary packaged as Python wheel",
    requires_python: str = ">=3.10",
    author: str | None = None,
    author_email: str | None = None,
    license_: str | None = None,
    url: str | None = None,
    readme: str | None = None,
    ldflags: str | None = None,
    set_version_var: str | None = None,
) -> list[str]:
    """Build Python wheels from a Go module."""
```

资料来源：[go_to_wheel/__init__.py:150-200](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

### `cross_compile_go()`

```python
def cross_compile_go(
    go_dir: Path,
    output_path: Path,
    goos: str,
    goarch: str,
    go_binary: str = "go",
    ldflags: str | None = None,
) -> None:
    """Cross-compile Go binary for target platform."""
```

资料来源：[go_to_wheel/__init__.py:65-92](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

## Dependency Architecture

```mermaid
graph TD
    A[go-to-wheel] --> B[Python Standard Library]
    
    B --> B1[argparse]
    B --> B2[zipfile]
    B --> B3[subprocess]
    B --> B4[pathlib]
    B --> B5[hashlib]
    B --> B6[csv]
    
    A --> C[External Dependency]
    C --> C1[Go Toolchain]
```

### Python Dependencies

The tool uses only Python standard library modules, requiring no external Python dependencies:

- `argparse`: CLI argument parsing
- `zipfile`: Wheel archive creation
- `subprocess`: Go compilation invocation
- `pathlib`: Path manipulation
- `hashlib`: SHA256 hashing for RECORD
- `csv`: RECORD file generation
- `tempfile`: Temporary build directory
- `shutil`: File operations

### External Dependencies

- **Go >= 1.16**: Required for `go build` and cross-compilation

资料来源：[spec.md](https://github.com/simonw/go-to-wheel/blob/main/spec.md)

## Version Information

| Item | Value |
|------|-------|
| Project Version | `0.1.0` |
| Python Requirement | `>=3.10` |
| Go Requirement | `>=1.16` |
| License | Apache 2.0 |

资料来源：[go_to_wheel/__init__.py:10](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

## Installation Methods

```mermaid
graph TD
    A[User] --> B{Installation Method}
    
    B --> C[pip install]
    B --> D[pipx install]
    
    C --> E[System Python]
    D --> F[Isolated environment<br/>with PATH access]
    
    E --> G[Requires Go in PATH]
    F --> G
```

资料来源：[README.md](https://github.com/simonw/go-to-wheel/blob/main/README.md)

---

<a id='page-platforms'></a>

## Supported Platforms

### 相关页面

相关主题：[System Architecture](#page-architecture), [Wheel Generation Process](#page-wheel-generation)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [go_to_wheel/__init__.py](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)
- [README.md](https://github.com/simonw/go-to-wheel/blob/main/README.md)
- [spec.md](https://github.com/simonw/go-to-wheel/blob/main/spec.md)
</details>

# Supported Platforms

`go-to-wheel` provides comprehensive cross-platform support for distributing Go CLI binaries as Python wheels. The tool automatically generates wheels for all supported platforms with correct PEP 427 tags, enabling seamless installation via `pip` or `pipx`.

## Platform Architecture

`go-to-wheel` maps Go's `GOOS`/`GOARCH` environment variables to Python wheel platform tags. The mapping system allows for precise targeting of specific architectures while maintaining compatibility with the Python packaging ecosystem.

```mermaid
graph TD
    A[Go Source Code] --> B[go-to-wheel build]
    B --> C{Platform Selection}
    C -->|Default| D[All 8 Platforms]
    C -->|Custom| E[User-specified subset]
    
    D --> F[Cross-compile with GOOS/GOARCH]
    E --> F
    
    F --> G[Generate wheel with platform tag]
    G --> H[Installable via pip/pipx]
```

资料来源：[go_to_wheel/__init__.py:9-27](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

## Default Supported Platforms

The following 8 platform targets are built by default when no `--platforms` flag is specified:

| Platform Identifier | GOOS | GOARCH | Wheel Tag |
|---------------------|------|--------|-----------|
| `linux-amd64` | `linux` | `amd64` | `manylinux_2_17_x86_64` |
| `linux-arm64` | `linux` | `arm64` | `manylinux_2_17_aarch64` |
| `linux-amd64-musl` | `linux` | `amd64` | `musllinux_1_2_x86_64` |
| `linux-arm64-musl` | `linux` | `arm64` | `musllinux_1_2_aarch64` |
| `darwin-amd64` | `darwin` | `amd64` | `macosx_10_9_x86_64` |
| `darwin-arm64` | `darwin` | `arm64` | `macosx_11_0_arm64` |
| `windows-amd64` | `windows` | `amd64` | `win_amd64` |
| `windows-arm64` | `windows` | `arm64` | `win_arm64` |

资料来源：[go_to_wheel/__init__.py:9-27](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

## Platform Selection Options

### Building All Platforms (Default)

Without specifying platforms, all 8 targets are built:

```bash
go-to-wheel ./mytool
```

### Building Specific Platforms

Use the `--platforms` flag with a comma-separated list:

```bash
go-to-wheel ./mytool --platforms linux-amd64,darwin-arm64
```

Only Linux amd64 and macOS ARM64 wheels will be generated.

资料来源：[README.md](https://github.com/simonw/go-to-wheel/blob/main/README.md)

## Linux Variants

### glibc-based (manylinux)

The `linux-amd64` and `linux-arm64` targets produce binaries linked against glibc, using the `manylinux_2_17` container tag. These wheels are compatible with most modern Linux distributions including:

- Ubuntu 18.04+
- Debian 10+
- Fedora 30+
- RHEL/CentOS 8+
- Amazon Linux 2

### musl-based (musllinux)

The `linux-amd64-musl` and `linux-arm64-musl` targets produce static binaries linked against musl libc. These wheels target:

- Alpine Linux (all versions)
- OpenWrt
- Other musl-based distributions

Musl builds are compiled with `CGO_ENABLED=0` to ensure fully static linking, eliminating any libc dependency issues.

资料来源：[spec.md](https://github.com/simonw/go-to-wheel/blob/main/spec.md)

## macOS Support

### Universal2 Consideration

While `go-to-wheel` does not natively generate `darwin-universal2` wheels that combine both architectures, the tool can build both `darwin-amd64` and `darwin-arm64` separately. Users can combine them using Apple's `lipo` tool if a single universal binary is required:

```bash
lipo -create mytool-darwin-amd64 mytool-darwin-arm64 -output mytool-darwin-universal
```

资料来源：[spec.md](https://github.com/simonw/go-to-wheel/blob/main/spec.md)

### macOS Version Compatibility

| Wheel Tag | Minimum macOS Version | Architecture |
|-----------|----------------------|--------------|
| `macosx_10_9_x86_64` | macOS 10.9 (Mavericks) | Intel |
| `macosx_11_0_arm64` | macOS 11.0 (Big Sur) | Apple Silicon |

The x86_64 tag maintains backwards compatibility to macOS 10.9, while the ARM64 tag starts from macOS 11.0 due to Apple Silicon hardware requirements.

## Windows Support

Windows builds are cross-compiled from Linux/macOS hosts using `CGO_ENABLED=0`. The tool automatically appends the `.exe` extension to the binary within the wheel.

| Wheel Tag | Architecture | Notes |
|-----------|-------------|-------|
| `win_amd64` | x86_64 | 64-bit Windows |
| `win_arm64` | ARM64 | Windows on ARM devices |

## Build Process

The platform-specific build workflow demonstrates how `go-to-wheel` handles cross-compilation:

```mermaid
graph LR
    A[Source Host] -->|GOOS=linux GOARCH=amd64| B[Linux amd64 binary]
    A -->|GOOS=linux GOARCH=arm64| C[Linux arm64 binary]
    A -->|GOOS=darwin GOARCH=amd64| D[macOS amd64 binary]
    A -->|GOOS=darwin GOARCH=arm64| E[macOS arm64 binary]
    A -->|GOOS=windows GOARCH=amd64| F[Windows amd64 binary]
    
    B --> G[Wheel: manylinux_2_17_x86_64]
    C --> H[Wheel: manylinux_2_17_aarch64]
    D --> I[Wheel: macosx_10_9_x86_64]
    E --> J[Wheel: macosx_11_0_arm64]
    F --> K[Wheel: win_amd64]
    
    style A fill:#f9f,color:#000
    style G fill:#9f9,color:#000
    style H fill:#9f9,color:#000
    style I fill:#9f9,color:#000
    style J fill:#9f9,color:#000
    style K fill:#9f9,color:#000
```

Each build uses the following environment configuration:

```python
env["GOOS"] = goos
env["GOARCH"] = goarch
env["CGO_ENABLED"] = "0"
```

资料来源：[go_to_wheel/__init__.py:129-136](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

## Wheel Installation Compatibility

The wheel filename format ensures pip automatically selects the correct wheel for the target platform:

```
{package_name}-{version}-py3-none-{platform_tag}.whl
```

Example wheel names:

| Wheel Filename | Platform |
|----------------|----------|
| `mytool-1.0.0-py3-none-manylinux_2_17_x86_64.whl` | Linux x86_64 (glibc) |
| `mytool-1.0.0-py3-none-musllinux_1_2_aarch64.whl` | Linux ARM64 (musl) |
| `mytool-1.0.0-py3-none-macosx_11_0_arm64.whl` | macOS Apple Silicon |
| `mytool-1.0.0-py3-none-win_amd64.whl` | Windows x86_64 |

资料来源：[spec.md](https://github.com/simonw/go-to-wheel/blob/main/spec.md)

## Requirements

Building wheels requires:

| Component | Requirement |
|-----------|-------------|
| Go | >= 1.16 (for `go mod` support) |
| Python | >= 3.10 |
| Python dependencies | None (stdlib only) |

The build host does not need to match the target platform due to Go's native cross-compilation support.

## Platform Detection for Binary Execution

The generated `__init__.py` wrapper uses `sys.platform` to handle platform-specific behavior:

```python
def main():
    """Execute the bundled binary."""
    binary = get_binary_path()
    if sys.platform == "win32":
        # On Windows, use subprocess to properly handle signals
        sys.exit(subprocess.call([binary] + sys.argv[1:]))
    else:
        # On Unix, exec replaces the process
        os.execvp(binary, [binary] + sys.argv[1:])
```

This ensures consistent behavior across all supported platforms while respecting OS-specific process management conventions.

资料来源：[go_to_wheel/__init__.py:158-170](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

---

<a id='page-wheel-generation'></a>

## Wheel Generation Process

### 相关页面

相关主题：[System Architecture](#page-architecture), [Supported Platforms](#page-platforms)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [go_to_wheel/__init__.py](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)
- [spec.md](https://github.com/simonw/go-to-wheel/blob/main/spec.md)
- [README.md](https://github.com/simonw/go-to-wheel/blob/main/README.md)
</details>

# Wheel Generation Process

## Overview

The Wheel Generation Process is the core mechanism of `go-to-wheel` that transforms a Go CLI program into a distributable Python wheel package. This process handles cross-compilation, binary packaging, and wheel metadata generation for multiple target platforms in a single operation.

The wheel generation workflow accepts a Go module directory, validates the input, compiles static binaries for each target platform, creates a Python package wrapper, and packages everything into properly tagged wheel files following PEP 427 and PEP 376 standards.

资料来源：[spec.md:1-25]()

## Platform Configuration

### Supported Platforms

The tool supports eight target platforms by default, covering major operating systems and architectures:

| Platform Key | GOOS | GOARCH | Wheel Tag |
|-------------|------|--------|-----------|
| `linux-amd64` | `linux` | `amd64` | `manylinux_2_17_x86_64` |
| `linux-arm64` | `linux` | `arm64` | `manylinux_2_17_aarch64` |
| `linux-amd64-musl` | `linux` | `amd64` | `musllinux_1_2_x86_64` |
| `linux-arm64-musl` | `linux` | `arm64` | `musllinux_1_2_aarch64` |
| `darwin-amd64` | `darwin` | `amd64` | `macosx_10_9_x86_64` |
| `darwin-arm64` | `darwin` | `arm64` | `macosx_11_0_arm64` |
| `windows-amd64` | `windows` | `amd64` | `win_amd64` |
| `windows-arm64` | `windows` | `arm64` | `win_arm64` |

资料来源：[go_to_wheel/__init__.py:15-29]()

### Platform Mapping Structure

The `PLATFORM_MAPPINGS` dictionary maps platform keys to a tuple containing the Go operating system, Go architecture, and the corresponding Python wheel platform tag:

```python
PLATFORM_MAPPINGS: dict[str, tuple[str, str, str]] = {
    "linux-amd64": ("linux", "amd64", "manylinux_2_17_x86_64"),
    # ... additional platforms
}
```

The `DEFAULT_PLATFORMS` list defines which platforms are built when no specific platform is specified:

```python
DEFAULT_PLATFORMS = [
    "linux-amd64",
    "linux-arm64",
    "linux-amd64-musl",
    "linux-arm64-musl",
    "darwin-amd64",
    "darwin-arm64",
    "windows-amd64",
    "windows-arm64",
]
```

资料来源：[go_to_wheel/__init__.py:31-37]()

## Build Process Architecture

### High-Level Workflow

```mermaid
graph TD
    A[Start: go-to-wheel Command] --> B[Validate Go Directory]
    B --> C{Valid?}
    C -->|No| D[Error: Directory not found or no go.mod]
    C -->|Yes| E[Parse Options and Set Defaults]
    E --> F{Platforms specified?}
    F -->|Yes| G[Use Specified Platforms]
    F -->|No| H[Use DEFAULT_PLATFORMS]
    G --> I[For Each Platform]
    H --> I
    I --> J[Cross-Compile Go Binary]
    J --> K[Create Package Directory Structure]
    K --> L[Generate Python Wrapper Files]
    L --> M[Generate Metadata Files]
    M --> N[Create Wheel ZIP Archive]
    N --> O{More Platforms?}
    O -->|Yes| I
    O -->|No| P[Move Wheels to Output Directory]
    P --> Q[Print Summary]
```

### Main Entry Point

The `build_wheels()` function serves as the primary entry point for the wheel generation process. It accepts the following parameters:

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `go_dir` | `str` | Required | Path to Go module directory |
| `name` | `str \| None` | `None` | Python package name (defaults to directory basename) |
| `version` | `str` | `"0.1.0"` | Package version |
| `output_dir` | `str` | `"./dist"` | Directory for built wheels |
| `entry_point` | `str \| None` | `None` | CLI command name (defaults to package name) |
| `platforms` | `list[str] \| None` | `None` | Target platforms (defaults to all) |
| `go_binary` | `str` | `"go"` | Path to Go binary |
| `description` | `str` | `"Go binary packaged as Python wheel"` | Package description |
| `requires_python` | `str` | `">=3.10"` | Python version requirement |
| `author` | `str \| None` | `None` | Author name |
| `author_email` | `str \| None` | `None` | Author email |
| `license_` | `str \| None` | `None` | License identifier |
| `url` | `str \| None` | `None` | Project URL |
| `readme` | `str \| None` | `None` | Path to README markdown file |
| `ldflags` | `str \| None` | `None` | Additional Go linker flags |
| `set_version_var` | `str \| None` | `None` | Go variable to set via -X ldflag |

资料来源：[go_to_wheel/__init__.py:136-168]()

## Step-by-Step Generation Process

### Step 1: Input Validation

The process begins with comprehensive validation of the input parameters:

1. **Directory Existence**: Verify the Go directory exists using `Path.resolve()`
2. **Go Module Verification**: Check for `go.mod` file to confirm valid Go module
3. **README File Check**: If `--readme` is provided, verify the file exists and read its content
4. **Default Value Assignment**: Set defaults for `name` and `entry_point` from directory name

```python
go_path = Path(go_dir).resolve()

if not go_path.exists():
    raise FileNotFoundError(f"Go directory not found: {go_dir}")

if not (go_path / "go.mod").exists():
    raise ValueError(f"Not a Go module: {go_dir} (no go.mod file found)")
```

资料来源：[go_to_wheel/__init__.py:179-186]()

### Step 2: Cross-Compilation

Each Go binary is compiled for its target platform using environment variables:

```mermaid
graph LR
    A[Platform: linux-amd64] --> B["GOOS=linux<br/>GOARCH=amd64<br/>CGO_ENABLED=0"]
    B --> C["go build<br/>-ldflags='-s -w'<br/>-o output"]
    C --> D[Static Binary]
    
    E[Platform: windows-amd64] --> F["GOOS=windows<br/>GOARCH=amd64<br/>CGO_ENABLED=0"]
    F --> G["go build<br/>-ldflags='-s -w'<br/>-o output.exe"]
    G --> H[Static Binary .exe]
```

**Compilation Environment Variables:**

| Variable | Value | Purpose |
|----------|-------|---------|
| `GOOS` | Platform's OS | Target operating system |
| `GOARCH` | Platform's architecture | Target CPU architecture |
| `CGO_ENABLED` | `0` | Disable CGO for static binaries |

**Linker Flags:**

The default linker flags `-s -w` strip debug information and symbol tables to reduce binary size. Additional flags can be appended via the `--ldflags` option:

```python
GOOS={goos} GOARCH={goarch} CGO_ENABLED=0 go build \
  -ldflags="-s -w {additional_flags}" \
  -o {output_path} \
  {go_module_path}
```

资料来源：[spec.md:145-156]()

### Step 3: Wheel Package Structure Creation

The wheel contains a specific directory structure following PEP 427:

```
{package_name}-{version}-py3-none-{platform_tag}.whl
├── {package_name}/
│   ├── __init__.py
│   ├── __main__.py
│   └── bin/
│       └── {binary_name}[.exe]
├── {package_name}-{version}.dist-info/
│   ├── METADATA
│   ├── WHEEL
│   ├── RECORD
│   └── entry_points.txt
```

资料来源：[spec.md:40-57]()

### Step 4: Python Wrapper Generation

The generated `__init__.py` provides a thin wrapper that executes the bundled binary:

```python
"""Go binary packaged as Python wheel."""

import os
import sys
import subprocess

__version__ = "{version}"

def get_binary_path():
    """Return the path to the bundled binary."""
    return os.path.join(os.path.dirname(__file__), "bin", "{binary_name}")

def main():
    """Execute the bundled binary."""
    binary = get_binary_path()
    if sys.platform == "win32":
        # On Windows, use subprocess to properly handle signals
        sys.exit(subprocess.call([binary] + sys.argv[1:]))
    else:
        # On Unix, exec replaces the process
        os.execvp(binary, [binary] + sys.argv[1:])
```

The `__main__.py` serves as the entry point bridge:

```python
from . import main
main()
```

资料来源：[spec.md:63-87]()

### Step 5: Metadata File Generation

#### METADATA (PEP 566)

Generated dynamically with package metadata:

```
Metadata-Version: 2.1
Name: {normalized_name}
Version: {version}
Summary: {description}
License: {license}
Author: {author}
Author-email: {author_email}
Home-page: {url}
Requires-Python: {requires_python}
```

#### WHEEL (PEP 427)

```python
Wheel-Version: 1.0
Generator: go-to-wheel {version}
Root-Is-Purelib: false
Tag: py3-none-{platform_tag}
```

#### entry_points.txt

```ini
[console_scripts]
{entry_point} = {package_name}:main
```

#### RECORD (PEP 376)

CSV format tracking all files with SHA256 hashes:

```csv
{package_name}/__init__.py,sha256={hash},{size}
{package_name}/__main__.py,sha256={hash},{size}
{package_name}/bin/{binary_name},sha256={hash},{size}
{package_name}-{version}.dist-info/METADATA,sha256={hash},{size}
{package_name}-{version}.dist-info/WHEEL,sha256={hash},{size}
{package_name}-{version}.dist-info/entry_points.txt,sha256={hash},{size}
{package_name}-{version}.dist-info/RECORD,,
```

资料来源：[spec.md:162-183]()

### Step 6: Wheel Archive Creation

The wheel is created as a ZIP archive with specific handling:

```python
with zipfile.ZipFile(wheel_path, "w", zipfile.ZIP_DEFLATED) as whl:
    for file_path, content in files.items():
        # Set executable permission for binary
        if "/bin/" in file_path:
            info = zipfile.ZipInfo(file_path)
            # Set Unix permissions: rwxr-xr-x (0755)
            info.external_attr = (
                stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | 
                stat.S_IROTH | stat.S_IXOTH
            ) << 16
            whl.writestr(info, content)
        else:
            whl.writestr(file_path, content)
```

Binary files receive executable permissions (0755) via the ZIP external attributes, ensuring they can be executed after installation.

资料来源：[go_to_wheel/__init__.py:110-123]()

## Wheel Naming Convention

Wheels follow PEP 427 naming with format:

```
{name}-{version}-py3-none-{platform_tag}.whl
```

**Examples:**

| Package | Version | Platform | Full Wheel Name |
|---------|---------|----------|-----------------|
| `myapp` | `1.0.0` | linux-amd64 | `myapp-1.0.0-py3-none-manylinux_2_17_x86_64.whl` |
| `myapp` | `1.0.0` | darwin-arm64 | `myapp-1.0.0-py3-none-macosx_11_0_arm64.whl` |
| `myapp` | `1.0.0` | windows-amd64 | `myapp-1.0.0-py3-none-win_amd64.whl` |

Package names are normalized per PEP 503: hyphens are used in wheel filenames, while the import name (directory) uses underscores.

资料来源：[spec.md:207-216]()

## Linker Flags Integration

### Version Variable Setting

The `--set-version-var` option embeds the package version into a Go variable at compile time:

```bash
go-to-wheel ./mytool --version 2.0.0 --set-version-var main.version
```

This passes `-X main.version=2.0.0` to the Go linker. The combined ldflags are constructed as:

```python
combined_ldflags_parts: list[str] = []
if set_version_var:
    combined_ldflags_parts.append(f"-X {set_version_var}={version}")
if ldflags:
    combined_ldflags_parts.append(ldflags)

combined_ldflags = " ".join(combined_ldflags_parts)
```

The final linker invocation becomes: `-ldflags="-s -w -X main.version=2.0.0"`

资料来源：[go_to_wheel/__init__.py:196-203]()

### Custom ldflags

Additional arbitrary linker flags can be passed with `--ldflags`:

```bash
go-to-wheel ./mytool --ldflags "-X main.version=2.0.0 -X main.commit=abc123"
```

These flags are appended to the default `-s -w`, so the full invocation becomes `-ldflags="-s -w -X main.version=2.0.0 -X main.commit=abc123"`.

资料来源：[README.md:48-51]()

## Error Handling

| Error Condition | Handling |
|-----------------|----------|
| Directory not found | `FileNotFoundError` with message |
| No `go.mod` file | `ValueError` indicating invalid Go module |
| README file not found | `FileNotFoundError` for README path |
| Go binary not found | `FileNotFoundError` from subprocess |
| Build failure | Exception propagates with Go error output |
| No wheels built | Prints error and returns exit code 1 |

The CLI entry point catches `FileNotFoundError` and `ValueError` exceptions, printing them to stderr and returning exit code 1:

```python
try:
    wheels = build_wheels(...)
except (FileNotFoundError, ValueError) as e:
    print(f"Error: {e}", file=sys.stderr)
    return 1
```

资料来源：[go_to_wheel/__init__.py:92-95]()

## Output Example

Successful wheel generation produces output like:

```
go-to-wheel v0.1.0
Building from ./myapp

  ✓ myapp-1.0.0-py3-none-manylinux_2_17_x86_64.whl
  ✓ myapp-1.0.0-py3-none-manylinux_2_17_aarch64.whl
  ✓ myapp-1.0.0-py3-none-musllinux_1_2_x86_64.whl
  ✓ myapp-1.0.0-py3-none-musllinux_1_2_aarch64.whl
  ✓ myapp-1.0.0-py3-none-macosx_10_9_x86_64.whl
  ✓ myapp-1.0.0-py3-none-macosx_11_0_arm64.whl
  ✓ myapp-1.0.0-py3-none-win_amd64.whl
  ✓ myapp-1.0.0-py3-none-win_arm64.whl

Done! Built 8 wheels in ./dist
```

资料来源：[spec.md:225-240]()

## Related Components

| Component | Purpose |
|-----------|---------|
| `build_wheels()` | Main orchestrator function |
| `build_single_wheel()` | Creates wheel for one platform |
| `compile_go_binary()` | Executes Go cross-compilation |
| `generate_metadata()` | Creates METADATA content |
| `generate_wheel_file()` | Creates WHEEL file content |
| `generate_record()` | Creates RECORD with hashes |
| `generate_entry_points()` | Creates entry_points.txt |

These functions work together to transform a Go module into a distributable Python wheel package that can be installed via `pip` or `pipx`.

资料来源：[go_to_wheel/__init__.py:96-135]()

## See Also

- [go-to-wheel GitHub Repository](https://github.com/simonw/go-to-wheel)
- [maturin](https://github.com/PyO3/maturin) - Rust equivalent tool
- [PEP 427 - Wheel Binary Package Format](https://peps.python.org/pep-0427/)
- [PEP 376 - Wheel Metadata and RECORD](https://peps.python.org/pep-0376/)

---

<a id='page-development-guide'></a>

## Development Guide

### 相关页面

相关主题：[Installation](#page-installation), [Configuration and Metadata](#page-configuration)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [go_to_wheel/__init__.py](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)
- [README.md](https://github.com/simonw/go-to-wheel/blob/main/README.md)
- [spec.md](https://github.com/simonw/go-to-wheel/blob/main/spec.md)
- [pyproject.toml](https://github.com/simonw/go-to-wheel/blob/main/pyproject.toml)
</details>

# Development Guide

## Overview

This guide covers everything you need to know to develop, test, and contribute to `go-to-wheel`. The project is a Python CLI tool that compiles Go programs into Python wheels, enabling distribution of Go binaries via PyPI and pipx. 资料来源：[README.md:1-15]()

The tool requires no external Python dependencies—only Python's standard library is used—making it lightweight and easy to maintain. 资料来源：[spec.md:95-97]()

## Prerequisites

Before setting up a development environment, ensure you have the following installed:

| Requirement | Minimum Version | Purpose |
|-------------|-----------------|---------|
| Python | >= 3.10 | Runtime for the tool |
| Go | >= 1.16 | Required for `go build` commands |
| uv | Latest | Package manager and test runner |
| Git | Any recent | Version control |

资料来源：[spec.md:95-100]()

## Repository Structure

```
go-to-wheel/
├── go_to_wheel/
│   └── __init__.py      # Main module with all logic
├── tests/
│   └── test_*.py        # Test files
├── pyproject.toml       # Project configuration
├── README.md            # User documentation
├── spec.md              # Technical specification
└── LICENSE              # Apache 2.0 license
```

The main implementation resides in `go_to_wheel/__init__.py`, which contains:

- Platform mapping definitions
- CLI argument parsing
- Go cross-compilation logic
- Wheel building functions
- Metadata generation

资料来源：[go_to_wheel/__init__.py:1-50]()

## Setting Up the Development Environment

### 1. Clone the Repository

```bash
git clone https://github.com/simonw/go-to-wheel
cd go-to-wheel
```

资料来源：[README.md:55-58]()

### 2. Install Dependencies

The project uses `uv` for dependency management. Install all development dependencies:

```bash
uv sync
```

This automatically installs the project and its test dependencies based on `pyproject.toml`.

### 3. Verify Installation

Confirm the tool is accessible:

```bash
uv run go-to-wheel --version
```

## Running Tests

The project uses `pytest` for testing. Execute the full test suite with:

```bash
uv run pytest
```

资料来源：[README.md:59-60]()

### Test Structure

Tests are located in the `tests/` directory and follow the naming pattern `test_*.py`. Each test file typically corresponds to a major component:

| Test File | Coverage Area |
|-----------|---------------|
| `test_platforms.py` | Platform mapping and validation |
| `test_build.py` | Wheel building logic |
| `test_cli.py` | Command-line argument parsing |

### Running Specific Tests

Run tests matching a pattern:

```bash
uv run pytest -k "test_name_pattern"
```

Run with verbose output:

```bash
uv run pytest -v
```

## Code Architecture

### Core Components

```mermaid
graph TD
    A[CLI Entry Point] --> B[Argument Parser]
    B --> C[build_wheels Function]
    C --> D[Platform Validation]
    C --> E[Go Cross-Compilation]
    E --> F[Wheel Assembly]
    F --> G[Metadata Generation]
    F --> H[ZIP Creation]
    G --> H
    H --> I[Output Wheels]
```

### Platform Mapping System

The tool defines platform mappings that translate human-readable platform names to Go environment variables and wheel tags:

```python
PLATFORM_MAPPINGS: dict[str, tuple[str, str, str]] = {
    "linux-amd64": ("linux", "amd64", "manylinux_2_17_x86_64"),
    "linux-arm64": ("linux", "arm64", "manylinux_2_17_aarch64"),
    "linux-amd64-musl": ("linux", "amd64", "musllinux_1_2_x86_64"),
    "linux-arm64-musl": ("linux", "arm64", "musllinux_1_2_aarch64"),
    "darwin-amd64": ("darwin", "amd64", "macosx_10_9_x86_64"),
    "darwin-arm64": ("darwin", "arm64", "macosx_11_0_arm64"),
    "windows-amd64": ("windows", "amd64", "win_amd64"),
    "windows-arm64": ("windows", "arm64", "win_arm64"),
}
```

资料来源：[go_to_wheel/__init__.py:19-27]()

### Default Platforms

```mermaid
graph LR
    A[Default Platforms] --> B[Linux amd64]
    A --> C[Linux arm64]
    A --> D[Linux amd64-musl]
    A --> E[Linux arm64-musl]
    A --> F[macOS amd64]
    A --> G[macOS arm64]
    A --> H[Windows amd64]
    A --> I[Windows arm64]
```

The `DEFAULT_PLATFORMS` list defines which platforms are built when none are specified:

```python
DEFAULT_PLATFORMS = [
    "linux-amd64",
    "linux-arm64",
    "linux-amd64-musl",
    "linux-arm64-musl",
    "darwin-amd64",
    "darwin-arm64",
    "windows-amd64",
    "windows-arm64",
]
```

资料来源：[go_to_wheel/__init__.py:29-37]()

### Build Workflow

```mermaid
sequenceDiagram
    participant User
    participant CLI
    participant Builder
    participant Go
    participant WheelBuilder
    
    User->>CLI: go-to-wheel ./myapp
    CLI->>Builder: build_wheels(go_dir)
    Builder->>Go: GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build
    Go-->>Builder: Binary for linux/amd64
    Builder->>Go: (repeat for each platform)
    Go-->>Builder: Binaries for all platforms
    Builder->>WheelBuilder: Create wheel structure
    WheelBuilder->>WheelBuilder: Generate __init__.py
    WheelBuilder->>WheelBuilder: Generate METADATA
    WheelBuilder->>WheelBuilder: Create RECORD with hashes
    WheelBuilder->>Builder: Wheel file
    Builder->>User: List of wheel paths
```

## Building Wheels Locally

### Local Installation

Install the package in development mode:

```bash
uv pip install -e .
```

### Building Wheels for Testing

Create test wheels for a sample Go module:

```bash
go-to-wheel ./path/to/go-module --name my-test-package
```

This creates wheels in `./dist` for all default platforms. 资料来源：[README.md:31-37]()

### Custom Platform Selection

Build only specific platforms to speed up iteration:

```bash
go-to-wheel ./myapp --platforms linux-amd64,darwin-arm64
```

## CLI Argument Reference

The tool accepts the following arguments for development and testing:

| Argument | Type | Default | Purpose |
|----------|------|---------|---------|
| `--name` | string | Directory name | Python package name |
| `--version` | string | `0.1.0` | Package version |
| `--output-dir` | string | `./dist` | Output directory |
| `--platforms` | string | All platforms | Target platforms |
| `--go-binary` | string | `go` | Go binary path |
| `--ldflags` | string | None | Additional linker flags |

资料来源：[go_to_wheel/__init__.py:75-100]()

## Cross-Compilation Process

The build process uses Go's cross-compilation with specific environment settings:

```python
def compile_go_binary(
    go_dir: str,
    goos: str,
    goarch: str,
    output_path: str,
    go_binary: str,
    ldflags: str | None = None,
) -> None:
    env = os.environ.copy()
    env["GOOS"] = goos
    env["GOARCH"] = goarch
    env["CGO_ENABLED"] = "0"  # Static binaries
    
    ldflags_value = "-s -w"  # Strip debug info
    if ldflags:
        ldflags_value += " " + ldflags
    
    cmd = [go_binary, "build", f"-ldflags={ldflags_value}", "-o", output_path, "."]
```

Key points:
- `CGO_ENABLED=0` ensures static binaries with no libc dependency
- `-ldflags="-s -w"` strips debug information to reduce binary size
- Windows builds automatically receive `.exe` extension

资料来源：[go_to_wheel/__init__.py:120-140]()

## Wheel Structure Generation

Each wheel contains a Python wrapper that executes the bundled binary:

```mermaid
graph TD
    subgraph Wheel Contents
        A[Package Directory] --> B[__init__.py]
        A --> C[__main__.py]
        A --> D[bin/]
        D --> E[Go Binary]
        A --> F[.dist-info/]
        F --> G[METADATA]
        F --> H[WHEEL]
        F --> I[RECORD]
        F --> J[entry_points.txt]
    end
```

The `__init__.py` includes:

```python
def get_binary_path():
    """Return the path to the bundled binary."""
    return os.path.join(os.path.dirname(__file__), "bin", "{binary_name}")

def main():
    """Execute the bundled binary."""
    binary = get_binary_path()
    if sys.platform == "win32":
        sys.exit(subprocess.call([binary] + sys.argv[1:]))
    else:
        os.execvp(binary, [binary] + sys.argv[1:])
```

资料来源：[spec.md:58-75]()

## Version Information

The project version is defined in the main module:

```python
__version__ = "0.1.0"
```

资料来源：[go_to_wheel/__init__.py:12]()

To check the installed version during development:

```bash
uv run python -c "import go_to_wheel; print(go_to_wheel.__version__)"
```

## Debugging

### Enable Verbose Output

The CLI outputs progress during builds:

```
go-to-wheel v0.1.0
Building from ./myapp

linux-amd64... done
darwin-arm64... done
```

### Common Build Failures

| Issue | Cause | Solution |
|-------|-------|----------|
| `go.mod not found` | Directory is not a Go module | Run `go mod init` first |
| `Go not found` | Go not in PATH | Install Go or use `--go-binary` |
| Build timeout | Complex Go project | Increase timeout or skip platforms |

### Inspecting Generated Wheels

List contents of a wheel:

```bash
unzip -l myapp-1.0.0-py3-none-manylinux_2_17_x86_64.whl
```

## Contributing

### Development Workflow

1. Fork the repository on GitHub
2. Clone your fork locally
3. Create a feature branch: `git checkout -b feature/my-feature`
4. Make changes and add tests
5. Run the test suite: `uv run pytest`
6. Commit your changes with clear messages
7. Push to your fork and submit a pull request

### Code Style

- Follow PEP 8 for Python code
- Use type hints for function parameters and return values
- Add docstrings to public functions
- Keep functions focused and small

### Testing Guidelines

- All new features should include tests
- Ensure existing tests pass before submitting
- Use descriptive test names: `test_platform_mapping_linux_amd64`

## Future Development Considerations

The specification outlines potential future features not yet implemented:

| Feature | Status | Description |
|---------|--------|-------------|
| Configuration file | Not started | Support `pyproject.toml` or `go-to-wheel.toml` |
| Auto version detection | Not started | Parse from VERSION file or git tags |
| Multiple entry points | Not started | Support Go modules with multiple binaries |
| Universal2 macOS | Not started | Combine arm64 and x86_64 with `lipo` |
| Build caching | Not started | Skip unchanged platforms |
| PyPI publishing | Not started | Add `go-to-wheel publish` command |

资料来源：[spec.md:80-93]()

## Related Documentation

- [User README](README.md) - Installation and usage instructions
- [Technical Specification](spec.md) - Detailed system design
- [maturin](https://github.com/PyO3/maturin) - Rust equivalent that inspired this project
- [pip-binary-factory](https://github.com/Bing-su/pip-binary-factory) - Template for pre-built binaries

---

<a id='page-configuration'></a>

## Configuration and Metadata

### 相关页面

相关主题：[CLI Options Reference](#page-cli-options), [Development Guide](#page-development-guide)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [go_to_wheel/__init__.py](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)
- [README.md](https://github.com/simonw/go-to-wheel/blob/main/README.md)
- [spec.md](https://github.com/simonw/go-to-wheel/blob/main/spec.md)
</details>

# Configuration and Metadata

This page documents the configuration system and metadata handling in go-to-wheel, a tool that compiles Go CLI programs into Python wheels.

## Overview

go-to-wheel provides extensive configuration options for customizing wheel builds. Configuration is passed through command-line arguments and is used to generate proper Python wheel metadata according to PEP 427 and PEP 566 standards.

The tool supports two layers of configuration:
1. **Build Configuration** - Controls how the Go binary is compiled (platforms, Go binary path, ldflags)
2. **Package Metadata** - Defines Python package metadata (name, version, author, license, etc.)

资料来源：[go_to_wheel/__init__.py:1-50](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

## Platform Configuration

### Supported Platforms

go-to-wheel supports cross-compilation for 8 different platform configurations:

| Platform Identifier | GOOS | GOARCH | Wheel Tag |
|---------------------|------|--------|-----------|
| `linux-amd64` | linux | amd64 | `manylinux_2_17_x86_64` |
| `linux-arm64` | linux | arm64 | `manylinux_2_17_aarch64` |
| `linux-amd64-musl` | linux | amd64 | `musllinux_1_2_x86_64` |
| `linux-arm64-musl` | linux | arm64 | `musllinux_1_2_aarch64` |
| `darwin-amd64` | darwin | amd64 | `macosx_10_9_x86_64` |
| `darwin-arm64` | darwin | arm64 | `macosx_11_0_arm64` |
| `windows-amd64` | windows | amd64 | `win_amd64` |
| `windows-arm64` | windows | arm64 | `win_arm64` |

资料来源：[go_to_wheel/__init__.py:22-30](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

### Platform Selection

By default, all 8 platforms are built. Users can specify a subset using the `--platforms` option:

```bash
go-to-wheel ./mytool --platforms linux-amd64,darwin-arm64
```

Platform identifiers are defined in the `PLATFORM_MAPPINGS` dictionary and can be parsed from comma-separated input.

资料来源：[go_to_wheel/__init__.py:86-90](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

### Build Workflow

```mermaid
graph TD
    A[Parse --platforms argument] --> B{Platforms specified?}
    B -->|No| C[Use DEFAULT_PLATFORMS]
    B -->|Yes| D[Split by comma]
    D --> E[Validate each platform]
    E --> F[For each platform]
    F --> G[Set GOOS/GOARCH env]
    G --> H[Run go build with CGO_ENABLED=0]
    H --> I[Create wheel structure]
    I --> J[Generate METADATA, WHEEL, RECORD]
    J --> K[Zip into .whl file]
    K --> F
```

## Command-Line Options

### Full Option Reference

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `--name` | string | Directory basename | Python package name |
| `--version` | string | `0.1.0` | Package version |
| `--output-dir` | string | `./dist` | Directory for built wheels |
| `--entry-point` | string | Same as `--name` | CLI command name |
| `--platforms` | string | All 8 platforms | Comma-separated platform list |
| `--go-binary` | string | `go` | Path to Go binary |
| `--description` | string | `"Go binary packaged as Python wheel"` | Package description |
| `--license` | string | None | SPDX license identifier |
| `--author` | string | None | Author name |
| `--author-email` | string | None | Author email |
| `--url` | string | None | Project URL |
| `--requires-python` | string | `>=3.10` | Python version requirement |
| `--readme` | string | None | Path to README markdown file |
| `--ldflags` | string | None | Additional Go linker flags |
| `--set-version-var` | string | None | Go variable for version embedding |

资料来源：[go_to_wheel/__init__.py:52-115](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

### Build Configuration Options

These options control the Go compilation process:

```python
def build_wheels(
    go_dir: str,
    *,
    name: str | None = None,
    version: str = "0.1.0",
    output_dir: str = "./dist",
    entry_point: str | None = None,
    platforms: list[str] | None = None,
    go_binary: str = "go",
    description: str = "Go binary packaged as Python wheel",
    # ... metadata options ...
    ldflags: str | None = None,
    set_version_var: str | None = None,
) -> list[str]:
```

资料来源：[go_to_wheel/__init__.py:178-220](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

### Linker Flags Configuration

The `--ldflags` and `--set-version-var` options control Go linker flags:

**Default flags:** `-s -w` (strips debug info and symbol tables)

**Additional flags** can be appended using `--ldflags`:

```bash
go-to-wheel ./mytool --ldflags "-X main.commit=abc123"
```

**Version embedding** via `--set-version-var`:

```bash
go-to-wheel ./mytool --version 2.0.0 --set-version-var main.version
```

This passes `-X main.version=2.0.0` to the Go linker.

资料来源：[README.md:30-50](https://github.com/simonw/go-to-wheel/blob/main/README.md)

The linker flags are combined in this order:
1. `-s -w` (default strip flags)
2. `-X {set_version_var}={version}` (if `--set-version-var` is set)
3. User-provided `--ldflags` (appended last)

资料来源：[go_to_wheel/__init__.py:255-265](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

## Metadata Generation

### METADATA File (PEP 566)

Generated by `generate_metadata()`:

```python
def generate_metadata(
    name: str,
    version: str,
    description: str,
    *,
    author: str | None = None,
    author_email: str | None = None,
    license_: str | None = None,
    url: str | None = None,
    requires_python: str = ">=3.10",
    readme_content: str | None = None,
) -> str:
    """Generate METADATA file content."""
    lines = [
        "Metadata-Version: 2.1",
        f"Name: {name}",
        f"Version: {version}",
        f"Summary: {description}",
    ]

    if author:
        lines.append(f"Author: {author}")
    if author_email:
        lines.append(f"Author-email: {author_email}")
    if license_:
        lines.append(f"License: {license_}")
    if url:
        lines.append(f"Home-page: {url}")

    lines.append(f"Requires-Python: {requires_python}")

    if readme_content:
        lines.append("Description-Content-Type: text/markdown")
        lines.append("")
        lines.append(readme_content)

    return "\n".join(lines) + "\n"
```

资料来源：[go_to_wheel/__init__.py:280-315](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

### WHEEL File (PEP 427)

Generated by `generate_wheel_metadata()`:

```
Wheel-Version: 1.0
Generator: go-to-wheel {version}
Root-Is-Purelib: false
Tag: py3-none-{platform_tag}
```

Key points:
- `Root-Is-Purelib: false` indicates platform-specific binary
- `py3-none` indicates Python 3+ requirement
- `{platform_tag}` varies by target (e.g., `manylinux_2_17_x86_64`)

资料来源：[go_to_wheel/__init__.py:317-325](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

### entry_points.txt

Generated for console script entry points:

```
[console_scripts]
{entry_point} = {import_name}:main
```

The `import_name` is derived from the package name by replacing hyphens with underscores.

资料来源：[go_to_wheel/__init__.py:327-332](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

### RECORD File

Generated by `generate_record()` using SHA256 hashes:

```python
def generate_record(files: dict[str, bytes]) -> str:
    """Generate RECORD file content."""
    output = io.StringIO()
    writer = csv.writer(output)

    for path, content in files.items():
        if path.endswith("RECORD"):
            writer.writerow([path, "", ""])
        else:
            hash_value = base64.urlsafe_b64encode(
                hashlib.sha256(content).digest()
            ).rstrip(b"=").decode("ascii")
            writer.writerow([path, f"sha256={hash_value}", len(content)])

    return output.getvalue()
```

资料来源：[go_to_wheel/__init__.py:334-348](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

## Package Structure

The generated wheel follows this structure:

```
{package_name}-{version}-py3-none-{platform_tag}.whl
├── {import_name}/
│   ├── __init__.py
│   ├── __main__.py
│   └── bin/
│       └── {binary_name}[.exe]
├── {import_name}-{version}.dist-info/
│   ├── METADATA
│   ├── WHEEL
│   ├── RECORD
│   └── entry_points.txt
```

资料来源：[spec.md:60-80](https://github.com/simonw/go-to-wheel/blob/main/spec.md)

### __init__.py Template

```python
"""Go binary packaged as Python wheel."""

import os
import sys
import subprocess

__version__ = "{version}"

def get_binary_path():
    """Return the path to the bundled binary."""
    return os.path.join(os.path.dirname(__file__), "bin", "{binary_name}")

def main():
    """Execute the bundled binary."""
    binary = get_binary_path()
    if sys.platform == "win32":
        sys.exit(subprocess.call([binary] + sys.argv[1:]))
    else:
        os.execvp(binary, [binary] + sys.argv[1:])
```

资料来源：[spec.md:82-100](https://github.com/simonw/go-to-wheel/blob/main/spec.md)

## Metadata Flow

```mermaid
graph LR
    A[CLI Arguments] --> B[ArgumentParser]
    B --> C[build_wheels function]
    C --> D[Input Validation]
    D --> E[README Processing]
    E --> F[Platform Loop]
    F --> G[Go Compilation]
    G --> H[Wheel Assembly]
    H --> I[Metadata Generation]
    I --> J[ZIP Creation]
    J --> K[Output Directory]
    
    C -->|name, version| L[METADATA]
    C -->|platform_tag| M[WHEEL]
    C -->|entry_point| N[entry_points.txt]
    H --> O[RECORD with hashes]
```

## Input Validation

The `build_wheels()` function validates inputs:

| Check | Behavior on Failure |
|-------|---------------------|
| Go directory exists | Raises `FileNotFoundError` |
| `go.mod` file present | Raises `ValueError` |
| README file exists (if provided) | Raises `FileNotFoundError` |
| Package name valid (PEP 503) | Raises `ValueError` |

资料来源：[go_to_wheel/__init__.py:225-235](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

## Configuration Precedence

When multiple configuration sources conflict, the following precedence applies:

1. **Command-line arguments** (highest priority)
2. **Default values** (lowest priority)

For `--ldflags`, user-provided flags are appended after default flags, allowing overrides.

## Environment Variables Used

During build, these environment variables are set:

| Variable | Value | Purpose |
|----------|-------|---------|
| `GOOS` | Platform GOOS | Cross-compilation target |
| `GOARCH` | Platform GOARCH | Cross-compilation target |
| `CGO_ENABLED` | `0` | Static binary compilation |

资料来源：[go_to_wheel/__init__.py:270-280](https://github.com/simonw/go-to-wheel/blob/main/go_to_wheel/__init__.py)

## Example: Full Metadata Configuration

```bash
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
```

This produces a wheel with complete PyPI-compatible metadata.

资料来源：[README.md:55-65](https://github.com/simonw/go-to-wheel/blob/main/README.md)

---

---

## Doramagic 踩坑日志

项目：simonw/go-to-wheel

摘要：发现 6 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：能力坑 - 能力判断依赖假设。

## 1. 能力坑 · 能力判断依赖假设

- 严重度：medium
- 证据强度：source_linked
- 发现：README/documentation is current enough for a first validation pass.
- 对用户的影响：假设不成立时，用户拿不到承诺的能力。
- 建议检查：将假设转成下游验证清单。
- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。
- 证据：capability.assumptions | hn_item:48109677 | https://news.ycombinator.com/item?id=48109677 | README/documentation is current enough for a first validation pass.

## 2. 维护坑 · 维护活跃度未知

- 严重度：medium
- 证据强度：source_linked
- 发现：未记录 last_activity_observed。
- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。
- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。
- 证据：evidence.maintainer_signals | hn_item:48109677 | https://news.ycombinator.com/item?id=48109677 | last_activity_observed missing

## 3. 安全/权限坑 · 下游验证发现风险项

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：下游已经要求复核，不能在页面中弱化。
- 建议检查：进入安全/权限治理复核队列。
- 防护动作：下游风险存在时必须保持 review/recommendation 降级。
- 证据：downstream_validation.risk_items | hn_item:48109677 | https://news.ycombinator.com/item?id=48109677 | no_demo; severity=medium

## 4. 安全/权限坑 · 存在评分风险

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：风险会影响是否适合普通用户安装。
- 建议检查：把风险写入边界卡，并确认是否需要人工复核。
- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。
- 证据：risks.scoring_risks | hn_item:48109677 | https://news.ycombinator.com/item?id=48109677 | no_demo; severity=medium

## 5. 维护坑 · issue/PR 响应质量未知

- 严重度：low
- 证据强度：source_linked
- 发现：issue_or_pr_quality=unknown。
- 对用户的影响：用户无法判断遇到问题后是否有人维护。
- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。
- 防护动作：issue/PR 响应未知时，必须提示维护风险。
- 证据：evidence.maintainer_signals | hn_item:48109677 | https://news.ycombinator.com/item?id=48109677 | issue_or_pr_quality=unknown

## 6. 维护坑 · 发布节奏不明确

- 严重度：low
- 证据强度：source_linked
- 发现：release_recency=unknown。
- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。
- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。
- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。
- 证据：evidence.maintainer_signals | hn_item:48109677 | https://news.ycombinator.com/item?id=48109677 | release_recency=unknown

<!-- canonical_name: simonw/go-to-wheel; human_manual_source: deepwiki_human_wiki -->
