Skip to main content

upyle — pure-Python OMF→MZ+LE linker

Takes 32-bit OMF .obj files (produced by nasm -f obj) plus a PMODE/W or DOS/32A extender stub binary and emits an MZ+LE executable that runs on FreeDOS / DOSBox / QEMU+FreeDOS / dos_emu / real DOS without an extra dos4gw.exe redistribution.

Designed for the i386/DOS retro-compiler family: uc386 (C23) and ucpp386 (C++) both use upyle to ship .exe artifacts without an Open Watcom installation on the build host. (Open Watcom has no native macOS build, so wlink-based pipelines can't run on a Mac; upyle removes that dependency.)

Origin

Extracted from uc386/addons/harness/pyle.py into a sibling package so both compilers can consume it. Mirrors how the peephole optimizer became upeep386 and how upeepz80 serves the Z80 compiler family.

Install

pip install upyle

The distribution and import name is upyle, not pyle: the name pyle on PyPI belongs to an unrelated project (a shell one-liner tool) that installs a top-level pyle.py, so sharing the name would mean the two silently shadow each other on sys.path. The u prefix also matches the sibling packages — uc386, upeep386, uplox.

Or from source:

pip install -e .

Quick start

from pathlib import Path
from upyle import parse_omf, link, write_le, STUB_DIR

objects = [parse_omf(Path("user.obj")), parse_omf(Path("bridge.obj"))]
image   = link(objects)
stub    = (STUB_DIR / "pmodew_stub.bin").read_bytes()
write_le(image, stub, entry_symbol="_pmodew_start",
         out_path=Path("user.exe"))

For DOS/32A: pass bind_dos32a_stub(raw_dos32a_bytes) to write_le instead, with explicit_stack_object=True. DOS/32A isn't bundled — fetch DOS32A.EXE from https://archive.org/details/dos32a-912-bin (zlib license).

CLI: upyle user.obj bridge.obj -o user.exe.

Scope

  • 32-bit USE32 segments only: _TEXT class=CODE, _DATA class=DATA, _BSS class=BSS.
  • Fixup kinds: rel32 (self-relative offset, used by call/jmp rel32) and off32 (32-bit absolute offset, used by mov eax, _label).
  • Multiple input objects, cross-object PUBDEF/EXTDEF resolution.
  • Single linker pass; produces an MZ+LE with the extender stub bundled as the MZ portion (the .exe is self-contained).

No 16-bit code, no far jumps, no COMDAT. Use Open Watcom's wlink when you need a richer linker.

What lives in the package

  • upyle/pyle.py — the linker (OMF parser + LE emitter + small linker).
  • pmodew_stub.bin — the PMODE/W extender as a ready-to-prepend blob (~9 KB). BSD-ish license; bundled with permission.

License

GPL-3.0-or-later for the linker code itself. The bundled extender stubs ship under their respective upstream licenses (PMODE/W: free-for-any-use with attribution).

Release files for upyle 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for upyle 0.2.0
File Size Uploaded
upyle-0.2.0.tar.gz 64.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for upyle 0.2.0
File Interpreter ABI Platform
upyle-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 125.1 kB

Release files / upyle-0.2.0.tar.gz

Download URL upyle-0.2.0.tar.gz
Size 64.0 kB
Tags Source
SHA-256 checksum
How to use checksums
decf10730e4119d2c9f22f52880c093cc56ba201b0c54dff83ebef77b8611bb0
BLAKE2b-256 checksum
How to use checksums
8c63c8ca3de311b4b84ec893884931851835549367b5d8a0b791c3f6c75bdbcf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 7, 2026.

Transparency log

Release files / upyle-0.2.0-py3-none-any.whl

Download URL upyle-0.2.0-py3-none-any.whl
Size 61.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
499b2c264830adbfda0ab3e426e9ecf6dc7ea661962f850f5fb0b88c91cb88dc
BLAKE2b-256 checksum
How to use checksums
f2a078b551e2383e1f336889fe065b1eec7fd4158a338a1134afc8176c325b84
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page