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.1.1

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.1.1
File Size Uploaded
upyle-0.1.1.tar.gz 44.4 kB Details

Built distribution (wheel)

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

Total release size: 85.6 kB

Release files / upyle-0.1.1.tar.gz

Download URL upyle-0.1.1.tar.gz
Size 44.4 kB
Tags Source
SHA-256 checksum
How to use checksums
3b5be78e1e8901c768ae245922c21c7c416de7ec4430cbd61246a1af42aefa15
BLAKE2b-256 checksum
How to use checksums
5dc873b53b9136b11885f140fe983a429ea51aa4bc644f7f7110bd2698b6c40d
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.1.1-py3-none-any.whl

Download URL upyle-0.1.1-py3-none-any.whl
Size 41.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1a0873a1cbade6eaed16eac1d4d137b22a811e88e9aee0cacf4905a9eefe93ea
BLAKE2b-256 checksum
How to use checksums
c1834be42c5f09a9e79308e58978064b9204644789685fc587e2bf0774424bca
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

0.2.0

2 release files

0.1.2

2 release files

This release

0.1.1 This release

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