diff mbox series

[libgpiod,1/1] bindings: python: standalone build tooling for tests

Message ID 20231107215156.2961942-2-phil@gadgetoid.com
State Superseded
Headers show
Series bindings: python: standalone build tooling for tests | expand

Commit Message

Phil Howard Nov. 7, 2023, 9:51 p.m. UTC
Move extension definitions and tooling for building tests into
`build_tests.py` and update Makefile.am to call it with appropriate path
prefixes.

`build_tests.py` will perform a standalone build of the text extensions,
keeping any build noise in a temporary directory and copying the final
built modules automatically out to `tests/gpiosim` and `tests/procname`.

Signed-off-by: Phil Howard <phil@gadgetoid.com>
---
 bindings/python/Makefile.am    | 25 +++++++----
 bindings/python/build_tests.py | 79 ++++++++++++++++++++++++++++++++++
 bindings/python/setup.py       | 28 +-----------
 3 files changed, 97 insertions(+), 35 deletions(-)
 create mode 100644 bindings/python/build_tests.py

Comments

Bartosz Golaszewski Nov. 8, 2023, 3:04 p.m. UTC | #1
On Tue, 7 Nov 2023 22:51:56 +0100, Phil Howard <phil@gadgetoid.com> said:
> Move extension definitions and tooling for building tests into
> `build_tests.py` and update Makefile.am to call it with appropriate path
> prefixes.
>
> `build_tests.py` will perform a standalone build of the text extensions,
> keeping any build noise in a temporary directory and copying the final
> built modules automatically out to `tests/gpiosim` and `tests/procname`.
>
> Signed-off-by: Phil Howard <phil@gadgetoid.com>
> ---

I'd like to be able to run the tests from the source tree but without
--inplace the core C extension is no longer built in-tree so I cannot do:

    PYTHONPATH=./bindings/python
LD_LIBRARY_PATH=./lib/.libs/:./tests/gpiosim/.libs/:bindings/python/
python -B -m tests

Could you somehow keep this behavior?

Bart
Phil Howard Nov. 8, 2023, 3:44 p.m. UTC | #2
On Wed, 8 Nov 2023 at 15:04, Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
> On Tue, 7 Nov 2023 22:51:56 +0100, Phil Howard <phil@gadgetoid.com> said:
> > Move extension definitions and tooling for building tests into
> > `build_tests.py` and update Makefile.am to call it with appropriate path
> > prefixes.
> >
> > `build_tests.py` will perform a standalone build of the text extensions,
> > keeping any build noise in a temporary directory and copying the final
> > built modules automatically out to `tests/gpiosim` and `tests/procname`.
> >
> > Signed-off-by: Phil Howard <phil@gadgetoid.com>
> > ---
>
> I'd like to be able to run the tests from the source tree but without
> --inplace the core C extension is no longer built in-tree so I cannot do:
>
>     PYTHONPATH=./bindings/python
> LD_LIBRARY_PATH=./lib/.libs/:./tests/gpiosim/.libs/:bindings/python/
> python -B -m tests
>
> Could you somehow keep this behavior?
>
> Bart

Sure, I can just add the gpiod extension to build_tests.py.

Looks like I had a stale one in my build directory, so when I ran the tests
they *just worked*. I'm adding gpiod/_ext.*.so and tests/*/_ext.*.so to
clean-local in Makefile.am to help prevent that.

I am also adding "python-tests-run" (could probably pick some better
names here?) to formalize your test command (I was running something
similar but not quite the same) so we (and any future pioneers) are working
on the same terms.
diff mbox series

Patch

diff --git a/bindings/python/Makefile.am b/bindings/python/Makefile.am
index 079ceb1..36fb66a 100644
--- a/bindings/python/Makefile.am
+++ b/bindings/python/Makefile.am
@@ -7,19 +7,28 @@  EXTRA_DIST = \
 
 if WITH_TESTS
 
-BUILD_TESTS = 1
+python-tests:
+	TOP_SRCDIR=$(abs_top_builddir) \
+	TOP_BUILDDIR=$(abs_top_builddir) \
+	$(PYTHON) build_tests.py
+
+else
+
+python-tests:
 
 endif
 
-all-local:
-	GPIOD_WITH_TESTS=$(BUILD_TESTS) \
-	$(PYTHON) setup.py build_ext --inplace \
-		--include-dirs=$(top_srcdir)/include/:$(top_srcdir)/tests/gpiosim/ \
-		--library-dirs=$(top_builddir)/lib/.libs/:$(top_srcdir)/tests/gpiosim/.libs/
+clean-local:
+	rm -rf dist
+
+all-local: python-tests
+	CFLAGS="-I$(abs_top_srcdir)/include/ -I$(abs_top_srcdir)/tests/gpiosim \
+	-L$(abs_top_builddir)/lib/.libs/ -L$(abs_top_builddir)/tests/gpiosim/.libs/" \
+	$(PYTHON) -m build
 
 install-exec-local:
