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.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.1.0
File Size Uploaded
upyle-0.1.0.tar.gz 44.1 kB Details

Built distribution (wheel)

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

Total release size: 85.0 kB

Release files / upyle-0.1.0.tar.gz

Download URL upyle-0.1.0.tar.gz
Size 44.1 kB
Tags Source
SHA-256 checksum
How to use checksums
ac25503f7b41e3d4bc786d536b198a0bfe36385f66ddcfcc40b2b79b2813415b
BLAKE2b-256 checksum
How to use checksums
4ef0d83d4738dba250bb2e7737e1b49a45175a4f6df5b7fbf0c2d4a58d74f25d
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 6, 2026.

Transparency log

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

Download URL upyle-0.1.0-py3-none-any.whl
Size 40.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
50b2730bcc5ccebb653662a3826b4bfd7c62a49fa867ac9183ff2cf1c1afa789
BLAKE2b-256 checksum
How to use checksums
44ecf4c2cf9d5690bc03c7ebbfedbca9cae2f4fbbecc53822aafd5af896f13cb
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 6, 2026.

Transparency log

Release history Release notifications | RSS feed

0.2.0

2 release files

0.1.2

2 release files

0.1.1

2 release files

This release

0.1.0 This release

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