|
21 | 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22 | 22 | # SOFTWARE.
|
23 | 23 |
|
| 24 | +import sys |
24 | 25 | import os.path
|
25 | 26 | import functools
|
| 27 | +import re |
26 | 28 | from pathlib import Path
|
27 | 29 | from distutils import log
|
28 | 30 | from distutils.ccompiler import new_compiler
|
|
35 | 37 | # NOTE: this file is also imported by PyPy tests, so it must be compatible
|
36 | 38 | # with both Python 2.7 and Python 3.x
|
37 | 39 |
|
| 40 | +DEFAULT_HPY_ABI = 'universal' |
| 41 | +if hasattr(sys, 'implementation') and sys.implementation.name == 'cpython': |
| 42 | + DEFAULT_HPY_ABI = 'cpython' |
38 | 43 |
|
39 | 44 | class HPyDevel:
|
40 | 45 | """ Extra sources for building HPy extensions with hpy.devel. """
|
@@ -129,6 +134,17 @@ def fix_distribution(self, dist):
|
129 | 134 | base_build_ext = dist.cmdclass.get("build_ext", build_ext)
|
130 | 135 | orig_bdist_egg_write_stub = bdist_egg_mod.write_stub
|
131 | 136 |
|
| 137 | + if isinstance(base_build_ext, type): |
| 138 | + assert ('setuptools.command.build_ext', 'build_ext') in [ |
| 139 | + (c.__module__, c.__name__) for c in base_build_ext.__mro__ |
| 140 | + ], ( |
| 141 | + "dist.cmdclass['build_ext'] does not inherit from" |
| 142 | + " setuptools.command.build_ext.build_ext. The HPy build" |
| 143 | + " system does not currently support any other build_ext" |
| 144 | + " classes. If you are using distutils.commands.build_ext," |
| 145 | + " please use setuptools.commands.build_ext instead." |
| 146 | + ) |
| 147 | + |
132 | 148 | class build_hpy_ext(build_hpy_ext_mixin, base_build_ext, object):
|
133 | 149 | _base_build_ext = base_build_ext
|
134 | 150 |
|
@@ -167,30 +183,30 @@ def handle_hpy_ext_modules(dist, attr, hpy_ext_modules):
|
167 | 183 | assert attr == 'hpy_ext_modules'
|
168 | 184 |
|
169 | 185 | # add a global option --hpy-abi to setup.py
|
170 |
| - dist.__class__.hpy_abi = 'cpython' |
| 186 | + dist.__class__.hpy_abi = DEFAULT_HPY_ABI |
171 | 187 | dist.__class__.global_options += [
|
172 |
| - ('hpy-abi=', None, 'Specify the HPy ABI mode (default: cpython)') |
| 188 | + ('hpy-abi=', None, 'Specify the HPy ABI mode (default: %s)' % DEFAULT_HPY_ABI) |
173 | 189 | ]
|
174 | 190 | hpydevel = HPyDevel()
|
175 | 191 | hpydevel.fix_distribution(dist)
|
176 | 192 |
|
177 | 193 |
|
178 | 194 | _HPY_UNIVERSAL_MODULE_STUB_TEMPLATE = """
|
179 |
| -class Spec: |
180 |
| - def __init__(self, name, origin): |
181 |
| - self.name = name |
182 |
| - self.origin = origin |
183 |
| -
|
| 195 | +# DO NOT EDIT THIS FILE! |
| 196 | +# This file is automatically generated by hpy |
184 | 197 |
|
185 | 198 | def __bootstrap__():
|
| 199 | +
|
186 | 200 | import sys, pkg_resources
|
187 |
| - from hpy.universal import load_from_spec |
| 201 | + from hpy.universal import load |
188 | 202 | ext_filepath = pkg_resources.resource_filename(__name__, {ext_file!r})
|
189 |
| - m = load_from_spec(Spec({module_name!r}, ext_filepath)) |
| 203 | + m = load({module_name!r}, ext_filepath) |
190 | 204 | m.__file__ = ext_filepath
|
191 | 205 | m.__loader__ = __loader__
|
| 206 | + m.__name__ = __name__ |
192 | 207 | m.__package__ = __package__
|
193 | 208 | m.__spec__ = __spec__
|
| 209 | + m.__spec__.origin = ext_filepath |
194 | 210 | sys.modules[__name__] = m
|
195 | 211 |
|
196 | 212 | __bootstrap__()
|
@@ -283,6 +299,9 @@ def _finalize_hpy_ext(self, ext):
|
283 | 299 | if ext.hpy_abi == 'universal':
|
284 | 300 | ext.define_macros.append(('HPY_UNIVERSAL_ABI', None))
|
285 | 301 | ext._hpy_needs_stub = True
|
| 302 | + else: |
| 303 | + raise DistutilsError('Unknown HPy ABI: %s. Valid values are: ' |
| 304 | + 'cpython, universal' % ext.hpy_abi) |
286 | 305 |
|
287 | 306 | def finalize_options(self):
|
288 | 307 | self._extensions = self.distribution.ext_modules or []
|
@@ -337,12 +356,23 @@ def write_stub(self, output_dir, ext, compile=False):
|
337 | 356 | log.info(
|
338 | 357 | "writing hpy universal stub loader for %s to %s",
|
339 | 358 | ext._full_name, stub_file)
|
340 |
| - if compile and os.path.exists(stub_file): |
341 |
| - raise DistutilsError(stub_file + " already exists! Please delete.") |
| 359 | + |
342 | 360 | ext_file = os.path.basename(ext._file_name)
|
343 | 361 | module_name = ext_file.split(".")[0]
|
344 | 362 | if not self.dry_run:
|
345 | 363 | with open(stub_file, 'w') as f:
|
346 | 364 | f.write(_HPY_UNIVERSAL_MODULE_STUB_TEMPLATE.format(
|
347 | 365 | ext_file=ext_file, module_name=module_name)
|
348 | 366 | )
|
| 367 | + |
| 368 | + def get_export_symbols(self, ext): |
| 369 | + """ Override .get_export_symbols to replace "PyInit_<module_name>" |
| 370 | + with "HPyInit_<module_name>. |
| 371 | +
|
| 372 | + Only relevant on Windows, where the .pyd file (DLL) must export the |
| 373 | + module "HPyInit_" function. |
| 374 | + """ |
| 375 | + exports = self._base_build_ext.get_export_symbols(self, ext) |
| 376 | + if hasattr(ext, "hpy_abi") and ext.hpy_abi == 'universal': |
| 377 | + exports = [re.sub(r"^PyInit_", "HPyInit_", name) for name in exports] |
| 378 | + return exports |
0 commit comments