-	GPIOD_WITH_TESTS= \
-	$(PYTHON) setup.py install --prefix=$(DESTDIR)$(prefix)
+	$(PYTHON) -m pip install dist/*.whl \
+	--prefix=$(DESTDIR)$(prefix)
 
 SUBDIRS = gpiod
 
diff --git a/bindings/python/build_tests.py b/bindings/python/build_tests.py
new file mode 100644
index 0000000..b984307
--- /dev/null
+++ b/bindings/python/build_tests.py
@@ -0,0 +1,79 @@ 
+# SPDX-License-Identifier: GPL-2.0-or-later
+# SPDX-FileCopyrightText: 2023 Phil Howard <phil@gadgetoid.com>
+
+"""
+Bring up just enough of setuptools/distutils in order to build the gpiod
+test module C extensions.
+
+Set "build_temp" and "build_lib" so that our source directory is not
+polluted with artefacts in build/
+
+Builds:
+
+    tests/gpiosim/_ext.<target>.so
+    tests/procname/_ext.<target>.so
+
+"""
+
+import tempfile
+from os import getenv, path
+
+from setuptools import Distribution, Extension
+from setuptools.command.build_ext import build_ext
+
+TOP_SRCDIR = getenv("TOP_SRCDIR", "../../")
+TOP_BUILDDIR = getenv("TOP_BUILDDIR", "../../")
+
+# __version__
+with open("gpiod/version.py", "r") as fd:
+    exec(fd.read())
+
+
+gpiosim_ext = Extension(
+    "tests.gpiosim._ext",
+    sources=["tests/gpiosim/ext.c"],
+    define_macros=[("_GNU_SOURCE", "1")],
+    libraries=["gpiosim"],
+    extra_compile_args=["-Wall", "-Wextra"],
+    include_dirs=[
+        path.join(TOP_SRCDIR, "include"),
+        path.join(TOP_SRCDIR, "tests/gpiosim"),
+    ],
+    library_dirs=[
+        path.join(TOP_BUILDDIR, "lib/.libs"),
+        path.join(TOP_BUILDDIR, "tests/gpiosim/.libs"),
+    ],
+)
+
+procname_ext = Extension(
+    "tests.procname._ext",
+    sources=["tests/procname/ext.c"],
+    define_macros=[("_GNU_SOURCE", "1")],
+    extra_compile_args=["-Wall", "-Wextra"],
+)
+
+dist = Distribution(
+    {
+        "name": "gpiod",
+        "ext_modules": [gpiosim_ext, procname_ext],
+        "version": __version__,
+        "platforms": ["linux"],
+    }
+)
+
+try:
+    from setuptools.logging import configure
+
+    configure()
+except ImportError:
+    from distutils.log import set_verbosity, DEBUG
+
+    set_verbosity(DEBUG)
+
+with tempfile.TemporaryDirectory(prefix="libgpiod-") as temp_dir:
+    command = build_ext(dist)
+    command.inplace = True
+    command.build_temp = temp_dir
+    command.build_lib = temp_dir
+    command.finalize_options()
+    command.run()
diff --git a/bindings/python/setup.py b/bindings/python/setup.py
index e8704d5..9607a28 100644
--- a/bindings/python/setup.py
+++ b/bindings/python/setup.py
@@ -13,7 +13,6 @@  from setuptools.errors import BaseError
 LINK_SYSTEM_LIBGPIOD = getenv("LINK_SYSTEM_LIBGPIOD") == "1"
 LIBGPIOD_MINIMUM_VERSION = "2.1"
 LIBGPIOD_VERSION = getenv("LIBGPIOD_VERSION")
-GPIOD_WITH_TESTS = getenv("GPIOD_WITH_TESTS") == "1"
 SRC_BASE_URL = "https://mirrors.edge.kernel.org/pub/software/libs/libgpiod/"
 TAR_FILENAME = "libgpiod-{version}.tar.gz"
 ASC_FILENAME = "sha256sums.asc"
@@ -189,11 +188,6 @@  class build_ext(orig_build_ext):
 
         super().run()
 
-        # We don't ever want the module tests directory in our package
-        # since this might include gpiosim._ext or procname._ext from a
-        # previous dirty build tree.
-        rmtree(path.join(self.build_lib, "tests"), ignore_errors=True)
-
 
 class sdist(orig_sdist):
     """
@@ -226,32 +220,12 @@  gpiod_ext = Extension(
     extra_compile_args=["-Wall", "-Wextra"],
 )
 
-gpiosim_ext = Extension(
-    "tests.gpiosim._ext",
-    sources=["tests/gpiosim/ext.c"],
-    define_macros=[("_GNU_SOURCE", "1")],
-    libraries=["gpiosim"],
-    extra_compile_args=["-Wall", "-Wextra"],
-)
-
-procname_ext = Extension(
-    "tests.procname._ext",
-    sources=["tests/procname/ext.c"],
-    define_macros=[("_GNU_SOURCE", "1")],
-    extra_compile_args=["-Wall", "-Wextra"],
-)
-
-extensions = [gpiod_ext]
-if GPIOD_WITH_TESTS:
-    extensions.append(gpiosim_ext)
-    extensions.append(procname_ext)
-
 setup(
     name="gpiod",
     url="https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git",
     packages=find_packages(exclude=["tests", "tests.*"]),
     python_requires=">=3.9.0",
-    ext_modules=extensions,
+    ext_modules=[gpiod_ext],
     cmdclass={"build_ext": build_ext, "sdist": sdist},
     version=__version__,
     author="Bartosz Golaszewski",