[lttng-dev] [PATCH babeltrace v3] Build Python bindings with distutils for consistent installs

Francis Deslauriers francis.deslauriers at efficios.com
Mon Feb 27 16:29:46 UTC 2017


v3: changes PYTHON_PATH -> PYTHONPATH in commit message and warning message.

This patch changes the build system used to compile and install the
Python Bindings. Distutils is used to find the right install directory.
When the install directory generated from the install prefix is not in
the Python search path (PYTHONPATH), we print a warning explaining what
can be done to include it.
It uses Distutils which is part of the Python standard library.

Signed-off-by: Francis Deslauriers <francis.deslauriers at efficios.com>
---
 .gitignore                                    | 10 +++-
 bindings/python/Makefile.am                   | 58 +++++++++++++++++-
 bindings/python/babeltrace/Makefile.am        | 30 ++--------
 bindings/python/babeltrace/__init__.py.in     | 25 ++++++++
 bindings/python/setup.py.in                   | 85 +++++++++++++++++++++++++++
 configure.ac                                  | 13 ++--
 m4/python_modules.m4                          | 23 --------
 tests/bin/intersection/bt_python_helper.py.in |  8 +--
 8 files changed, 187 insertions(+), 65 deletions(-)
 create mode 100644 bindings/python/babeltrace/__init__.py.in
 create mode 100644 bindings/python/setup.py.in
 delete mode 100644 m4/python_modules.m4

diff --git a/.gitignore b/.gitignore
index a7c9e3c..9259b6f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -47,8 +47,12 @@ converter/babeltrace-log
 core
 formats/ctf/metadata/ctf-parser.output
 stamp-h1
-bindings/python/babeltrace.i
-bindings/python/babeltrace.py
-bindings/python/babeltrace_wrap.c
+bindings/python/setup.py
+bindings/python/installed_files.txt
+bindings/python/build
+bindings/python/babeltrace/__init__.py
+bindings/python/babeltrace/babeltrace.i
+bindings/python/babeltrace/babeltrace.py
+bindings/python/babeltrace/babeltrace_wrap.c
 babeltrace.pc
 babeltrace-ctf.pc
diff --git a/bindings/python/Makefile.am b/bindings/python/Makefile.am
index d6b3648..37ae14e 100644
--- a/bindings/python/Makefile.am
+++ b/bindings/python/Makefile.am
@@ -1,3 +1,59 @@
 if USE_PYTHON
-SUBDIRS = babeltrace
+SUBDIRS = babeltrace .
+
+AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include -I$(srcdir)/babeltrace/
+
+# Since the shared object used by the python bindings is not built with libtool
+# we need to manually set the `rpath` during linkage
+AM_LDFLAGS=-L$(top_builddir)/formats/ctf/.libs -L$(top_builddir)/lib/.libs -Wl,-rpath,$(prefix)/lib
+
+INSTALLED_FILES=installed_files.txt
+
+all-local: build-python-bindings.stamp
+
+$(builddir)/babeltrace/__init__.py: $(srcdir)/babeltrace/__init__.py.in
+	cd babeltrace && $(MAKE) __init__.py
+
+$(builddir)/babeltrace/babeltrace.i: $(srcdir)/babeltrace/babeltrace.i.in
+	cd babeltrace && $(MAKE) babeltrace.i
+
+BINDINGS_DEPS=setup.py \
+		babeltrace/__init__.py \
+		babeltrace/babeltrace.i \
+		babeltrace/python-complements.c \
+		babeltrace/python-complements.h
+
+BUILD_FLAGS=CC="$(CC)" \
+		CFLAGS="$(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(GLIB_CFLAGS) $(AM_CFLAGS)" \
+		CPPFLAGS="$(AM_CPPFLAGS) $(CPPFLAGS)" \
+		LDFLAGS="$(AM_LDFLAGS) $(LDFLAGS)"
+
+build-python-bindings.stamp: $(BINDINGS_DEPS)
+	$(BUILD_FLAGS) $(PYTHON) $(builddir)/setup.py build_ext
+	$(BUILD_FLAGS) $(PYTHON) $(builddir)/setup.py build
+	touch $@
+
+# This target installs the Python package and saves the path of all the
+# installed files in the INSTALLED_FILES text file to be used during this
+# uninstallation
+install-exec-local:
+	@opts="--prefix=$(prefix) --verbose --record $(INSTALLED_FILES) --no-compile $(DISTSETUPOPTS)"; \
+	if [ "$(DESTDIR)" != "" ]; then \
+		opts="$$opts --root=$(DESTDIR)"; \
+	fi; \
+	$(PYTHON) $(builddir)/setup.py install $$opts;
+
+clean-local:
+	rm -rf $(builddir)/build
+
+# Distutils' setup.py does not include an uninstall target, we thus need to do it
+# manually. We use the INSTALLED_FILES file produced during the install to
+# clean up the install folder and delete the folder it self.
+uninstall-local:
+	cat $(builddir)/$(INSTALLED_FILES) | xargs rm -rf
+	cat $(builddir)/$(INSTALLED_FILES) | $(GREP) "__init__.py" | xargs dirname | xargs rmdir
+	rm -f $(builddir)/$(INSTALLED_FILES)
+
+CLEANFILES = babeltrace/babeltrace_wrap.c babeltrace/babeltrace.py build-python-bindings.stamp
+DISTCLEANFILES = setup.py
 endif
