Build Python bindings with distutils for consistent installs
authorFrancis Deslauriers <francis.deslauriers@efficios.com>
Tue, 11 Apr 2017 19:27:37 +0000 (15:27 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 26 May 2017 13:34:11 +0000 (09:34 -0400)
v5: Manually load shared objects used by the Babeltrace Python module

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@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
.gitignore
bindings/python/Makefile.am
bindings/python/babeltrace/Makefile.am
bindings/python/babeltrace/__init__.py.in [new file with mode: 0644]
bindings/python/setup.py.in [new file with mode: 0644]
configure.ac
m4/python_modules.m4 [deleted file]
tests/bin/intersection/bt_python_helper.py.in

index a7c9e3ca4cd67bfbcbb8cdd4252e4de63e26c8d0..9259b6fbdd9ae13c23c46dd82490e1bc7f258946 100644 (file)
@@ -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
index d6b3648e4b9768c73d35b1438b67630409815a4b..9e44127613768c10019cca592005d12781816827 100644 (file)
@@ -1,3 +1,58 @@
 if USE_PYTHON
-SUBDIRS = babeltrace
+SUBDIRS = babeltrace .
+
+INSTALLED_FILES=$(builddir)/installed_files.txt
+
+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
+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 $@
+
+install-exec-local: build-python-bindings.stamp
+       @opts="--prefix=$(prefix) --record $(INSTALLED_FILES) --verbose --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 save the path of the files that were installed during the install target
+# and delete them during the uninstallation.
+uninstall-local:
+       if [ "$(DESTDIR)" != "" ]; then \
+               $(SED) -i "s|^|$(DESTDIR)/|g" $(INSTALLED_FILES); \
+       fi
+       cat $(INSTALLED_FILES) | xargs rm -rf || true
+       $(GREP) "__init__.py" $(INSTALLED_FILES) | xargs dirname | xargs rm -rf || true
+       rm -f $(INSTALLED_FILES)
+
+CLEANFILES = babeltrace/babeltrace_wrap.c babeltrace/babeltrace.py build-python-bindings.stamp
+DISTCLEANFILES = setup.py
 endif
index 11dcdf0e06b75d0cf487e40e3b5da83eab3e399c..f612aa6ecb751e80d32673fd63f4a13f3c8c6f86 100644 (file)
@@ -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 (file)
index 0000000..eb1e76a
--- /dev/null
@@ -0,0 +1,25 @@
+# The MIT License (MIT)
+#
+# Copyright (C) 2017 - Francis Deslauriers <francis.deslauriers@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 (file)
index 0000000..9baa062
--- /dev/null
@@ -0,0 +1,84 @@
+# The MIT License (MIT)
+#
+# Copyright (C) 2017 - Francis Deslauriers <francis.deslauriers@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_lib'
+                },
+                'build_ext':
+                {
+                    'build_lib': 'build/build_lib'
+                }
+            },
+            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()
index eb3f34d026243bcc25d94883e2a84436c73fe94d..d7c458056fd7d36553f8ccdab217d08fb350271d 100644 (file)
@@ -235,11 +235,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([3.0], [], [ AC_MSG_ERROR([Python 3.0 or newer is needed]) ])
 
-  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"], [
@@ -323,7 +318,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
@@ -347,6 +344,13 @@ 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
+       bindings/python/babeltrace/babeltrace.i.in:bindings/python/babeltrace/babeltrace.i.in
+])
+
 AC_OUTPUT
 
 #
diff --git a/m4/python_modules.m4 b/m4/python_modules.m4
deleted file mode 100644 (file)
index 132c4c2..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-# python_modules.m4 -- Get the Python modules install path
-#
-# Copyright (C) 2014 - Jérémie Galarneau <jeremie.galarneau@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"`])
index 11b4ab16afd556b315e050ae4f73334c4983311f..747f0e7b4ccdca31bc1a90c971d36ac264b37ca1 100644 (file)
 # SOFTWARE.
 
 import sys
+import ctypes
 
 # 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/build_lib/'
 
 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)
+
+# Manually load the shared libraries used by the Babeltrace module during the
+# tests
+bt_lib_ctf_path = '@abs_top_builddir@/formats/ctf/.libs/libbabeltrace-ctf.so'
+bt_lib_bt_path = '@abs_top_builddir@/lib/.libs/libbabeltrace.so'
+
+ctypes.cdll.LoadLibrary(bt_lib_ctf_path)
+ctypes.cdll.LoadLibrary(bt_lib_bt_path)
This page took 0.042251 seconds and 4 git commands to generate.