unofficial mirror of notmuch@notmuchmail.org
 help / color / mirror / code / Atom feed
* SWIG (and particularly Python) bindings
@ 2009-12-29  9:16 Ben Gamari
  2009-12-30 10:52 ` Adrian Perez de Castro
  2010-01-20  8:45 ` Carl Worth
  0 siblings, 2 replies; 10+ messages in thread
From: Ben Gamari @ 2009-12-29  9:16 UTC (permalink / raw)
  To: notmuch

Hey all,

I've been looking at switching away from sup recently to something with
a slightly little less everything-and-the-kitchen-sink philosophy.
Notmuch looks excellent, although it appears that its current front-end
for my editor of choice (vim) is a little lacking in some ways
(operations involving a call to notmuch invariably lock up vi for the
duration of the operation).

Regardless, I thought it might be nice to have access to the notmuch
backend from a language other than C (preferably my high-level language
of choice, python). To this end, I took a few hours today acquainting
myself with SWIG and produced these bindings for Python. Unfortunately,
it doesn't appear that SWIG has particularly good support for
object-oriented C, so the approach I took was using SWIG to generate the
low-level glue, on top of which I wrote a properly structured set of
Python bindings. While I theoretically have full interface coverage,
I unfortunately haven't had a chance to use these for anything useful,
so who knows whether much of it actually works. Regardless, I thought
folks might be interested.

While the bindings are currently in the form of a patch to notmuch
(creating a top-level swig directory in the source tree), they could
certainly be moved out-of-tree if the powers that be don't feel it
appropriate to include them. Unfortunately, the build system is
currently almost entirely independent from the notmuch build system. If
these are to be included in-tree, I would be curious to hear people have
to say about how we might integrate it into the sup build system.

Hope this helps someone. I'll hopefully have a chance to work with the
bindings soon and will send a new set of patches once I think I've found
all of the obvious issues.

- Ben


---
 swig/Makefile        |   18 ++++
 swig/notmuch.py      |  222 ++++++++++++++++++++++++++++++++++++++++++++++++++
 swig/notmuch_funcs.i |    9 ++
 3 files changed, 249 insertions(+), 0 deletions(-)
 create mode 100644 swig/Makefile
 create mode 100644 swig/notmuch.py
 create mode 100644 swig/notmuch_funcs.i

