omdev 0.0.0.dev7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- omdev/__about__.py +35 -0
- omdev/__init__.py +0 -0
- omdev/amalg/__init__.py +0 -0
- omdev/amalg/__main__.py +4 -0
- omdev/amalg/amalg.py +513 -0
- omdev/classdot.py +61 -0
- omdev/cmake.py +164 -0
- omdev/exts/__init__.py +0 -0
- omdev/exts/_distutils/__init__.py +10 -0
- omdev/exts/_distutils/build_ext.py +367 -0
- omdev/exts/_distutils/compilers/__init__.py +3 -0
- omdev/exts/_distutils/compilers/ccompiler.py +1032 -0
- omdev/exts/_distutils/compilers/options.py +80 -0
- omdev/exts/_distutils/compilers/unixccompiler.py +385 -0
- omdev/exts/_distutils/dir_util.py +76 -0
- omdev/exts/_distutils/errors.py +62 -0
- omdev/exts/_distutils/extension.py +107 -0
- omdev/exts/_distutils/file_util.py +216 -0
- omdev/exts/_distutils/modified.py +47 -0
- omdev/exts/_distutils/spawn.py +103 -0
- omdev/exts/_distutils/sysconfig.py +349 -0
- omdev/exts/_distutils/util.py +201 -0
- omdev/exts/_distutils/version.py +308 -0
- omdev/exts/build.py +43 -0
- omdev/exts/cmake.py +195 -0
- omdev/exts/importhook.py +88 -0
- omdev/exts/scan.py +74 -0
- omdev/interp/__init__.py +1 -0
- omdev/interp/__main__.py +4 -0
- omdev/interp/cli.py +63 -0
- omdev/interp/inspect.py +105 -0
- omdev/interp/providers.py +67 -0
- omdev/interp/pyenv.py +353 -0
- omdev/interp/resolvers.py +76 -0
- omdev/interp/standalone.py +187 -0
- omdev/interp/system.py +125 -0
- omdev/interp/types.py +92 -0
- omdev/mypy/__init__.py +0 -0
- omdev/mypy/debug.py +86 -0
- omdev/pyproject/__init__.py +1 -0
- omdev/pyproject/__main__.py +4 -0
- omdev/pyproject/cli.py +319 -0
- omdev/pyproject/configs.py +97 -0
- omdev/pyproject/ext.py +107 -0
- omdev/pyproject/pkg.py +196 -0
- omdev/scripts/__init__.py +0 -0
- omdev/scripts/execrss.py +19 -0
- omdev/scripts/findimports.py +62 -0
- omdev/scripts/findmagic.py +70 -0
- omdev/scripts/interp.py +2118 -0
- omdev/scripts/pyproject.py +3584 -0
- omdev/scripts/traceimport.py +502 -0
- omdev/tokens.py +42 -0
- omdev/toml/__init__.py +1 -0
- omdev/toml/parser.py +823 -0
- omdev/toml/writer.py +104 -0
- omdev/tools/__init__.py +0 -0
- omdev/tools/dockertools.py +81 -0
- omdev/tools/sqlrepl.py +193 -0
- omdev/versioning/__init__.py +1 -0
- omdev/versioning/specifiers.py +531 -0
- omdev/versioning/versions.py +416 -0
- omdev-0.0.0.dev7.dist-info/LICENSE +21 -0
- omdev-0.0.0.dev7.dist-info/METADATA +24 -0
- omdev-0.0.0.dev7.dist-info/RECORD +67 -0
- omdev-0.0.0.dev7.dist-info/WHEEL +5 -0
- omdev-0.0.0.dev7.dist-info/top_level.txt +1 -0
omdev/cmake.py
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import io
|
|
3
|
+
import typing as ta
|
|
4
|
+
|
|
5
|
+
from omlish import dataclasses as dc
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dc.dataclass(frozen=True)
|
|
9
|
+
class Command:
|
|
10
|
+
name: str
|
|
11
|
+
args: str | ta.Sequence[str]
|
|
12
|
+
lines: ta.Sequence[str] | None = None
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dc.dataclass(frozen=True)
|
|
16
|
+
class Var:
|
|
17
|
+
name: str
|
|
18
|
+
value: str | ta.Sequence[str]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dc.dataclass(frozen=True)
|
|
22
|
+
class Target(abc.ABC):
|
|
23
|
+
name: str
|
|
24
|
+
src_files: ta.Sequence[str]
|
|
25
|
+
|
|
26
|
+
include_dirs: ta.Sequence[str] | None = None
|
|
27
|
+
compile_opts: ta.Sequence[str] | None = None
|
|
28
|
+
link_dirs: ta.Sequence[str] | None = None
|
|
29
|
+
link_opts: ta.Sequence[str] | None = None
|
|
30
|
+
|
|
31
|
+
compile_flags_by_source_file: ta.Mapping[str, ta.Sequence[str]] | None = None
|
|
32
|
+
|
|
33
|
+
link_libs: ta.Sequence[str] | None = None
|
|
34
|
+
|
|
35
|
+
extra_cmds: ta.Sequence[Command] | None = None
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
@abc.abstractmethod
|
|
39
|
+
def command_name(self) -> str:
|
|
40
|
+
raise NotImplementedError
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def command_extra(self) -> ta.Sequence[str]:
|
|
44
|
+
return []
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dc.dataclass(frozen=True)
|
|
48
|
+
class Library(Target):
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def command_name(self) -> str:
|
|
52
|
+
return 'add_library'
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dc.dataclass(frozen=True)
|
|
56
|
+
class StaticLibrary(Library):
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def command_extra(self) -> ta.Sequence[str]:
|
|
60
|
+
return ['STATIC']
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dc.dataclass(frozen=True)
|
|
64
|
+
class ModuleLibrary(Library):
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def command_extra(self) -> ta.Sequence[str]:
|
|
68
|
+
return ['MODULE']
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dc.dataclass(frozen=True)
|
|
72
|
+
class Executable(Target):
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def command_name(self) -> str:
|
|
76
|
+
return 'add_executable'
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class CmakeGen:
|
|
80
|
+
|
|
81
|
+
def __init__(
|
|
82
|
+
self,
|
|
83
|
+
out: io.TextIOBase,
|
|
84
|
+
*,
|
|
85
|
+
indent: int = 4,
|
|
86
|
+
) -> None:
|
|
87
|
+
super().__init__()
|
|
88
|
+
|
|
89
|
+
self._out = out
|
|
90
|
+
self._indent = indent
|
|
91
|
+
|
|
92
|
+
def write(
|
|
93
|
+
self,
|
|
94
|
+
obj: str | ta.Sequence[str] = '',
|
|
95
|
+
*,
|
|
96
|
+
spacing: int | str = 0,
|
|
97
|
+
indent: int | str | None = None,
|
|
98
|
+
) -> None:
|
|
99
|
+
if isinstance(obj, str):
|
|
100
|
+
obj = [obj]
|
|
101
|
+
if isinstance(spacing, int):
|
|
102
|
+
spacing = '\n' * spacing
|
|
103
|
+
if isinstance(indent, int):
|
|
104
|
+
indent = ' ' * indent
|
|
105
|
+
for line in obj:
|
|
106
|
+
if indent is not None:
|
|
107
|
+
line = indent + line
|
|
108
|
+
self._out.write(line)
|
|
109
|
+
self._out.write('\n')
|
|
110
|
+
if spacing is not None:
|
|
111
|
+
self._out.write(spacing)
|
|
112
|
+
|
|
113
|
+
def write_section(self, label: str) -> None:
|
|
114
|
+
self.write(['', f'### {label}', ''])
|
|
115
|
+
|
|
116
|
+
def write_cmd(self, cmd: Command) -> None:
|
|
117
|
+
args = cmd.args
|
|
118
|
+
if not isinstance(args, str):
|
|
119
|
+
args = ' '.join(args)
|
|
120
|
+
if not cmd.lines:
|
|
121
|
+
self.write(f'{cmd.name}({args})')
|
|
122
|
+
else:
|
|
123
|
+
if isinstance(cmd.lines, str):
|
|
124
|
+
raise TypeError(cmd.lines)
|
|
125
|
+
self.write(f'{cmd.name}({args}')
|
|
126
|
+
self.write(cmd.lines, indent=self._indent)
|
|
127
|
+
self.write(')')
|
|
128
|
+
self.write()
|
|
129
|
+
|
|
130
|
+
def write_var(self, var: Var) -> None:
|
|
131
|
+
return self.write_cmd(Command('set', var.name, [var.value] if isinstance(var.value, str) else var.value))
|
|
132
|
+
|
|
133
|
+
def write_target(self, target: Target) -> None:
|
|
134
|
+
self.write_section(target.name)
|
|
135
|
+
|
|
136
|
+
self.write_cmd(Command(target.command_name, [target.name, *target.command_extra], target.src_files))
|
|
137
|
+
|
|
138
|
+
if target.include_dirs:
|
|
139
|
+
self.write_cmd(Command('target_include_directories', [target.name, 'PRIVATE'], target.include_dirs))
|
|
140
|
+
if target.compile_opts:
|
|
141
|
+
self.write_cmd(Command('target_compile_options', [target.name, 'PRIVATE'], target.compile_opts))
|
|
142
|
+
|
|
143
|
+
if target.link_dirs:
|
|
144
|
+
self.write_cmd(Command('target_link_directories', [target.name, 'PRIVATE'], target.link_dirs))
|
|
145
|
+
if target.link_opts:
|
|
146
|
+
self.write_cmd(Command('target_link_options', [target.name, 'PRIVATE'], target.link_opts))
|
|
147
|
+
|
|
148
|
+
if target.compile_flags_by_source_file:
|
|
149
|
+
for sf, cf in target.compile_flags_by_source_file.items():
|
|
150
|
+
cf = ['"' + f.replace('"', '\\"') + '"' for f in cf]
|
|
151
|
+
self.write_cmd(Command('set_source_files_properties', [sf, 'PROPERTIES', 'COMPILE_FLAGS'], cf))
|
|
152
|
+
|
|
153
|
+
if target.link_libs:
|
|
154
|
+
self.write_cmd(Command('target_link_libraries', [target.name, 'PRIVATE'], target.link_libs))
|
|
155
|
+
|
|
156
|
+
for cmd in (target.extra_cmds or ()):
|
|
157
|
+
self.write_cmd(cmd)
|
|
158
|
+
|
|
159
|
+
@property
|
|
160
|
+
def preamble(self) -> ta.Sequence[str]:
|
|
161
|
+
return [
|
|
162
|
+
'cmake_minimum_required(VERSION 3.1...3.16)',
|
|
163
|
+
'set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR})',
|
|
164
|
+
]
|
omdev/exts/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from . import build_ext # noqa
|
|
2
|
+
from . import compilers # noqa
|
|
3
|
+
from . import errors # noqa
|
|
4
|
+
from . import extension # noqa
|
|
5
|
+
from . import modified # noqa
|
|
6
|
+
from . import sysconfig # noqa
|
|
7
|
+
from . import util # noqa
|
|
8
|
+
|
|
9
|
+
from .build_ext import BuildExt # noqa
|
|
10
|
+
from .extension import Extension # noqa
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
"""
|
|
2
|
+
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
|
|
3
|
+
--------------------------------------------
|
|
4
|
+
|
|
5
|
+
1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and the Individual or Organization
|
|
6
|
+
("Licensee") accessing and otherwise using this software ("Python") in source or binary form and its associated
|
|
7
|
+
documentation.
|
|
8
|
+
|
|
9
|
+
2. Subject to the terms and conditions of this License Agreement, PSF hereby grants Licensee a nonexclusive,
|
|
10
|
+
royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works,
|
|
11
|
+
distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License Agreement
|
|
12
|
+
and PSF's notice of copyright, i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
|
|
13
|
+
2012, 2013, 2014, 2015, 2016, 2017 Python Software Foundation; All Rights Reserved" are retained in Python alone or in
|
|
14
|
+
any derivative version prepared by Licensee.
|
|
15
|
+
|
|
16
|
+
3. In the event Licensee prepares a derivative work that is based on or incorporates Python or any part thereof, and
|
|
17
|
+
wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any
|
|
18
|
+
such work a brief summary of the changes made to Python.
|
|
19
|
+
|
|
20
|
+
4. PSF is making Python available to Licensee on an "AS IS" basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS
|
|
21
|
+
OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF
|
|
22
|
+
MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT INFRINGE ANY THIRD PARTY
|
|
23
|
+
RIGHTS.
|
|
24
|
+
|
|
25
|
+
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL
|
|
26
|
+
DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, OR ANY DERIVATIVE THEREOF, EVEN IF
|
|
27
|
+
ADVISED OF THE POSSIBILITY THEREOF.
|
|
28
|
+
|
|
29
|
+
6. This License Agreement will automatically terminate upon a material breach of its terms and conditions.
|
|
30
|
+
|
|
31
|
+
7. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture
|
|
32
|
+
between PSF and Licensee. This License Agreement does not grant permission to use PSF trademarks or trade name in a
|
|
33
|
+
trademark sense to endorse or promote products or services of Licensee, or any third party.
|
|
34
|
+
|
|
35
|
+
8. By copying, installing or otherwise using Python, Licensee agrees to be bound by the terms and conditions of this
|
|
36
|
+
License Agreement.
|
|
37
|
+
"""
|
|
38
|
+
import contextlib
|
|
39
|
+
import dataclasses as dc
|
|
40
|
+
import logging
|
|
41
|
+
import os
|
|
42
|
+
import site
|
|
43
|
+
import sys
|
|
44
|
+
import typing as ta
|
|
45
|
+
|
|
46
|
+
from omlish import cached
|
|
47
|
+
from omlish import check
|
|
48
|
+
from omlish import lang
|
|
49
|
+
|
|
50
|
+
from . import compilers
|
|
51
|
+
from . import errors
|
|
52
|
+
from . import extension
|
|
53
|
+
from . import modified
|
|
54
|
+
from . import sysconfig
|
|
55
|
+
from . import util
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
log = logging.getLogger(__name__)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _get_str_config_var(name: str) -> str:
|
|
62
|
+
return check.isinstance(sysconfig.get_config_var(name), str)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class BuildExt:
|
|
66
|
+
|
|
67
|
+
@dc.dataclass(frozen=True)
|
|
68
|
+
class Options:
|
|
69
|
+
build_base: str | None = None
|
|
70
|
+
build_lib: str | None = None # directory for compiled extension modules
|
|
71
|
+
build_temp: str | None = None # directory for temporary files (build by-products)
|
|
72
|
+
|
|
73
|
+
plat_name: str | None = None # platform name to cross-compile for, if supported
|
|
74
|
+
|
|
75
|
+
include_dirs: ta.Sequence[str] | None = None # list of directories to search for header files (pathsep)
|
|
76
|
+
define: ta.Mapping[str, str] | None = None # C preprocessor macros to define
|
|
77
|
+
undef: ta.Sequence[str] | None = None # C preprocessor macros to undefine
|
|
78
|
+
|
|
79
|
+
libraries: ta.Sequence[str] | None = None # external C libraries to link with
|
|
80
|
+
library_dirs: ta.Sequence[str] | None = None # directories to search for external C libraries (pathsep)
|
|
81
|
+
rpath: ta.Sequence[str] | None = None # directories to search for shared C libraries at runtime
|
|
82
|
+
link_objects: ta.Sequence[str] | None = None # extra explicit link objects to include in the link
|
|
83
|
+
|
|
84
|
+
inplace: bool = False # ignore build-lib and put compiled extensions into the source directory
|
|
85
|
+
debug: bool = False # compile/link with debugging information
|
|
86
|
+
force: bool = False # forcibly build everything (ignore file timestamps)
|
|
87
|
+
compiler: str | None = None # specify the compiler type
|
|
88
|
+
parallel: int | None = None # number of parallel build jobs
|
|
89
|
+
user: bool = False # add user include, library and rpath
|
|
90
|
+
|
|
91
|
+
dry_run: bool = False
|
|
92
|
+
verbose: bool = False
|
|
93
|
+
|
|
94
|
+
package: str | None = None
|
|
95
|
+
package_dir: ta.Mapping[str, str] | None = None
|
|
96
|
+
|
|
97
|
+
def __init__(self, opts: Options = Options()) -> None:
|
|
98
|
+
super().__init__()
|
|
99
|
+
|
|
100
|
+
self._opts = check.isinstance(opts, BuildExt.Options)
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def options(self) -> Options:
|
|
104
|
+
return self._opts
|
|
105
|
+
|
|
106
|
+
@cached.property
|
|
107
|
+
def build_base(self) -> str:
|
|
108
|
+
return self._opts.build_base or 'build'
|
|
109
|
+
|
|
110
|
+
@cached.property
|
|
111
|
+
def plat_name(self) -> str:
|
|
112
|
+
return self._opts.plat_name or util.get_host_platform()
|
|
113
|
+
|
|
114
|
+
@cached.property
|
|
115
|
+
def plat_specifier(self) -> str:
|
|
116
|
+
ps = '.{}-{:d}.{:d}'.format(self.plat_name, *sys.version_info[:2])
|
|
117
|
+
if hasattr(sys, 'gettotalrefcount'):
|
|
118
|
+
ps += '-pydebug'
|
|
119
|
+
return ps
|
|
120
|
+
|
|
121
|
+
@cached.property
|
|
122
|
+
def build_lib(self) -> str:
|
|
123
|
+
return self._opts.build_lib or os.path.join(self.build_base, 'lib' + self.plat_specifier)
|
|
124
|
+
|
|
125
|
+
@cached.property
|
|
126
|
+
def build_temp(self) -> str:
|
|
127
|
+
if self._opts.build_temp:
|
|
128
|
+
return self._opts.build_temp
|
|
129
|
+
bt = os.path.join(self.build_base, 'temp' + self.plat_specifier)
|
|
130
|
+
return bt
|
|
131
|
+
|
|
132
|
+
@dc.dataclass(frozen=True)
|
|
133
|
+
class CDirs:
|
|
134
|
+
include: ta.Sequence[str]
|
|
135
|
+
library: ta.Sequence[str]
|
|
136
|
+
runtime: ta.Sequence[str]
|
|
137
|
+
|
|
138
|
+
@cached.property
|
|
139
|
+
def cdirs(self) -> CDirs:
|
|
140
|
+
include_dirs = list(self._opts.include_dirs or [])
|
|
141
|
+
library_dirs = list(self._opts.library_dirs or [])
|
|
142
|
+
rpath = list(self._opts.rpath or [])
|
|
143
|
+
|
|
144
|
+
plat_py_include = sysconfig.get_python_inc(plat_specific=1)
|
|
145
|
+
|
|
146
|
+
if sys.exec_prefix != sys.base_exec_prefix:
|
|
147
|
+
include_dirs.append(os.path.join(sys.exec_prefix, 'include'))
|
|
148
|
+
|
|
149
|
+
py_include = sysconfig.get_python_inc()
|
|
150
|
+
include_dirs.extend(py_include.split(os.path.pathsep))
|
|
151
|
+
if plat_py_include != py_include:
|
|
152
|
+
include_dirs.extend(plat_py_include.split(os.path.pathsep))
|
|
153
|
+
|
|
154
|
+
if (sysconfig.get_config_var('Py_ENABLE_SHARED')):
|
|
155
|
+
if not sysconfig.python_build: # noqa
|
|
156
|
+
library_dirs.append(_get_str_config_var('LIBDIR'))
|
|
157
|
+
else:
|
|
158
|
+
library_dirs.append('.')
|
|
159
|
+
|
|
160
|
+
if self._opts.user:
|
|
161
|
+
user_include = os.path.join(check.isinstance(site.USER_BASE, str), 'include')
|
|
162
|
+
if os.path.isdir(user_include):
|
|
163
|
+
include_dirs.append(user_include)
|
|
164
|
+
|
|
165
|
+
user_lib = os.path.join(check.isinstance(site.USER_BASE, str), 'lib')
|
|
166
|
+
if os.path.isdir(user_lib):
|
|
167
|
+
library_dirs.append(user_lib)
|
|
168
|
+
rpath.append(user_lib)
|
|
169
|
+
|
|
170
|
+
return BuildExt.CDirs(
|
|
171
|
+
include=include_dirs,
|
|
172
|
+
library=library_dirs,
|
|
173
|
+
runtime=rpath,
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
@lang.cached_function
|
|
177
|
+
def get_compiler(self) -> compilers.ccompiler.CCompiler:
|
|
178
|
+
cc = compilers.ccompiler.new_compiler(
|
|
179
|
+
compiler=self._opts.compiler,
|
|
180
|
+
verbose=int(self._opts.verbose),
|
|
181
|
+
dry_run=int(self._opts.dry_run),
|
|
182
|
+
force=int(self._opts.force),
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
sysconfig.customize_compiler(cc)
|
|
186
|
+
|
|
187
|
+
cc.set_include_dirs(list(self.cdirs.include))
|
|
188
|
+
|
|
189
|
+
if self._opts.define:
|
|
190
|
+
for (name, value) in self._opts.define.items():
|
|
191
|
+
cc.define_macro(name, value)
|
|
192
|
+
|
|
193
|
+
if self._opts.undef is not None:
|
|
194
|
+
for macro in self._opts.undef:
|
|
195
|
+
cc.undefine_macro(macro)
|
|
196
|
+
|
|
197
|
+
if self._opts.libraries:
|
|
198
|
+
cc.set_libraries(list(self._opts.libraries))
|
|
199
|
+
|
|
200
|
+
cc.set_library_dirs(list(self.cdirs.library))
|
|
201
|
+
|
|
202
|
+
cc.set_runtime_library_dirs(list(self.cdirs.runtime))
|
|
203
|
+
|
|
204
|
+
if self._opts.link_objects:
|
|
205
|
+
cc.set_link_objects(list(self._opts.link_objects))
|
|
206
|
+
|
|
207
|
+
return cc
|
|
208
|
+
|
|
209
|
+
def get_ext_fullpath(self, ext_name: str) -> str:
|
|
210
|
+
fullname = self.get_ext_fullname(ext_name)
|
|
211
|
+
modpath = fullname.split('.')
|
|
212
|
+
filename = self.get_ext_filename(modpath[-1])
|
|
213
|
+
|
|
214
|
+
if not self._opts.inplace:
|
|
215
|
+
filename = os.path.join(*modpath[:-1] + [filename])
|
|
216
|
+
return os.path.join(self.build_lib, filename) # noqa
|
|
217
|
+
|
|
218
|
+
package = '.'.join(modpath[0:-1])
|
|
219
|
+
package_dir = os.path.abspath(self.get_package_dir(package))
|
|
220
|
+
|
|
221
|
+
return os.path.join(package_dir, filename)
|
|
222
|
+
|
|
223
|
+
def get_package_dir(self, package: str) -> str:
|
|
224
|
+
path = package.split('.')
|
|
225
|
+
|
|
226
|
+
package_dir = self._opts.package_dir
|
|
227
|
+
if package_dir is None:
|
|
228
|
+
if path:
|
|
229
|
+
return os.path.join(*path) # noqa
|
|
230
|
+
else:
|
|
231
|
+
return ''
|
|
232
|
+
|
|
233
|
+
tail: list[str] = []
|
|
234
|
+
while path:
|
|
235
|
+
try:
|
|
236
|
+
pdir = package_dir['.'.join(path)]
|
|
237
|
+
except KeyError:
|
|
238
|
+
tail.insert(0, path[-1])
|
|
239
|
+
del path[-1]
|
|
240
|
+
else:
|
|
241
|
+
tail.insert(0, pdir)
|
|
242
|
+
return os.path.join(*tail) # noqa
|
|
243
|
+
|
|
244
|
+
pdir = package_dir.get('') # type: ignore
|
|
245
|
+
if pdir is not None:
|
|
246
|
+
tail.insert(0, pdir)
|
|
247
|
+
|
|
248
|
+
if tail:
|
|
249
|
+
return os.path.join(*tail) # noqa
|
|
250
|
+
else:
|
|
251
|
+
return ''
|
|
252
|
+
|
|
253
|
+
def get_ext_fullname(self, ext_name: str) -> str:
|
|
254
|
+
if self._opts.package is None:
|
|
255
|
+
return ext_name
|
|
256
|
+
else:
|
|
257
|
+
return self._opts.package + '.' + ext_name
|
|
258
|
+
|
|
259
|
+
def get_ext_filename(self, ext_name: str) -> str:
|
|
260
|
+
ext_path = ext_name.split('.')
|
|
261
|
+
ext_suffix = _get_str_config_var('EXT_SUFFIX')
|
|
262
|
+
return os.path.join(*ext_path) + ext_suffix # noqa
|
|
263
|
+
|
|
264
|
+
def get_export_symbols(self, ext: extension.Extension) -> ta.Sequence[str]:
|
|
265
|
+
suffix = '_' + ext.name.split('.')[-1]
|
|
266
|
+
try:
|
|
267
|
+
# Unicode module name support as defined in PEP-489
|
|
268
|
+
# https://www.python.org/dev/peps/pep-0489/#export-hook-name
|
|
269
|
+
suffix.encode('ascii')
|
|
270
|
+
except UnicodeEncodeError:
|
|
271
|
+
suffix = 'U' + suffix.encode('punycode').replace(b'-', b'_').decode('ascii')
|
|
272
|
+
|
|
273
|
+
initfunc_name = 'PyInit' + suffix
|
|
274
|
+
if initfunc_name not in ext.export_symbols:
|
|
275
|
+
ext.export_symbols.append(initfunc_name)
|
|
276
|
+
return ext.export_symbols
|
|
277
|
+
|
|
278
|
+
def get_libraries(self, ext: extension.Extension) -> ta.Sequence[str]:
|
|
279
|
+
if sys.platform == 'win32':
|
|
280
|
+
from distutils._msvccompiler import MSVCCompiler # noqa
|
|
281
|
+
|
|
282
|
+
if not isinstance(self.get_compiler(), MSVCCompiler):
|
|
283
|
+
template = 'python%d%d'
|
|
284
|
+
if self._opts.debug:
|
|
285
|
+
template = template + '_d'
|
|
286
|
+
pythonlib = (template % (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff))
|
|
287
|
+
return [*ext.libraries, pythonlib]
|
|
288
|
+
|
|
289
|
+
else:
|
|
290
|
+
link_libpython = False
|
|
291
|
+
if sysconfig.get_config_var('Py_ENABLE_SHARED'):
|
|
292
|
+
if hasattr(sys, 'getandroidapilevel') or sys.platform == 'cygwin':
|
|
293
|
+
link_libpython = True
|
|
294
|
+
|
|
295
|
+
if link_libpython:
|
|
296
|
+
ldversion = _get_str_config_var('LDVERSION')
|
|
297
|
+
return [*ext.libraries, 'python' + ldversion]
|
|
298
|
+
|
|
299
|
+
return ext.libraries
|
|
300
|
+
|
|
301
|
+
def build_extension(self, ext: extension.Extension) -> ta.Sequence[str]:
|
|
302
|
+
with self._filter_build_errors(ext):
|
|
303
|
+
return self._build_extension(ext)
|
|
304
|
+
|
|
305
|
+
@contextlib.contextmanager
|
|
306
|
+
def _filter_build_errors(self, ext: extension.Extension) -> ta.Iterator[None]:
|
|
307
|
+
try:
|
|
308
|
+
yield
|
|
309
|
+
except (
|
|
310
|
+
errors.CCompilerError,
|
|
311
|
+
errors.CompileError,
|
|
312
|
+
errors.DistutilsError,
|
|
313
|
+
) as e:
|
|
314
|
+
if not ext.optional:
|
|
315
|
+
raise
|
|
316
|
+
log.warning('building extension "%s" failed: %s', ext.name, e)
|
|
317
|
+
|
|
318
|
+
def _build_extension(self, ext: extension.Extension) -> ta.Sequence[str]:
|
|
319
|
+
sources = ext.sources
|
|
320
|
+
sources = sorted(sources)
|
|
321
|
+
|
|
322
|
+
ext_path = self.get_ext_fullpath(ext.name)
|
|
323
|
+
depends = sources + ext.depends
|
|
324
|
+
if not (self._opts.force or modified.newer_group(depends, ext_path, 'newer')):
|
|
325
|
+
log.debug('skipping "%s" extension (up-to-date)', ext.name)
|
|
326
|
+
return []
|
|
327
|
+
else:
|
|
328
|
+
log.info('building "%s" extension', ext.name)
|
|
329
|
+
|
|
330
|
+
extra_args = ext.extra_compile_args or []
|
|
331
|
+
|
|
332
|
+
macros = ext.define_macros[:]
|
|
333
|
+
for undef in ext.undef_macros:
|
|
334
|
+
macros.append((undef,)) # type: ignore # noqa
|
|
335
|
+
|
|
336
|
+
cc = self.get_compiler()
|
|
337
|
+
|
|
338
|
+
objects = cc.compile(
|
|
339
|
+
sources,
|
|
340
|
+
output_dir=self.build_temp,
|
|
341
|
+
macros=macros, # noqa
|
|
342
|
+
include_dirs=ext.include_dirs,
|
|
343
|
+
debug=int(self._opts.debug), # noqa
|
|
344
|
+
extra_postargs=extra_args,
|
|
345
|
+
depends=ext.depends,
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
if ext.extra_objects:
|
|
349
|
+
objects.extend(ext.extra_objects)
|
|
350
|
+
extra_args = ext.extra_link_args or []
|
|
351
|
+
|
|
352
|
+
language = ext.language or cc.detect_language(sources)
|
|
353
|
+
|
|
354
|
+
cc.link_shared_object(
|
|
355
|
+
objects,
|
|
356
|
+
ext_path,
|
|
357
|
+
libraries=list(self.get_libraries(ext)),
|
|
358
|
+
library_dirs=ext.library_dirs,
|
|
359
|
+
runtime_library_dirs=ext.runtime_library_dirs,
|
|
360
|
+
extra_postargs=extra_args,
|
|
361
|
+
export_symbols=list(self.get_export_symbols(ext)),
|
|
362
|
+
debug=int(self._opts.debug), # noqa
|
|
363
|
+
build_temp=self.build_temp,
|
|
364
|
+
target_lang=language,
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
return objects
|