1# This file is dual licensed under the terms of the Apache License, Version 2# 2.0, and the BSD License. See the LICENSE file in the root of this repository 3# for complete details. 4 5from __future__ import absolute_import, division, print_function 6 7import sys 8from distutils.ccompiler import new_compiler 9from distutils.dist import Distribution 10 11from cffi import FFI 12 13 14def build_ffi_for_binding(module_name, module_prefix, modules, libraries=[], 15 extra_compile_args=[], extra_link_args=[]): 16 """ 17 Modules listed in ``modules`` should have the following attributes: 18 19 * ``INCLUDES``: A string containing C includes. 20 * ``TYPES``: A string containing C declarations for types. 21 * ``FUNCTIONS``: A string containing C declarations for functions & macros. 22 * ``CUSTOMIZATIONS``: A string containing arbitrary top-level C code, this 23 can be used to do things like test for a define and provide an 24 alternate implementation based on that. 25 """ 26 types = [] 27 includes = [] 28 functions = [] 29 customizations = [] 30 for name in modules: 31 __import__(module_prefix + name) 32 module = sys.modules[module_prefix + name] 33 34 types.append(module.TYPES) 35 functions.append(module.FUNCTIONS) 36 includes.append(module.INCLUDES) 37 customizations.append(module.CUSTOMIZATIONS) 38 39 verify_source = "\n".join( 40 includes + 41 customizations 42 ) 43 ffi = build_ffi( 44 module_name, 45 cdef_source="\n".join(types + functions), 46 verify_source=verify_source, 47 libraries=libraries, 48 extra_compile_args=extra_compile_args, 49 extra_link_args=extra_link_args, 50 ) 51 52 return ffi 53 54 55def build_ffi(module_name, cdef_source, verify_source, libraries=[], 56 extra_compile_args=[], extra_link_args=[]): 57 ffi = FFI() 58 ffi.cdef(cdef_source) 59 ffi.set_source( 60 module_name, 61 verify_source, 62 libraries=libraries, 63 extra_compile_args=extra_compile_args, 64 extra_link_args=extra_link_args, 65 ) 66 return ffi 67 68 69def extra_link_args(compiler_type): 70 if compiler_type == 'msvc': 71 # Enable NX and ASLR for Windows builds on MSVC. These are enabled by 72 # default on Python 3.3+ but not on 2.x. 73 return ['/NXCOMPAT', '/DYNAMICBASE'] 74 else: 75 return [] 76 77 78def compiler_type(): 79 """ 80 Gets the compiler type from distutils. On Windows with MSVC it will be 81 "msvc". On macOS and linux it is "unix". 82 """ 83 dist = Distribution() 84 dist.parse_config_files() 85 cmd = dist.get_command_obj('build') 86 cmd.ensure_finalized() 87 compiler = new_compiler(compiler=cmd.compiler) 88 return compiler.compiler_type 89