1b2732e9dSimarom# coding: utf-8
2b2732e9dSimarom"""The main CFFI wrapping of libzmq"""
3b2732e9dSimarom
4b2732e9dSimarom# Copyright (C) PyZMQ Developers
5b2732e9dSimarom# Distributed under the terms of the Modified BSD License.
6b2732e9dSimarom
7b2732e9dSimarom
8b2732e9dSimaromimport json
9b2732e9dSimaromimport os
10b2732e9dSimaromfrom os.path import dirname, join
11b2732e9dSimaromfrom cffi import FFI
12b2732e9dSimarom
13b2732e9dSimaromfrom zmq.utils.constant_names import all_names, no_prefix
14b2732e9dSimarom
15b2732e9dSimarom
16b2732e9dSimarombase_zmq_version = (3,2,2)
17b2732e9dSimarom
18b2732e9dSimaromdef load_compiler_config():
19b2732e9dSimarom    """load pyzmq compiler arguments"""
20b2732e9dSimarom    import zmq
21b2732e9dSimarom    zmq_dir = dirname(zmq.__file__)
22b2732e9dSimarom    zmq_parent = dirname(zmq_dir)
23b2732e9dSimarom
24b2732e9dSimarom    fname = join(zmq_dir, 'utils', 'compiler.json')
25b2732e9dSimarom    if os.path.exists(fname):
26b2732e9dSimarom        with open(fname) as f:
27b2732e9dSimarom            cfg = json.load(f)
28b2732e9dSimarom    else:
29b2732e9dSimarom        cfg = {}
30b2732e9dSimarom
31b2732e9dSimarom    cfg.setdefault("include_dirs", [])
32b2732e9dSimarom    cfg.setdefault("library_dirs", [])
33b2732e9dSimarom    cfg.setdefault("runtime_library_dirs", [])
34b2732e9dSimarom    cfg.setdefault("libraries", ["zmq"])
35b2732e9dSimarom
36b2732e9dSimarom    # cast to str, because cffi can't handle unicode paths (?!)
37b2732e9dSimarom    cfg['libraries'] = [str(lib) for lib in cfg['libraries']]
38b2732e9dSimarom    for key in ("include_dirs", "library_dirs", "runtime_library_dirs"):
39b2732e9dSimarom        # interpret paths relative to parent of zmq (like source tree)
40b2732e9dSimarom        abs_paths = []
41b2732e9dSimarom        for p in cfg[key]:
42b2732e9dSimarom            if p.startswith('zmq'):
43b2732e9dSimarom                p = join(zmq_parent, p)
44b2732e9dSimarom            abs_paths.append(str(p))
45b2732e9dSimarom        cfg[key] = abs_paths
46b2732e9dSimarom    return cfg
47b2732e9dSimarom
48b2732e9dSimarom
49b2732e9dSimaromdef zmq_version_info():
50b2732e9dSimarom    """Get libzmq version as tuple of ints"""
51b2732e9dSimarom    major = ffi.new('int*')
52b2732e9dSimarom    minor = ffi.new('int*')
53b2732e9dSimarom    patch = ffi.new('int*')
54b2732e9dSimarom
55b2732e9dSimarom    C.zmq_version(major, minor, patch)
56b2732e9dSimarom
57b2732e9dSimarom    return (int(major[0]), int(minor[0]), int(patch[0]))
58b2732e9dSimarom
59b2732e9dSimarom
60b2732e9dSimaromcfg = load_compiler_config()
61b2732e9dSimaromffi = FFI()
62b2732e9dSimarom
63b2732e9dSimaromdef _make_defines(names):
64b2732e9dSimarom    _names = []
65b2732e9dSimarom    for name in names:
66b2732e9dSimarom        define_line = "#define %s ..." % (name)
67b2732e9dSimarom        _names.append(define_line)
68b2732e9dSimarom
69b2732e9dSimarom    return "\n".join(_names)
70b2732e9dSimarom
71b2732e9dSimaromc_constant_names = []
72b2732e9dSimaromfor name in all_names:
73b2732e9dSimarom    if no_prefix(name):
74b2732e9dSimarom        c_constant_names.append(name)
75b2732e9dSimarom    else:
76b2732e9dSimarom        c_constant_names.append("ZMQ_" + name)
77b2732e9dSimarom
78b2732e9dSimarom# load ffi definitions
79b2732e9dSimaromhere = os.path.dirname(__file__)
80b2732e9dSimaromwith open(os.path.join(here, '_cdefs.h')) as f:
81b2732e9dSimarom    _cdefs = f.read()
82b2732e9dSimarom
83b2732e9dSimaromwith open(os.path.join(here, '_verify.c')) as f:
84b2732e9dSimarom    _verify = f.read()
85b2732e9dSimarom
86b2732e9dSimaromffi.cdef(_cdefs)
87b2732e9dSimaromffi.cdef(_make_defines(c_constant_names))
88b2732e9dSimarom
89b2732e9dSimaromtry:
90b2732e9dSimarom    C = ffi.verify(_verify,
91b2732e9dSimarom        modulename='_cffi_ext',
92b2732e9dSimarom        libraries=cfg['libraries'],
93b2732e9dSimarom        include_dirs=cfg['include_dirs'],
94b2732e9dSimarom        library_dirs=cfg['library_dirs'],
95b2732e9dSimarom        runtime_library_dirs=cfg['runtime_library_dirs'],
96b2732e9dSimarom    )
97b2732e9dSimarom    _version_info = zmq_version_info()
98b2732e9dSimaromexcept Exception as e:
99b2732e9dSimarom    raise ImportError("PyZMQ CFFI backend couldn't find zeromq: %s\n"
100b2732e9dSimarom    "Please check that you have zeromq headers and libraries." % e)
101b2732e9dSimarom
102b2732e9dSimaromif _version_info < (3,2,2):
103b2732e9dSimarom    raise ImportError("PyZMQ CFFI backend requires zeromq >= 3.2.2,"
104b2732e9dSimarom        " but found %i.%i.%i" % _version_info
105b2732e9dSimarom    )
106b2732e9dSimarom
107b2732e9dSimaromnsp = new_sizet_pointer = lambda length: ffi.new('size_t*', length)
108b2732e9dSimarom
109b2732e9dSimaromnew_uint64_pointer = lambda: (ffi.new('uint64_t*'),
110b2732e9dSimarom                              nsp(ffi.sizeof('uint64_t')))
111b2732e9dSimaromnew_int64_pointer = lambda: (ffi.new('int64_t*'),
112b2732e9dSimarom                             nsp(ffi.sizeof('int64_t')))
113b2732e9dSimaromnew_int_pointer = lambda: (ffi.new('int*'),
114b2732e9dSimarom                           nsp(ffi.sizeof('int')))
115b2732e9dSimaromnew_binary_data = lambda length: (ffi.new('char[%d]' % (length)),
116b2732e9dSimarom                                  nsp(ffi.sizeof('char') * length))
117b2732e9dSimarom
118b2732e9dSimaromvalue_uint64_pointer = lambda val : (ffi.new('uint64_t*', val),
119b2732e9dSimarom                                     ffi.sizeof('uint64_t'))
120b2732e9dSimaromvalue_int64_pointer = lambda val: (ffi.new('int64_t*', val),
121b2732e9dSimarom                                   ffi.sizeof('int64_t'))
122b2732e9dSimaromvalue_int_pointer = lambda val: (ffi.new('int*', val),
123b2732e9dSimarom                                 ffi.sizeof('int'))
124b2732e9dSimaromvalue_binary_data = lambda val, length: (ffi.new('char[%d]' % (length + 1), val),
125b2732e9dSimarom                                         ffi.sizeof('char') * length)
126b2732e9dSimarom
127b2732e9dSimaromIPC_PATH_MAX_LEN = C.get_ipc_path_max_len()
128