summaryrefslogtreecommitdiff
path: root/cffi
diff options
context:
space:
mode:
authorMichal Vyskocil <michal.vyskocil@gmail.com>2019-01-08 10:29:51 +0100
committerMichal Vyskocil <michal.vyskocil@gmail.com>2019-01-08 10:29:51 +0100
commit2793a648435f6dd867b9462daa865b3790492305 (patch)
treed3ec0d309f947a2c9303bd4fbb45a7f0c8b7807a /cffi
parentc5d2062cbf82b19b372fcc9798d34cb9f656d6cf (diff)
parenta074df4d40f178c21249bc3f0791082f6230499f (diff)
downloadcffi-2793a648435f6dd867b9462daa865b3790492305.tar.gz
merge with latest tip
Diffstat (limited to 'cffi')
-rw-r--r--cffi/api.py7
-rw-r--r--cffi/pkgconfig.py86
2 files changed, 93 insertions, 0 deletions
diff --git a/cffi/api.py b/cffi/api.py
index f4c4ddc..deff905 100644
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -2,6 +2,7 @@ import sys, types
from .lock import allocate_lock
from .error import CDefError
from . import model
+from . import pkgconfig
try:
callable
@@ -640,6 +641,12 @@ class FFI(object):
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 and pkgconfig.is_installed():
+ if "libraries" in kwds:
+ del kwds["libraries"] # real library names are going to be
+ # provided by pkg-config
+ pkgconfig.merge_flags(kwds, pkgconfig.kwargs(kwds["pkgconfig"]))
+ del kwds["pkgconfig"]
self._assigned_source = (str(module_name), source,
source_extension, kwds)
diff --git a/cffi/pkgconfig.py b/cffi/pkgconfig.py
new file mode 100644
index 0000000..0601802
--- /dev/null
+++ b/cffi/pkgconfig.py
@@ -0,0 +1,86 @@
+# pkg-config, https://www.freedesktop.org/wiki/Software/pkg-config/ integration for cffi
+import subprocess
+
+def is_installed():
+ """Check if pkg-config is installed or not"""
+ try:
+ subprocess.check_output(["pkg-config", "--version"])
+ return True
+ except subprocess.CalledProcessError:
+ return False
+
+
+def merge_flags(cfg1, cfg2):
+ """Merge values from cffi config flags cfg2 to cf1
+
+ Example:
+ merge_flags({"libraries": ["one"]}, {"libraries": "two"})
+ {"libraries}" : ["one", "two"]}
+ """
+ for key, value in cfg2.items():
+ if not key in cfg1:
+ cfg1 [key] = value
+ else:
+ cfg1 [key].extend(value)
+ return cfg1
+
+
+def call(libname, flag):
+ """Calls pkg-config and returing the output"""
+ a = ["pkg-config", "--print-errors"]
+ a.append(flag)
+ a.append(libname)
+ return subprocess.check_output(a)
+
+
+def flags(libs):
+ r"""Return compiler line flags for FFI.set_source based on pkg-config output
+
+ Usage
+ ...
+ ffibuilder.set_source("_foo", libraries = ["foo", "bar"], pkgconfig = ["libfoo", "libbar"])
+
+ If `pkg-config` is installed on build machine, then arguments
+ `include_dirs`, `library_dirs`, `libraries`, `define_macros`,
+ `extra_compile_args` and `extra_link_args` are extended with an output of
+ `pkg-config` for `libfoo` and `libbar`.
+ """
+
+ # 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(b"-I") or string.startswith(b"-L") or string.startswith(b"-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(b"=", 2))
+ return [_macros(x) for x in string.split() if x.startswith(b"-D")]
+
+ def drop_macros(string):
+ return [x for x in string.split() if not x.startswith(b"-D")]
+
+ # return kwargs for given libname
+ def kwargs(libname):
+ return {
+ "include_dirs" : dropILl(call(libname, "--cflags-only-I")),
+ "library_dirs" : dropILl(call(libname, "--libs-only-L")),
+ "libraries" : dropILl(call(libname, "--libs-only-l")),
+ "define_macros" : macros(call(libname, "--cflags-only-other")),
+ "extra_compile_args" : drop_macros(call(libname, "--cflags-only-other")),
+ "extra_link_args" : call(libname, "--libs-only-other").split()
+ }
+
+ # merge all arguments together
+ ret = {}
+ for libname in libs:
+ foo = kwargs(libname)
+ merge_flags(ret, foo)
+
+ return ret