(ab)using the python packaging ecosystem for non-python tools
- Python 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| examples | ||
| .gitignore | ||
| .python-version | ||
| pipshim.py | ||
| pyproject.toml | ||
| README.md | ||
| uv.lock | ||
pipshim
A PEP-517 compatible build backend for making non-Python tools installable via pip-compatible package managers.
Why
Publishing consumable software for multiple platforms (especially Linux and Windows) is a pain in the ass.
Rather than invent a new package manager for everyone to adopt, this tool tries to solve that problem by adapting to a tool that everyone has, pip!
pip gives us the following things:
- Broad distribution and usage
- Centralized updates and version pinning (depending on package manager)
- Auditability
- Build isolation
- Virtual environment support
- Compatibility with existing package repositories and tooling
- A lot more
Outputs
pipshim builds the following files:
- A source distribution, which contains the source code for the project and the code required to build it. Consumers can install this file and build the tool locally on their own systems. It is not architecture or platform-specific.
- A wheel file, which is a compiled ZIP distribution which is essentially extracted and copied into the Python site-packages folder. This output is host-and-architecture specific as it (can) contains compiled code.
pipshimassumes all tools built are host-and-architecture specific.
Most consumers will want to install the wheel file, as it is much faster to install and doesn't require build tools to be installed on their system.
Expectations
pipshimdoesn't support cross-compilation. The source distribution is platform-agnostic, but the wheel file must be built on the host platform.- Binary-only software isn't really supported, for the same reason.
- Presence of the tooling for compiling the source distribution into a wheel file is left up to the package author. It's possible to package required toolchains themselves with
pipshimand provide them as build dependencies. pipshimwon't de-reference symlinks outside of your repo. Ensure your code is self-contained. (except forpyproject.tomlandpipshim.py)pipshimwon't manage your build tools' sandboxes. Agolang-based source_distribution will use the build host'sGOPATHto cache dependencies.- Editable builds don't really work.
pipshimcan only build your code when your package manager reinstalls your package.
Usage
(TODO, better packaging)
- Create a
pyproject.toml:
[project]
name = "my-awesome-tool"
version = "0.1.0"
description = "my-awesome-tool"
readme = "README.md"
authors = [
#...
]
requires-python = ">=3.8" # Generated wrapper scripts require v3.8 or newer
dependencies = [] # Leave blank
[build-system]
requires = [] # Todo: better packaging
build-backend = "pipshim"
backend-path = ["."]
[build-system]
requires = ["pipshim @ git+https://gitea.wesj.app/wjordan/[email protected]"]
build-backend = "pipshim"
[tool.pipshim]
## Source distribution options:
# If packaging an external project, provide the git URL and target git ref to build from.
source_git_url = "https://github.com/example/example.git"
source_git_ref = "0.1.0" # defaults to project.version if not set
# patch_step = ["git", "lfs", "pull"]
# If packging a local project, use sources to specify which files and folders are included in the source.
# sources = ["src", "Makefile"]
## Wheel build options
# configure_step = ["./configure", "--with-something"]
build_step = ["make"]
# output executables generated by the build step.
# These will be added to PATH by creating a self-destructing python wrapper script.
[tool.pipshim.executables]
example = "out/example" # format: <COMMAND> = <PATH TO BUILT EXECUTABLE>
# other non-executable files required for distribution.
[tool.pipshim.dists]
include = "include/" # format: <INSTALLED PATH> = <PATH IN SOURCE>
"lib/mylib.a" = "out/mylib.a"
- Build with your preferred Python packaging tool, e.g.
uv build. - Consumers can install the wheel file that matches their platform with any
pip-compatible tool, e.g.pip install my-awesome-tool-0.1.0-py3.8-none-macosx_11_0_arm64.whl - The executables in
tool.pipshim.executableswill be symlinked into the virtual environment's PATH. Python's packaging only supports adding Python scripts into the PATH, sopipshimgenerates a Python wrapper script for each executable that replaces itself with a symlink to the actual executable file when it runs.
❯❯❯ python3 -m venv .venv
❯❯❯ . .venv/bin/activate
❯❯❯ pip install odin-2026.08.dev.1-py3.8-none-macosx_11_0_arm64.whl
Processing odin-2026.08.dev.1-py3.8-none-macosx_11_0_arm64.whl
Installing collected packages: odin
Successfully installed odin-2026.8.dev1
[notice] A new release of pip is available: 26.1.2 -> 26.2.1
[notice] To update, run: pip install --upgrade pip
❯❯❯ odin version
pipshim v0.1.0: installed simlink /Users/user/tmp/.venv/bin/odin => /Users/user/tmp/.venv/lib/python3.14/site-packages/odin
/Users/user/tmp/.venv/bin/odin version dev-2026-08
# Wrapper disappears after first call
❯❯❯ odin version
odin version dev-2026-08
# Binary is stored in virtualenv's site-packages folder
❯❯❯ readlink $(which odin)
/Users/user/tmp/.venv/lib/python3.14/site-packages/odin