[pypy-commit] cffi default: Passing of proper CFLAGS/CXXFLAGS/LDFLAGS is hard and error prone

vyskocilm pypy.commits at gmail.com
Thu Jan 31 04:26:40 EST 2019


Author: Michal Vyskocil <michal.vyskocil at gmail.com>
Branch: 
Changeset: r3189:4e8e9cab26fd
Date: 2017-05-22 23:49 +0200
http://bitbucket.org/cffi/cffi/changeset/4e8e9cab26fd/

Log:	Passing of proper CFLAGS/CXXFLAGS/LDFLAGS is hard and error prone

	Add pkg-config wrapper, which is the cross-platform tool telling
	exactly this.

diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -2,6 +2,7 @@
 from .lock import allocate_lock
 from .error import CDefError
 from . import model
+from .pkgconfig import pkgconfig_installed, merge_dicts, pkgconfig_kwargs
 
 try:
     callable
@@ -611,6 +612,18 @@
         if os.sep in module_name or (os.altsep and os.altsep in module_name):
             raise ValueError("'module_name' must not contain '/': use a dotted "
                              "name to make a 'package.module' location")
+        if "pkgconfig" in kwds:
+            if pkgconfig_installed ():
+                try:
+                    del kwds ["libraries"]
+                except KeyError:
+                    pass
+                merge_dicts (kwds, pkgconfig_kwargs (kwds ["pkgconfig"]))
+                try:
+                    del kwds ["pkgconfig"]
+                except KeyError:
+                    pass
+        print (kwds)
         self._assigned_source = (str(module_name), source,
                                  source_extension, kwds)
 
diff --git a/cffi/pkgconfig.py b/cffi/pkgconfig.py
new file mode 100644
--- /dev/null
+++ b/cffi/pkgconfig.py
@@ -0,0 +1,65 @@
+# pkg-config, https://www.freedesktop.org/wiki/Software/pkg-config/ integration for cffi
+import subprocess
+
+def pkgconfig_installed ():
+    try:
+        subprocess.check_output (["pkg-config", "--version"])
+        return True
+    except subprocess.CalledProcessError:
+        return False
+
+def merge_dicts (d1, d2):
+    for key, value in d2.items ():
+        if not key in d1:
+            d1 [key] = value
+        else:
+            d1 [key].extend (value)
+    return d1
+
+def pkgconfig_kwargs (libs):
+    """If pkg-config is available, then return kwargs for set_source based on pkg-config output
+    
+    It setup include_dirs, library_dirs, libraries and define_macros
+    """
+
+    # make API great again!
+    if isinstance (libs, (str, bytes)):
+        libs = (libs, )
+    
+    # drop starting -I -L -l from cflags
+    def dropILl (string):
+        def _dropILl (string):
+            if string.startswith ("-I") or string.startswith ("-L") or string.startswith ("-l"):
+                return string [2:]
+        return [_dropILl (x) for x in string.split ()]
+
+    # convert -Dfoo=bar to list of tuples [("foo", "bar")] expected by cffi
+    def macros (string):
+        def _macros (string):
+            return tuple (string [2:].split ('=', 2))
+        return [_macros (x) for x in string.split () if x.startswith ("-D")]
+
+    # pkg-config call
+    def pc (libname, *args):
+        a = ["pkg-config", "--print-errors"]
+        a.extend (args)
+        a.append (libname)
+        return subprocess.check_output (a)
+
+    # return kwargs for given libname
+    def kwargs (libname):
+        return {
+                "include_dirs" : dropILl (pc (libname, "--cflags-only-I")),
+                "library_dirs" : dropILl (pc (libname, "--libs-only-L")),
+                "libraries" : dropILl (pc (libname, "--libs-only-l")),
+                "define_macros" : macros (pc (libname, "--cflags")),
+                }
+
+    # merge all arguments together
+    ret = {}
+    for libname in libs:
+        foo = kwargs (libname)
+        merge_dicts (ret, foo)
+
+    return ret
+


More information about the pypy-commit mailing list