NonameSsSs commited on
Commit
09cf315
·
verified ·
1 Parent(s): e359f37

Upload api.py

Browse files
Files changed (1) hide show
  1. cffi/api.py +967 -0
cffi/api.py ADDED
@@ -0,0 +1,967 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys, types
2
+ from .lock import allocate_lock
3
+ from .error import CDefError
4
+ from . import model
5
+
6
+ try:
7
+ callable
8
+ except NameError:
9
+ # Python 3.1
10
+ from collections import Callable
11
+ callable = lambda x: isinstance(x, Callable)
12
+
13
+ try:
14
+ basestring
15
+ except NameError:
16
+ # Python 3.x
17
+ basestring = str
18
+
19
+ _unspecified = object()
20
+
21
+
22
+
23
+ class FFI(object):
24
+ r'''
25
+ The main top-level class that you instantiate once, or once per module.
26
+
27
+ Example usage:
28
+
29
+ ffi = FFI()
30
+ ffi.cdef("""
31
+ int printf(const char *, ...);
32
+ """)
33
+
34
+ C = ffi.dlopen(None) # standard library
35
+ -or-
36
+ C = ffi.verify() # use a C compiler: verify the decl above is right
37
+
38
+ C.printf("hello, %s!\n", ffi.new("char[]", "world"))
39
+ '''
40
+
41
+ def __init__(self, backend=None):
42
+ """Create an FFI instance. The 'backend' argument is used to
43
+ select a non-default backend, mostly for tests.
44
+ """
45
+ if backend is None:
46
+ # You need PyPy (>= 2.0 beta), or a CPython (>= 2.6) with
47
+ # _cffi_backend.so compiled.
48
+ import _cffi_backend as backend
49
+ from . import __version__
50
+ if backend.__version__ != __version__:
51
+ # bad version! Try to be as explicit as possible.
52
+ if hasattr(backend, '__file__'):
53
+ # CPython
54
+ raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. When we import the top-level '_cffi_backend' extension module, we get version %s, located in %r. The two versions should be equal; check your installation." % (
55
+ __version__, __file__,
56
+ backend.__version__, backend.__file__))
57
+ else:
58
+ # PyPy
59
+ raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. This interpreter comes with a built-in '_cffi_backend' module, which is version %s. The two versions should be equal; check your installation." % (
60
+ __version__, __file__, backend.__version__))
61
+ # (If you insist you can also try to pass the option
62
+ # 'backend=backend_ctypes.CTypesBackend()', but don't
63
+ # rely on it! It's probably not going to work well.)
64
+
65
+ from . import cparser
66
+ self._backend = backend
67
+ self._lock = allocate_lock()
68
+ self._parser = cparser.Parser()
69
+ self._cached_btypes = {}
70
+ self._parsed_types = types.ModuleType('parsed_types').__dict__
71
+ self._new_types = types.ModuleType('new_types').__dict__
72
+ self._function_caches = []
73
+ self._libraries = []
74
+ self._cdefsources = []
75
+ self._included_ffis = []
76
+ self._windows_unicode = None
77
+ self._init_once_cache = {}
78
+ self._cdef_version = None
79
+ self._embedding = None
80
+ self._typecache = model.get_typecache(backend)
81
+ if hasattr(backend, 'set_ffi'):
82
+ backend.set_ffi(self)
83
+ for name in list(backend.__dict__):
84
+ if name.startswith('RTLD_'):
85
+ setattr(self, name, getattr(backend, name))
86
+ #
87
+ with self._lock:
88
+ self.BVoidP = self._get_cached_btype(model.voidp_type)
89
+ self.BCharA = self._get_cached_btype(model.char_array_type)
90
+ if isinstance(backend, types.ModuleType):
91
+ # _cffi_backend: attach these constants to the class
92
+ if not hasattr(FFI, 'NULL'):
93
+ FFI.NULL = self.cast(self.BVoidP, 0)
94
+ FFI.CData, FFI.CType = backend._get_types()
95
+ else:
96
+ # ctypes backend: attach these constants to the instance
97
+ self.NULL = self.cast(self.BVoidP, 0)
98
+ self.CData, self.CType = backend._get_types()
99
+ self.buffer = backend.buffer
100
+
101
+ def cdef(self, csource, override=False, packed=False, pack=None):
102
+ """Parse the given C source. This registers all declared functions,
103
+ types, and global variables. The functions and global variables can
104
+ then be accessed via either 'ffi.dlopen()' or 'ffi.verify()'.
105
+ The types can be used in 'ffi.new()' and other functions.
106
+ If 'packed' is specified as True, all structs declared inside this
107
+ cdef are packed, i.e. laid out without any field alignment at all.
108
+ Alternatively, 'pack' can be a small integer, and requests for
109
+ alignment greater than that are ignored (pack=1 is equivalent to
110
+ packed=True).
111
+ """
112
+ self._cdef(csource, override=override, packed=packed, pack=pack)
113
+
114
+ def embedding_api(self, csource, packed=False, pack=None):
115
+ self._cdef(csource, packed=packed, pack=pack, dllexport=True)
116
+ if self._embedding is None:
117
+ self._embedding = ''
118
+
119
+ def _cdef(self, csource, override=False, **options):
120
+ if not isinstance(csource, str): # unicode, on Python 2
121
+ if not isinstance(csource, basestring):
122
+ raise TypeError("cdef() argument must be a string")
123
+ csource = csource.encode('ascii')
124
+ with self._lock:
125
+ self._cdef_version = object()
126
+ self._parser.parse(csource, override=override, **options)
127
+ self._cdefsources.append(csource)
128
+ if override:
129
+ for cache in self._function_caches:
130
+ cache.clear()
131
+ finishlist = self._parser._recomplete
132
+ if finishlist:
133
+ self._parser._recomplete = []
134
+ for tp in finishlist:
135
+ tp.finish_backend_type(self, finishlist)
136
+
137
+ def dlopen(self, name, flags=0):
138
+ """Load and return a dynamic library identified by 'name'.
139
+ The standard C library can be loaded by passing None.
140
+ Note that functions and types declared by 'ffi.cdef()' are not
141
+ linked to a particular library, just like C headers; in the
142
+ library we only look for the actual (untyped) symbols.
143
+ """
144
+ if not (isinstance(name, basestring) or
145
+ name is None or
146
+ isinstance(name, self.CData)):
147
+ raise TypeError("dlopen(name): name must be a file name, None, "
148
+ "or an already-opened 'void *' handle")
149
+ with self._lock:
150
+ lib, function_cache = _make_ffi_library(self, name, flags)
151
+ self._function_caches.append(function_cache)
152
+ self._libraries.append(lib)
153
+ return lib
154
+
155
+ def dlclose(self, lib):
156
+ """Close a library obtained with ffi.dlopen(). After this call,
157
+ access to functions or variables from the library will fail
158
+ (possibly with a segmentation fault).
159
+ """
160
+ type(lib).__cffi_close__(lib)
161
+
162
+ def _typeof_locked(self, cdecl):
163
+ # call me with the lock!
164
+ key = cdecl
165
+ if key in self._parsed_types:
166
+ return self._parsed_types[key]
167
+ #
168
+ if not isinstance(cdecl, str): # unicode, on Python 2
169
+ cdecl = cdecl.encode('ascii')
170
+ #
171
+ type = self._parser.parse_type(cdecl)
172
+ really_a_function_type = type.is_raw_function
173
+ if really_a_function_type:
174
+ type = type.as_function_pointer()
175
+ btype = self._get_cached_btype(type)
176
+ result = btype, really_a_function_type
177
+ self._parsed_types[key] = result
178
+ return result
179
+
180
+ def _typeof(self, cdecl, consider_function_as_funcptr=False):
181
+ # string -> ctype object
182
+ try:
183
+ result = self._parsed_types[cdecl]
184
+ except KeyError:
185
+ with self._lock:
186
+ result = self._typeof_locked(cdecl)
187
+ #
188
+ btype, really_a_function_type = result
189
+ if really_a_function_type and not consider_function_as_funcptr:
190
+ raise CDefError("the type %r is a function type, not a "
191
+ "pointer-to-function type" % (cdecl,))
192
+ return btype
193
+
194
+ def typeof(self, cdecl):
195
+ """Parse the C type given as a string and return the
196
+ corresponding <ctype> object.
197
+ It can also be used on 'cdata' instance to get its C type.
198
+ """
199
+ if isinstance(cdecl, basestring):
200
+ return self._typeof(cdecl)
201
+ if isinstance(cdecl, self.CData):
202
+ return self._backend.typeof(cdecl)
203
+ if isinstance(cdecl, types.BuiltinFunctionType):
204
+ res = _builtin_function_type(cdecl)
205
+ if res is not None:
206
+ return res
207
+ if (isinstance(cdecl, types.FunctionType)
208
+ and hasattr(cdecl, '_cffi_base_type')):
209
+ with self._lock:
210
+ return self._get_cached_btype(cdecl._cffi_base_type)
211
+ raise TypeError(type(cdecl))
212
+
213
+ def sizeof(self, cdecl):
214
+ """Return the size in bytes of the argument. It can be a
215
+ string naming a C type, or a 'cdata' instance.
216
+ """
217
+ if isinstance(cdecl, basestring):
218
+ BType = self._typeof(cdecl)
219
+ return self._backend.sizeof(BType)
220
+ else:
221
+ return self._backend.sizeof(cdecl)
222
+
223
+ def alignof(self, cdecl):
224
+ """Return the natural alignment size in bytes of the C type
225
+ given as a string.
226
+ """
227
+ if isinstance(cdecl, basestring):
228
+ cdecl = self._typeof(cdecl)
229
+ return self._backend.alignof(cdecl)
230
+
231
+ def offsetof(self, cdecl, *fields_or_indexes):
232
+ """Return the offset of the named field inside the given
233
+ structure or array, which must be given as a C type name.
234
+ You can give several field names in case of nested structures.
235
+ You can also give numeric values which correspond to array
236
+ items, in case of an array type.
237
+ """
238
+ if isinstance(cdecl, basestring):
239
+ cdecl = self._typeof(cdecl)
240
+ return self._typeoffsetof(cdecl, *fields_or_indexes)[1]
241
+
242
+ def new(self, cdecl, init=None):
243
+ """Allocate an instance according to the specified C type and
244
+ return a pointer to it. The specified C type must be either a
245
+ pointer or an array: ``new('X *')`` allocates an X and returns
246
+ a pointer to it, whereas ``new('X[n]')`` allocates an array of
247
+ n X'es and returns an array referencing it (which works
248
+ mostly like a pointer, like in C). You can also use
249
+ ``new('X[]', n)`` to allocate an array of a non-constant
250
+ length n.
251
+
252
+ The memory is initialized following the rules of declaring a
253
+ global variable in C: by default it is zero-initialized, but
254
+ an explicit initializer can be given which can be used to
255
+ fill all or part of the memory.
256
+
257
+ When the returned <cdata> object goes out of scope, the memory
258
+ is freed. In other words the returned <cdata> object has
259
+ ownership of the value of type 'cdecl' that it points to. This
260
+ means that the raw data can be used as long as this object is
261
+ kept alive, but must not be used for a longer time. Be careful
262
+ about that when copying the pointer to the memory somewhere
263
+ else, e.g. into another structure.
264
+ """
265
+ if isinstance(cdecl, basestring):
266
+ cdecl = self._typeof(cdecl)
267
+ return self._backend.newp(cdecl, init)
268
+
269
+ def new_allocator(self, alloc=None, free=None,
270
+ should_clear_after_alloc=True):
271
+ """Return a new allocator, i.e. a function that behaves like ffi.new()
272
+ but uses the provided low-level 'alloc' and 'free' functions.
273
+
274
+ 'alloc' is called with the size as argument. If it returns NULL, a
275
+ MemoryError is raised. 'free' is called with the result of 'alloc'
276
+ as argument. Both can be either Python function or directly C
277
+ functions. If 'free' is None, then no free function is called.
278
+ If both 'alloc' and 'free' are None, the default is used.
279
+
280
+ If 'should_clear_after_alloc' is set to False, then the memory
281
+ returned by 'alloc' is assumed to be already cleared (or you are
282
+ fine with garbage); otherwise CFFI will clear it.
283
+ """
284
+ compiled_ffi = self._backend.FFI()
285
+ allocator = compiled_ffi.new_allocator(alloc, free,
286
+ should_clear_after_alloc)
287
+ def allocate(cdecl, init=None):
288
+ if isinstance(cdecl, basestring):
289
+ cdecl = self._typeof(cdecl)
290
+ return allocator(cdecl, init)
291
+ return allocate
292
+
293
+ def cast(self, cdecl, source):
294
+ """Similar to a C cast: returns an instance of the named C
295
+ type initialized with the given 'source'. The source is
296
+ casted between integers or pointers of any type.
297
+ """
298
+ if isinstance(cdecl, basestring):
299
+ cdecl = self._typeof(cdecl)
300
+ return self._backend.cast(cdecl, source)
301
+
302
+ def string(self, cdata, maxlen=-1):
303
+ """Return a Python string (or unicode string) from the 'cdata'.
304
+ If 'cdata' is a pointer or array of characters or bytes, returns
305
+ the null-terminated string. The returned string extends until
306
+ the first null character, or at most 'maxlen' characters. If
307
+ 'cdata' is an array then 'maxlen' defaults to its length.
308
+
309
+ If 'cdata' is a pointer or array of wchar_t, returns a unicode
310
+ string following the same rules.
311
+
312
+ If 'cdata' is a single character or byte or a wchar_t, returns
313
+ it as a string or unicode string.
314
+
315
+ If 'cdata' is an enum, returns the value of the enumerator as a
316
+ string, or 'NUMBER' if the value is out of range.
317
+ """
318
+ return self._backend.string(cdata, maxlen)
319
+
320
+ def unpack(self, cdata, length):
321
+ """Unpack an array of C data of the given length,
322
+ returning a Python string/unicode/list.
323
+
324
+ If 'cdata' is a pointer to 'char', returns a byte string.
325
+ It does not stop at the first null. This is equivalent to:
326
+ ffi.buffer(cdata, length)[:]
327
+
328
+ If 'cdata' is a pointer to 'wchar_t', returns a unicode string.
329
+ 'length' is measured in wchar_t's; it is not the size in bytes.
330
+
331
+ If 'cdata' is a pointer to anything else, returns a list of
332
+ 'length' items. This is a faster equivalent to:
333
+ [cdata[i] for i in range(length)]
334
+ """
335
+ return self._backend.unpack(cdata, length)
336
+
337
+ #def buffer(self, cdata, size=-1):
338
+ # """Return a read-write buffer object that references the raw C data
339
+ # pointed to by the given 'cdata'. The 'cdata' must be a pointer or
340
+ # an array. Can be passed to functions expecting a buffer, or directly
341
+ # manipulated with:
342
+ #
343
+ # buf[:] get a copy of it in a regular string, or
344
+ # buf[idx] as a single character
345
+ # buf[:] = ...
346
+ # buf[idx] = ... change the content
347
+ # """
348
+ # note that 'buffer' is a type, set on this instance by __init__
349
+
350
+ def from_buffer(self, cdecl, python_buffer=_unspecified,
351
+ require_writable=False):
352
+ """Return a cdata of the given type pointing to the data of the
353
+ given Python object, which must support the buffer interface.
354
+ Note that this is not meant to be used on the built-in types
355
+ str or unicode (you can build 'char[]' arrays explicitly)
356
+ but only on objects containing large quantities of raw data
357
+ in some other format, like 'array.array' or numpy arrays.
358
+
359
+ The first argument is optional and default to 'char[]'.
360
+ """
361
+ if python_buffer is _unspecified:
362
+ cdecl, python_buffer = self.BCharA, cdecl
363
+ elif isinstance(cdecl, basestring):
364
+ cdecl = self._typeof(cdecl)
365
+ return self._backend.from_buffer(cdecl, python_buffer,
366
+ require_writable)
367
+
368
+ def memmove(self, dest, src, n):
369
+ """ffi.memmove(dest, src, n) copies n bytes of memory from src to dest.
370
+
371
+ Like the C function memmove(), the memory areas may overlap;
372
+ apart from that it behaves like the C function memcpy().
373
+
374
+ 'src' can be any cdata ptr or array, or any Python buffer object.
375
+ 'dest' can be any cdata ptr or array, or a writable Python buffer
376
+ object. The size to copy, 'n', is always measured in bytes.
377
+
378
+ Unlike other methods, this one supports all Python buffer including
379
+ byte strings and bytearrays---but it still does not support
380
+ non-contiguous buffers.
381
+ """
382
+ return self._backend.memmove(dest, src, n)
383
+
384
+ def callback(self, cdecl, python_callable=None, error=None, onerror=None):
385
+ """Return a callback object or a decorator making such a
386
+ callback object. 'cdecl' must name a C function pointer type.
387
+ The callback invokes the specified 'python_callable' (which may
388
+ be provided either directly or via a decorator). Important: the
389
+ callback object must be manually kept alive for as long as the
390
+ callback may be invoked from the C level.
391
+ """
392
+ def callback_decorator_wrap(python_callable):
393
+ if not callable(python_callable):
394
+ raise TypeError("the 'python_callable' argument "
395
+ "is not callable")
396
+ return self._backend.callback(cdecl, python_callable,
397
+ error, onerror)
398
+ if isinstance(cdecl, basestring):
399
+ cdecl = self._typeof(cdecl, consider_function_as_funcptr=True)
400
+ if python_callable is None:
401
+ return callback_decorator_wrap # decorator mode
402
+ else:
403
+ return callback_decorator_wrap(python_callable) # direct mode
404
+
405
+ def getctype(self, cdecl, replace_with=''):
406
+ """Return a string giving the C type 'cdecl', which may be itself
407
+ a string or a <ctype> object. If 'replace_with' is given, it gives
408
+ extra text to append (or insert for more complicated C types), like
409
+ a variable name, or '*' to get actually the C type 'pointer-to-cdecl'.
410
+ """
411
+ if isinstance(cdecl, basestring):
412
+ cdecl = self._typeof(cdecl)
413
+ replace_with = replace_with.strip()
414
+ if (replace_with.startswith('*')
415
+ and '&[' in self._backend.getcname(cdecl, '&')):
416
+ replace_with = '(%s)' % replace_with
417
+ elif replace_with and not replace_with[0] in '[(':
418
+ replace_with = ' ' + replace_with
419
+ return self._backend.getcname(cdecl, replace_with)
420
+
421
+ def gc(self, cdata, destructor, size=0):
422
+ """Return a new cdata object that points to the same
423
+ data. Later, when this new cdata object is garbage-collected,
424
+ 'destructor(old_cdata_object)' will be called.
425
+
426
+ The optional 'size' gives an estimate of the size, used to
427
+ trigger the garbage collection more eagerly. So far only used
428
+ on PyPy. It tells the GC that the returned object keeps alive
429
+ roughly 'size' bytes of external memory.
430
+ """
431
+ return self._backend.gcp(cdata, destructor, size)
432
+
433
+ def _get_cached_btype(self, type):
434
+ assert self._lock.acquire(False) is False
435
+ # call me with the lock!
436
+ try:
437
+ BType = self._cached_btypes[type]
438
+ except KeyError:
439
+ finishlist = []
440
+ BType = type.get_cached_btype(self, finishlist)
441
+ for type in finishlist:
442
+ type.finish_backend_type(self, finishlist)
443
+ return BType
444
+
445
+ def verify(self, source='', tmpdir=None, **kwargs):
446
+ """Verify that the current ffi signatures compile on this
447
+ machine, and return a dynamic library object. The dynamic
448
+ library can be used to call functions and access global
449
+ variables declared in this 'ffi'. The library is compiled
450
+ by the C compiler: it gives you C-level API compatibility
451
+ (including calling macros). This is unlike 'ffi.dlopen()',
452
+ which requires binary compatibility in the signatures.
453
+ """
454
+ from .verifier import Verifier, _caller_dir_pycache
455
+ #
456
+ # If set_unicode(True) was called, insert the UNICODE and
457
+ # _UNICODE macro declarations
458
+ if self._windows_unicode:
459
+ self._apply_windows_unicode(kwargs)
460
+ #
461
+ # Set the tmpdir here, and not in Verifier.__init__: it picks
462
+ # up the caller's directory, which we want to be the caller of
463
+ # ffi.verify(), as opposed to the caller of Veritier().
464
+ tmpdir = tmpdir or _caller_dir_pycache()
465
+ #
466
+ # Make a Verifier() and use it to load the library.
467
+ self.verifier = Verifier(self, source, tmpdir, **kwargs)
468
+ lib = self.verifier.load_library()
469
+ #
470
+ # Save the loaded library for keep-alive purposes, even
471
+ # if the caller doesn't keep it alive itself (it should).
472
+ self._libraries.append(lib)
473
+ return lib
474
+
475
+ def _get_errno(self):
476
+ return self._backend.get_errno()
477
+ def _set_errno(self, errno):
478
+ self._backend.set_errno(errno)
479
+ errno = property(_get_errno, _set_errno, None,
480
+ "the value of 'errno' from/to the C calls")
481
+
482
+ def getwinerror(self, code=-1):
483
+ return self._backend.getwinerror(code)
484
+
485
+ def _pointer_to(self, ctype):
486
+ with self._lock:
487
+ return model.pointer_cache(self, ctype)
488
+
489
+ def addressof(self, cdata, *fields_or_indexes):
490
+ """Return the address of a <cdata 'struct-or-union'>.
491
+ If 'fields_or_indexes' are given, returns the address of that
492
+ field or array item in the structure or array, recursively in
493
+ case of nested structures.
494
+ """
495
+ try:
496
+ ctype = self._backend.typeof(cdata)
497
+ except TypeError:
498
+ if '__addressof__' in type(cdata).__dict__:
499
+ return type(cdata).__addressof__(cdata, *fields_or_indexes)
500
+ raise
501
+ if fields_or_indexes:
502
+ ctype, offset = self._typeoffsetof(ctype, *fields_or_indexes)
503
+ else:
504
+ if ctype.kind == "pointer":
505
+ raise TypeError("addressof(pointer)")
506
+ offset = 0
507
+ ctypeptr = self._pointer_to(ctype)
508
+ return self._backend.rawaddressof(ctypeptr, cdata, offset)
509
+
510
+ def _typeoffsetof(self, ctype, field_or_index, *fields_or_indexes):
511
+ ctype, offset = self._backend.typeoffsetof(ctype, field_or_index)
512
+ for field1 in fields_or_indexes:
513
+ ctype, offset1 = self._backend.typeoffsetof(ctype, field1, 1)
514
+ offset += offset1
515
+ return ctype, offset
516
+
517
+ def include(self, ffi_to_include):
518
+ """Includes the typedefs, structs, unions and enums defined
519
+ in another FFI instance. Usage is similar to a #include in C,
520
+ where a part of the program might include types defined in
521
+ another part for its own usage. Note that the include()
522
+ method has no effect on functions, constants and global
523
+ variables, which must anyway be accessed directly from the
524
+ lib object returned by the original FFI instance.
525
+ """
526
+ if not isinstance(ffi_to_include, FFI):
527
+ raise TypeError("ffi.include() expects an argument that is also of"
528
+ " type cffi.FFI, not %r" % (
529
+ type(ffi_to_include).__name__,))
530
+ if ffi_to_include is self:
531
+ raise ValueError("self.include(self)")
532
+ with ffi_to_include._lock:
533
+ with self._lock:
534
+ self._parser.include(ffi_to_include._parser)
535
+ self._cdefsources.append('[')
536
+ self._cdefsources.extend(ffi_to_include._cdefsources)
537
+ self._cdefsources.append(']')
538
+ self._included_ffis.append(ffi_to_include)
539
+
540
+ def new_handle(self, x):
541
+ return self._backend.newp_handle(self.BVoidP, x)
542
+
543
+ def from_handle(self, x):
544
+ return self._backend.from_handle(x)
545
+
546
+ def release(self, x):
547
+ self._backend.release(x)
548
+
549
+ def set_unicode(self, enabled_flag):
550
+ """Windows: if 'enabled_flag' is True, enable the UNICODE and
551
+ _UNICODE defines in C, and declare the types like TCHAR and LPTCSTR
552
+ to be (pointers to) wchar_t. If 'enabled_flag' is False,
553
+ declare these types to be (pointers to) plain 8-bit characters.
554
+ This is mostly for backward compatibility; you usually want True.
555
+ """
556
+ if self._windows_unicode is not None:
557
+ raise ValueError("set_unicode() can only be called once")
558
+ enabled_flag = bool(enabled_flag)
559
+ if enabled_flag:
560
+ self.cdef("typedef wchar_t TBYTE;"
561
+ "typedef wchar_t TCHAR;"
562
+ "typedef const wchar_t *LPCTSTR;"
563
+ "typedef const wchar_t *PCTSTR;"
564
+ "typedef wchar_t *LPTSTR;"
565
+ "typedef wchar_t *PTSTR;"
566
+ "typedef TBYTE *PTBYTE;"
567
+ "typedef TCHAR *PTCHAR;")
568
+ else:
569
+ self.cdef("typedef char TBYTE;"
570
+ "typedef char TCHAR;"
571
+ "typedef const char *LPCTSTR;"
572
+ "typedef const char *PCTSTR;"
573
+ "typedef char *LPTSTR;"
574
+ "typedef char *PTSTR;"
575
+ "typedef TBYTE *PTBYTE;"
576
+ "typedef TCHAR *PTCHAR;")
577
+ self._windows_unicode = enabled_flag
578
+
579
+ def _apply_windows_unicode(self, kwds):
580
+ defmacros = kwds.get('define_macros', ())
581
+ if not isinstance(defmacros, (list, tuple)):
582
+ raise TypeError("'define_macros' must be a list or tuple")
583
+ defmacros = list(defmacros) + [('UNICODE', '1'),
584
+ ('_UNICODE', '1')]
585
+ kwds['define_macros'] = defmacros
586
+
587
+ def _apply_embedding_fix(self, kwds):
588
+ # must include an argument like "-lpython2.7" for the compiler
589
+ def ensure(key, value):
590
+ lst = kwds.setdefault(key, [])
591
+ if value not in lst:
592
+ lst.append(value)
593
+ #
594
+ if '__pypy__' in sys.builtin_module_names:
595
+ import os
596
+ if sys.platform == "win32":
597
+ # we need 'libpypy-c.lib'. Current distributions of
598
+ # pypy (>= 4.1) contain it as 'libs/python27.lib'.
599
+ pythonlib = "python{0[0]}{0[1]}".format(sys.version_info)
600
+ if hasattr(sys, 'prefix'):
601
+ ensure('library_dirs', os.path.join(sys.prefix, 'libs'))
602
+ else:
603
+ # we need 'libpypy-c.{so,dylib}', which should be by
604
+ # default located in 'sys.prefix/bin' for installed
605
+ # systems.
606
+ if sys.version_info < (3,):
607
+ pythonlib = "pypy-c"
608
+ else:
609
+ pythonlib = "pypy3-c"
610
+ if hasattr(sys, 'prefix'):
611
+ ensure('library_dirs', os.path.join(sys.prefix, 'bin'))
612
+ # On uninstalled pypy's, the libpypy-c is typically found in
613
+ # .../pypy/goal/.
614
+ if hasattr(sys, 'prefix'):
615
+ ensure('library_dirs', os.path.join(sys.prefix, 'pypy', 'goal'))
616
+ else:
617
+ if sys.platform == "win32":
618
+ template = "python%d%d"
619
+ if hasattr(sys, 'gettotalrefcount'):
620
+ template += '_d'
621
+ else:
622
+ try:
623
+ import sysconfig
624
+ except ImportError: # 2.6
625
+ from cffi._shimmed_dist_utils import sysconfig
626
+ template = "python%d.%d"
627
+ if sysconfig.get_config_var('DEBUG_EXT'):
628
+ template += sysconfig.get_config_var('DEBUG_EXT')
629
+ pythonlib = (template %
630
+ (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff))
631
+ if hasattr(sys, 'abiflags'):
632
+ pythonlib += sys.abiflags
633
+ ensure('libraries', pythonlib)
634
+ if sys.platform == "win32":
635
+ ensure('extra_link_args', '/MANIFEST')
636
+
637
+ def set_source(self, module_name, source, source_extension='.c', **kwds):
638
+ import os
639
+ if hasattr(self, '_assigned_source'):
640
+ raise ValueError("set_source() cannot be called several times "
641
+ "per ffi object")
642
+ if not isinstance(module_name, basestring):
643
+ raise TypeError("'module_name' must be a string")
644
+ if os.sep in module_name or (os.altsep and os.altsep in module_name):
645
+ raise ValueError("'module_name' must not contain '/': use a dotted "
646
+ "name to make a 'package.module' location")
647
+ self._assigned_source = (str(module_name), source,
648
+ source_extension, kwds)
649
+
650
+ def set_source_pkgconfig(self, module_name, pkgconfig_libs, source,
651
+ source_extension='.c', **kwds):
652
+ from . import pkgconfig
653
+ if not isinstance(pkgconfig_libs, list):
654
+ raise TypeError("the pkgconfig_libs argument must be a list "
655
+ "of package names")
656
+ kwds2 = pkgconfig.flags_from_pkgconfig(pkgconfig_libs)
657
+ pkgconfig.merge_flags(kwds, kwds2)
658
+ self.set_source(module_name, source, source_extension, **kwds)
659
+
660
+ def distutils_extension(self, tmpdir='build', verbose=True):
661
+ from cffi._shimmed_dist_utils import mkpath
662
+ from .recompiler import recompile
663
+ #
664
+ if not hasattr(self, '_assigned_source'):
665
+ if hasattr(self, 'verifier'): # fallback, 'tmpdir' ignored
666
+ return self.verifier.get_extension()
667
+ raise ValueError("set_source() must be called before"
668
+ " distutils_extension()")
669
+ module_name, source, source_extension, kwds = self._assigned_source
670
+ if source is None:
671
+ raise TypeError("distutils_extension() is only for C extension "
672
+ "modules, not for dlopen()-style pure Python "
673
+ "modules")
674
+ mkpath(tmpdir)
675
+ ext, updated = recompile(self, module_name,
676
+ source, tmpdir=tmpdir, extradir=tmpdir,
677
+ source_extension=source_extension,
678
+ call_c_compiler=False, **kwds)
679
+ if verbose:
680
+ if updated:
681
+ sys.stderr.write("regenerated: %r\n" % (ext.sources[0],))
682
+ else:
683
+ sys.stderr.write("not modified: %r\n" % (ext.sources[0],))
684
+ return ext
685
+
686
+ def emit_c_code(self, filename):
687
+ from .recompiler import recompile
688
+ #
689
+ if not hasattr(self, '_assigned_source'):
690
+ raise ValueError("set_source() must be called before emit_c_code()")
691
+ module_name, source, source_extension, kwds = self._assigned_source
692
+ if source is None:
693
+ raise TypeError("emit_c_code() is only for C extension modules, "
694
+ "not for dlopen()-style pure Python modules")
695
+ recompile(self, module_name, source,
696
+ c_file=filename, call_c_compiler=False,
697
+ uses_ffiplatform=False, **kwds)
698
+
699
+ def emit_python_code(self, filename):
700
+ from .recompiler import recompile
701
+ #
702
+ if not hasattr(self, '_assigned_source'):
703
+ raise ValueError("set_source() must be called before emit_c_code()")
704
+ module_name, source, source_extension, kwds = self._assigned_source
705
+ if source is not None:
706
+ raise TypeError("emit_python_code() is only for dlopen()-style "
707
+ "pure Python modules, not for C extension modules")
708
+ recompile(self, module_name, source,
709
+ c_file=filename, call_c_compiler=False,
710
+ uses_ffiplatform=False, **kwds)
711
+
712
+ def compile(self, tmpdir='.', verbose=0, target=None, debug=None):
713
+ """The 'target' argument gives the final file name of the
714
+ compiled DLL. Use '*' to force distutils' choice, suitable for
715
+ regular CPython C API modules. Use a file name ending in '.*'
716
+ to ask for the system's default extension for dynamic libraries
717
+ (.so/.dll/.dylib).
718
+
719
+ The default is '*' when building a non-embedded C API extension,
720
+ and (module_name + '.*') when building an embedded library.
721
+ """
722
+ from .recompiler import recompile
723
+ #
724
+ if not hasattr(self, '_assigned_source'):
725
+ raise ValueError("set_source() must be called before compile()")
726
+ module_name, source, source_extension, kwds = self._assigned_source
727
+ return recompile(self, module_name, source, tmpdir=tmpdir,
728
+ target=target, source_extension=source_extension,
729
+ compiler_verbose=verbose, debug=debug, **kwds)
730
+
731
+ def init_once(self, func, tag):
732
+ # Read _init_once_cache[tag], which is either (False, lock) if
733
+ # we're calling the function now in some thread, or (True, result).
734
+ # Don't call setdefault() in most cases, to avoid allocating and
735
+ # immediately freeing a lock; but still use setdefaut() to avoid
736
+ # races.
737
+ try:
738
+ x = self._init_once_cache[tag]
739
+ except KeyError:
740
+ x = self._init_once_cache.setdefault(tag, (False, allocate_lock()))
741
+ # Common case: we got (True, result), so we return the result.
742
+ if x[0]:
743
+ return x[1]
744
+ # Else, it's a lock. Acquire it to serialize the following tests.
745
+ with x[1]:
746
+ # Read again from _init_once_cache the current status.
747
+ x = self._init_once_cache[tag]
748
+ if x[0]:
749
+ return x[1]
750
+ # Call the function and store the result back.
751
+ result = func()
752
+ self._init_once_cache[tag] = (True, result)
753
+ return result
754
+
755
+ def embedding_init_code(self, pysource):
756
+ if self._embedding:
757
+ raise ValueError("embedding_init_code() can only be called once")
758
+ # fix 'pysource' before it gets dumped into the C file:
759
+ # - remove empty lines at the beginning, so it starts at "line 1"
760
+ # - dedent, if all non-empty lines are indented
761
+ # - check for SyntaxErrors
762
+ import re
763
+ match = re.match(r'\s*\n', pysource)
764
+ if match:
765
+ pysource = pysource[match.end():]
766
+ lines = pysource.splitlines() or ['']
767
+ prefix = re.match(r'\s*', lines[0]).group()
768
+ for i in range(1, len(lines)):
769
+ line = lines[i]
770
+ if line.rstrip():
771
+ while not line.startswith(prefix):
772
+ prefix = prefix[:-1]
773
+ i = len(prefix)
774
+ lines = [line[i:]+'\n' for line in lines]
775
+ pysource = ''.join(lines)
776
+ #
777
+ compile(pysource, "cffi_init", "exec")
778
+ #
779
+ self._embedding = pysource
780
+
781
+ def def_extern(self, *args, **kwds):
782
+ raise ValueError("ffi.def_extern() is only available on API-mode FFI "
783
+ "objects")
784
+
785
+ def list_types(self):
786
+ """Returns the user type names known to this FFI instance.
787
+ This returns a tuple containing three lists of names:
788
+ (typedef_names, names_of_structs, names_of_unions)
789
+ """
790
+ typedefs = []
791
+ structs = []
792
+ unions = []
793
+ for key in self._parser._declarations:
794
+ if key.startswith('typedef '):
795
+ typedefs.append(key[8:])
796
+ elif key.startswith('struct '):
797
+ structs.append(key[7:])
798
+ elif key.startswith('union '):
799
+ unions.append(key[6:])
800
+ typedefs.sort()
801
+ structs.sort()
802
+ unions.sort()
803
+ return (typedefs, structs, unions)
804
+
805
+
806
+ def _load_backend_lib(backend, name, flags):
807
+ import os
808
+ if not isinstance(name, basestring):
809
+ if sys.platform != "win32" or name is not None:
810
+ return backend.load_library(name, flags)
811
+ name = "c" # Windows: load_library(None) fails, but this works
812
+ # on Python 2 (backward compatibility hack only)
813
+ first_error = None
814
+ if '.' in name or '/' in name or os.sep in name:
815
+ try:
816
+ return backend.load_library(name, flags)
817
+ except OSError as e:
818
+ first_error = e
819
+ import ctypes.util
820
+ path = ctypes.util.find_library(name)
821
+ if path is None:
822
+ if name == "c" and sys.platform == "win32" and sys.version_info >= (3,):
823
+ raise OSError("dlopen(None) cannot work on Windows for Python 3 "
824
+ "(see http://bugs.python.org/issue23606)")
825
+ msg = ("ctypes.util.find_library() did not manage "
826
+ "to locate a library called %r" % (name,))
827
+ if first_error is not None:
828
+ msg = "%s. Additionally, %s" % (first_error, msg)
829
+ raise OSError(msg)
830
+ return backend.load_library(path, flags)
831
+
832
+ def _make_ffi_library(ffi, libname, flags):
833
+ backend = ffi._backend
834
+ backendlib = _load_backend_lib(backend, libname, flags)
835
+ #
836
+ def accessor_function(name):
837
+ key = 'function ' + name
838
+ tp, _ = ffi._parser._declarations[key]
839
+ BType = ffi._get_cached_btype(tp)
840
+ value = backendlib.load_function(BType, name)
841
+ library.__dict__[name] = value
842
+ #
843
+ def accessor_variable(name):
844
+ key = 'variable ' + name
845
+ tp, _ = ffi._parser._declarations[key]
846
+ BType = ffi._get_cached_btype(tp)
847
+ read_variable = backendlib.read_variable
848
+ write_variable = backendlib.write_variable
849
+ setattr(FFILibrary, name, property(
850
+ lambda self: read_variable(BType, name),
851
+ lambda self, value: write_variable(BType, name, value)))
852
+ #
853
+ def addressof_var(name):
854
+ try:
855
+ return addr_variables[name]
856
+ except KeyError:
857
+ with ffi._lock:
858
+ if name not in addr_variables:
859
+ key = 'variable ' + name
860
+ tp, _ = ffi._parser._declarations[key]
861
+ BType = ffi._get_cached_btype(tp)
862
+ if BType.kind != 'array':
863
+ BType = model.pointer_cache(ffi, BType)
864
+ p = backendlib.load_function(BType, name)
865
+ addr_variables[name] = p
866
+ return addr_variables[name]
867
+ #
868
+ def accessor_constant(name):
869
+ raise NotImplementedError("non-integer constant '%s' cannot be "
870
+ "accessed from a dlopen() library" % (name,))
871
+ #
872
+ def accessor_int_constant(name):
873
+ library.__dict__[name] = ffi._parser._int_constants[name]
874
+ #
875
+ accessors = {}
876
+ accessors_version = [False]
877
+ addr_variables = {}
878
+ #
879
+ def update_accessors():
880
+ if accessors_version[0] is ffi._cdef_version:
881
+ return
882
+ #
883
+ for key, (tp, _) in ffi._parser._declarations.items():
884
+ if not isinstance(tp, model.EnumType):
885
+ tag, name = key.split(' ', 1)
886
+ if tag == 'function':
887
+ accessors[name] = accessor_function
888
+ elif tag == 'variable':
889
+ accessors[name] = accessor_variable
890
+ elif tag == 'constant':
891
+ accessors[name] = accessor_constant
892
+ else:
893
+ for i, enumname in enumerate(tp.enumerators):
894
+ def accessor_enum(name, tp=tp, i=i):
895
+ tp.check_not_partial()
896
+ library.__dict__[name] = tp.enumvalues[i]
897
+ accessors[enumname] = accessor_enum
898
+ for name in ffi._parser._int_constants:
899
+ accessors.setdefault(name, accessor_int_constant)
900
+ accessors_version[0] = ffi._cdef_version
901
+ #
902
+ def make_accessor(name):
903
+ with ffi._lock:
904
+ if name in library.__dict__ or name in FFILibrary.__dict__:
905
+ return # added by another thread while waiting for the lock
906
+ if name not in accessors:
907
+ update_accessors()
908
+ if name not in accessors:
909
+ raise AttributeError(name)
910
+ accessors[name](name)
911
+ #
912
+ class FFILibrary(object):
913
+ def __getattr__(self, name):
914
+ make_accessor(name)
915
+ return getattr(self, name)
916
+ def __setattr__(self, name, value):
917
+ try:
918
+ property = getattr(self.__class__, name)
919
+ except AttributeError:
920
+ make_accessor(name)
921
+ setattr(self, name, value)
922
+ else:
923
+ property.__set__(self, value)
924
+ def __dir__(self):
925
+ with ffi._lock:
926
+ update_accessors()
927
+ return accessors.keys()
928
+ def __addressof__(self, name):
929
+ if name in library.__dict__:
930
+ return library.__dict__[name]
931
+ if name in FFILibrary.__dict__:
932
+ return addressof_var(name)
933
+ make_accessor(name)
934
+ if name in library.__dict__:
935
+ return library.__dict__[name]
936
+ if name in FFILibrary.__dict__:
937
+ return addressof_var(name)
938
+ raise AttributeError("cffi library has no function or "
939
+ "global variable named '%s'" % (name,))
940
+ def __cffi_close__(self):
941
+ backendlib.close_lib()
942
+ self.__dict__.clear()
943
+ #
944
+ if isinstance(libname, basestring):
945
+ try:
946
+ if not isinstance(libname, str): # unicode, on Python 2
947
+ libname = libname.encode('utf-8')
948
+ FFILibrary.__name__ = 'FFILibrary_%s' % libname
949
+ except UnicodeError:
950
+ pass
951
+ library = FFILibrary()
952
+ return library, library.__dict__
953
+
954
+ def _builtin_function_type(func):
955
+ # a hack to make at least ffi.typeof(builtin_function) work,
956
+ # if the builtin function was obtained by 'vengine_cpy'.
957
+ import sys
958
+ try:
959
+ module = sys.modules[func.__module__]
960
+ ffi = module._cffi_original_ffi
961
+ types_of_builtin_funcs = module._cffi_types_of_builtin_funcs
962
+ tp = types_of_builtin_funcs[func]
963
+ except (KeyError, AttributeError, TypeError):
964
+ return None
965
+ else:
966
+ with ffi._lock:
967
+ return ffi._get_cached_btype(tp)