ffiplatform.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import sys, os
  2. from .error import VerificationError
  3. LIST_OF_FILE_NAMES = ['sources', 'include_dirs', 'library_dirs',
  4. 'extra_objects', 'depends']
  5. def get_extension(srcfilename, modname, sources=(), **kwds):
  6. from cffi._shimmed_dist_utils import Extension
  7. allsources = [srcfilename]
  8. for src in sources:
  9. allsources.append(os.path.normpath(src))
  10. return Extension(name=modname, sources=allsources, **kwds)
  11. def compile(tmpdir, ext, compiler_verbose=0, debug=None):
  12. """Compile a C extension module using distutils."""
  13. saved_environ = os.environ.copy()
  14. try:
  15. outputfilename = _build(tmpdir, ext, compiler_verbose, debug)
  16. outputfilename = os.path.abspath(outputfilename)
  17. finally:
  18. # workaround for a distutils bugs where some env vars can
  19. # become longer and longer every time it is used
  20. for key, value in saved_environ.items():
  21. if os.environ.get(key) != value:
  22. os.environ[key] = value
  23. return outputfilename
  24. def _build(tmpdir, ext, compiler_verbose=0, debug=None):
  25. # XXX compact but horrible :-(
  26. from cffi._shimmed_dist_utils import Distribution, CompileError, LinkError, set_threshold, set_verbosity
  27. dist = Distribution({'ext_modules': [ext]})
  28. dist.parse_config_files()
  29. options = dist.get_option_dict('build_ext')
  30. if debug is None:
  31. debug = sys.flags.debug
  32. options['debug'] = ('ffiplatform', debug)
  33. options['force'] = ('ffiplatform', True)
  34. options['build_lib'] = ('ffiplatform', tmpdir)
  35. options['build_temp'] = ('ffiplatform', tmpdir)
  36. #
  37. try:
  38. old_level = set_threshold(0) or 0
  39. try:
  40. set_verbosity(compiler_verbose)
  41. dist.run_command('build_ext')
  42. cmd_obj = dist.get_command_obj('build_ext')
  43. [soname] = cmd_obj.get_outputs()
  44. finally:
  45. set_threshold(old_level)
  46. except (CompileError, LinkError) as e:
  47. raise VerificationError('%s: %s' % (e.__class__.__name__, e))
  48. #
  49. return soname
  50. try:
  51. from os.path import samefile
  52. except ImportError:
  53. def samefile(f1, f2):
  54. return os.path.abspath(f1) == os.path.abspath(f2)
  55. def maybe_relative_path(path):
  56. if not os.path.isabs(path):
  57. return path # already relative
  58. dir = path
  59. names = []
  60. while True:
  61. prevdir = dir
  62. dir, name = os.path.split(prevdir)
  63. if dir == prevdir or not dir:
  64. return path # failed to make it relative
  65. names.append(name)
  66. try:
  67. if samefile(dir, os.curdir):
  68. names.reverse()
  69. return os.path.join(*names)
  70. except OSError:
  71. pass
  72. # ____________________________________________________________
  73. try:
  74. int_or_long = (int, long)
  75. import cStringIO
  76. except NameError:
  77. int_or_long = int # Python 3
  78. import io as cStringIO
  79. def _flatten(x, f):
  80. if isinstance(x, str):
  81. f.write('%ds%s' % (len(x), x))
  82. elif isinstance(x, dict):
  83. keys = sorted(x.keys())
  84. f.write('%dd' % len(keys))
  85. for key in keys:
  86. _flatten(key, f)
  87. _flatten(x[key], f)
  88. elif isinstance(x, (list, tuple)):
  89. f.write('%dl' % len(x))
  90. for value in x:
  91. _flatten(value, f)
  92. elif isinstance(x, int_or_long):
  93. f.write('%di' % (x,))
  94. else:
  95. raise TypeError(
  96. "the keywords to verify() contains unsupported object %r" % (x,))
  97. def flatten(x):
  98. f = cStringIO.StringIO()
  99. _flatten(x, f)
  100. return f.getvalue()