mbox series

[libgpiod,v9,0/1] bindings: python: optionally include module in sdist

Message ID 20231025082707.821368-1-phil@gadgetoid.com
Headers show
Series bindings: python: optionally include module in sdist | expand

Message

Phil Howard Oct. 25, 2023, 8:27 a.m. UTC
This changeset vendors the gpiod library into the Python package.

Why?

So that setup.py can produce an sdist that is installable irrespective of
the availability or version of a distro-supplied libgpiod.

This prevents a libgpiod pypi package install balking because the distro
libgpiod is outdated or otherwise incompatible. This happens when
attempting to install the current libgpiod from pypi onto - for example -
the Debian Bookworm based Raspberry Pi OS or Ubuntu 23.10 Mantic which both
ship with libgpiod v1.6.3.

The availability of a distro agnostic package also ensures that libgpiod
can be installed via pypi into an isolated virtual environment, safely
specified as a dependency for Python packages and allows Python developers
to target the newest API version irrespective of their distro supplied
libgpiod.

This is essential, since a venv is now widely *required* for user Python
projects due to recommendations in pep-688 [1]

For Raspberry Pi this sdist can also be converted into a precompiled wheel
by piwheels [2] which is, by default, added to Raspberry Pi OS as a pip
index.

How?

If "LINK_SYSTEM_LIBGPIOD=1" is not specified and a valid "LIBGPIOD_VERSION"
is supplied then setup.py will first verify the requested version meets or
exceeds "GPIOD_MINIMUM_VERSION".

If this check passes it will fetch the requested, stable tarball from
mirrors.edge.kernel.org, verify the checksum, unpack the "lib" and
"include" directories and vendor them into the output sdist.

It will also drop a "libgpiod-version.txt" so that the sdist knows what
GPIOD_VERSION_STR to pass into the gpiod build, eg:

LIBGPIOD_VERSION="2.1.0" python3 -m build . --sdist

Will output dist/libgpiod-2.1.0.tar.gz vendoring libgpiod v2.1.0.

If "libgpiod-version.txt" exists and the version in "libgpiod-version.txt"
matches the requested LIBGPIOD_VERSION then lib and include are assumed to
already exist and the tarball fetch will be skipped. This prevents build
from trying to fetch the tarball twice when called with:

LIBGPIOD_VERSION="2.1.0" python3 -m build .

Runtime dependencies for fetching and vendoring a tarball are only imported
when an sdist or build_ext command is triggered with "LIBGPIOD_VERSION".

When a user builds or installs an sdist (via pip install or otherwise) if a
"libgpiod-version.txt" exists and "LINK_SYSTEM_LIBGPIOD=1" is not specified
in their environment then the gpiod._ext C Extension is amended to include
all of the vendored C sources for gpiod and the resulting module build will
function independently of the system libgpiod.

Fetching libgpiod tarballs is an effort to reconsile the fact that both
libgpiod and the Python bindings live in the same source tree but are
versioned independently of each other. Bugfixes and changes to Python
bindings should not vendor unstable, development versions of libgpiod.

No effort has been made to allow an unstable, vendored build since it's
assumed developers will build and install libgpiod and use
"LINK_SYSTEM_LIBGPIOD".

While the output sdist will - by default - build a standalone gpiod module
it's possible for the end user to supply the "LINK_SYSTEM_LIBGPIOD=1" env
variable to override this behaviour and attempt to link their system
libgpiod (this will fail if it's incompatible with the bindings) eg:

LINK_SYSTEM_LIBPGIOD=1 pip install libgpiod

[1] - https://peps.python.org/pep-0668/
[2] - https://www.piwheels.org/

Changes v8 -> v9
- Removed Version testing hack

Changes v7 -> v8
- Tweak sha256sums parsing for better clarity
- Add check for libgpiod-version.txt to prevent "build" trying to refetch
- Added a URL to metadata to stop setup.py complaining
- Change GPIOD_MINIMUM_VERSION to LIBGPIOD_MINIMUM_VERSION
- Change GPIOD_VERSION to LIBGPIOD_VERSION

Changes v6 -> v7
- Added GPIOD_MINIMUM_VERSION to catch builds against incompatible libgpiod
- Set GPIOD_MINIMUM_VERSION to 2.1.0
- New requirement "packaging" added to pyproject.toml

Changes v5 -> v6
- Change SRC_BASE_URL to mirrors.edge.kernel.org
- Fetch sha256sums.asc and verify tarball signature
- Moved tarfile and urllib imports to fetch_tarball for fewer runtime deps
- Download and extract into a temporary directory
- Changed print to log.info
- Changed print/return errors to raise BaseError
- Check for lib/include in build tree and bail early

Changes v4 -> v5
- Move logic from main program flow to build_ext and sdist overloads
- GPIOD_VERSION_STR is now GPIOD_VERSION
- Fetch sources from a libgpiod tarball if GPIOD_VERSION is supplied
- Removed changes to bindings/python/Makefile.am
- Moved and rephrased comment about build_ext rmtree("tests")

Changes v3 -> v4
- Check for lack of "GPIOD_VERSION_STR" and revert to original behaviour
- Add status messages to setup.py, hinting at the package build mode

Changes v2 -> v3
- Pass in correct "GPIOD_VERSION_STR" from build
- Output an sdist build for pypi

Changes v1 -> v2
- Switch from symlinks to explicit file copy

Phil Howard (1):
  bindings: python: optionally include module in sdist

 bindings/python/MANIFEST.in    |   5 +
 bindings/python/pyproject.toml |   2 +-
 bindings/python/setup.py       | 212 +++++++++++++++++++++++++++++++--
 3 files changed, 207 insertions(+), 12 deletions(-)