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 os 8import sys 9from distutils.ccompiler import new_compiler 10from distutils.dist import Distribution 11 12from cffi import FFI 13 14 15# Load the cryptography __about__ to get the current package version 16base_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17about = {} 18with open(os.path.join(base_src, "cryptography", "__about__.py")) as f: 19 exec (f.read(), about) 20 21 22def build_ffi_for_binding( 23 module_name, 24 module_prefix, 25 modules, 26 libraries=[], 27 extra_compile_args=[], 28 extra_link_args=[], 29): 30 """ 31 Modules listed in ``modules`` should have the following attributes: 32 33 * ``INCLUDES``: A string containing C includes. 34 * ``TYPES``: A string containing C declarations for types. 35 * ``FUNCTIONS``: A string containing C declarations for functions & macros. 36 * ``CUSTOMIZATIONS``: A string containing arbitrary top-level C code, this 37 can be used to do things like test for a define and provide an 38 alternate implementation based on that. 39 """ 40 types = [] 41 includes = [] 42 functions = [] 43 customizations = [] 44 for name in modules: 45 __import__(module_prefix + name) 46 module = sys.modules[module_prefix + name] 47 48 types.append(module.TYPES) 49 functions.append(module.FUNCTIONS) 50 includes.append(module.INCLUDES) 51 customizations.append(module.CUSTOMIZATIONS) 52 53 verify_source = "\n".join(includes + customizations) 54 ffi = build_ffi( 55 module_name, 56 cdef_source="\n".join(types + functions), 57 verify_source=verify_source, 58 libraries=libraries, 59 extra_compile_args=extra_compile_args, 60 extra_link_args=extra_link_args, 61 ) 62 63 return ffi 64 65 66def build_ffi( 67 module_name, 68 cdef_source, 69 verify_source, 70 libraries=[], 71 extra_compile_args=[], 72 extra_link_args=[], 73): 74 ffi = FFI() 75 # Always add the CRYPTOGRAPHY_PACKAGE_VERSION to the shared object 76 cdef_source += "\nstatic const char *const CRYPTOGRAPHY_PACKAGE_VERSION;" 77 verify_source += '\n#define CRYPTOGRAPHY_PACKAGE_VERSION "{}"'.format( 78 about["__version__"] 79 ) 80 ffi.cdef(cdef_source) 81 ffi.set_source( 82 module_name, 83 verify_source, 84 libraries=libraries, 85 extra_compile_args=extra_compile_args, 86 extra_link_args=extra_link_args, 87 ) 88 return ffi 89 90 91def extra_link_args(compiler_type): 92 if compiler_type == "msvc": 93 # Enable NX and ASLR for Windows builds on MSVC. These are enabled by 94 # default on Python 3.3+ but not on 2.x. 95 return ["/NXCOMPAT", "/DYNAMICBASE"] 96 else: 97 return [] 98 99 100def compiler_type(): 101 """ 102 Gets the compiler type from distutils. On Windows with MSVC it will be 103 "msvc". On macOS and linux it is "unix". 104 """ 105 dist = Distribution() 106 dist.parse_config_files() 107 cmd = dist.get_command_obj("build") 108 cmd.ensure_finalized() 109 compiler = new_compiler(compiler=cmd.compiler) 110 return compiler.compiler_type 111