Skip to content

Ship a microcontroller only what can run on one - #46

Merged
bdbarnett merged 2 commits into
mainfrom
housekeeping/mip-split
Sep 22, 2026
Merged

bdbarnett merged 2 commits into
mainfrom
housekeeping/mip-split

Conversation

@bdbarnett

Copy link
Copy Markdown
Contributor

The publisher half of pydevices#30. The declaration half is already on pydevices main as mip-split.toml (e2bce5c), inert until this merges.

The dry install listing, before and after

Through mip's own tools/build.py, which is what the index serves — not a count of files on disk:

pydevices          51 -> 31 files
pydevices-desktop  58 -> 58 files, and the identical set

The 20 the device stops carrying:

audiodev/   android_audio pygame_audio sdl2_audio wasm_audio web_audio win_audio
displaydev/ _desktop _domkeys androidsdl jndisplay pgdisplay psdisplay sdldisplay
            wasmdisplay windisplay
multimer/   librt sdl2 threading wasm win32

Nothing is added anywhere, and nothing is lost: the union of the two packages is the same 58 files it was. A desktop, browser or Android host installs pydevices-desktop exactly as before and gets exactly what it got, because that package already require()s pydevices and build.py materialises the requirement.

Why this is safe

auto.py stays on the device in every case. Every host branch in displaydev/auto.py, audiodev/auto.py and multimer/auto.py imports inside the function, so importing the module on a board is fine — and calling AutoDisplay() there was never the intent ("board configs stay MCU-shaped wiring only", displaydev/auto.py:9). Checked before writing any of this: no MCU-side module imports a host-only one at module scope, which is the one way the split could break an import.

The guards, both shown failing

A split declared in one file and enforced nowhere rots the first time somebody renames a module.

$ # a name in mip-split.toml that no longer matches anything
mip-split.toml [displaydev] names modules that no longer exist: gonedisplay
exit 1

$ # busdisplay.py given a module-scope import of a host-only backend
displaydev/busdisplay.py:21 imports the host-only module 'sdldisplay' at module
scope, so it would not import on a microcontroller. Move the import inside the
function, or drop 'sdldisplay' from mip-split.toml.
exit 1

$ # the real tree
exit 0

The asymmetry is deliberate: a new backend that nobody classifies ships to the device. So the cost of forgetting is one extra file on a board, never a missing import on a host.

What this does not do

It does not create new packages, new PyPI distributions or new install commands — pydevices and pydevices-desktop are the same two names, and the board bring-up path (mip.install pydevices, then the board package) is unchanged. The issue listed per-platform packages and an extras split as the other options; this is the third, and the cheapest to undo.

mip.install("pydevices") wrote 51 files to a board, about twenty of them
desktop, browser or Android backends: windisplay, wasmdisplay, pgdisplay,
sdldisplay, jndisplay, psdisplay, androidsdl, win_audio, pygame_audio,
sdl2_audio, wasm_audio, web_audio, android_audio, win32, sdl2, threading, wasm,
librt and two desktop helpers (#30). Minutes over WiFi and flash spent
on modules that cannot execute.

synchronize_mip_package.py now reads mip-split.toml from the source repository,
which names those modules per package, and routes them into pydevices-desktop,
which already require()s pydevices. The device package names its files one by
one -- package("displaydev", files=(...)) -- so the install list is the
manifest and nothing else decides it.

Measured through mip's own tools/build.py, which is what the index serves:

    pydevices          51 -> 31 files
    pydevices-desktop  58 -> 58, the identical set

Two guards, both shown failing: a name in mip-split.toml that no longer exists
fails the sync ("names modules that no longer exist: gonedisplay"), and so does
an MCU-side module that imports a host-only one at module scope
("busdisplay.py:21 imports the host-only module 'sdldisplay' at module scope").
Exit 1 in both cases, 0 on the real tree. A new backend nobody classifies ships
to the device, so forgetting costs a board one file, never a host an import.
The guard was re-proved after the rewrite: the planted module-scope import
still fails the sync with exit 1, the real tree still exits 0, and the device
package is still 31 files.
@bdbarnett
bdbarnett merged commit 60e2ab9 into main Sep 22, 2026
5 checks passed
@bdbarnett
bdbarnett deleted the housekeeping/mip-split branch September 22, 2026 04:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant