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