/Lib/distutils/tests/setuptools_build_ext.py

http://unladen-swallow.googlecode.com/ · Python · 287 lines · 244 code · 30 blank · 13 comment · 52 complexity · ea68e74f93a2464d54dac3bca14802cb MD5 · raw file

  1. from distutils.command.build_ext import build_ext as _du_build_ext
  2. try:
  3. # Attempt to use Pyrex for building extensions, if available
  4. from Pyrex.Distutils.build_ext import build_ext as _build_ext
  5. except ImportError:
  6. _build_ext = _du_build_ext
  7. import os, sys
  8. from distutils.file_util import copy_file
  9. from distutils.tests.setuptools_extension import Library
  10. from distutils.ccompiler import new_compiler
  11. from distutils.sysconfig import customize_compiler, get_config_var
  12. get_config_var("LDSHARED") # make sure _config_vars is initialized
  13. from distutils.sysconfig import _config_vars
  14. from distutils import log
  15. from distutils.errors import *
  16. have_rtld = False
  17. use_stubs = False
  18. libtype = 'shared'
  19. if sys.platform == "darwin":
  20. use_stubs = True
  21. elif os.name != 'nt':
  22. try:
  23. from dl import RTLD_NOW
  24. have_rtld = True
  25. use_stubs = True
  26. except ImportError:
  27. pass
  28. def if_dl(s):
  29. if have_rtld:
  30. return s
  31. return ''
  32. class build_ext(_build_ext):
  33. def run(self):
  34. """Build extensions in build directory, then copy if --inplace"""
  35. old_inplace, self.inplace = self.inplace, 0
  36. _build_ext.run(self)
  37. self.inplace = old_inplace
  38. if old_inplace:
  39. self.copy_extensions_to_source()
  40. def copy_extensions_to_source(self):
  41. build_py = self.get_finalized_command('build_py')
  42. for ext in self.extensions:
  43. fullname = self.get_ext_fullname(ext.name)
  44. filename = self.get_ext_filename(fullname)
  45. modpath = fullname.split('.')
  46. package = '.'.join(modpath[:-1])
  47. package_dir = build_py.get_package_dir(package)
  48. dest_filename = os.path.join(package_dir,os.path.basename(filename))
  49. src_filename = os.path.join(self.build_lib,filename)
  50. # Always copy, even if source is older than destination, to ensure
  51. # that the right extensions for the current Python/platform are
  52. # used.
  53. copy_file(
  54. src_filename, dest_filename, verbose=self.verbose,
  55. dry_run=self.dry_run
  56. )
  57. if ext._needs_stub:
  58. self.write_stub(package_dir or os.curdir, ext, True)
  59. if _build_ext is not _du_build_ext and not hasattr(_build_ext,'pyrex_sources'):
  60. # Workaround for problems using some Pyrex versions w/SWIG and/or 2.4
  61. def swig_sources(self, sources, *otherargs):
  62. # first do any Pyrex processing
  63. sources = _build_ext.swig_sources(self, sources) or sources
  64. # Then do any actual SWIG stuff on the remainder
  65. return _du_build_ext.swig_sources(self, sources, *otherargs)
  66. def get_ext_filename(self, fullname):
  67. filename = _build_ext.get_ext_filename(self,fullname)
  68. ext = self.ext_map[fullname]
  69. if isinstance(ext,Library):
  70. fn, ext = os.path.splitext(filename)
  71. return self.shlib_compiler.library_filename(fn,libtype)
  72. elif use_stubs and ext._links_to_dynamic:
  73. d,fn = os.path.split(filename)
  74. return os.path.join(d,'dl-'+fn)
  75. else:
  76. return filename
  77. def initialize_options(self):
  78. _build_ext.initialize_options(self)
  79. self.shlib_compiler = None
  80. self.shlibs = []
  81. self.ext_map = {}
  82. def finalize_options(self):
  83. _build_ext.finalize_options(self)
  84. self.extensions = self.extensions or []
  85. self.check_extensions_list(self.extensions)
  86. self.shlibs = [ext for ext in self.extensions
  87. if isinstance(ext,Library)]
  88. if self.shlibs:
  89. self.setup_shlib_compiler()
  90. for ext in self.extensions:
  91. ext._full_name = self.get_ext_fullname(ext.name)
  92. for ext in self.extensions:
  93. fullname = ext._full_name
  94. self.ext_map[fullname] = ext
  95. ltd = ext._links_to_dynamic = \
  96. self.shlibs and self.links_to_dynamic(ext) or False
  97. ext._needs_stub = ltd and use_stubs and not isinstance(ext,Library)
  98. filename = ext._file_name = self.get_ext_filename(fullname)
  99. libdir = os.path.dirname(os.path.join(self.build_lib,filename))
  100. if ltd and libdir not in ext.library_dirs:
  101. ext.library_dirs.append(libdir)
  102. if ltd and use_stubs and os.curdir not in ext.runtime_library_dirs:
  103. ext.runtime_library_dirs.append(os.curdir)
  104. def setup_shlib_compiler(self):
  105. compiler = self.shlib_compiler = new_compiler(
  106. compiler=self.compiler, dry_run=self.dry_run, force=self.force
  107. )
  108. if sys.platform == "darwin":
  109. tmp = _config_vars.copy()
  110. try:
  111. # XXX Help! I don't have any idea whether these are right...
  112. _config_vars['LDSHARED'] = "gcc -Wl,-x -dynamiclib -undefined dynamic_lookup"
  113. _config_vars['CCSHARED'] = " -dynamiclib"
  114. _config_vars['SO'] = ".dylib"
  115. customize_compiler(compiler)
  116. finally:
  117. _config_vars.clear()
  118. _config_vars.update(tmp)
  119. else:
  120. customize_compiler(compiler)
  121. if self.include_dirs is not None:
  122. compiler.set_include_dirs(self.include_dirs)
  123. if self.define is not None:
  124. # 'define' option is a list of (name,value) tuples
  125. for (name,value) in self.define:
  126. compiler.define_macro(name, value)
  127. if self.undef is not None:
  128. for macro in self.undef:
  129. compiler.undefine_macro(macro)
  130. if self.libraries is not None:
  131. compiler.set_libraries(self.libraries)
  132. if self.library_dirs is not None:
  133. compiler.set_library_dirs(self.library_dirs)
  134. if self.rpath is not None:
  135. compiler.set_runtime_library_dirs(self.rpath)
  136. if self.link_objects is not None:
  137. compiler.set_link_objects(self.link_objects)
  138. # hack so distutils' build_extension() builds a library instead
  139. compiler.link_shared_object = link_shared_object.__get__(compiler)
  140. def get_export_symbols(self, ext):
  141. if isinstance(ext,Library):
  142. return ext.export_symbols
  143. return _build_ext.get_export_symbols(self,ext)
  144. def build_extension(self, ext):
  145. _compiler = self.compiler
  146. try:
  147. if isinstance(ext,Library):
  148. self.compiler = self.shlib_compiler
  149. _build_ext.build_extension(self,ext)
  150. if ext._needs_stub:
  151. self.write_stub(
  152. self.get_finalized_command('build_py').build_lib, ext
  153. )
  154. finally:
  155. self.compiler = _compiler
  156. def links_to_dynamic(self, ext):
  157. """Return true if 'ext' links to a dynamic lib in the same package"""
  158. # XXX this should check to ensure the lib is actually being built
  159. # XXX as dynamic, and not just using a locally-found version or a
  160. # XXX static-compiled version
  161. libnames = dict.fromkeys([lib._full_name for lib in self.shlibs])
  162. pkg = '.'.join(ext._full_name.split('.')[:-1]+[''])
  163. for libname in ext.libraries:
  164. if pkg+libname in libnames: return True
  165. return False
  166. def get_outputs(self):
  167. outputs = _build_ext.get_outputs(self)
  168. optimize = self.get_finalized_command('build_py').optimize
  169. for ext in self.extensions:
  170. if ext._needs_stub:
  171. base = os.path.join(self.build_lib, *ext._full_name.split('.'))
  172. outputs.append(base+'.py')
  173. outputs.append(base+'.pyc')
  174. if optimize:
  175. outputs.append(base+'.pyo')
  176. return outputs
  177. def write_stub(self, output_dir, ext, compile=False):
  178. log.info("writing stub loader for %s to %s",ext._full_name, output_dir)
  179. stub_file = os.path.join(output_dir, *ext._full_name.split('.'))+'.py'
  180. if compile and os.path.exists(stub_file):
  181. raise DistutilsError(stub_file+" already exists! Please delete.")
  182. if not self.dry_run:
  183. f = open(stub_file,'w')
  184. f.write('\n'.join([
  185. "def __bootstrap__():",
  186. " global __bootstrap__, __file__, __loader__",
  187. " import sys, os, pkg_resources, imp"+if_dl(", dl"),
  188. " __file__ = pkg_resources.resource_filename(__name__,%r)"
  189. % os.path.basename(ext._file_name),
  190. " del __bootstrap__",
  191. " if '__loader__' in globals():",
  192. " del __loader__",
  193. if_dl(" old_flags = sys.getdlopenflags()"),
  194. " old_dir = os.getcwd()",
  195. " try:",
  196. " os.chdir(os.path.dirname(__file__))",
  197. if_dl(" sys.setdlopenflags(dl.RTLD_NOW)"),
  198. " imp.load_dynamic(__name__,__file__)",
  199. " finally:",
  200. if_dl(" sys.setdlopenflags(old_flags)"),
  201. " os.chdir(old_dir)",
  202. "__bootstrap__()",
  203. "" # terminal \n
  204. ]))
  205. f.close()
  206. if compile:
  207. from distutils.util import byte_compile
  208. byte_compile([stub_file], optimize=0,
  209. force=True, dry_run=self.dry_run)
  210. optimize = self.get_finalized_command('install_lib').optimize
  211. if optimize > 0:
  212. byte_compile([stub_file], optimize=optimize,
  213. force=True, dry_run=self.dry_run)
  214. if os.path.exists(stub_file) and not self.dry_run:
  215. os.unlink(stub_file)
  216. if use_stubs or os.name=='nt':
  217. # Build shared libraries
  218. #
  219. def link_shared_object(self, objects, output_libname, output_dir=None,
  220. libraries=None, library_dirs=None, runtime_library_dirs=None,
  221. export_symbols=None, debug=0, extra_preargs=None,
  222. extra_postargs=None, build_temp=None, target_lang=None
  223. ): self.link(
  224. self.SHARED_LIBRARY, objects, output_libname,
  225. output_dir, libraries, library_dirs, runtime_library_dirs,
  226. export_symbols, debug, extra_preargs, extra_postargs,
  227. build_temp, target_lang
  228. )
  229. else:
  230. # Build static libraries everywhere else
  231. libtype = 'static'
  232. def link_shared_object(self, objects, output_libname, output_dir=None,
  233. libraries=None, library_dirs=None, runtime_library_dirs=None,
  234. export_symbols=None, debug=0, extra_preargs=None,
  235. extra_postargs=None, build_temp=None, target_lang=None
  236. ):
  237. # XXX we need to either disallow these attrs on Library instances,
  238. # or warn/abort here if set, or something...
  239. #libraries=None, library_dirs=None, runtime_library_dirs=None,
  240. #export_symbols=None, extra_preargs=None, extra_postargs=None,
  241. #build_temp=None
  242. assert output_dir is None # distutils build_ext doesn't pass this
  243. output_dir,filename = os.path.split(output_libname)
  244. basename, ext = os.path.splitext(filename)
  245. if self.library_filename("x").startswith('lib'):
  246. # strip 'lib' prefix; this is kludgy if some platform uses
  247. # a different prefix
  248. basename = basename[3:]
  249. self.create_static_lib(
  250. objects, basename, output_dir, debug, target_lang
  251. )