diff --git a/swig/Makefile b/swig/Makefile
new file mode 100644
index 0000000..c01c427
--- /dev/null
+++ b/swig/Makefile
@@ -0,0 +1,18 @@
+include ../Makefile.config
+
+INCLUDES=-I../lib -I/usr/include/python2.6
+CFLAGS=${INCLUDES}
+
+all : python
+
+python : _notmuch_funcs.so notmuch.py
+
+_notmuch_funcs.so : notmuch_funcs_wrap.o
+	g++ -shared ${XAPIAN_LDFLAGS} ${GMIME_LDFLAGS} ${TALLOC_LDFLAGS} -o $@ $< ../lib/notmuch.a
+
+%_wrap.o : %_wrap.c
+	gcc ${CFLAGS} -fPIC -c -o $@ $<
+
+%_wrap.c %.py : %.i 
+	swig -python ${INCLUDES} $<
+
diff --git a/swig/notmuch.py b/swig/notmuch.py
new file mode 100644
index 0000000..95b81ad
--- /dev/null
+++ b/swig/notmuch.py
@@ -0,0 +1,222 @@
+import notmuch_funcs as nm
+from datetime import datetime
+
+class Exception(Exception):
+        def get_message():
+                errors = {
+                        nm.NOTMUCH_STATUS_OUT_OF_MEMORY: 'out of memory',
+                        nm.NOTMUCH_STATUS_READONLY_DATABASE: 'database opened as read-only',
+                        nm.NOTMUCH_STATUS_XAPIAN_EXCEPTION: 'xapian error',
+                        nm.NOTMUCH_STATUS_FILE_ERROR: 'file error',
+                        nm.NOTMUCH_STATUS_FILE_NOT_EMAIL: 'file not email message',
+                        nm.NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: 'duplicate message id',
+                        nm.NOTMUCH_STATUS_NULL_POINTER: 'null pointer',
+                        nm.NOTMUCH_STATUS_TAG_TOO_LONG: 'tag name too long',
+                        nm.NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: 'unbalanced freeze/thaw',
+                }
+                return errors.get(self.status, 'unknown error')
+
+        def __init__(self, status):
+                self.status = status
+
+def _handle_status(status):
+        if (status != nm.NOTMUCH_STATUS_SUCCESS):
+                raise Exception(status)
+
+class Database(object):
+        MODE_READ_ONLY = nm.NOTMUCH_DATABASE_MODE_READ_ONLY
+        MODE_READ_WRITE = nm.NOTMUCH_DATABASE_MODE_READ_WRITE
+
+        def __init__(self, db):
+                if not db:
+                        raise "Failed to open database"
+                self.db = db
+
+        @staticmethod
+        def create(path):
+                return Database(nm.notmuch_database_create(path))
+
+        @staticmethod
+        def open(path, mode):
+                return Database(nm.notmuch_database_open(path, mode))
+
+        def close(self):
+                nm.notmuch_database_close(self.db)
+
+        def get_path(self):
+                return nm.notmuch_database_get_path(self.db)
+
+        def set_timestamp(self, key, timestamp):
+                _handle_status(nm.notmuch_database_set_timestamp(self.db, key, timestamp))
+
+        def get_timestamp(self, key):
+                return datetime.fromtimestamp(nm.notmuch_database_get_timestamp(self.db, key))
+
+        def add_message(self, filename, message):
+                _handle_status(nm.notmuch_database_add_message(self.db, filename, message.message))
+
+        def find_message(self, message_id):
+                return Message(nm.notmuch_database_find_message(self.db, message_id))
+
+        def get_all_tags(self):
+                return Tags(nm.notmuch_database_get_all_tags(self.db))
+
+        def __destroy__(self):
+                self.close()
+        
+class Query(object):
+        def __init__(self, db, query_string):
+                self.query = nm.notmuch_query_create(db, query_string)
+                if not self.query: # This might not work
+                        raise "Failed to create query"
+
+        def set_sort(self, sort):
+                nm.notmuch_query_set_sort(self.query, sort)
+                
+        def search_threads(self):
+                return Threads(nm.notmuch_query_search_threads(self.query))
+
+        def search_messages(self):
+                return Messages(nm.notmuch_query_search_messages(self.query))
+
+        def count_message(self):
+                return nm.notmuch_query_count_messages(self.query)
+
+        def __destroy__(self):
+                nm.notmuch_query_destroy(self.query)
+
+class Tags(object):
+        def __init__(self, tags):
+                self.tags = tags
+
+        def __iter__(self):
+                return self
+
+        def next(self):
+                if not nm.notmuch_tags_has_more(self.tags):
+                        raise StopIteration
+                else:
+                        h = nm.notmuch_tags_get(self.tags)
+                        nm.notmuch_tags_advance(self.tags)
+                        return h
+
+        def __destroy__(self):
+                nm.notmuch_messages_destroy(self.tags)
+
+class Thread(object):
+        def __init__(self, thread):
+                self.thread = thread
+
+        def get_thread_id(self):
+                return nm.notmuch_thread_get_thread_id(self.thread)
+
+        def get_total_messages(self):
+                return nm.notmuch_thread_total_messages(self.thread)
+        
+        def get_toplevel_messages(self):
+                return Messages(nm.notmuch_thread_get_toplevel_messages(self.thread))
+
+        def get_matched_messages(self):
+                return nm.notmuch_thread_get_matched_messages(self.thread)
+
+        def get_authors(self):
+                return nm.notmuch_thread_get_authors(self.thread)
+
+        def get_subject(self):
+                return nm.notmuch_thread_get_subject(self.thread)
+
+        def get_oldest_date(self):
+                return nm.notmuch_thread_get_oldest_date(self.thread)
+
+        def get_newest_date(self):
+                return nm.notmuch_thread_get_newest_date(self.thread)
+
+        def get_tags(self):
+                return Tags(nm.notmuch_thread_get_tags(self.thread))
+
+        def __destroy__(self):
+                nm.notmuch_thread_destroy(self.thread)
+
+class Threads(object):
+        def __init__(self, threads):
+                self.threads = threads
+
+        def __iter__(self):
+                return self
+
+        def next(self):
+                if not nm.notmuch_threads_has_more(self.threads):
+                        raise StopIteration
+                else:
+                        h = Thread(nm.notmuch_threads_get(self.threads))
+                        nm.notmuch_threads_advance(self.threads)
+                        return h
+
+        def __destroy__(self):
+                nm.notmuch_threads_destroy(self.threads)
+
+class Messages(object):
+        def __init__(self, messages):
+                self.messages = messages
+
+        def __iter__(self):
+                return self
+
+        def next(self):
+                if not nm.notmuch_messages_has_more(self.messages):
+                        raise StopIteration
+                else:
+                        h = Message(nm.notmuch_messages_get(self.messages))
+                        nm.notmuch_messages_advance(self.messages)
+                        return h
+
+        def __destroy__(self):
+                nm.notmuch_messages_destroy(self.messages)
+
+        def collect_tags(self):
+                return Tags(nm.notmuch_messages_collect_tags(self.messages))
+
+class Message(object):
+        def __init__(self, message):
+                self.message = message
+
+        def get_replies(self):
+                return Messages(nm.notmuch_message_get_replies(self.message))
+
+        def get_filename(self):
+                return nm.notmuch_message_get_filename(self.message)
+
+        def get_flag(self, flag):
+                return bool(nm.notmuch_message_get_flag(self.message, flag))
+
+        def set_flag(self, flag, value):
+                return nm.notmuch_message_set_flag(self.message, flag, value)
+
+        def get_date(self):
+                return datetime.fromtimestamp(nm.notmuch_message_get_date(self.message))
+
+        def get_header(self, header):
+                return nm.notmuch_message_get_header(self.message, header)
+
+        def get_tags(self):
+                return Tags(nm.notmuch_message_get_tags(self.message))
+
+        def add_tag(self, tag):
+                _handle_status(nm.notmuch_message_add_tag(self.message, tag))
+
+        def remove_tag(self, tag):
+                _handle_status(nm.notmuch_message_remove_tag(self.message, tag))
+
+        def remove_all_tags(self):
+                nm.notmuch_message_remove_all_tags(self.message)
+
+        def freeze(self):
+                nm.notmuch_message_freeze(self.message)
+
+        def thaw(self):
+                nm.notmuch_message_thaw(self.message)
+
+        def __destroy__(self):
+                nm.notmuch_message_destroy(self.message)
+
+
diff --git a/swig/notmuch_funcs.i b/swig/notmuch_funcs.i
new file mode 100644
index 0000000..cc1826e
--- /dev/null
+++ b/swig/notmuch_funcs.i
@@ -0,0 +1,9 @@
+%module notmuch_funcs
+
+%{
+#define SWIG_FILE_WITH_INIT
+#include "notmuch.h"
+%}
+
+%include "notmuch.h"
+
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: SWIG (and particularly Python) bindings
  2009-12-29  9:16 SWIG (and particularly Python) bindings Ben Gamari
@ 2009-12-30 10:52 ` Adrian Perez de Castro
  2009-12-30 11:34   ` Scott Robinson
                     ` (2 more replies)
  2010-01-20  8:45 ` Carl Worth
  1 sibling, 3 replies; 10+ messages in thread
From: Adrian Perez de Castro @ 2009-12-30 10:52 UTC (permalink / raw)
  To: notmuch


[-- Attachment #1.1: Type: text/plain, Size: 2425 bytes --]

On Tue, 29 Dec 2009 04:16:43 -0500, Ben wrote:

> Regardless, I thought it might be nice to have access to the notmuch
> backend from a language other than C (preferably my high-level language
> of choice, python) [...]

Funny, I was just doing the same: a Python binding. Haha, so now we have
two just-backed Python bindings. What should we do?

> [...] To this end, I took a few hours today acquainting
> myself with SWIG and produced these bindings for Python. Unfortunately,
> it doesn't appear that SWIG has particularly good support for
> object-oriented C [...]

I already used SWIG sometimes in the past (and did not like it a lot), so
my binding is using Cython [*] (which is exactly like Pyrex plus some extra
features), so the binding is partly manual.

> While the bindings are currently in the form of a patch to notmuch
> (creating a top-level swig directory in the source tree), they could
> certainly be moved out-of-tree if the powers that be don't feel it
> appropriate to include them. [...]

Same here, see attached patch. It is currently unfinished, and I was just
about to add support for iterating notmuch_threads_t and other similar
structures. I can also publish a Git repo with the entire branch, just
drop me a line if you want me to do that.

> [...] Unfortunately, the build system is currently almost entirely
> independent from the notmuch build system. If  these are to be
> included in-tree, I would be curious to hear people have
> to say about how we might integrate it into the sup build system.
                                                  ^^^
(Mmmh, I suppose you mean "notmuch build system" there :P)

Mine is a little more cooked, as I have added a distutils "setup.py"
script. The bad news is that Python modules need to be compiled as
relocatable object files (-fPIC to teh rescue!), and the linker will
refuse to link the generated code with "notmuch.a" -- so I am instructing
distutils to compile *all* sources again. Not nice.

BTW, I think that if more bindings start to appear, Notmuch might be built
as a shared library, to avoid duplicating it everywhere. One option may be
using *just* libtool but not the rest of auto-foo tools (for the record:
I agree with Carl that they are slow and wicked).

Regards,


[*] http://www.cython.org/
-- 
Adrian Perez de Castro <aperez@igalia.com>
Igalia - Free Software Engineering

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: notmuch-python-wip.patch --]
[-- Type: text/x-patch, Size: 17456 bytes --]

 Makefile              |    1 +
 python/.gitignore     |    2 +
 python/Makefile       |    6 +
 python/Makefile.local |   15 ++
 python/notmuch.pyx    |  397 +++++++++++++++++++++++++++++++++++++++++++++++++
 python/pyutil.h       |   16 ++
 python/setup.py       |   89 +++++++++++
 7 files changed, 526 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile
