Skip to main content

python-to-binary

py2bin turns Python into machine code using nothing but the Python standard library. No Cython, Nuitka, mypyc, Rust, C, C++, PyInstaller, PPCI, bootloader, assembler, linker or SDK - and no gcc or clang at any point. The only thing a build needs is an interpreter.

pip install python-to-binary
py2bin compile-capi app.py --target darwin-arm64 -o app

Source, issues and the full documentation: https://github.com/yu314-coder/python_to_binary

Platforms

What compile-capi - the tier that turns your program into machine code that drives CPython - can target today.

x86-64 arm64
macOS ✅ works ✅ works
Windows ✅ works ⬜ future work
Linux ⬜ future work ⬜ future work

Each working target is held to the same standard: an 889-program corpus is compiled for it and every program's output and exit code compared against CPython's. macOS agrees on 878 and differs on 7; a 100-program slice run through Wine agrees on 93 and differs on 5. The differences are the same on every platform and are inherent rather than open - CPython's "Did you mean" needs a Python frame to suggest from, and the repr of a compiled function really is a builtin function's.

The native tier (py2bin compile, no CPython at all) targets all six.

The paths through it

compile-capi translates ordinary Python into C that drives the CPython C API, then compiles that C with py2bin's own C compiler. This is the tier Nuitka occupies, with Nuitka's dependency removed - Nuitka hands its generated C to clang, and this compiles it itself. Your logic becomes machine code; Python's object semantics stay in libpython, which the binary links.

compile removes CPython entirely: Python AST → py2bin IR → optimizer → handwritten x86-64/ARM64 instructions → ELF, PE or Mach-O. Nothing is interpreted and nothing is linked. The price is the smallest accepted subset.

freeze / bundle is compatibility packaging: your program shipped beside an interpreter that runs it, which is how a project with NumPy or a GUI gets an artifact at all. It is not translation.

Using it

pip install python-to-binary
command what it does
py2bin compile-capi Python → C driving the CPython C API → machine code
py2bin compile Python → machine code, no CPython anywhere
py2bin compile-c py2bin's own C compiler, on your C
py2bin freeze ship the program beside an interpreter
py2bin targets list the targets this build knows

Bundling a real application into a macOS .app that carries its own interpreter and packages:

py2bin compile-capi app.py --target darwin-arm64 \
  --app --name "My App" --icon icon.icns \
  --embed-python --site ../Resources/site-packages \
  --bundle-site /path/to/venv/lib/python3.14/site-packages \
  --prune-unused --zip-stdlib \
  -o dist/MyApp.app --clean

How it works

Nothing wraps a toolchain; each stage is a module you can read.

capi_emit.py        Python AST  ->  C that calls the CPython C API
capi_ints.py          which locals may live in a machine register
c_preprocessor.py   #include, macros, conditionals
c_frontend.py       C  ->  py2bin IR
native/ir.py        the IR itself
native/optimizer.py constant folding, dead code, write merging
native/arm64.py     IR  ->  ARM64 instructions
native/x86_64.py    IR  ->  x86-64, System V and Microsoft x64
native/formats/     Mach-O, PE32+, ELF
freezer.py          bundling: interpreter, packages, pruning, archives
cabi.py             the vetted CPython entry points

So compile-capi is five stages, all of them in this package: capi_emitc_preprocessorc_frontendnative.x86_64/native.arm64native.formats.macho/pe.

There is no import ctypes anywhere on that path, which a test asserts by compiling in a fresh interpreter and listing what got loaded. ctypes is standard library and would pass an imports-only-stdlib check, but it pulls in subprocess - and there are Pythons where a subprocess is not something a program may have.

Measured against Nuitka

manim_app: 10,100 lines, pywebview + Pillow + pyobjc, built both ways on the same machine.

py2bin Nuitka
whole .app 61.2 MB 72.6 MB
main binary 9.2 MB 29.6 MB
bare interpreter start 9.5 ms 16.2 ms
start with the app's imports 52.1 ms 44.8 ms
compile time 16.7 s minutes

Run time, median of 5, seconds:

workload py2bin CPython Nuitka
integer arithmetic 0.050 0.084 0.095
while loop 0.045 0.070 0.045
nested loops 0.022 0.035 0.042
function calls 0.065 0.023 0.020
string building 0.025 0.011 0.009

Loops beat both because a local the analysis picks out is held in a register rather than on the heap, with the overflow check that falls back to unbounded arithmetic when it leaves the word. Calls still lose: an argument is boxed at the call and unboxed inside, where the interpreter's specialised call pays neither.

Licence

MIT. Full documentation, source and issues: https://github.com/yu314-coder/python_to_binary

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

python_to_binary-0.3.0.tar.gz (703.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

python_to_binary-0.3.0-py3-none-any.whl (470.9 kB view details)

Uploaded Python 3

File details

Details for the file python_to_binary-0.3.0.tar.gz.

File metadata

  • Download URL: python_to_binary-0.3.0.tar.gz
  • Upload date:
  • Size: 703.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.6

File hashes

Hashes for python_to_binary-0.3.0.tar.gz
Algorithm Hash digest
SHA256 01805c6e226000ac97ea9f58cf159be8fada81aad34b53de109b8d6fa0b09bc7
MD5 75a8e0d9c403bb3250de2d8f86d6d524
BLAKE2b-256 59b879f28774ff64baf13e779f919563d19feb705a599d37f99beb81fafc95e4

See more details on using hashes here.

File details

Details for the file python_to_binary-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for python_to_binary-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 70344a48c261d69108973865ab8dbf0f294ed5b623da8b6bb236d462881d995b
MD5 3a59fe4b327917983a7f53306e1a5861
BLAKE2b-256 7f75e8c52f1f02580c4b1e10fc4cfacdd9ea85e7d3b87f4b2554f61c7cc6d0a6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page