]> crepu.dev Git - config.git/blame - djavu-asus/elpy/rpc-venv/lib/python3.11/site-packages/setuptools/command/build_ext.py
Actualizado el Readme
[config.git] / djavu-asus / elpy / rpc-venv / lib / python3.11 / site-packages / setuptools / command / build_ext.py
CommitLineData
53e6db90
DC
1import os
2import sys
3import itertools
4from importlib.machinery import EXTENSION_SUFFIXES
5from importlib.util import cache_from_source as _compiled_file_name
6from typing import Dict, Iterator, List, Tuple
7
8from distutils.command.build_ext import build_ext as _du_build_ext
9from distutils.ccompiler import new_compiler
10from distutils.sysconfig import customize_compiler, get_config_var
11from distutils import log
12
13from setuptools.errors import BaseError
14from setuptools.extension import Extension, Library
15
16try:
17 # Attempt to use Cython for building extensions, if available
18 from Cython.Distutils.build_ext import build_ext as _build_ext
19 # Additionally, assert that the compiler module will load
20 # also. Ref #1229.
21 __import__('Cython.Compiler.Main')
22except ImportError:
23 _build_ext = _du_build_ext
24
25# make sure _config_vars is initialized
26get_config_var("LDSHARED")
27from distutils.sysconfig import _config_vars as _CONFIG_VARS # noqa
28
29
30def _customize_compiler_for_shlib(compiler):
31 if sys.platform == "darwin":
32 # building .dylib requires additional compiler flags on OSX; here we
33 # temporarily substitute the pyconfig.h variables so that distutils'
34 # 'customize_compiler' uses them before we build the shared libraries.
35 tmp = _CONFIG_VARS.copy()
36 try:
37 # XXX Help! I don't have any idea whether these are right...
38 _CONFIG_VARS['LDSHARED'] = (
39 "gcc -Wl,-x -dynamiclib -undefined dynamic_lookup")
40 _CONFIG_VARS['CCSHARED'] = " -dynamiclib"
41 _CONFIG_VARS['SO'] = ".dylib"
42 customize_compiler(compiler)
43 finally:
44 _CONFIG_VARS.clear()
45 _CONFIG_VARS.update(tmp)
46 else:
47 customize_compiler(compiler)
48
49
50have_rtld = False
51use_stubs = False
52libtype = 'shared'
53
54if sys.platform == "darwin":
55 use_stubs = True
56elif os.name != 'nt':
57 try:
58 import dl
59 use_stubs = have_rtld = hasattr(dl, 'RTLD_NOW')
60 except ImportError:
61 pass
62
63
64def if_dl(s):
65 return s if have_rtld else ''
66
67
68def get_abi3_suffix():
69 """Return the file extension for an abi3-compliant Extension()"""
70 for suffix in EXTENSION_SUFFIXES:
71 if '.abi3' in suffix: # Unix
72 return suffix
73 elif suffix == '.pyd': # Windows
74 return suffix
75
76
77class build_ext(_build_ext):
78 editable_mode: bool = False
79 inplace: bool = False
80
81 def run(self):
82 """Build extensions in build directory, then copy if --inplace"""
83 old_inplace, self.inplace = self.inplace, 0
84 _build_ext.run(self)
85 self.inplace = old_inplace
86 if old_inplace:
87 self.copy_extensions_to_source()
88
89 def _get_inplace_equivalent(self, build_py, ext: Extension) -> Tuple[str, str]:
90 fullname = self.get_ext_fullname(ext.name)
91 filename = self.get_ext_filename(fullname)
92 modpath = fullname.split('.')
93 package = '.'.join(modpath[:-1])
94 package_dir = build_py.get_package_dir(package)
95 inplace_file = os.path.join(package_dir, os.path.basename(filename))
96 regular_file = os.path.join(self.build_lib, filename)
97 return (inplace_file, regular_file)
98
99 def copy_extensions_to_source(self):
100 build_py = self.get_finalized_command('build_py')
101 for ext in self.extensions:
102 inplace_file, regular_file = self._get_inplace_equivalent(build_py, ext)
103
104 # Always copy, even if source is older than destination, to ensure
105 # that the right extensions for the current Python/platform are
106 # used.
107 if os.path.exists(regular_file) or not ext.optional:
108 self.copy_file(regular_file, inplace_file, level=self.verbose)
109
110 if ext._needs_stub:
111 inplace_stub = self._get_equivalent_stub(ext, inplace_file)
112 self._write_stub_file(inplace_stub, ext, compile=True)
113 # Always compile stub and remove the original (leave the cache behind)
114 # (this behaviour was observed in previous iterations of the code)
115
116 def _get_equivalent_stub(self, ext: Extension, output_file: str) -> str:
117 dir_ = os.path.dirname(output_file)
118 _, _, name = ext.name.rpartition(".")
119 return f"{os.path.join(dir_, name)}.py"
120
121 def _get_output_mapping(self) -> Iterator[Tuple[str, str]]:
122 if not self.inplace:
123 return
124
125 build_py = self.get_finalized_command('build_py')
126 opt = self.get_finalized_command('install_lib').optimize or ""
127
128 for ext in self.extensions:
129 inplace_file, regular_file = self._get_inplace_equivalent(build_py, ext)
130 yield (regular_file, inplace_file)
131
132 if ext._needs_stub:
133 # This version of `build_ext` always builds artifacts in another dir,
134 # when "inplace=True" is given it just copies them back.
135 # This is done in the `copy_extensions_to_source` function, which
136 # always compile stub files via `_compile_and_remove_stub`.
137 # At the end of the process, a `.pyc` stub file is created without the
138 # corresponding `.py`.
139
140 inplace_stub = self._get_equivalent_stub(ext, inplace_file)
141 regular_stub = self._get_equivalent_stub(ext, regular_file)
142 inplace_cache = _compiled_file_name(inplace_stub, optimization=opt)
143 output_cache = _compiled_file_name(regular_stub, optimization=opt)
144 yield (output_cache, inplace_cache)
145
146 def get_ext_filename(self, fullname):
147 so_ext = os.getenv('SETUPTOOLS_EXT_SUFFIX')
148 if so_ext:
149 filename = os.path.join(*fullname.split('.')) + so_ext
150 else:
151 filename = _build_ext.get_ext_filename(self, fullname)
152 so_ext = get_config_var('EXT_SUFFIX')
153
154 if fullname in self.ext_map:
155 ext = self.ext_map[fullname]
156 use_abi3 = getattr(ext, 'py_limited_api') and get_abi3_suffix()
157 if use_abi3:
158 filename = filename[:-len(so_ext)]
159 so_ext = get_abi3_suffix()
160 filename = filename + so_ext
161 if isinstance(ext, Library):
162 fn, ext = os.path.splitext(filename)
163 return self.shlib_compiler.library_filename(fn, libtype)
164 elif use_stubs and ext._links_to_dynamic:
165 d, fn = os.path.split(filename)
166 return os.path.join(d, 'dl-' + fn)
167 return filename
168
169 def initialize_options(self):
170 _build_ext.initialize_options(self)
171 self.shlib_compiler = None
172 self.shlibs = []
173 self.ext_map = {}
174 self.editable_mode = False
175
176 def finalize_options(self):
177 _build_ext.finalize_options(self)
178 self.extensions = self.extensions or []
179 self.check_extensions_list(self.extensions)
180 self.shlibs = [ext for ext in self.extensions
181 if isinstance(ext, Library)]
182 if self.shlibs:
183 self.setup_shlib_compiler()
184 for ext in self.extensions:
185 ext._full_name = self.get_ext_fullname(ext.name)
186 for ext in self.extensions:
187 fullname = ext._full_name
188 self.ext_map[fullname] = ext
189
190 # distutils 3.1 will also ask for module names
191 # XXX what to do with conflicts?
192 self.ext_map[fullname.split('.')[-1]] = ext
193
194 ltd = self.shlibs and self.links_to_dynamic(ext) or False
195 ns = ltd and use_stubs and not isinstance(ext, Library)
196 ext._links_to_dynamic = ltd
197 ext._needs_stub = ns
198 filename = ext._file_name = self.get_ext_filename(fullname)
199 libdir = os.path.dirname(os.path.join(self.build_lib, filename))
200 if ltd and libdir not in ext.library_dirs:
201 ext.library_dirs.append(libdir)
202 if ltd and use_stubs and os.curdir not in ext.runtime_library_dirs:
203 ext.runtime_library_dirs.append(os.curdir)
204
205 if self.editable_mode:
206 self.inplace = True
207
208 def setup_shlib_compiler(self):
209 compiler = self.shlib_compiler = new_compiler(
210 compiler=self.compiler, dry_run=self.dry_run, force=self.force
211 )
212 _customize_compiler_for_shlib(compiler)
213
214 if self.include_dirs is not None:
215 compiler.set_include_dirs(self.include_dirs)
216 if self.define is not None:
217 # 'define' option is a list of (name,value) tuples
218 for (name, value) in self.define:
219 compiler.define_macro(name, value)
220 if self.undef is not None:
221 for macro in self.undef:
222 compiler.undefine_macro(macro)
223 if self.libraries is not None:
224 compiler.set_libraries(self.libraries)
225 if self.library_dirs is not None:
226 compiler.set_library_dirs(self.library_dirs)
227 if self.rpath is not None:
228 compiler.set_runtime_library_dirs(self.rpath)
229 if self.link_objects is not None:
230 compiler.set_link_objects(self.link_objects)
231
232 # hack so distutils' build_extension() builds a library instead
233 compiler.link_shared_object = link_shared_object.__get__(compiler)
234
235 def get_export_symbols(self, ext):
236 if isinstance(ext, Library):
237 return ext.export_symbols
238 return _build_ext.get_export_symbols(self, ext)
239
240 def build_extension(self, ext):
241 ext._convert_pyx_sources_to_lang()
242 _compiler = self.compiler
243 try:
244 if isinstance(ext, Library):
245 self.compiler = self.shlib_compiler
246 _build_ext.build_extension(self, ext)
247 if ext._needs_stub:
248 build_lib = self.get_finalized_command('build_py').build_lib
249 self.write_stub(build_lib, ext)
250 finally:
251 self.compiler = _compiler
252
253 def links_to_dynamic(self, ext):
254 """Return true if 'ext' links to a dynamic lib in the same package"""
255 # XXX this should check to ensure the lib is actually being built
256 # XXX as dynamic, and not just using a locally-found version or a
257 # XXX static-compiled version
258 libnames = dict.fromkeys([lib._full_name for lib in self.shlibs])
259 pkg = '.'.join(ext._full_name.split('.')[:-1] + [''])
260 return any(pkg + libname in libnames for libname in ext.libraries)
261
262 def get_outputs(self) -> List[str]:
263 if self.inplace:
264 return list(self.get_output_mapping().keys())
265 return sorted(_build_ext.get_outputs(self) + self.__get_stubs_outputs())
266
267 def get_output_mapping(self) -> Dict[str, str]:
268 """See :class:`setuptools.commands.build.SubCommand`"""
269 mapping = self._get_output_mapping()
270 return dict(sorted(mapping, key=lambda x: x[0]))
271
272 def __get_stubs_outputs(self):
273 # assemble the base name for each extension that needs a stub
274 ns_ext_bases = (
275 os.path.join(self.build_lib, *ext._full_name.split('.'))
276 for ext in self.extensions
277 if ext._needs_stub
278 )
279 # pair each base with the extension
280 pairs = itertools.product(ns_ext_bases, self.__get_output_extensions())
281 return list(base + fnext for base, fnext in pairs)
282
283 def __get_output_extensions(self):
284 yield '.py'
285 yield '.pyc'
286 if self.get_finalized_command('build_py').optimize:
287 yield '.pyo'
288
289 def write_stub(self, output_dir, ext, compile=False):
290 stub_file = os.path.join(output_dir, *ext._full_name.split('.')) + '.py'
291 self._write_stub_file(stub_file, ext, compile)
292
293 def _write_stub_file(self, stub_file: str, ext: Extension, compile=False):
294 log.info("writing stub loader for %s to %s", ext._full_name, stub_file)
295 if compile and os.path.exists(stub_file):
296 raise BaseError(stub_file + " already exists! Please delete.")
297 if not self.dry_run:
298 f = open(stub_file, 'w')
299 f.write(
300 '\n'.join([
301 "def __bootstrap__():",
302 " global __bootstrap__, __file__, __loader__",
303 " import sys, os, pkg_resources, importlib.util" +
304 if_dl(", dl"),
305 " __file__ = pkg_resources.resource_filename"
306 "(__name__,%r)"
307 % os.path.basename(ext._file_name),
308 " del __bootstrap__",
309 " if '__loader__' in globals():",
310 " del __loader__",
311 if_dl(" old_flags = sys.getdlopenflags()"),
312 " old_dir = os.getcwd()",
313 " try:",
314 " os.chdir(os.path.dirname(__file__))",
315 if_dl(" sys.setdlopenflags(dl.RTLD_NOW)"),
316 " spec = importlib.util.spec_from_file_location(",
317 " __name__, __file__)",
318 " mod = importlib.util.module_from_spec(spec)",
319 " spec.loader.exec_module(mod)",
320 " finally:",
321 if_dl(" sys.setdlopenflags(old_flags)"),
322 " os.chdir(old_dir)",
323 "__bootstrap__()",
324 "" # terminal \n
325 ])
326 )
327 f.close()
328 if compile:
329 self._compile_and_remove_stub(stub_file)
330
331 def _compile_and_remove_stub(self, stub_file: str):
332 from distutils.util import byte_compile
333
334 byte_compile([stub_file], optimize=0,
335 force=True, dry_run=self.dry_run)
336 optimize = self.get_finalized_command('install_lib').optimize
337 if optimize > 0:
338 byte_compile([stub_file], optimize=optimize,
339 force=True, dry_run=self.dry_run)
340 if os.path.exists(stub_file) and not self.dry_run:
341 os.unlink(stub_file)
342
343
344if use_stubs or os.name == 'nt':
345 # Build shared libraries
346 #
347 def link_shared_object(
348 self, objects, output_libname, output_dir=None, libraries=None,
349 library_dirs=None, runtime_library_dirs=None, export_symbols=None,
350 debug=0, extra_preargs=None, extra_postargs=None, build_temp=None,
351 target_lang=None):
352 self.link(
353 self.SHARED_LIBRARY, objects, output_libname,
354 output_dir, libraries, library_dirs, runtime_library_dirs,
355 export_symbols, debug, extra_preargs, extra_postargs,
356 build_temp, target_lang
357 )
358else:
359 # Build static libraries everywhere else
360 libtype = 'static'
361
362 def link_shared_object(
363 self, objects, output_libname, output_dir=None, libraries=None,
364 library_dirs=None, runtime_library_dirs=None, export_symbols=None,
365 debug=0, extra_preargs=None, extra_postargs=None, build_temp=None,
366 target_lang=None):
367 # XXX we need to either disallow these attrs on Library instances,
368 # or warn/abort here if set, or something...
369 # libraries=None, library_dirs=None, runtime_library_dirs=None,
370 # export_symbols=None, extra_preargs=None, extra_postargs=None,
371 # build_temp=None
372
373 assert output_dir is None # distutils build_ext doesn't pass this
374 output_dir, filename = os.path.split(output_libname)
375 basename, ext = os.path.splitext(filename)
376 if self.library_filename("x").startswith('lib'):
377 # strip 'lib' prefix; this is kludgy if some platform uses
378 # a different prefix
379 basename = basename[3:]
380
381 self.create_static_lib(
382 objects, basename, output_dir, debug, target_lang
383 )