index 021fdb8..081d670 100644
--- a/Makefile
+++ b/Makefile
@@ -37,6 +37,7 @@ include Makefile.config
 
 include lib/Makefile.local
 include compat/Makefile.local
+include python/Makefile.local
 include Makefile.local
 
 # The user has not set any verbosity, default to quiet mode and inform the
diff --git a/python/.gitignore b/python/.gitignore
new file mode 100644
index 0000000..7f0efa8
--- /dev/null
+++ b/python/.gitignore
@@ -0,0 +1,2 @@
+notmuch.c
+build/
diff --git a/python/Makefile b/python/Makefile
new file mode 100644
index 0000000..e1e5c43
--- /dev/null
+++ b/python/Makefile
@@ -0,0 +1,6 @@
+
+all: python
+
+%:
+	make -C .. $@
+
diff --git a/python/Makefile.local b/python/Makefile.local
new file mode 100644
index 0000000..140a701
--- /dev/null
+++ b/python/Makefile.local
@@ -0,0 +1,15 @@
+dir=python
+
+python: $(dir)/build/.stamp
+	(cd $(dir) && python setup.py build)
+	touch $@
+
+$(dir)/build/.stamp: lib/notmuch.a
+
+clean: clean-python
+
+clean-python:
+	$(RM) -r $(dir)/build
+
+.PHONY: clean-python python
+
diff --git a/python/notmuch.pyx b/python/notmuch.pyx
new file mode 100644
index 0000000..f38b719
--- /dev/null
+++ b/python/notmuch.pyx
@@ -0,0 +1,397 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+# vim: fenc=utf-8 ft=pyrex
+#
+# Copyright © 2009 Adrian Perez <aperez@igalia.com>
+#
+# Distributed under terms of the GPLv3 license.
+#
+
+cdef extern from "talloc.h":
+	void* talloc_init(char *fmt, ...)
+	int   talloc_free(void *ctx)
+
+
+cdef extern from "pyutil.h":
+	#
+	# Utility macros
+	#
+	char** pyutil_alloc_strv(void *ctx, unsigned nitems)
+
+
+cdef extern from "notmuch.h":
+	#
+	# Return status handling
+	#
+	ctypedef enum notmuch_status_t:
+		NOTMUCH_STATUS_SUCCESS
+		NOTMUCH_STATUS_OUT_OF_MEMORY
+		NOTMUCH_STATUS_READONLY_DATABASE
+		NOTMUCH_STATUS_XAPIAN_EXCEPTION
+		NOTMUCH_STATUS_FILE_ERROR
+		NOTMUCH_STATUS_FILE_NOT_EMAIL
+		NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID
+		NOTMUCH_STATUS_NULL_POINTER
+		NOTMUCH_STATUS_TAG_TOO_LONG
+		NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW
+
+	char* notmuch_status_to_string(notmuch_status_t status)
+
+	#
+	# notmuch_database_* -> notmuch.Database
+	#
+	ctypedef enum notmuch_database_mode_t:
+		NOTMUCH_DATABASE_MODE_READ_ONLY
+		NOTMUCH_DATABASE_MODE_READ_WRITE
+
+	ctypedef enum notmuch_sort_t:
+		NOTMUCH_SORT_OLDEST_FIRST
+		NOTMUCH_SORT_NEWEST_FIRST
+		NOTMUCH_SORT_MESSAGE_ID
+
+	ctypedef struct notmuch_database_t
+	ctypedef struct notmuch_messages_t
+	ctypedef struct notmuch_message_t
+	ctypedef struct notmuch_threads_t
+	ctypedef struct notmuch_thread_t
+	ctypedef struct notmuch_query_t
+	ctypedef struct notmuch_tags_t
+	ctypedef int time_t
+
+	int notmuch_threads_has_more(notmuch_threads_t *threads)
+	void notmuch_threads_advance(notmuch_threads_t *threads)
+	void notmuch_threads_destroy(notmuch_threads_t *threads)
+	notmuch_thread_t* notmuch_threads_get(notmuch_threads_t *threads)
+
+	void   notmuch_thread_destroy(notmuch_thread_t *thread)
+	char*  notmuch_thread_get_authors(notmuch_thread_t *thread)
+	char*  notmuch_thread_get_subject(notmuch_thread_t *thread)
+	char*  notmuch_thread_get_thread_id(notmuch_thread_t *thread)
+	time_t notmuch_thread_get_oldest_date(notmuch_thread_t *thread)
+	time_t notmuch_thread_get_newest_date(notmuch_thread_t *thread)
+	int    notmuch_thread_get_total_messages(notmuch_thread_t *thread)
+	int    notmuch_thread_get_matched_messages(notmuch_thread_t *thread)
+	notmuch_tags_t*     notmuch_thread_get_tags(notmuch_thread_t *thread)
+	notmuch_messages_t* notmuch_thread_get_toplevel_messages(notmuch_thread_t *thread)
+
+	notmuch_database_t* notmuch_database_create(char *path)
+	notmuch_database_t* notmuch_database_open(char *path, notmuch_database_mode_t mode)
+	char* notmuch_database_get_path(notmuch_database_t *db)
+	void  notmuch_database_close(notmuch_database_t *db)
+
+	time_t notmuch_database_get_timestamp(notmuch_database_t *db, char *key)
+	notmuch_status_t notmuch_database_set_timestamp(
+			notmuch_database_t *db, char *key, time_t timestamp)
+
+	notmuch_status_t notmuch_database_add_message(
+			notmuch_database_t *db, char *filename, notmuch_message_t **mesage)
+
+	notmuch_message_t* notmuch_database_find_message(
+			notmuch_database_t *db, char *message_id)
+
+	notmuch_tags_t* notmuch_database_get_all_tags(notmuch_database_t *db)
+
+	notmuch_query_t* notmuch_query_create(notmuch_database_t *db, char *qstring)
+
+	void notmuch_query_destroy(notmuch_query_t *query)
+	void notmuch_query_set_sort(notmuch_query_t *query, notmuch_sort_t sort)
+	unsigned notmuch_query_count_messages(notmuch_query_t *query)
+	notmuch_threads_t*  notmuch_query_search_threads(notmuch_query_t *query)
+	notmuch_messages_t* notmuch_query_search_messages(notmuch_query_t *query)
+
+	char* notmuch_message_get_message_id(notmuch_message_t *msg)
+	char* notmuch_message_get_thread_id(notmuch_message_t *msg)
+	char* notmuch_message_get_filename(notmuch_message_t *msg)
+	char* notmuch_message_get_header(notmuch_message_t *msg, char *name)
+	notmuch_status_t notmuch_message_add_tag(notmuch_message_t *msg, char *tag)
+	notmuch_status_t notmuch_message_remove_tag(notmuch_message_t *msg, char *tag)
+	void notmuch_message_remove_all_tags(notmuch_message_t *msg)
+	void notmuch_message_destroy(notmuch_message_t *msg)
+	void notmuch_message_freeze(notmuch_message_t *msg)
+	void notmuch_message_thaw(notmuch_message_t *msg)
+
+
+cdef extern from "notmuch-client.h":
+	#
+	# notmuch_config_* -> notmuch.Config
+	#
+	ctypedef struct notmuch_config_t
+
+	notmuch_config_t* notmuch_config_open(void *ctx, char *filename, int *is_new_ret)
+	void   notmuch_config_close(notmuch_config_t *cfg)
+	int    notmuch_config_save(notmuch_config_t *cfg)
+	char*  notmuch_config_get_database_path(notmuch_config_t *cfg)
+	void   notmuch_config_set_database_path(notmuch_config_t *cfg, char *path)
+	char*  notmuch_config_get_user_name(notmuch_config_t *cfg)
+	void   notmuch_config_set_user_name(notmuch_config_t *cfg, char *name)
+	char*  notmuch_config_get_user_primary_email(notmuch_config_t *cfg)
+	void   notmuch_config_set_user_primary_email(notmuch_config_t *cfg, char *email)
+	char** notmuch_config_get_user_other_email(notmuch_config_t *cfg, size_t *length)
+	void   notmuch_config_set_user_other_email(notmuch_config_t *cfg, char **other_email, size_t length)
+
+	#
+	# Miscellaneous
+	#
+	int debugger_is_active()
+
+
+#
+# Import needed Python built-in modules
+#
+from datetime import datetime, date
+
+#
+# Miscellaneous functions and information
+#
+debugger_active = bool(debugger_is_active())
+
+
+#
+# notmuch_database_* -> notmuch.Database
+#
+
+
+#
+# notmuch_config_* -> notmuch.Config
+#
+cdef class Config:
+	"""Handles the Notmuch configuration file.
+	"""
+	cdef notmuch_config_t * _cfg
+	cdef void * _ctx
+	cdef object _filename
+
+	def __init__(self, filename="~/.notmuch-config"):
+		"""Open a Notmuch configuration file.
+		"""
+		cdef int newret
+		self._ctx = talloc_init("notmuch.Config")
+		self._cfg = notmuch_config_open(self._ctx, filename, &newret)
+		self._filename = filename
+
+	def __dealloc__(self):
+		notmuch_config_close(self._cfg)
+		talloc_free(self._ctx)
+
+	property filename:
+		"""File name containing the configuration (string)"""
+		def __get__(self):
+			return self._filename
+
+	property database_path:
+		"""Path to the Notmuch database (string)"""
+		def __get__(self):
+			return notmuch_config_get_database_path(self._cfg)
+		def __set__(self, path):
+			notmuch_config_set_database_path(self._cfg, path)
+
+	property user_name:
+		"""User name (string)"""
+		def __get__(self):
+			return notmuch_config_get_user_name(self._cfg)
+		def __set__(self, name):
+			notmuch_config_set_user_name(self._cfg, name)
+
+	property user_primary_email:
+		"""Primary e-mail address of the user (string)"""
+		def __get__(self):
+			return notmuch_config_get_user_primary_email(self._cfg)
+		def __set__(self, email):
+			notmuch_config_set_user_primary_email(self._cfg, email)
+
+	property other_email:
+		"""List of other e-mail addresses of the user (tuple of strings)"""
+		def __get__(self):
+			cdef size_t length
+			cdef size_t i
+			cdef char **emails
+			emails = notmuch_config_get_user_other_email(self._cfg, &length)
+
+			result = []
+			for i from 0 <= i < length:
+				result.append(emails[i])
+
+			# XXX We do not want the result to be modifiable, because the property
+			#     must be assigned as a whole, and not just modified only in the
+			#     Python side of the world.
+			return tuple(result)
+
+		def __set__(self, emaillist):
+			cdef size_t length = len(emaillist)
+			cdef char **emails = pyutil_alloc_strv(self._ctx, length)
+			cdef size_t i
+
+			for i from 0 <= i < len(emaillist):
+				emails[i] = emaillist[i]
+			notmuch_config_set_user_other_email(self._cfg, emails, len(emaillist))
+
+
+	def save(self):
+		"""Save the Notmuch configuration"""
+		notmuch_config_save(self._cfg)
+
+
+cdef class Database
+
+
+cdef class Message:
+	cdef notmuch_message_t *_msg
+
+	def __cinit__(self, object messageptr):
+		# XXX Counterpart of bogus cast
+		self._msg = <notmuch_message_t*> messageptr
+
+	def __dealloc__(self):
+		notmuch_message_destroy(self._msg)
+
+	property message_id:
+		def __get__(self):
+			return notmuch_message_get_message_id(self._msg)
+
+	property thread_id:
+		def __get__(self):
+			return notmuch_message_get_thread_id(self._msg)
+
+	property filename:
+		def __get__(self):
+			return notmuch_message_get_filename(self._msg)
+
+	def get_header(self, name):
+		return notmuch_message_get_header(self._msg, name)
+
+	def add_tag(self, tag):
+		cdef notmuch_status_t ret = notmuch_message_add_tag(self._msg, tag)
+		if ret != NOTMUCH_STATUS_SUCCESS:
+			raise ValueError(notmuch_status_to_string(ret))
+
+	def remove_tag(self, tag):
+		cdef notmuch_status_t ret = notmuch_message_remove_tag(self._msg, tag)
+		if ret != NOTMUCH_STATUS_SUCCESS:
+			raise ValueError(notmuch_status_to_string(ret))
+
+	def remove_all_tags(self):
+		notmuch_message_remove_all_tags(self._msg)
+
+	def freeze(self):
+		notmuch_message_freeze(self._msg)
+
+	def thaw(self):
+		notmuch_message_thaw(self._msg)
+
+
+cdef class Thread:
+	cdef notmuch_thread_t *_thread
+
+	def __cinit__(self, object threadptr):
+		self._thread = <notmuch_thread_t*> threadptr
+
+	def __dealloc__(self):
+		notmuch_thread_destroy(self._thread)
+
+	property authors:
+		def __get__(self):
+			return notmuch_thread_get_authors(self._thread)
+
+	property subject:
+		def __get__(self):
+			return notmuch_thread_get_subject(self._thread)
+
+	property thread_id:
+		def __get__(self):
+			return notmuch_thread_get_thread_id(self._thread)
+
+	property oldest_date:
+		def __get__(self):
+			return datetime.fromtimestamp(notmuch_thread_get_oldest_date(self._thread))
+
+	property newest_date:
+		def __get__(self):
+			return datetime.fromtimestamp(notmuch_thread_get_newest_date(self._thread))
+
+	property total_messages:
+		def __get__(self):
+			return notmuch_thread_get_total_messages(self._thread)
+
+	property matched_messages:
+		def __get__(self):
+			return notmuch_thread_get_matched_messages(self._thread)
+
+	def __len__(self):
+		return self.matched_messages
+
+
+cdef class Query:
+	cdef notmuch_query_t *_query
+
+	def __cinit__(self, Database db not None, qs):
+		self._query = notmuch_query_create(db._db, qs)
+
+	def __dealloc__(self):
+		notmuch_query_destroy(self._query)
+
+	def __len__(self):
+		return notmuch_query_count_messages(self._query)
+
+	def sort(self, notmuch_sort_t ordering):
+		notmuch_query_set_sort(self._query, ordering)
+		return self
+
+
+
+cdef class Database:
+	cdef notmuch_database_t *_db
+
+	def __init__(self, path=None, readonly=True):
+		cdef notmuch_database_mode_t mode = NOTMUCH_DATABASE_MODE_READ_WRITE
+		if path is None:
+			path = Config().database_path
+		if readonly:
+			mode = NOTMUCH_DATABASE_MODE_READ_ONLY
+		self._db = notmuch_database_open(path, mode)
+
+	def __dealloc__(self):
+		notmuch_database_close(self._db)
+
+	def get_timestamp(self, key):
+		cdef time_t ts = notmuch_database_get_timestamp(self._db, key)
+		return datetime.fromtimestamp(ts)
+
+	def set_timestamp(self, key, timestamp):
+		cdef time_t ts
+		if isinstance(timestamp, date):
+			ts = int(timestamp.strftime("%s"))
+		elif isinstance(timestamp, float):
+			ts = <time_t> timestamp
+		elif isinstance(timestamp, int):
+			ts = timestamp
+		else:
+			raise ValueError("Numeric timestamp or datetime.date object expected")
+
+	def add_message(self, filename):
+		cdef notmuch_message_t *message = NULL
+		cdef notmuch_status_t   status
+		status = notmuch_database_add_message(self._db, filename, &message)
+		if status == NOTMUCH_STATUS_SUCCESS:
+			# XXX This cast seems bogus, it may work, though
+			return Message(<object> message)
+		else:
+			if message != NULL:
+				notmuch_message_destroy(message)
+			raise ValueError(notmuch_status_to_string(status))
+
+	def find_message(self, message_id):
+		cdef notmuch_message_t *message
+		message = notmuch_database_find_message(self._db, message_id)
+		if message == NULL:
+			raise KeyError(message_id)
+		return Message(<object> message)
+
+	property path:
+		"""Database path"""
+		def __get__(self):
+			return notmuch_database_get_path(self._db)
+
+	def query(self, qstring):
+		return Query(self, qstring)
+
+
diff --git a/python/pyutil.h b/python/pyutil.h
new file mode 100644
index 0000000..64d93bf
--- /dev/null
+++ b/python/pyutil.h
@@ -0,0 +1,16 @@
+/*
+ * pyutil.h
+ * Copyright (C) 2009 Adrian Perez <aperez@igalia.com>
+ *
+ * Distributed under terms of the GPLv3 license.
+ */
+
+#ifndef __pyutil_h__
+#define __pyutil_h__
+
+#include <talloc.h>
+
+#define pyutil_alloc_strv(_ctx, _n)  talloc_array ((_ctx), char*, (_n))
+
+#endif /* !__pyutil_h__ */
+
diff --git a/python/setup.py b/python/setup.py
new file mode 100644
index 0000000..ffd43b2
--- /dev/null
+++ b/python/setup.py
@@ -0,0 +1,89 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+# vim:fenc=utf-8
+#
+# Copyright © 2009 Adrian Perez <aperez@igalia.com>
+#
+# Distributed under terms of the GPLv3 license.
+
+from distutils.core import setup
+from distutils.extension import Extension
+from Cython.Distutils import build_ext
+import commands
+
+
+class FlagOMatic(dict):
+    _KEYS = ("extra_link_args", "include_dirs", "library_dirs", "libraries")
+
+    def __init__(self, *arg, **kw):
+        super(FlagOMatic, self).__init__(*arg, **kw)
+        for key in self._KEYS:
+            self[key] = set(self.get(key, []))
+
+    extra_link_args = property(lambda self: self["extra_link_args"])
+    include_dirs    = property(lambda self: self["include_dirs"])
+    library_dirs    = property(lambda self: self["library_dirs"])
+    libraries       = property(lambda self: self["libraries"])
+
+    _FLAG_MAP = {
+            "-I": "include_dirs",
+            "-L": "library_dirs",
+            "-l": "libraries",
+        }
+
+    def add_compiler_flags(self, text):
+        for token in text.split():
+            key = self._FLAG_MAP.get(token[:2], "extra_link_args")
+            if key == "extra_link_args":
+                self.extra_link_args.add(token)
+            else:
+                self[key].add(token[2:])
+
+    def add_pkgconfig_flags(self, *modules):
+        self.add_command_output_flags(
+                "pkg-config --libs --cflags %s" % " ".join(modules))
+
+    def add_command_output_flags(self, command):
+        self.add_compiler_flags(commands.getoutput(command))
+
+    @property
+    def kwargs(self):
+        return dict((k, list(v)) for k, v in self.iteritems())
+
+
+# Gather compiler flags
+#
+flags = FlagOMatic(
+       #extra_link_args = ("../lib/notmuch.a",),
+        include_dirs    = ("..", "../lib", "../compat"))
+
+flags.add_pkgconfig_flags("gmime-2.4", "talloc")
+flags.add_command_output_flags("xapian-config --cxxflags --libs")
+
+# We are building a extension module
+#
+import os
+
+srcs = ["notmuch.pyx"]
+srcs.extend(
+    map(lambda s: "../"+s,
+        filter(lambda s: s.endswith(".c"),
+            os.listdir(".."))))
+srcs.extend(
+    map(lambda s: "../lib/"+s,
+        filter(lambda s: s.endswith(".cc") or s.endswith(".c"),
+            os.listdir("../lib"))))
+
+ext_modules = [Extension("notmuch", srcs, **flags.kwargs)]
+
+
+# And now for the easy part :-)
+#
+setup(
+    name         = "notmuch",
+    author       = "Adrian Perez",
+    author_email = "aperez@igalia.com",
+    cmdclass     = {"build_ext": build_ext},
+    ext_modules  = ext_modules,
+)
+

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: SWIG (and particularly Python) bindings
  2009-12-30 10:52 ` Adrian Perez de Castro
@ 2009-12-30 11:34   ` Scott Robinson
  2010-01-16  4:09     ` Ben Gamari
  2009-12-30 16:10   ` SWIG (and particularly Python) bindings Ben Gamari
  2010-01-20  8:48   ` Carl Worth
  2 siblings, 1 reply; 10+ messages in thread
From: Scott Robinson @ 2009-12-30 11:34 UTC (permalink / raw)
  To: notmuch

Excerpts from Adrian Perez de Castro's message of Wed Dec 30 02:52:23 -0800 2009:
> BTW, I think that if more bindings start to appear, Notmuch might be built
> as a shared library, to avoid duplicating it everywhere. One option may be
> using *just* libtool but not the rest of auto-foo tools (for the record:
> I agree with Carl that they are slow and wicked).

http://github.com/quad/notmuch/tree/libtool
-- 
Scott Robinson | http://quadhome.com/

Q: Why are my replies five sentences or less?
A: http://five.sentenc.es/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: SWIG (and particularly Python) bindings
  2009-12-30 10:52 ` Adrian Perez de Castro
  2009-12-30 11:34   ` Scott Robinson
@ 2009-12-30 16:10   ` Ben Gamari
  2010-01-20  8:48   ` Carl Worth
  2 siblings, 0 replies; 10+ messages in thread
From: Ben Gamari @ 2009-12-30 16:10 UTC (permalink / raw)
  To: notmuch

Excerpts from Adrian Perez de Castro's message of Wed Dec 30 05:52:23 -0500 2009:
> On Tue, 29 Dec 2009 04:16:43 -0500, Ben wrote:
> 
> > Regardless, I thought it might be nice to have access to the notmuch
> > backend from a language other than C (preferably my high-level language
> > of choice, python) [...]
> 
> Funny, I was just doing the same: a Python binding. Haha, so now we have
> two just-backed Python bindings. What should we do?

Heh, it's a small world, eh?

> 
> > [...] To this end, I took a few hours today acquainting
> > myself with SWIG and produced these bindings for Python. Unfortunately,
> > it doesn't appear that SWIG has particularly good support for
> > object-oriented C [...]
> 
> I already used SWIG sometimes in the past (and did not like it a lot), so
> my binding is using Cython [*] (which is exactly like Pyrex plus some extra
> features), so the binding is partly manual.
> 
I liked that SWIG would give us coverage for a multitude of languages
with little work. Unfortunately, getting an object oriented interface
requires wrapping the functions exposed by SWIG. Nevertheless, I think
being able to generically hide the ugliness of the binding glue itself
is quite nice. Moveover, there's effectively no SWIG interface code to
maintain.  It's literally just a [#%]include "notmuch.h". The rest is
all the Python wrapper. This seems like a nice binding model, short of
SWIG doing everything (the developers at some point might add support
for proper wrapping of object-oriented C code).

> > While the bindings are currently in the form of a patch to notmuch
> > (creating a top-level swig directory in the source tree), they could
> > certainly be moved out-of-tree if the powers that be don't feel it
> > appropriate to include them. [...]
> 
> Same here, see attached patch. It is currently unfinished, and I was just
> about to add support for iterating notmuch_threads_t and other similar
> structures. I can also publish a Git repo with the entire branch, just
> drop me a line if you want me to do that.
> 
In my approach, I just used the iterator protocol.

> > [...] Unfortunately, the build system is currently almost entirely
> > independent from the notmuch build system. If  these are to be
> > included in-tree, I would be curious to hear people have
> > to say about how we might integrate it into the sup build system.
>                                                   ^^^
> (Mmmh, I suppose you mean "notmuch build system" there :P)

Heh, yep.

> 
> Mine is a little more cooked, as I have added a distutils "setup.py"
> script. The bad news is that Python modules need to be compiled as
> relocatable object files (-fPIC to teh rescue!), and the linker will
> refuse to link the generated code with "notmuch.a" -- so I am instructing
> distutils to compile *all* sources again. Not nice.
> 
In my patch I simple I modified the LDFLAGS to include -fPIC. Not sure if
that's an acceptable option or not.

> BTW, I think that if more bindings start to appear, Notmuch might be built
> as a shared library, to avoid duplicating it everywhere. One option may be
> using *just* libtool but not the rest of auto-foo tools (for the record:
> I agree with Carl that they are slow and wicked).
> 
I think you're probably right. Libtool is probably the best option here
(Despite the fact that I, too, have a bitter hatred of autotools).

Cheers,
- Ben

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: SWIG (and particularly Python) bindings
  2009-12-30 11:34   ` Scott Robinson
