• 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 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