English | 한국어
A Python project that has to run on a phone as well as a desktop needs more than installing packages:
dependencies resolved for a platform that is not the one you build on, extension modules compiled
for it, and the result packaged so an app can carry it. pypackpack (ppp) does that work, so you
never configure a Python, a JVM or a cross-compiler by hand.
pypackpack = crossenv + compiler + bundler + codepush
It delegates instead of reimplementing: dependency resolution and installation are
uv's, and pypackpack adds targets, per-target markers and
per-target install directories on top.
- 🎯 Targets as triples. Android, iOS, macOS, Linux and Windows, by canonical target triple
(
aarch64-linux-android,arm64-apple-ios, …) or a few aliases. - 📦 Dependencies per target.
ppp <package> add numpy --target aarch64-linux-androidwrites the marker uv evaluates for that target, andsyncinstalls each target's wheels intobuild/crossenv/<triple>/. - 🐍 Pinned interpreters.
ppp python install 3.14 <target>fetches a CPython build for the target and checks its SHA-256 before unpacking anything. - 🛠️ C/C++ extensions.
ppp buildgenerates ameson.buildand compiles them. - 🧳 Bundles. The
resourcepayload that python-multiplatform runs, plus single, fat and patch wheels. - ☕ One codebase, two front doors. The
pypackpackcommand line, and the same work as a JVM library that toolchain (the Gradle plugin) calls.
uv tool install pypackpack # puts pypackpack and ppp on PATH
pypackpack --help # alias: ppp
uvx pypackpack --help # or run it without installingThe wheel carries the command line as a native binary (GraalVM Native Image), one wheel per platform: macOS 11+ on Apple silicon, Linux x86_64 and aarch64 (glibc), Windows x86_64. On any other platform the installer finds no matching wheel. There is deliberately no source distribution: building needs a JDK and GraalVM, and an sdist would install the launcher without the binary.
uv is needed at run time. When none is on PATH, pypackpack downloads one into
~/.pypackpack/uv.
Build from a checkout instead
git clone -b develop https://github.com/thisisthepy/pypackpack
cd pypackpack
./gradlew :packpack:installCliDist # JDK 21
alias ppp="$PWD/packpack/build/install/pypackpack/bin/pypackpack"
./gradlew :packpack:nativeCompile # the native binary; needs GraalVM as JAVA_HOMEppp init myapp --python 3.13
cd myapp
ppp package add packages/core
ppp target add aarch64-linux-android arm64-apple-ios
ppp core add requests # every target of the package
ppp core add six --target arm64-apple-ios # one target only
ppp core sync --target aarch64-linux-android arm64-apple-ios \
--python-version 3.14 --only-binary :all: # → packages/core/build/crossenv/<triple>/
ppp build core --target aarch64-apple-darwin # Meson; host only for nowWithout --target, sync and tree use the host's target only. Put your modules in a package directory such as packages/core/src/main/core/; platform-specific
code goes in src/android/, src/ios/ and so on.
repositories { mavenLocal() } // ./gradlew :packpack:publishToMavenLocal
dependencies { implementation("org.thisisthepy.python.multiplatform:packpack:0.1.0") }BundlerInterface.create(BundleType.RESOURCE).bundle(
BundleRequest(packageDir = packageDir, target = "aarch64-linux-android", buildLevel = "bytecode")
)The library page of the guide covers bundling, Python installs into a directory you choose, and per-target dependency installs.
| Repository | Owns |
|---|---|
| pypackpack | The work: acquiring Python, resolving dependencies, cross-compiling, bundling |
| toolchain | The Gradle python { } block that turns into pypackpack calls |
| python-multiplatform | The runtime: CPython embedded in Kotlin Multiplatform, which loads the resource bundle |
An honest summary. The status page has the item-by-item contract.
| Area | State |
|---|---|
| Python distributions (install, list, find, uninstall; pinned SHA-256) | ✅ implemented |
Targets and per-target dependencies (add, remove, sync, tree) |
🟡 working; part of it has no test yet |
| C/C++ extensions through Meson | 🟡 host only, no cross-compiling yet |
Bundles: resource, single, fat, patch |
✅ implemented |
Build levels: instant / bytecode |
✅ / 🟡 (resource only) |
Build levels: native / mixed |
⏳ planned; semantics decided, compile slot in draft |
deploy, code push, binary bundle |
⏳ planned |
- Guide: getting started, targets and dependencies, Python distributions, build levels and bundles, the library API. English and 한국어.
- 한국어 README
Work here runs intent → spec → test → code: a behaviour change starts as a spec change, its test is written and seen failing, then the code makes it pass. The guide's contributing notes say how to run the tests.
Apache-2.0 © thisisthepy