# This file is dual licensed under the terms of the Apache License, Version # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. from __future__ import absolute_import, division, print_function import sys from distutils.ccompiler import new_compiler from distutils.dist import Distribution from cffi import FFI def build_ffi_for_binding(module_name, module_prefix, modules, pre_include="", post_include="", libraries=[], extra_compile_args=[], extra_link_args=[]): """ Modules listed in ``modules`` should have the following attributes: * ``INCLUDES``: A string containing C includes. * ``TYPES``: A string containing C declarations for types. * ``FUNCTIONS``: A string containing C declarations for functions. * ``MACROS``: A string containing C declarations for any macros. * ``CUSTOMIZATIONS``: A string containing arbitrary top-level C code, this can be used to do things like test for a define and provide an alternate implementation based on that. """ types = [] includes = [] functions = [] macros = [] customizations = [] for name in modules: __import__(module_prefix + name) module = sys.modules[module_prefix + name] types.append(module.TYPES) macros.append(module.MACROS) functions.append(module.FUNCTIONS) includes.append(module.INCLUDES) customizations.append(module.CUSTOMIZATIONS) # We include functions here so that if we got any of their definitions # wrong, the underlying C compiler will explode. In C you are allowed # to re-declare a function if it has the same signature. That is: # int foo(int); # int foo(int); # is legal, but the following will fail to compile: # int foo(int); # int foo(short); verify_source = "\n".join( [pre_include] + includes + [post_include] + functions + customizations ) ffi = build_ffi( module_name, cdef_source="\n".join(types + functions + macros), verify_source=verify_source, libraries=libraries, extra_compile_args=extra_compile_args, extra_link_args=extra_link_args, ) return ffi def build_ffi(module_name, cdef_source, verify_source, libraries=[], extra_compile_args=[], extra_link_args=[]): ffi = FFI() ffi.cdef(cdef_source) ffi.set_source( module_name, verify_source, libraries=libraries, extra_compile_args=extra_compile_args, extra_link_args=extra_link_args, ) return ffi def extra_link_args(compiler_type): if compiler_type == 'msvc': # Enable NX and ASLR for Windows builds on MSVC. These are enabled by # default on Python 3.3+ but not on 2.x. return ['/NXCOMPAT', '/DYNAMICBASE'] else: return [] def compiler_type(): """ Gets the compiler type from distutils. On Windows with MSVC it will be "msvc". On OS X and linux it is "unix". """ dist = Distribution() dist.parse_config_files() cmd = dist.get_command_obj('build') cmd.ensure_finalized() compiler = new_compiler(compiler=cmd.compiler) return compiler.compiler_type 'n3' href='#n3'>3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63