import distutils.ccompiler import distutils.log import distutils.sysconfig import os import shutil import tempfile import cffi # Also look in these directories for include files, i.e. notmuch.h (-I) INCLUDE_DIRS = ["../../lib"] # Also look in these directories for libraries, i.e. libnotmuch.so.5 (-L) LIBRARY_DIRS = ["../../lib"] # Add extra linker flags, e.g. -Wl,--enable-new-dtags,-R/path/to/notmuch/libdir EXTRA_LINK_ARGS = ["-Wl,--enable-new-dtags,-R/home/flub/Projects/notmuch/lib"] def extract_functions(): """Extract the function definitions from notmuch.h. This creates a .h file with a single `#include ` line in it. It then runs the C preprocessor with the PY_CFFI symbol defined to create an output file which contains all function definitions found in `notmuch.h`. """ distutils.log.set_verbosity(distutils.log.INFO) cc = distutils.ccompiler.new_compiler(force=True) distutils.sysconfig.customize_compiler(cc) tmpdir = tempfile.mkdtemp() try: src_name = os.path.join(tmpdir, "include.h") dst_name = os.path.join(tmpdir, "expanded.h") with open(src_name, "w") as src_fp: src_fp.write("#include ") cc.preprocess( source=src_name, output_file=dst_name, include_dirs=INCLUDE_DIRS, macros=[("PY_CFFI", "1")], ) with open(dst_name, "r") as dst_fp: return dst_fp.read() finally: shutil.rmtree(tmpdir) ffibuilder = cffi.FFI() ffibuilder.set_source( "notmuch2._capi", r""" #include #include #include #if LIBNOTMUCH_MAJOR_VERSION < 5 #error libnotmuch version not supported by notmuch2 python bindings #endif #if LIBNOTMUCH_MINOR_VERSION < 1 #ERROR libnotmuch version < 5.1 not supported #endif """, include_dirs=INCLUDE_DIRS, library_dirs=LIBRARY_DIRS, extra_link_args=EXTRA_LINK_ARGS, libraries=["notmuch"], ) ffibuilder.cdef( r""" void free(void *ptr); typedef int... time_t; #define LIBNOTMUCH_MAJOR_VERSION ... #define LIBNOTMUCH_MINOR_VERSION ... #define LIBNOTMUCH_MICRO_VERSION ... #define NOTMUCH_TAG_MAX ... """ ) ffibuilder.cdef(extract_functions()) if __name__ == "__main__": ffibuilder.compile(verbose=True)