@ 2010-01-16  4:09     ` Ben Gamari
  2010-01-16  4:28       ` [PATCH] libtoolize notmuch Ben Gamari
  0 siblings, 1 reply; 10+ messages in thread
From: Ben Gamari @ 2010-01-16  4:09 UTC (permalink / raw)
  To: Carl Worth; +Cc: notmuch

Excerpts from Scott Robinson's message of Wed Dec 30 06:34:15 -0500 2009:
> Excerpts from Adrian Perez de Castro's message of Wed Dec 30 02:52:23 -0800 2009:
> > BTW, I think that if more bindings start to appear, Notmuch might be built
> > as a shared library, to avoid duplicating it everywhere. One option may be
> > using *just* libtool but not the rest of auto-foo tools (for the record:
> > I agree with Carl that they are slow and wicked).
> 
> http://github.com/quad/notmuch/tree/libtool

Is this branch being considered for merge? The build output arguably
isn't as pretty as it was before, but it seems to work. Moreover, my
SWIG patches currently depend upon having a shared library involved.

- Ben

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH] libtoolize notmuch.
  2010-01-16  4:09     ` Ben Gamari
@ 2010-01-16  4:28       ` Ben Gamari
  2010-01-20  8:51         ` Carl Worth
  0 siblings, 1 reply; 10+ messages in thread
From: Ben Gamari @ 2010-01-16  4:28 UTC (permalink / raw)
  To: cworth; +Cc: notmuch

Here is a patch based on  quad's libtool branch rebased on current master. It
has been tested and verified to work on my machine

---
 Makefile           |   27 ++++++++++++++++-----------
 Makefile.local     |   12 ++++++++----
 lib/Makefile.local |    8 ++++----
 3 files changed, 28 insertions(+), 19 deletions(-)

diff --git a/Makefile b/Makefile
index 021fdb8..9022a39 100644
--- a/Makefile
+++ b/Makefile
@@ -3,6 +3,10 @@ WARN_CFLAGS=$(WARN_CXXFLAGS) -Wmissing-declarations
 
 # Additional programs that are used during the compilation process.
 EMACS ?= emacs
+libtool = libtool
+# Needed so libtool replaces parameters in a modern fashion.
+CC = gcc
+CXX = g++
 # Lowercase to avoid clash with GZIP environment variable for passing
 # arguments to gzip.
 gzip = gzip
@@ -43,34 +47,35 @@ include Makefile.local
 # user how to enable verbose compiles.
 ifeq ($(V),)
 quiet_DOC := "Use \"$(MAKE) V=1\" to see the verbose compile lines.\n"
-quiet = @printf $(quiet_DOC)$(eval quiet_DOC:=)"  $1 $2	$@\n"; $($1)
+V = 0
 endif
 # The user has explicitly enabled quiet compilation.
 ifeq ($(V),0)
-quiet = @printf "  $1	$@\n"; $($1)
+quiet = @printf $(quiet_DOC)$(eval quiet_DOC:=)"  $1 $2	$@\n"; $($1)
+libtool += --silent
 endif
 # Otherwise, print the full command line.
 quiet ?= $($1)
 
-%.o: %.cc $(all_deps)
-	$(call quiet,CXX,$(CXXFLAGS)) -c $(FINAL_CXXFLAGS) $< -o $@
+%.lo: %.cc $(all_deps)
+	$(call quiet,libtool,$(CXXFLAGS)) --mode=compile $(CXX) -c $(FINAL_CXXFLAGS) $< -o $@
 
-%.o: %.c $(all_deps)
-	$(call quiet,CC,$(CFLAGS)) -c $(FINAL_CFLAGS) $< -o $@
+%.lo: %.c $(all_deps)
+	$(call quiet,libtool,$(CFLAGS)) --mode=compile $(CC) -c $(FINAL_CFLAGS) $< -o $@
 
 %.elc: %.el
 	$(call quiet,EMACS) -batch -f batch-byte-compile $<
 
 .deps/%.d: %.c $(all_deps)
 	@set -e; rm -f $@; mkdir -p $$(dirname $@) ; \
-	$(CC) -M $(CPPFLAGS) $(FINAL_CFLAGS) $< > $@.$$$$ 2>/dev/null ; \
-	sed 's,'$$(basename $*)'\.o[ :]*,$*.o $@ : ,g' < $@.$$$$ > $@; \
+	$(CC) -M $(CPPFLAGS) $(FINAL_CFLAGS) $< > $@.$$$$; \
+	sed 's,'$$(basename $*)'\.lo[ :]*,$*.lo $@ : ,g' < $@.$$$$ > $@; \
 	rm -f $@.$$$$
 
 .deps/%.d: %.cc $(all_deps)
 	@set -e; rm -f $@; mkdir -p $$(dirname $@) ; \
-	$(CXX) -M $(CPPFLAGS) $(FINAL_CXXFLAGS) $< > $@.$$$$ 2>/dev/null ; \
-	sed 's,'$$(basename $*)'\.o[ :]*,$*.o $@ : ,g' < $@.$$$$ > $@; \
+	$(CXX) -M $(CPPFLAGS) $(FINAL_CXXFLAGS) $< > $@.$$$$; \
+	sed 's,'$$(basename $*)'\.lo[ :]*,$*.lo $@ : ,g' < $@.$$$$ > $@; \
 	rm -f $@.$$$$
 
 DEPS := $(SRCS:%.c=.deps/%.d)
@@ -79,4 +84,4 @@ DEPS := $(DEPS:%.cc=.deps/%.d)
 
 .PHONY : clean
 clean:
-	rm -f $(CLEAN); rm -rf .deps
+	$(libtool) --mode=clean rm -f $(CLEAN); rm -rf .deps
diff --git a/Makefile.local b/Makefile.local
index 933ff4c..ccff76c 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -20,9 +20,9 @@ notmuch_client_srcs =		\
 	query-string.c		\
 	show-message.c
 
-notmuch_client_modules = $(notmuch_client_srcs:.c=.o)
-notmuch: $(notmuch_client_modules) lib/notmuch.a
-	$(call quiet,CXX,$(LDFLAGS)) $^ $(FINAL_LDFLAGS) -o $@
+notmuch_client_modules = $(notmuch_client_srcs:.c=.lo)
+notmuch: $(notmuch_client_modules) lib/libnotmuch.la
+	$(call quiet,libtool,$(LDFLAGS)) --mode=link $(CXX) $^ $(FINAL_LDFLAGS) -o $@
 
 notmuch.1.gz: notmuch.1
 	$(call quiet,gzip) --stdout $^ > $@
@@ -32,8 +32,12 @@ install: all notmuch.1.gz
 	do \
 		install -d $$d ; \
 	done ;
-	install notmuch $(DESTDIR)$(prefix)/bin/
+	$(libtool) --mode=install install -c lib/libnotmuch.la $(DESTDIR)$(prefix)/lib/
+	$(libtool) --mode=install install -c notmuch $(DESTDIR)$(prefix)/bin/
 	install -m0644 notmuch.1.gz $(DESTDIR)$(prefix)/share/man/man1/
+	install contrib/notmuch-completion.bash \
+		$(DESTDIR)$(bash_completion_dir)/notmuch
+	$(libtool) --mode=finish $(DESTDIR)$(prefix)/lib/
 
 install-emacs: install emacs
 	for d in $(DESTDIR)/$(emacs_lispdir) ; \
diff --git a/lib/Makefile.local b/lib/Makefile.local
index 70489e1..b03dff6 100644
--- a/lib/Makefile.local
+++ b/lib/Makefile.local
@@ -17,9 +17,9 @@ libnotmuch_cxx_srcs =		\
 	$(dir)/query.cc		\
 	$(dir)/thread.cc
 
-libnotmuch_modules = $(libnotmuch_c_srcs:.c=.o) $(libnotmuch_cxx_srcs:.cc=.o)
-$(dir)/notmuch.a: $(libnotmuch_modules)
-	$(call quiet,AR) rcs $@ $^
+libnotmuch_modules = $(libnotmuch_c_srcs:.c=.lo) $(libnotmuch_cxx_srcs:.cc=.lo)
+$(dir)/libnotmuch.la: $(libnotmuch_modules)
+	$(call quiet,libtool) --mode=link $(CXX) -rpath $(DESTDIR)$(prefix)/lib -o $@ $^
 
 SRCS  := $(SRCS) $(libnotmuch_c_srcs) $(libnotmuch_cxx_srcs)
-CLEAN := $(CLEAN) $(libnotmuch_modules) $(dir)/notmuch.a
+CLEAN := $(CLEAN) $(libnotmuch_modules) $(dir)/notmuch.la
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: SWIG (and particularly Python) bindings
  2009-12-29  9:16 SWIG (and particularly Python) bindings Ben Gamari
  2009-12-30 10:52 ` Adrian Perez de Castro
@ 2010-01-20  8:45 ` Carl Worth
  2010-01-20 18:39   ` Ben Gamari
  1 sibling, 1 reply; 10+ messages in thread
From: Carl Worth @ 2010-01-20  8:45 UTC (permalink / raw)
  To: Ben Gamari, notmuch

[-- Attachment #1: Type: text/plain, Size: 1084 bytes --]

On Tue, 29 Dec 2009 04:16:43 -0500, Ben Gamari <bgamari@gmail.com> wrote:
> I've been looking at switching away from sup recently to something with
> a slightly little less everything-and-the-kitchen-sink philosophy.

Hi Ben,

Welcome to Notmuch!

> Notmuch looks excellent, although it appears that its current front-end
> for my editor of choice (vim) is a little lacking in some ways
> (operations involving a call to notmuch invariably lock up vi for the
> duration of the operation).

Yes. The emacs mode was similarly crippled initially and fairly painful
until we fixed that, (and quite nice afterwards).

> these are to be included in-tree, I would be curious to hear people have
> to say about how we might integrate it into the sup build system.

I can't say much about integrating with the sup build system...

;-)

> Hope this helps someone. I'll hopefully have a chance to work with the
> bindings soon and will send a new set of patches once I think I've found
> all of the obvious issues.

Thanks for sharing. I'll look forward to future contributions from you!

