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/jmprel32) and off32 (32-bit absolute offset, used bymov 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
.exeis 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)
| File | Size | Uploaded | |
|---|---|---|---|
| upyle-0.2.0.tar.gz | 64.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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 logRelease 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