[PATCH] NEWS, python: add --libnotmuch-dir option to "setup.py install"

Subject: [PATCH] NEWS, python: add --libnotmuch-dir option to "setup.py install"

Date: Tue, 28 Jun 2016 00:04:21 -0400

To: notmuch@notmuchmail.org

Cc:

From: Daniel Lee Harple


This change fixes the python bindings on OS X 10.11, which introduced a
feature called System Integrity Protection. The /usr/bin/python
executable has the "restricted" flag set, which means dlopen() requires
an absolute path to the library that is to be loaded.
---
 NEWS                               |  5 +++++
 bindings/python/notmuch/globals.py | 32 ++++++++++++++++++++++++--------
 bindings/python/setup.py           | 17 +++++++++++++++++
 3 files changed, 46 insertions(+), 8 deletions(-)

diff --git a/NEWS b/NEWS
index cb6e21c..8164875 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,11 @@
 Notmuch 0.23 (UNRELEASED)
 =========================

+Python Bindings
+---------------
+
+Added `--libnotmuch-dir` option to `setup.py install`
+
 Ruby Bindings
 -------------

diff --git a/bindings/python/notmuch/globals.py
b/bindings/python/notmuch/globals.py
index b1eec2c..499f090 100644
--- a/bindings/python/notmuch/globals.py
+++ b/bindings/python/notmuch/globals.py
@@ -17,19 +17,35 @@ along with notmuch.  If not, see
<https://www.gnu.org/licenses/>.
 Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
 """

+import os
 from ctypes import CDLL, Structure, POINTER
 from notmuch.version import SOVERSION

-#-----------------------------------------------------------------------------
-#package-global instance of the notmuch library
+# This module only exists when this library is installed with setup.py
 try:
-    from os import uname
-    if uname()[0] == 'Darwin':
-        nmlib = CDLL("libnotmuch.{0:s}.dylib".format(SOVERSION))
+    from .libnotmuch import LIBNOTMUCH_DIR
+except ImportError:
+    LIBNOTMUCH_DIR = None
+
+def load_library():
+    if os.uname()[0] == 'Darwin':
+        name = 'libnotmuch.{0:s}.dylib'
+    else:
+        name = 'libnotmuch.so.{0:s}'
+    formatted_name = name.format(SOVERSION)
+
+    if LIBNOTMUCH_DIR is None:
+        path = formatted_name
     else:
-        nmlib = CDLL("libnotmuch.so.{0:s}".format(SOVERSION))
-except:
-    raise ImportError("Could not find shared 'notmuch' library.")
+        path = os.path.join(LIBNOTMUCH_DIR, formatted_name)
+
+    try:
+        return CDLL(path)
+    except:
+        raise ImportError('Could not find shared library {!r}.'.format(path))
+
+# package-global instance of the notmuch library
+nmlib = load_library()

 from .compat import Python3StringMixIn, encode_utf8 as _str

diff --git a/bindings/python/setup.py b/bindings/python/setup.py
index d986f0c..1594c1d 100644
--- a/bindings/python/setup.py
+++ b/bindings/python/setup.py
@@ -21,6 +21,22 @@ Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>

 import os
 from distutils.core import setup
+from distutils.command.install import install as default_install
+
+class install(default_install):
+    user_options = default_install.user_options +
[('libnotmuch-dir=', None, 'path to directory containing libnotmuch')]
+
+    def initialize_options(self):
+        default_install.initialize_options(self)
+        self.libnotmuch_dir = None
+
+    def run(self):
+        default_install.run(self)
+        if self.dry_run:
+            return
+        with open(os.path.join(self.install_libbase, 'notmuch',
'libnotmuch.py'), 'w') as f:
+            f.write('# This file is auto-generated from setup.py\n')
+            f.write('LIBNOTMUCH_DIR = {!r}\n'.format(self.libnotmuch_dir))

 # get the notmuch version number without importing the notmuch module
 version_file = os.path.join(os.path.dirname(__file__),
@@ -36,6 +52,7 @@ setup(name='notmuch',
       author_email='Sebastian@SSpaeth.de',
       url='https://notmuchmail.org/',
       download_url='https://notmuchmail.org/releases/notmuch-%s.tar.gz'
% __VERSION__,
+      cmdclass={'install': install},
       packages=['notmuch'],
       keywords=['library', 'email'],
       long_description='''Overview
-- 
2.8.2

Thread: