# mkwheels Build a reproducible, pinned Python wheels tarball for vendoring into a SlackBuild (or any offline `pip install`). Generic over package + version, with two source modes: PyPI packages and GitHub source releases. ## Usage ``` mkwheels pypi --name PKG --ver VER [--epoch N] mkwheels gh --repo OWNER/REPO --ver VER [--name PKG] [--tag TAG] [--epoch N] ``` Common flags: - `--ver VER` — version for the output filename. A leading `v` is stripped. - `--epoch N` — optional `SOURCE_DATE_EPOCH`. Omitted → auto-derived (see each mode). Pass it to override. - `OUTPUT` env var overrides the output directory (default: current dir). ### pypi mode - `--name PKG` — the PyPI package, downloaded at exactly `--ver`. - Epoch auto-derived from the PyPI release upload time. ### gh mode For packages not on PyPI (GitHub source, possibly with git dependencies). The tagged source is downloaded and pip builds the project plus its whole dependency tree (PyPI deps and any `git+` deps) into wheels. - `--repo OWNER/REPO` — the GitHub repository. - `--name PKG` — output name; defaults to the repo basename, lowercased. - `--tag TAG` — git tag to fetch; a leading `v` is stripped for naming, and the real ref is resolved by trying `` then `v`. Defaults to `--ver`. - Epoch auto-derived from the GitHub release `published_at` (the repo must publish a GitHub Release for the tag). Outputs `-wheels-.tar.gz` and `requirements.txt` (pinned + hashed). Prints the md5sum and the resolved epoch. The `requirements.txt` is an audit record of the resolved versions, not the install input: the SlackBuild installs straight from the wheel files (`--find-links`), it does not re-resolve the lockfile. ## Requirements `bash`, `python3` + `pip`, `jq`, `curl`, `tar`, `gzip`, `md5sum`. ## Reproducibility PyPI releases are immutable, so the wheel set for a fixed version is deterministic. The tarball normalizes tar metadata (sorted entries, fixed mtime/owner, `gzip -n`) so it is byte-identical for the same inputs + epoch. In `gh` mode the project (and any source-only deps) are built from source. With a fixed epoch this is byte-identical on the same machine, which is what vendoring needs: build once, upload, pin the md5. Wheels containing compiled extensions may differ across machines/toolchains, so build the vendored tarball on the target platform. Git-sourced dependencies (packages whose upstream pins a git URL) are frozen at build time: pip resolves whatever is current, and the emitted `requirements.txt` records the exact resolved versions. Once built, the tarball is the source of truth. ## SBo integration Run `mkwheels`, upload the tarball to your package host, and set `DOWNLOAD_x86_64` / `MD5SUM_x86_64` in the SlackBuild `.info` to point at it. The SlackBuild then `pip install --no-index --find-links=` into a venv. ## Test `./selftest` builds twice with a fixed epoch in both modes (`pypi` six, `gh` pyparsing) and asserts each pair of wheels tarballs is byte-identical. Run it after changing the tar/packing or mode-resolution logic. ## License GPLv2 (v2-only). See `LICENSE`. Copyright (C) 2026 Danilo M. .