-Carl

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: SWIG (and particularly Python) bindings
  2009-12-30 10:52 ` Adrian Perez de Castro
  2009-12-30 11:34   ` Scott Robinson
  2009-12-30 16:10   ` SWIG (and particularly Python) bindings Ben Gamari
@ 2010-01-20  8:48   ` Carl Worth
  2 siblings, 0 replies; 10+ messages in thread
From: Carl Worth @ 2010-01-20  8:48 UTC (permalink / raw)
  To: Adrian Perez de Castro, notmuch

[-- Attachment #1: Type: text/plain, Size: 981 bytes --]

On Wed, 30 Dec 2009 11:52:23 +0100, Adrian Perez de Castro <aperez@igalia.com> wrote:
> BTW, I think that if more bindings start to appear, Notmuch might be built
> as a shared library, to avoid duplicating it everywhere.

Yes. As soon as we have users of the library we can install it as a
shared library.

>                                                          One option may be
> using *just* libtool but not the rest of auto-foo tools (for the record:
> I agree with Carl that they are slow and wicked).

Totally uninterested in libtool personally. It does so many things wrong
(.la files that *only* cause breakage on Linux, a tendency to shove
hard-coded rpath entries in the library where unwanted), and doesn't
seem to do much of anything that's really interesting. I'm happy to just
accept patches that tweak the command in the Makefile for "build a
shared library now" for each platform that's of practical interest. The
job here is just not that complicated.

-Carl

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] libtoolize notmuch.
  2010-01-16  4:28       ` [PATCH] libtoolize notmuch Ben Gamari
@ 2010-01-20  8:51         ` Carl Worth
  0 siblings, 0 replies; 10+ messages in thread
