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