utils.py 3.2 KB

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