codekingpro/portable-devtools
115k
1import sys, types2from .lock import allocate_lock3from .error import CDefError4from . import model5 6try:7 callable8except NameError:9 # Python 3.110 from collections import Callable11 callable = lambda x: isinstance(x, Callable)12 13try:14 basestring15except NameError:16 # Python 3.x17 basestring = str18 19_unspecified = object()20 21 22 23class 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 library35 -or-36 C = ffi.verify() # use a C compiler: verify the decl above is right37 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 to43 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) with47 # _cffi_backend.so compiled.48 import _cffi_backend as backend49 from . import __version__50 if backend.__version__ != __version__:51 # bad version! Try to be as explicit as possible.52 if hasattr(backend, '__file__'):53 # CPython54 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 # PyPy59 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 option62 # 'backend=backend_ctypes.CTypesBackend()', but don't63 # rely on it! It's probably not going to work well.)64 65 from . import cparser66 self._backend = backend67 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 = None77 self._init_once_cache = {}78 self._cdef_version = None79 self._embedding = None80 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 class92 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 instance97 self.NULL = self.cast(self.BVoidP, 0)98 self.CData, self.CType = backend._get_types()99 self.buffer = backend.buffer100 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 can104 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 this107 cdef are packed, i.e. laid out without any field alignment at all.108 Alternatively, 'pack' can be a small integer, and requests for109 alignment greater than that are ignored (pack=1 is equivalent to110 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 2121 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._recomplete132 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 not141 linked to a particular library, just like C headers; in the142 library we only look for the actual (untyped) symbols.143 """144 if not (isinstance(name, basestring) or145 name is None or146 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 lib154 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 fail158 (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 = cdecl165 if key in self._parsed_types:166 return self._parsed_types[key]167 #168 if not isinstance(cdecl, str): # unicode, on Python 2169 cdecl = cdecl.encode('ascii')170 #171 type = self._parser.parse_type(cdecl)172 really_a_function_type = type.is_raw_function173 if really_a_function_type:174 type = type.as_function_pointer()175 btype = self._get_cached_btype(type)176 result = btype, really_a_function_type177 self._parsed_types[key] = result178 return result179 180 def _typeof(self, cdecl, consider_function_as_funcptr=False):181 # string -> ctype object182 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 = result189 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 btype193 194 def typeof(self, cdecl):195 """Parse the C type given as a string and return the196 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 res207 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 a215 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 type225 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 given233 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 array236 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 and244 return a pointer to it. The specified C type must be either a245 pointer or an array: ``new('X *')`` allocates an X and returns246 a pointer to it, whereas ``new('X[n]')`` allocates an array of247 n X'es and returns an array referencing it (which works248 mostly like a pointer, like in C). You can also use249 ``new('X[]', n)`` to allocate an array of a non-constant250 length n.251 252 The memory is initialized following the rules of declaring a253 global variable in C: by default it is zero-initialized, but254 an explicit initializer can be given which can be used to255 fill all or part of the memory.256 257 When the returned <cdata> object goes out of scope, the memory258 is freed. In other words the returned <cdata> object has259 ownership of the value of type 'cdecl' that it points to. This260 means that the raw data can be used as long as this object is261 kept alive, but must not be used for a longer time. Be careful262 about that when copying the pointer to the memory somewhere263 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, a275 MemoryError is raised. 'free' is called with the result of 'alloc'276 as argument. Both can be either Python function or directly C277 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 memory281 returned by 'alloc' is assumed to be already cleared (or you are282 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 allocate292 293 def cast(self, cdecl, source):294 """Similar to a C cast: returns an instance of the named C295 type initialized with the given 'source'. The source is296 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, returns305 the null-terminated string. The returned string extends until306 the first null character, or at most 'maxlen' characters. If307 'cdata' is an array then 'maxlen' defaults to its length.308 309 If 'cdata' is a pointer or array of wchar_t, returns a unicode310 string following the same rules.311 312 If 'cdata' is a single character or byte or a wchar_t, returns313 it as a string or unicode string.314 315 If 'cdata' is an enum, returns the value of the enumerator as a316 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 of332 '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 data339 # pointed to by the given 'cdata'. The 'cdata' must be a pointer or340 # an array. Can be passed to functions expecting a buffer, or directly341 # manipulated with:342 #343 # buf[:] get a copy of it in a regular string, or344 # buf[idx] as a single character345 # buf[:] = ...346 # buf[idx] = ... change the content347 # """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 the353 given Python object, which must support the buffer interface.354 Note that this is not meant to be used on the built-in types355 str or unicode (you can build 'char[]' arrays explicitly)356 but only on objects containing large quantities of raw data357 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, cdecl363 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 buffer376 object. The size to copy, 'n', is always measured in bytes.377 378 Unlike other methods, this one supports all Python buffer including379 byte strings and bytearrays---but it still does not support380 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 a386 callback object. 'cdecl' must name a C function pointer type.387 The callback invokes the specified 'python_callable' (which may388 be provided either directly or via a decorator). Important: the389 callback object must be manually kept alive for as long as the390 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 mode402 else:403 return callback_decorator_wrap(python_callable) # direct mode404 405 def getctype(self, cdecl, replace_with=''):406 """Return a string giving the C type 'cdecl', which may be itself407 a string or a <ctype> object. If 'replace_with' is given, it gives408 extra text to append (or insert for more complicated C types), like409 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_with417 elif replace_with and not replace_with[0] in '[(':418 replace_with = ' ' + replace_with419 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 same423 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 to427 trigger the garbage collection more eagerly. So far only used428 on PyPy. It tells the GC that the returned object keeps alive429 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 False435 # 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 BType444 445 def verify(self, source='', tmpdir=None, **kwargs):446 """Verify that the current ffi signatures compile on this447 machine, and return a dynamic library object. The dynamic448 library can be used to call functions and access global449 variables declared in this 'ffi'. The library is compiled450 by the C compiler: it gives you C-level API compatibility451 (including calling macros). This is unlike 'ffi.dlopen()',452 which requires binary compatibility in the signatures.453 """454 from .verifier import Verifier, _caller_dir_pycache455 #456 # If set_unicode(True) was called, insert the UNICODE and457 # _UNICODE macro declarations458 if self._windows_unicode:459 self._apply_windows_unicode(kwargs)460 #461 # Set the tmpdir here, and not in Verifier.__init__: it picks462 # up the caller's directory, which we want to be the caller of463 # 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, even471 # if the caller doesn't keep it alive itself (it should).472 self._libraries.append(lib)473 return lib474 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 that492 field or array item in the structure or array, recursively in493 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 raise501 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 = 0507 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 += offset1515 return ctype, offset516 517 def include(self, ffi_to_include):518 """Includes the typedefs, structs, unions and enums defined519 in another FFI instance. Usage is similar to a #include in C,520 where a part of the program might include types defined in521 another part for its own usage. Note that the include()522 method has no effect on functions, constants and global523 variables, which must anyway be accessed directly from the524 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 and551 _UNICODE defines in C, and declare the types like TCHAR and LPTCSTR552 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_flag578 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'] = defmacros586 587 def _apply_embedding_fix(self, kwds):588 # must include an argument like "-lpython2.7" for the compiler589 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 os596 if sys.platform == "win32":597 # we need 'libpypy-c.lib'. Current distributions of598 # 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 by604 # default located in 'sys.prefix/bin' for installed605 # 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 in613 # .../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 sysconfig624 except ImportError: # 2.6625 from cffi._shimmed_dist_utils import sysconfig626 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.abiflags633 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 os639 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 pkgconfig653 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 mkpath662 from .recompiler import recompile663 #664 if not hasattr(self, '_assigned_source'):665 if hasattr(self, 'verifier'): # fallback, 'tmpdir' ignored666 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_source670 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 ext685 686 def emit_c_code(self, filename):687 from .recompiler import recompile688 #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_source692 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 recompile701 #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_source705 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 the714 compiled DLL. Use '*' to force distutils' choice, suitable for715 regular CPython C API modules. Use a file name ending in '.*'716 to ask for the system's default extension for dynamic libraries717 (.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 recompile723 #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_source727 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) if733 # we're calling the function now in some thread, or (True, result).734 # Don't call setdefault() in most cases, to avoid allocating and735 # immediately freeing a lock; but still use setdefaut() to avoid736 # 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 result754 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 indented761 # - check for SyntaxErrors762 import re763 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 = pysource780 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 806def _load_backend_lib(backend, name, flags):807 import os808 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 works812 # on Python 2 (backward compatibility hack only)813 first_error = None814 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 = e819 import ctypes.util820 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 832def _make_ffi_library(ffi, libname, flags):833 backend = ffi._backend834 backendlib = _load_backend_lib(backend, libname, flags)835 #836 def accessor_function(name):837 key = 'function ' + name838 tp, _ = ffi._parser._declarations[key]839 BType = ffi._get_cached_btype(tp)840 value = backendlib.load_function(BType, name)841 library.__dict__[name] = value842 #843 def accessor_variable(name):844 key = 'variable ' + name845 tp, _ = ffi._parser._declarations[key]846 BType = ffi._get_cached_btype(tp)847 read_variable = backendlib.read_variable848 write_variable = backendlib.write_variable849 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 ' + name860 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] = p866 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 return882 #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_function888 elif tag == 'variable':889 accessors[name] = accessor_variable890 elif tag == 'constant':891 accessors[name] = accessor_constant892 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_enum898 for name in ffi._parser._int_constants:899 accessors.setdefault(name, accessor_int_constant)900 accessors_version[0] = ffi._cdef_version901 #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 lock906 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 2947 libname = libname.encode('utf-8')948 FFILibrary.__name__ = 'FFILibrary_%s' % libname949 except UnicodeError:950 pass951 library = FFILibrary()952 return library, library.__dict__953 954def _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 sys958 try:959 module = sys.modules[func.__module__]960 ffi = module._cffi_original_ffi961 types_of_builtin_funcs = module._cffi_types_of_builtin_funcs962 tp = types_of_builtin_funcs[func]963 except (KeyError, AttributeError, TypeError):964 return None965 else:966 with ffi._lock:967 return ffi._get_cached_btype(tp)968 