Build and develop the native CPython extension locally. Day-to-day use should prefer the TestPyPI wheel — see README.md.
This repo is self-contained for a normal build: you only need this clone
(plus the lvgl submodule). No MicroPython, CircuitPython, or workspace
orchestrator is required.
These files are committed in this repo (they track the latest published binding sync from lvgl-bindings):
| Path | Role |
|---|---|
generated/lvgl_python.c |
Generated CPython binding |
generated/lvgl.pyi |
Type stubs (copied into the install) |
lv_conf.h |
LVGL config used for the build |
display_driver.py |
Optional helper (import display_driver) |
lvgl/ |
LVGL C sources (git submodule) |
A normal pip install -e . compiles those vendored sources. You do not need
a local lvgl-bindings tree to build or test this package.
Clone lvgl-bindings as a sibling only when you are changing the generator or regenerating bindings:
workspace/
lvgl-bindings/ # optional — generator + regenerate_lvpy.sh
lvgl-python/ # this repo
Do that when you need to:
- Edit
lvgl-bindings/binding/emit_cpython.py(e.g.max_phase) or other emitters - Run
./regenerate_lvpy.shin lvgl-bindings, then sync the output into this repo - Run the shared cross-runtime smoke script at
lvgl-bindings/tools/test_lvgl_smoke.py
To refresh vendored files from GitHub without a sibling clone, use:
./scripts/sync_from_lvgl_bindings.sh # lvgl-bindings main
./scripts/sync_from_lvgl_bindings.sh --ref SHA # pin a commit/tag/branchThat script clones lvgl-bindings into a temp directory, copies the generated
files, and updates the lvgl submodule pin. Release flow: publishing.md.
- Python 3.9+ with
pipandsetuptools - Vendored files above (already in the clone)
git submodule update --init lvgl
- GCC or Clang
python3-dev(or equivalent) matching your Python version
On Debian/Ubuntu:
sudo apt install python3-dev build-essential- python.org CPython (or another MSVC-built Python 3.9+)
- Microsoft C++ Build Tools with the Desktop development with C++ workload
(Visual Studio Build Tools) - MinGW is not supported for python.org Windows Python; use MSVC.
setup.py selects MSVC warning flags on Windows and uses a linker response file
(LVGL compiles many .c files; the raw link.exe command line exceeds Windows
limits).
lvgl-python/
├── generated/lvgl_python.c # vendored binding (synced from lvgl-bindings)
├── generated/lvgl.pyi
├── lv_conf.h
├── display_driver.py
├── lvgl/ # LVGL git submodule
├── src/lvpy_runtime.c
├── src/lvpy_runtime.h
├── tests/ # unit tests
├── scripts/ # sync / publish / pyodide wheel
└── setup.py
Clone with submodules:
git clone --recurse-submodules https://github.com/PyDevices/lvgl-python.git
# or after a plain clone:
git submodule update --init lvglpip install compiles src/lvpy_runtime.c, generated/lvgl_python.c, and LVGL
sources under lvgl/src.
Use editable install (-e) while developing so the .so / .pyd beside
this directory stays in sync with rebuilds.
git clone --recurse-submodules https://github.com/PyDevices/lvgl-python.git
cd lvgl-python
python3 -m venv .venv
.venv/bin/pip install -r requirements-dev.txt
.venv/bin/pip install -e .Quick import check:
.venv/bin/python -c "import lvgl as lv; lv.init(); lv.deinit(); print('ok')"Unit tests:
.venv/bin/python -m unittest discover -s testsKeep the repo on the WSL filesystem and install into Windows Python with
pip.exe:
cd /path/to/lvgl-python
pip.exe install -e "$(wslpath -w "$PWD")"
python.exe -c "import lvgl as lv; lv.init(); lv.deinit(); print('ok')"The first build compiles every LVGL source and may take several minutes over
\\wsl.localhost\....
cd C:\path\to\lvgl-python
git submodule update --init lvgl
py -m pip install -e .
py -c "import lvgl as lv; lv.init(); lv.deinit(); print('ok')"Open a new terminal after installing Build Tools so cl.exe is on PATH.
To change how much of the API is emitted, clone lvgl-bindings as a sibling, edit
max_phase in lvgl-bindings/binding/emit_cpython.py, regenerate, sync, then
reinstall:
cd ../lvgl-bindings && ./regenerate_lvpy.sh
cd ../lvgl-python
./scripts/sync_from_lvgl_bindings.sh # or copy generated files by hand
.venv/bin/pip install -e . # or pip.exe on WindowsAfter the first full build, incremental rebuilds are much faster. With
setuptools and wheel in the target venv:
.venv/bin/python setup.py build_ext --inplaceEditable install does not recompile on import; rerun pip install -e . (or
build_ext --inplace) after C source changes (src/lvpy_runtime.c or
generated/lvgl_python.c).
- Generator work:
lvgl-bindings - CPython runtime / packaging: this repo (
src/lvpy_runtime.c,setup.py)
Prefer a prebuilt pydevices-lvgl wheel tagged android_21_* for your ABI
(arm64_v8a or x86_64) from TestPyPI. The
pydevices-android-template pydeviceslvgl p4a recipe
installs a matching wheel when --extra-index-url points at TestPyPI, otherwise
cross-compiles from this tree (git submodule update --init lvgl).
export P4A_pydeviceslvgl_DIR=/path/to/lvgl-python # optional in-tree fallbackNative Linux/macOS/Windows wheels from TestPyPI are not loadable in Pyodide.
Each Publish TestPyPI release also builds a pyemscripten_2026_0 wasm32
wheel. Preferred install in the browser:
import micropip
await micropip.install("pydevices-lvgl", index_urls="https://test.pypi.org/simple/")- Host Python 3.14 (match the xbuildenv CPython)
- Node.js (for Emscripten)
- Network on first run (downloads xbuildenv + emsdk)
./scripts/build_pyodide_wheel.sh
./scripts/build_pyodide_wheel.sh --no-copy # dist/ only
PYODIDE_VERSION=314.0.0 ./scripts/build_pyodide_wheel.sh| Component | Role |
|---|---|
generated/lvgl_python.c (vendored) |
Types, methods, module functions, callbacks |
src/lvpy_runtime.c / src/lvpy_runtime.h |
CPython glue: wrappers, convertors, GIL |
setup.py |
Builds the lvgl extension module |
lvgl-bindings (optional sibling) |
Generator only — not required to compile |
Object wrappers (py_lv_obj_t) map lv_obj_t * to Python and keep
per-object callback dicts. Struct wrappers (py_lv_struct_t) expose LVGL
structs.
Event callbacks (phase 7): pass a Python callable to add_event_cb. With
user_data=None, the wrapper stores callbacks on the target object.
| Phase | Coverage |
|---|---|
| 1 | lv.init() / lv.deinit(), integer constants, LV_SYMBOL_* strings |
| 2 | Enum namespaces (lv.EVENT.CLICKED, lv.COLOR_FORMAT.*, …) |
| 3 | Struct types, field get/set |
| 4 | Struct methods (event.get_code(), …) |
| 5 | Widget / lv_obj types, constructors, methods |
| 6 | Module-level functions (display_create, screen_active, …) |
| 7 | Python callbacks (add_event_cb, flush/timer hooks, …) |
Phases 1–7 are enabled in the generator today.
- Vendored build inputs: you can compile from this repo alone; regenerate in lvgl-bindings only when changing the generator, then sync.
- Windows toolchain: python.org CPython on Windows requires MSVC Build Tools; MinGW cannot build this extension for that interpreter.
- PyDevices/lvgl-bindings — binding generator
- PyDevices/pydevices-examples — consumer of
import lvgl