diff --git a/bindings/python/babeltrace/Makefile.am b/bindings/python/babeltrace/Makefile.am
index 11dcdf0..f612aa6 100644
--- a/bindings/python/babeltrace/Makefile.am
+++ b/bindings/python/babeltrace/Makefile.am
@@ -1,31 +1,9 @@
+if USE_PYTHON
 babeltrace.i: babeltrace.i.in
 	sed "s/BABELTRACE_VERSION_STR/Babeltrace $(PACKAGE_VERSION)/g" < \
 		$(top_srcdir)/bindings/python/babeltrace/babeltrace.i.in > \
 		$(top_builddir)/bindings/python/babeltrace/babeltrace.i
 
-AM_CFLAGS = $(PYTHON_INCLUDE) -I$(top_srcdir)/include/ \
-		-I$(top_srcdir)/bindings/python/babeltrace
-
-EXTRA_DIST = babeltrace.i.in
-nodist_python_PYTHON = babeltrace.py
-pyexec_LTLIBRARIES = _babeltrace.la
-
-MAINTAINERCLEANFILES = babeltrace_wrap.c babeltrace.py
-
-nodist__babeltrace_la_SOURCES = babeltrace_wrap.c
-_babeltrace_la_SOURCES = python-complements.h python-complements.c
-_babeltrace_la_LDFLAGS = -module
-
-_babeltrace_la_CFLAGS = $(GLIB_CFLAGS) $(AM_CFLAGS)
-
-_babeltrace_la_LIBS = $(GLIB_LIBS)
-
-_babeltrace_la_LIBADD = $(top_builddir)/formats/ctf/libbabeltrace-ctf.la \
-	$(top_builddir)/formats/ctf-text/libbabeltrace-ctf-text.la
-
-# SWIG 'warning md variable unused' fixed after SWIG build:
-babeltrace_wrap.c: babeltrace.i
-	$(SWIG) -python -Wall -I. -I$(top_srcdir)/include \
-		$(top_builddir)/bindings/python/babeltrace/babeltrace.i
-
-CLEANFILES = babeltrace.i babeltrace.py babeltrace_wrap.c
+#the __init__.py target is generated by the automake
+DISTCLEANFILES = __init__.py babeltrace.i
+endif
diff --git a/bindings/python/babeltrace/__init__.py.in b/bindings/python/babeltrace/__init__.py.in
new file mode 100644
index 0000000..eb1e76a
--- /dev/null
+++ b/bindings/python/babeltrace/__init__.py.in
@@ -0,0 +1,25 @@
+# The MIT License (MIT)
+#
+# Copyright (C) 2017 - Francis Deslauriers <francis.deslauriers at efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from .babeltrace import *
+
+__version__ = '@PACKAGE_VERSION@'
diff --git a/bindings/python/setup.py.in b/bindings/python/setup.py.in
new file mode 100644
index 0000000..ea7acce
--- /dev/null
+++ b/bindings/python/setup.py.in
@@ -0,0 +1,85 @@
+# The MIT License (MIT)
+#
+# Copyright (C) 2017 - Francis Deslauriers <francis.deslauriers at efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+import sys
+
+from distutils.core import setup, Extension
+
+PY_PATH_WARN_MSG = """
+-------------------------------------WARNING------------------------------------
+The install directory used:\n ({})\nis not included in your PYTHONPATH.
+
+To add this directory to your Python search path permanently you can add the
+following command to your .bashrc/.zshrc:
+    export PYTHONPATH="${{PYTHONPATH}}:{}"
+--------------------------------------------------------------------------------
+"""
+
+def main():
+    babeltrace_ext = Extension('babeltrace/_babeltrace',
+                        sources=['babeltrace/babeltrace.i','babeltrace/python-complements.c'],
+                        libraries=['babeltrace', 'babeltrace-ctf'],)
+
+    dist = setup(name='babeltrace',
+            version='@PACKAGE_VERSION@',
+            description='Babeltrace Python Bindings',
+            packages=['babeltrace'],
+            package_dir={'babeltrace': 'babeltrace'},
+            options={'build':
+                {
+                    'build_base': 'build',
+                    'build_lib': 'build',
+                    'build_scripts': 'build'
+                },
+                'build_ext':
+                {
+                    'build_lib': 'build'
+                }
+            },
+            url='http://diamon.org/babeltrace',
+            ext_modules=[babeltrace_ext],
+            license='MIT',
+            classifiers=[
+                'Development Status :: 5 - Production/Stable',
+                'Intended Audience :: Developers',
+                'License :: OSI Approved :: The MIT License',
+                'Programming Language :: Python :: 3'
+                'Topic :: System :: Logging',
+                ])
+
+# After the installation, we check that the install directory is included in
+# the Python search path and we print a warning message when it's not.
+# We need to do this because Python search path differs depending on the distro
+# and some distros don't include any /usr/local/ in the search path. This is
+# also useful for out-of-tree installs and tests.
+# It's only relevant to make this check on the `install` command.
+
+    if 'install' in dist.command_obj:
+        install_dir = dist.command_obj['install'].install_libbase
+        if install_dir not in sys.path:
+            # We can't consider this an error because if affects every
+            # distro differently. We only warn the user that some
+            # extra configuration is needed to use the bindings
+            print(PY_PATH_WARN_MSG.format(install_dir, install_dir))
+
+if __name__ == "__main__":
+    main()
diff --git a/configure.ac b/configure.ac
index 2382e53..fd80fd9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -241,11 +241,6 @@ if test "x${enable_python:-yes}" = xyes; then
   AX_PKG_SWIG($swig_version, [], [ AC_MSG_ERROR([SWIG $swig_version or newer is needed]) ])
   AM_PATH_PYTHON
 
