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

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.2
File Size Uploaded
upyle-0.1.2.tar.gz 44.8 kB Details

Built distribution (wheel)

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

Total release size: 86.5 kB

Release files / upyle-0.1.2.tar.gz

Download URL upyle-0.1.2.tar.gz
Size 44.8 kB
Tags Source
SHA-256 checksum
How to use checksums
1318d1fc82e85df66fb5cdea22ff8850afd309b9158a5df437d1cd566899daec
BLAKE2b-256 checksum
How to use checksums
fe0c5a2a4f2b8ec40d6fc8d5164412874e37907b5ecf1bc007402bbf7188f847
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.2-py3-none-any.whl

Download URL upyle-0.1.2-py3-none-any.whl
Size 41.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
91d8911279e1950737b6fcc13bad63997c30ffde6ca3a4021c39ba20f7bc35d2
BLAKE2b-256 checksum
How to use checksums
d293147c5f36a538b72773f7ddeda2c6d1ae3c6449a6574646d4b6d4a22f6d2d
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

This release

0.1.2 This release

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