Metadata-Version: 2.4
Name: upyle
Version: 0.1.1
Summary: Pure-Python OMF to MZ+LE linker for i386/DOS extender binaries (PMODE/W, DOS/32A)
Author: pyle project
License-Expression: GPL-3.0-or-later
Project-URL: Homepage, https://github.com/avwohl/pyle
Project-URL: Repository, https://github.com/avwohl/pyle
Keywords: compiler,linker,i386,x86,dos,omf,le,pmodew,dos32a,freedos,retro
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Compilers
Classifier: Topic :: Software Development :: Code Generators
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=7.4.0; extra == "dev"
Dynamic: license-file

# 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](https://github.com/avwohl/uc386) (C23) and
[ucpp386](https://github.com/avwohl/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](https://github.com/avwohl/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).