-  AM_PATH_PYTHON_MODULES([PYTHON])
-  # pythondir is the path where extra modules are to be installed
-  pythondir=$PYTHON_PREFIX/$PYTHON_MODULES_PATH
-  # pyexecdir is the path that contains shared objects used by the extra modules
-  pyexecdir=$PYTHON_EXEC_PREFIX/$PYTHON_MODULES_PATH
   AC_ARG_VAR([PYTHON_INCLUDE], [Include flags for python, bypassing python-config])
   AC_ARG_VAR([PYTHON_CONFIG], [Path to python-config])
   AS_IF([test -z "$PYTHON_INCLUDE"], [
@@ -333,7 +328,9 @@ AC_CONFIG_FILES([
 	include/Makefile
 	bindings/Makefile
 	bindings/python/Makefile
+	bindings/python/setup.py
 	bindings/python/babeltrace/Makefile
+	bindings/python/babeltrace/__init__.py
 	tests/Makefile
 	tests/bin/Makefile
 	tests/bin/intersection/Makefile
@@ -357,6 +354,12 @@ AC_CONFIG_FILES([tests/bin/intersection/test_intersection], [chmod +x tests/bin/
 AC_CONFIG_FILES([tests/bin/intersection/bt_python_helper.py])
 AC_CONFIG_FILES([tests/bin/test_packet_seq_num], [chmod +x tests/bin/test_packet_seq_num])
 
+# Create link for Babeltrace complements files for out-of-tree builds
+AC_CONFIG_LINKS([
+	bindings/python/babeltrace/python-complements.c:bindings/python/babeltrace/python-complements.c
+	bindings/python/babeltrace/python-complements.h:bindings/python/babeltrace/python-complements.h
+])
+
 AC_OUTPUT
 
 #
diff --git a/m4/python_modules.m4 b/m4/python_modules.m4
deleted file mode 100644
index 132c4c2..0000000
--- a/m4/python_modules.m4
+++ /dev/null
@@ -1,23 +0,0 @@
-# python_modules.m4 -- Get the Python modules install path
-#
-# Copyright (C) 2014 - Jérémie Galarneau <jeremie.galarneau at efficios.com>
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-# While extra Python modules are generaly installed in the Python
-# interpreter's "site-packages" directory, Debian prefers using the
-# "dist-packages" nomenclature. This macro uses the interpreter
-# designated by the PYTHON variable to check the interpreter's PATH
-# and sets the PYTHON_MODULES_PATH by taking the prefix into account.
-
-# AM_PATH_PYTHON_MODULES(PYTHON)
-# ---------------------------------------------------------------------------
-AC_DEFUN([AM_PATH_PYTHON_MODULES],
- [prog="import sys
-for path in sys.path:
-    if path.endswith(\"-packages\"):
-       print(path[[path.find(\"/lib\"):]])
-       break"
-  PYTHON_MODULES_PATH=`${$1} -c "$prog"`])
diff --git a/tests/bin/intersection/bt_python_helper.py.in b/tests/bin/intersection/bt_python_helper.py.in
index 11b4ab1..cb53304 100644
--- a/tests/bin/intersection/bt_python_helper.py.in
+++ b/tests/bin/intersection/bt_python_helper.py.in
@@ -26,12 +26,6 @@ import sys
 
 # Point the Python interpreter to the builddir's library and Babeltrace
 # bindings
-bt_module_path = '@abs_top_builddir@/bindings/python/babeltrace'
-bt_lib_py_path = '@abs_top_builddir@/bindings/python/babeltrace/.libs'
-bt_lib_bt_path = '@abs_top_builddir@/lib/.libs'
-bt_lib_ctf_path = '@abs_top_builddir@/format/ctf/.libs'
+bt_module_path = '@abs_top_builddir@/bindings/python/build'
 
 sys.path.insert(0, bt_module_path)
-sys.path.insert(1, bt_lib_py_path)
-sys.path.insert(2, bt_lib_bt_path)
-sys.path.insert(3, bt_lib_ctf_path)
-- 
2.7.4



More information about the lttng-dev mailing list