extension.py 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. import sys
  2. import re
  3. import functools
  4. import distutils.core
  5. import distutils.extension
  6. from setuptools.dist import _get_unpatched
  7. _Extension = _get_unpatched(distutils.core.Extension)
  8. def have_pyrex():
  9. """
  10. Return True if Cython or Pyrex can be imported.
  11. """
  12. pyrex_impls = 'Cython.Distutils.build_ext', 'Pyrex.Distutils.build_ext'
  13. for pyrex_impl in pyrex_impls:
  14. try:
  15. # from (pyrex_impl) import build_ext
  16. __import__(pyrex_impl, fromlist=['build_ext']).build_ext
  17. return True
  18. except Exception:
  19. pass
  20. return False
  21. class Extension(_Extension):
  22. """Extension that uses '.c' files in place of '.pyx' files"""
  23. def __init__(self, *args, **kw):
  24. _Extension.__init__(self, *args, **kw)
  25. self._convert_pyx_sources_to_lang()
  26. def _convert_pyx_sources_to_lang(self):
  27. """
  28. Replace sources with .pyx extensions to sources with the target
  29. language extension. This mechanism allows language authors to supply
  30. pre-converted sources but to prefer the .pyx sources.
  31. """
  32. if have_pyrex():
  33. # the build has Cython, so allow it to compile the .pyx files
  34. return
  35. lang = self.language or ''
  36. target_ext = '.cpp' if lang.lower() == 'c++' else '.c'
  37. sub = functools.partial(re.sub, '.pyx$', target_ext)
  38. self.sources = list(map(sub, self.sources))
  39. class Library(Extension):
  40. """Just like a regular Extension, but built as a library instead"""
  41. distutils.core.Extension = Extension
  42. distutils.extension.Extension = Extension
  43. if 'distutils.command.build_ext' in sys.modules:
  44. sys.modules['distutils.command.build_ext'].Extension = Extension