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