| # 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 annotations | |
| import os | |
| import platform | |
| import sys | |
| from cffi import FFI | |
| # Load the cryptography __about__ to get the current package version | |
| base_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | |
| about: dict = {} | |
| with open(os.path.join(base_src, "cryptography", "__about__.py")) as f: | |
| exec(f.read(), about) | |
| def build_ffi_for_binding( | |
| module_name: str, | |
| module_prefix: str, | |
| modules: list[str], | |
| ): | |
| """ | |
| 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. | |
| * ``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 = [] | |
| customizations = [] | |
| for name in modules: | |
| __import__(module_prefix + name) | |
| module = sys.modules[module_prefix + name] | |
| types.append(module.TYPES) | |
| functions.append(module.FUNCTIONS) | |
| includes.append(module.INCLUDES) | |
| customizations.append(module.CUSTOMIZATIONS) | |
| verify_source = "\n".join(includes + customizations) | |
| return build_ffi( | |
| module_name, | |
| cdef_source="\n".join(types + functions), | |
| verify_source=verify_source, | |
| ) | |
| def build_ffi( | |
| module_name: str, | |
| cdef_source: str, | |
| verify_source: str, | |
| ): | |
| ffi = FFI() | |
| # Always add the CRYPTOGRAPHY_PACKAGE_VERSION to the shared object | |
| cdef_source += "\nstatic const char *const CRYPTOGRAPHY_PACKAGE_VERSION;" | |
| verify_source += '\n#define CRYPTOGRAPHY_PACKAGE_VERSION "{}"'.format( | |
| about["__version__"] | |
| ) | |
| if platform.python_implementation() == "PyPy": | |
| verify_source += r""" | |
| int Cryptography_make_openssl_module(void) { | |
| int result; | |
| Py_BEGIN_ALLOW_THREADS | |
| result = cffi_start_python(); | |
| Py_END_ALLOW_THREADS | |
| return result; | |
| } | |
| """ | |
| ffi.cdef(cdef_source) | |
| ffi.set_source( | |
| module_name, | |
| verify_source, | |
| ) | |
| return ffi |