• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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