From: Carl Worth @ 2010-01-20  8:51 UTC (permalink / raw)
  To: Ben Gamari; +Cc: notmuch

[-- Attachment #1: Type: text/plain, Size: 472 bytes --]

On Fri, 15 Jan 2010 23:28:55 -0500, Ben Gamari <bgamari.foss@gmail.com> wrote:
> Here is a patch based on  quad's libtool branch rebased on current master. It
> has been tested and verified to work on my machine

How about something similar that simply creates a .so with ld?

I'd be interested in using automake before libtool, (but similarly,
don't actually see any benefit in using automake as opposed to just
using GNU make features as notmuch does currently).

-Carl

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: SWIG (and particularly Python) bindings
  2010-01-20  8:45 ` Carl Worth
@ 2010-01-20 18:39   ` Ben Gamari
  0 siblings, 0 replies; 10+ messages in thread
From: Ben Gamari @ 2010-01-20 18:39 UTC (permalink / raw)
  To: notmuch

Excerpts from Carl Worth's message of Wed Jan 20 03:45:34 -0500 2010:
> Welcome to Notmuch!
> 
Thanks!

> > Notmuch looks excellent, although it appears that its current front-end
> > for my editor of choice (vim) is a little lacking in some ways
> > (operations involving a call to notmuch invariably lock up vi for the
> > duration of the operation).
> 
> Yes. The emacs mode was similarly crippled initially and fairly painful
> until we fixed that, (and quite nice afterwards).
> 
I can easily believe that. I've tried using the vim mode and quickly
gave up. I think I'm going to have to stick with sup until I've added
the appropriate subprocess support into vim. I have some half-completed
code, but still have a ways to go.

> > these are to be included in-tree, I would be curious to hear people have
> > to say about how we might integrate it into the sup build system.
> 
> I can't say much about integrating with the sup build system...
> 
Heh. My bad.

- Ben

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2010-01-20 18:40 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-12-29  9:16 SWIG (and particularly Python) bindings Ben Gamari
2009-12-30 10:52 ` Adrian Perez de Castro
2009-12-30 11:34   ` Scott Robinson
2010-01-16  4:09     ` Ben Gamari
2010-01-16  4:28       ` [PATCH] libtoolize notmuch Ben Gamari
2010-01-20  8:51         ` Carl Worth
2009-12-30 16:10   ` SWIG (and particularly Python) bindings Ben Gamari
2010-01-20  8:48   ` Carl Worth
2010-01-20  8:45 ` Carl Worth
2010-01-20 18:39   ` Ben Gamari

Code repositories for project(s) associated with this public inbox

	https://yhetil.org/notmuch.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).