Bug 170443 - [Feature Request] Implement Python Stable ABI (Limited API) for PyUNO to decouple LibreOffice from external Python versions
Summary: [Feature Request] Implement Python Stable ABI (Limited API) for PyUNO to deco...
Status: UNCONFIRMED
Alias: None
Product: LibreOffice
Classification: Unclassified
Component: sdk (show other bugs)
Version:
(earliest affected)
24.2.0.0 alpha0+
Hardware: All All
: medium enhancement
Assignee: Not Assigned
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: Macro-Python Dev-related
  Show dependency treegraph
 
Reported: 2026-01-23 05:56 UTC by flexiphire
Modified: 2026-06-27 13:43 UTC (History)
4 users (show)

See Also:
Crash report or crash signature:


Attachments
pyuno: build pyuno against Python Stable ABI (47.96 KB, patch)
2026-06-18 21:20 UTC, flexiphire
Details

Note You need to log in before you can comment on or make changes to this bug.
Description flexiphire 2026-01-23 05:56:11 UTC
Description:
PROBLEM DESCRIPTION:
The pyuno bridge on Windows is currently compiled against a specific version of Python (e.g., Python 3.11). This creates a hard binary dependency, preventing external Python scripts running on any other version (e.g., 3.12, 3.13) from importing "uno". This creates a "Version Lock" that hinders professional automation and Data Science integration.

BENEFITS OF FIXING THIS:
1. Decoupling: Users can upgrade their external Python environment (e.g., to use modern AI/ML libraries) without breaking LibreOffice automation.
2. Enterprise Deployment: IT departments can deploy standard Python versions without conflict.
3. Longevity: Automation scripts won't break every time LibreOffice updates its bundled Python version.

Steps to Reproduce:
1. Install LibreOffice (which currently bundles Python 3.11).
2. Install an external Python 3.12 (or newer) environment (e.g., via Anaconda or python.org).
3. In the external Python 3.12 environment, append the LibreOffice "program" directory to sys.path.
4. Attempt to run: "import uno"

Actual Results:
The import fails with a DLL conflict error:
"ImportError: Module use of python311.dll conflicts with this version of Python."

Expected Results:
The "uno" module should import successfully.

If pyuno were compiled with the Python Stable ABI (Limited API), the bridge would be able to load into Python 3.11, 3.12, or 3.13 processes seamlessly without binary conflicts.


Reproducible: Always


User Profile Reset: No

Additional Info:
TECHNICAL IMPLEMENTATION PROPOSAL:
To support this, the Windows build process for the PyUNO bridge needs to be updated to target the Python Stable ABI.

1. Compiler Flags: Define `Py_LIMITED_API` (e.g., 0x03080000 for Python 3.8+ compatibility) in the pyuno makefiles.
2. Linker: Link against `python3.lib` (the stable ABI library) instead of the version-specific `python311.lib`.
3. Source Refactoring: Refactor `pyuno` C++ source files to replace direct access to Python internal structures (e.g., ob_refcnt, ob_type) with the equivalent Stable API macros/functions (Py_REFCNT, Py_TYPE), as direct structure access is forbidden in the Limited API.
Comment 1 Roman Kuznetsov 2026-03-27 13:11:39 UTC
Neil, what's your opinion for this one?
Comment 2 flexiphire 2026-06-18 21:20:03 UTC
Created attachment 207478 [details]
pyuno: build pyuno against Python Stable ABI

Subject: pyuno: build pyuno against Python Stable ABI

This patch is a concrete first pass at removing pyuno's CPython-minor-version
lock by moving the pyuno C extension surface toward Python's Stable ABI.

Problem:
pyuno currently depends on CPython-version-specific ABI details. On Windows this
shows up directly as a pyuno.pyd built for a specific pythonXY.dll, so Python
automation clients must match LibreOffice's bundled CPython minor version.

Approach:
- Add a pyuno-specific `python_abi3` external that defines
  `Py_LIMITED_API=0x030A0000`.
- Link pyuno through a pyuno-specific ABI3 external while leaving other
  LibreOffice Python consumers on the existing Python external. On POSIX builds,
  prefer the non-embed `python3` pkg-config module and allow pyuno's Python API
  symbols to resolve from the loading interpreter instead of adding a
  minor-versioned `libpython3.x` dependency.
- Convert pyuno's static `PyTypeObject` definitions to heap types created with
  `PyType_FromSpec`.
- Replace direct CPython struct access such as `PyThreadState_Get()->interp`,
  `Py_TYPE(obj)->tp_dict`, and `tp_free` with public API usage.
- Replace APIs/macros not available at the Python 3.10 Limited API floor, such
  as `PyUnicode_AsUTF8` and `PyUnicode_FromKindAndData`.

Validation done here:
- Confirmed MSVC Build Tools and Windows SDK are installed and usable.
- Compiled, linked, and ran a small Windows C++ smoke test with `cl.exe`.
- Applied this patch to a full LibreOffice core checkout at commit `ea59b2284`.
- Configured a WSL Ubuntu 24.04 build with system Python 3.12 and a minimized
  headless build profile.
- Ran `make fetch`, `PARALLELISM=2 make Library_pyuno`, and
  `PARALLELISM=2 make Pyuno` successfully.
- Verified `instdir/program/libpyuno.so` does not have a `libpython3.12`
  `DT_NEEDED` entry.
- Smoke-loaded `instdir/program/libpyuno.so` from Python 3.12 with
  `ctypes.CDLL(...)` and `LD_LIBRARY_PATH` pointed at `instdir/program`.
- Scanned the patched pyuno module for remaining static type objects,
  CPython-version conditionals, direct type-field access, and removed Unicode
  APIs.
- Checked the used `PyType_Slot` constants and main APIs against CPython 3.10
  headers, matching the `Py_LIMITED_API=0x030A0000` floor.

Still needed upstream:
- Review whether POSIX pyuno should explicitly opt out of `-z defs` as done here
  or use a gbuild-level Python-extension abstraction.
- Run the full pyuno Python tests, including Writer/Calc UNO import and bridge
  smoke tests from more than one Python 3 minor version.
- Run Windows and macOS builds, especially the Windows `python3.lib`/`python3.dll`
  Stable ABI path that motivated this change.


# Validation Notes

LibreOffice core checkout:

- Source: `https://github.com/LibreOffice/core.git`
- Commit tested: `ea59b2284`
- Build host: Ubuntu 24.04 in WSL
- Python: system Python 3.12

Configure/build commands:

```sh
./autogen.sh --enable-python=system --disable-gui --without-x --without-java \
  --disable-gtk3 --disable-gtk4 --disable-dbus --disable-cups \
  --disable-gstreamer-1-0 --disable-sdremote --disable-sdremote-bluetooth \
  --disable-pdfimport --disable-skia --disable-lpsolve --disable-coinmp \
  --disable-firebird-sdbc --disable-postgresql-sdbc --disable-report-builder \
  --disable-extension-integration --without-help --without-myspell-dicts \
  --disable-ccache --disable-dependency-tracking --disable-werror

make fetch
PARALLELISM=2 make Library_pyuno
PARALLELISM=2 make Pyuno
```

Results:

- `Library_pyuno` built successfully.
- `Pyuno` built successfully.
- `config_host.mk` generated `PYTHON_ABI3_LIBS=$(gb_SPACE) -ldl`.
- `config_host.mk` still generated legacy `PYTHON_LIBS=$(gb_SPACE) -lpython3.12 -ldl`.
- `instdir/program/libpyuno.so` was produced.
- `readelf -d instdir/program/libpyuno.so` did not show any `libpython3.12`
  `DT_NEEDED` entry.
- This smoke load succeeded:

```sh
LD_LIBRARY_PATH=$PWD/instdir/program python3 - <<'PY'
import ctypes
ctypes.CDLL('instdir/program/libpyuno.so')
print('loaded libpyuno.so')
PY
```

Remaining upstream work:

- Run full pyuno Python tests and UNO bridge smoke tests.
- Build on Windows to validate the intended `python3.lib` / `python3.dll`
  Stable ABI path.
- Build on macOS and review platform-specific Python Stable ABI policy.