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