Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +2 -0
- .venv/lib/python3.11/site-packages/setuptools/__pycache__/__init__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/__pycache__/_entry_points.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/__pycache__/_importlib.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/__pycache__/_path.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/__pycache__/_reqs.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/__pycache__/build_meta.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/__pycache__/dep_util.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/__pycache__/depends.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/__pycache__/dist.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/__pycache__/logging.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/__pycache__/namespaces.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/__pycache__/sandbox.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/__pycache__/unicode_utils.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/__init__.py +24 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/_collections.py +56 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/_functools.py +20 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/_macos_compat.py +12 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/_msvccompiler.py +572 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/archive_util.py +280 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/bcppcompiler.py +408 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/ccompiler.py +1220 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/cmd.py +436 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/_framework_compat.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/bdist_dumb.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/bdist_rpm.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/build.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/build_clib.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/build_scripts.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/clean.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/install.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/install_data.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/install_headers.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/install_lib.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/install_scripts.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/py37compat.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/register.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/sdist.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/bdist_dumb.py +144 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/build.py +153 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/build_ext.py +787 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/build_py.py +407 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/build_scripts.py +173 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/config.py +377 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/install.py +814 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/install_data.py +84 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/install_egg_info.py +91 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/install_headers.py +45 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/install_lib.py +238 -0
- .venv/lib/python3.11/site-packages/setuptools/_distutils/command/install_scripts.py +61 -0
.gitattributes
CHANGED
|
@@ -259,3 +259,5 @@ tuning-competition-baseline/.venv/lib/python3.11/site-packages/torch/_inductor/_
|
|
| 259 |
.venv/lib/python3.11/site-packages/opencv_python_headless.libs/libswresample-3e7db482.so.4.7.100 filter=lfs diff=lfs merge=lfs -text
|
| 260 |
.venv/lib/python3.11/site-packages/opencv_python_headless.libs/libquadmath-96973f99.so.0.0.0 filter=lfs diff=lfs merge=lfs -text
|
| 261 |
.venv/lib/python3.11/site-packages/propcache/_helpers_c.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
| 259 |
.venv/lib/python3.11/site-packages/opencv_python_headless.libs/libswresample-3e7db482.so.4.7.100 filter=lfs diff=lfs merge=lfs -text
|
| 260 |
.venv/lib/python3.11/site-packages/opencv_python_headless.libs/libquadmath-96973f99.so.0.0.0 filter=lfs diff=lfs merge=lfs -text
|
| 261 |
.venv/lib/python3.11/site-packages/propcache/_helpers_c.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 262 |
+
.venv/lib/python3.11/site-packages/setuptools/cli-arm64.exe filter=lfs diff=lfs merge=lfs -text
|
| 263 |
+
.venv/lib/python3.11/site-packages/setuptools/gui-arm64.exe filter=lfs diff=lfs merge=lfs -text
|
.venv/lib/python3.11/site-packages/setuptools/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (12.9 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/__pycache__/_entry_points.cpython-311.pyc
ADDED
|
Binary file (4.79 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/__pycache__/_importlib.cpython-311.pyc
ADDED
|
Binary file (1.95 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/__pycache__/_path.cpython-311.pyc
ADDED
|
Binary file (1.47 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/__pycache__/_reqs.cpython-311.pyc
ADDED
|
Binary file (1.13 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/__pycache__/build_meta.cpython-311.pyc
ADDED
|
Binary file (28.1 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/__pycache__/dep_util.cpython-311.pyc
ADDED
|
Binary file (1.29 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/__pycache__/depends.cpython-311.pyc
ADDED
|
Binary file (7.97 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/__pycache__/dist.cpython-311.pyc
ADDED
|
Binary file (64.1 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/__pycache__/logging.cpython-311.pyc
ADDED
|
Binary file (2.04 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/__pycache__/namespaces.cpython-311.pyc
ADDED
|
Binary file (5.66 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/__pycache__/sandbox.cpython-311.pyc
ADDED
|
Binary file (27.3 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/__pycache__/unicode_utils.cpython-311.pyc
ADDED
|
Binary file (1.82 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/__init__.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""distutils
|
| 2 |
+
|
| 3 |
+
The main package for the Python Module Distribution Utilities. Normally
|
| 4 |
+
used from a setup script as
|
| 5 |
+
|
| 6 |
+
from distutils.core import setup
|
| 7 |
+
|
| 8 |
+
setup (...)
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
import sys
|
| 12 |
+
import importlib
|
| 13 |
+
|
| 14 |
+
__version__ = sys.version[: sys.version.index(' ')]
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
try:
|
| 18 |
+
# Allow Debian and pkgsrc (only) to customize system
|
| 19 |
+
# behavior. Ref pypa/distutils#2 and pypa/distutils#16.
|
| 20 |
+
# This hook is deprecated and no other environments
|
| 21 |
+
# should use it.
|
| 22 |
+
importlib.import_module('_distutils_system_mod')
|
| 23 |
+
except ImportError:
|
| 24 |
+
pass
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/_collections.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import collections
|
| 2 |
+
import itertools
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
# from jaraco.collections 3.5.1
|
| 6 |
+
class DictStack(list, collections.abc.Mapping):
|
| 7 |
+
"""
|
| 8 |
+
A stack of dictionaries that behaves as a view on those dictionaries,
|
| 9 |
+
giving preference to the last.
|
| 10 |
+
|
| 11 |
+
>>> stack = DictStack([dict(a=1, c=2), dict(b=2, a=2)])
|
| 12 |
+
>>> stack['a']
|
| 13 |
+
2
|
| 14 |
+
>>> stack['b']
|
| 15 |
+
2
|
| 16 |
+
>>> stack['c']
|
| 17 |
+
2
|
| 18 |
+
>>> len(stack)
|
| 19 |
+
3
|
| 20 |
+
>>> stack.push(dict(a=3))
|
| 21 |
+
>>> stack['a']
|
| 22 |
+
3
|
| 23 |
+
>>> set(stack.keys()) == set(['a', 'b', 'c'])
|
| 24 |
+
True
|
| 25 |
+
>>> set(stack.items()) == set([('a', 3), ('b', 2), ('c', 2)])
|
| 26 |
+
True
|
| 27 |
+
>>> dict(**stack) == dict(stack) == dict(a=3, c=2, b=2)
|
| 28 |
+
True
|
| 29 |
+
>>> d = stack.pop()
|
| 30 |
+
>>> stack['a']
|
| 31 |
+
2
|
| 32 |
+
>>> d = stack.pop()
|
| 33 |
+
>>> stack['a']
|
| 34 |
+
1
|
| 35 |
+
>>> stack.get('b', None)
|
| 36 |
+
>>> 'c' in stack
|
| 37 |
+
True
|
| 38 |
+
"""
|
| 39 |
+
|
| 40 |
+
def __iter__(self):
|
| 41 |
+
dicts = list.__iter__(self)
|
| 42 |
+
return iter(set(itertools.chain.from_iterable(c.keys() for c in dicts)))
|
| 43 |
+
|
| 44 |
+
def __getitem__(self, key):
|
| 45 |
+
for scope in reversed(tuple(list.__iter__(self))):
|
| 46 |
+
if key in scope:
|
| 47 |
+
return scope[key]
|
| 48 |
+
raise KeyError(key)
|
| 49 |
+
|
| 50 |
+
push = list.append
|
| 51 |
+
|
| 52 |
+
def __contains__(self, other):
|
| 53 |
+
return collections.abc.Mapping.__contains__(self, other)
|
| 54 |
+
|
| 55 |
+
def __len__(self):
|
| 56 |
+
return len(list(iter(self)))
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/_functools.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import functools
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
# from jaraco.functools 3.5
|
| 5 |
+
def pass_none(func):
|
| 6 |
+
"""
|
| 7 |
+
Wrap func so it's not called if its first param is None
|
| 8 |
+
|
| 9 |
+
>>> print_text = pass_none(print)
|
| 10 |
+
>>> print_text('text')
|
| 11 |
+
text
|
| 12 |
+
>>> print_text(None)
|
| 13 |
+
"""
|
| 14 |
+
|
| 15 |
+
@functools.wraps(func)
|
| 16 |
+
def wrapper(param, *args, **kwargs):
|
| 17 |
+
if param is not None:
|
| 18 |
+
return func(param, *args, **kwargs)
|
| 19 |
+
|
| 20 |
+
return wrapper
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/_macos_compat.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
import importlib
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
def bypass_compiler_fixup(cmd, args):
|
| 6 |
+
return cmd
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
if sys.platform == 'darwin':
|
| 10 |
+
compiler_fixup = importlib.import_module('_osx_support').compiler_fixup
|
| 11 |
+
else:
|
| 12 |
+
compiler_fixup = bypass_compiler_fixup
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/_msvccompiler.py
ADDED
|
@@ -0,0 +1,572 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""distutils._msvccompiler
|
| 2 |
+
|
| 3 |
+
Contains MSVCCompiler, an implementation of the abstract CCompiler class
|
| 4 |
+
for Microsoft Visual Studio 2015.
|
| 5 |
+
|
| 6 |
+
The module is compatible with VS 2015 and later. You can find legacy support
|
| 7 |
+
for older versions in distutils.msvc9compiler and distutils.msvccompiler.
|
| 8 |
+
"""
|
| 9 |
+
|
| 10 |
+
# Written by Perry Stoll
|
| 11 |
+
# hacked by Robin Becker and Thomas Heller to do a better job of
|
| 12 |
+
# finding DevStudio (through the registry)
|
| 13 |
+
# ported to VS 2005 and VS 2008 by Christian Heimes
|
| 14 |
+
# ported to VS 2015 by Steve Dower
|
| 15 |
+
|
| 16 |
+
import os
|
| 17 |
+
import subprocess
|
| 18 |
+
import contextlib
|
| 19 |
+
import warnings
|
| 20 |
+
import unittest.mock as mock
|
| 21 |
+
|
| 22 |
+
with contextlib.suppress(ImportError):
|
| 23 |
+
import winreg
|
| 24 |
+
|
| 25 |
+
from distutils.errors import (
|
| 26 |
+
DistutilsExecError,
|
| 27 |
+
DistutilsPlatformError,
|
| 28 |
+
CompileError,
|
| 29 |
+
LibError,
|
| 30 |
+
LinkError,
|
| 31 |
+
)
|
| 32 |
+
from distutils.ccompiler import CCompiler, gen_lib_options
|
| 33 |
+
from distutils import log
|
| 34 |
+
from distutils.util import get_platform
|
| 35 |
+
|
| 36 |
+
from itertools import count
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
def _find_vc2015():
|
| 40 |
+
try:
|
| 41 |
+
key = winreg.OpenKeyEx(
|
| 42 |
+
winreg.HKEY_LOCAL_MACHINE,
|
| 43 |
+
r"Software\Microsoft\VisualStudio\SxS\VC7",
|
| 44 |
+
access=winreg.KEY_READ | winreg.KEY_WOW64_32KEY,
|
| 45 |
+
)
|
| 46 |
+
except OSError:
|
| 47 |
+
log.debug("Visual C++ is not registered")
|
| 48 |
+
return None, None
|
| 49 |
+
|
| 50 |
+
best_version = 0
|
| 51 |
+
best_dir = None
|
| 52 |
+
with key:
|
| 53 |
+
for i in count():
|
| 54 |
+
try:
|
| 55 |
+
v, vc_dir, vt = winreg.EnumValue(key, i)
|
| 56 |
+
except OSError:
|
| 57 |
+
break
|
| 58 |
+
if v and vt == winreg.REG_SZ and os.path.isdir(vc_dir):
|
| 59 |
+
try:
|
| 60 |
+
version = int(float(v))
|
| 61 |
+
except (ValueError, TypeError):
|
| 62 |
+
continue
|
| 63 |
+
if version >= 14 and version > best_version:
|
| 64 |
+
best_version, best_dir = version, vc_dir
|
| 65 |
+
return best_version, best_dir
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
def _find_vc2017():
|
| 69 |
+
"""Returns "15, path" based on the result of invoking vswhere.exe
|
| 70 |
+
If no install is found, returns "None, None"
|
| 71 |
+
|
| 72 |
+
The version is returned to avoid unnecessarily changing the function
|
| 73 |
+
result. It may be ignored when the path is not None.
|
| 74 |
+
|
| 75 |
+
If vswhere.exe is not available, by definition, VS 2017 is not
|
| 76 |
+
installed.
|
| 77 |
+
"""
|
| 78 |
+
root = os.environ.get("ProgramFiles(x86)") or os.environ.get("ProgramFiles")
|
| 79 |
+
if not root:
|
| 80 |
+
return None, None
|
| 81 |
+
|
| 82 |
+
try:
|
| 83 |
+
path = subprocess.check_output(
|
| 84 |
+
[
|
| 85 |
+
os.path.join(
|
| 86 |
+
root, "Microsoft Visual Studio", "Installer", "vswhere.exe"
|
| 87 |
+
),
|
| 88 |
+
"-latest",
|
| 89 |
+
"-prerelease",
|
| 90 |
+
"-requires",
|
| 91 |
+
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
|
| 92 |
+
"-property",
|
| 93 |
+
"installationPath",
|
| 94 |
+
"-products",
|
| 95 |
+
"*",
|
| 96 |
+
],
|
| 97 |
+
encoding="mbcs",
|
| 98 |
+
errors="strict",
|
| 99 |
+
).strip()
|
| 100 |
+
except (subprocess.CalledProcessError, OSError, UnicodeDecodeError):
|
| 101 |
+
return None, None
|
| 102 |
+
|
| 103 |
+
path = os.path.join(path, "VC", "Auxiliary", "Build")
|
| 104 |
+
if os.path.isdir(path):
|
| 105 |
+
return 15, path
|
| 106 |
+
|
| 107 |
+
return None, None
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
PLAT_SPEC_TO_RUNTIME = {
|
| 111 |
+
'x86': 'x86',
|
| 112 |
+
'x86_amd64': 'x64',
|
| 113 |
+
'x86_arm': 'arm',
|
| 114 |
+
'x86_arm64': 'arm64',
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
def _find_vcvarsall(plat_spec):
|
| 119 |
+
# bpo-38597: Removed vcruntime return value
|
| 120 |
+
_, best_dir = _find_vc2017()
|
| 121 |
+
|
| 122 |
+
if not best_dir:
|
| 123 |
+
best_version, best_dir = _find_vc2015()
|
| 124 |
+
|
| 125 |
+
if not best_dir:
|
| 126 |
+
log.debug("No suitable Visual C++ version found")
|
| 127 |
+
return None, None
|
| 128 |
+
|
| 129 |
+
vcvarsall = os.path.join(best_dir, "vcvarsall.bat")
|
| 130 |
+
if not os.path.isfile(vcvarsall):
|
| 131 |
+
log.debug("%s cannot be found", vcvarsall)
|
| 132 |
+
return None, None
|
| 133 |
+
|
| 134 |
+
return vcvarsall, None
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
def _get_vc_env(plat_spec):
|
| 138 |
+
if os.getenv("DISTUTILS_USE_SDK"):
|
| 139 |
+
return {key.lower(): value for key, value in os.environ.items()}
|
| 140 |
+
|
| 141 |
+
vcvarsall, _ = _find_vcvarsall(plat_spec)
|
| 142 |
+
if not vcvarsall:
|
| 143 |
+
raise DistutilsPlatformError("Unable to find vcvarsall.bat")
|
| 144 |
+
|
| 145 |
+
try:
|
| 146 |
+
out = subprocess.check_output(
|
| 147 |
+
f'cmd /u /c "{vcvarsall}" {plat_spec} && set',
|
| 148 |
+
stderr=subprocess.STDOUT,
|
| 149 |
+
).decode('utf-16le', errors='replace')
|
| 150 |
+
except subprocess.CalledProcessError as exc:
|
| 151 |
+
log.error(exc.output)
|
| 152 |
+
raise DistutilsPlatformError(f"Error executing {exc.cmd}")
|
| 153 |
+
|
| 154 |
+
env = {
|
| 155 |
+
key.lower(): value
|
| 156 |
+
for key, _, value in (line.partition('=') for line in out.splitlines())
|
| 157 |
+
if key and value
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
return env
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
def _find_exe(exe, paths=None):
|
| 164 |
+
"""Return path to an MSVC executable program.
|
| 165 |
+
|
| 166 |
+
Tries to find the program in several places: first, one of the
|
| 167 |
+
MSVC program search paths from the registry; next, the directories
|
| 168 |
+
in the PATH environment variable. If any of those work, return an
|
| 169 |
+
absolute path that is known to exist. If none of them work, just
|
| 170 |
+
return the original program name, 'exe'.
|
| 171 |
+
"""
|
| 172 |
+
if not paths:
|
| 173 |
+
paths = os.getenv('path').split(os.pathsep)
|
| 174 |
+
for p in paths:
|
| 175 |
+
fn = os.path.join(os.path.abspath(p), exe)
|
| 176 |
+
if os.path.isfile(fn):
|
| 177 |
+
return fn
|
| 178 |
+
return exe
|
| 179 |
+
|
| 180 |
+
|
| 181 |
+
# A map keyed by get_platform() return values to values accepted by
|
| 182 |
+
# 'vcvarsall.bat'. Always cross-compile from x86 to work with the
|
| 183 |
+
# lighter-weight MSVC installs that do not include native 64-bit tools.
|
| 184 |
+
PLAT_TO_VCVARS = {
|
| 185 |
+
'win32': 'x86',
|
| 186 |
+
'win-amd64': 'x86_amd64',
|
| 187 |
+
'win-arm32': 'x86_arm',
|
| 188 |
+
'win-arm64': 'x86_arm64',
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
|
| 192 |
+
class MSVCCompiler(CCompiler):
|
| 193 |
+
"""Concrete class that implements an interface to Microsoft Visual C++,
|
| 194 |
+
as defined by the CCompiler abstract class."""
|
| 195 |
+
|
| 196 |
+
compiler_type = 'msvc'
|
| 197 |
+
|
| 198 |
+
# Just set this so CCompiler's constructor doesn't barf. We currently
|
| 199 |
+
# don't use the 'set_executables()' bureaucracy provided by CCompiler,
|
| 200 |
+
# as it really isn't necessary for this sort of single-compiler class.
|
| 201 |
+
# Would be nice to have a consistent interface with UnixCCompiler,
|
| 202 |
+
# though, so it's worth thinking about.
|
| 203 |
+
executables = {}
|
| 204 |
+
|
| 205 |
+
# Private class data (need to distinguish C from C++ source for compiler)
|
| 206 |
+
_c_extensions = ['.c']
|
| 207 |
+
_cpp_extensions = ['.cc', '.cpp', '.cxx']
|
| 208 |
+
_rc_extensions = ['.rc']
|
| 209 |
+
_mc_extensions = ['.mc']
|
| 210 |
+
|
| 211 |
+
# Needed for the filename generation methods provided by the
|
| 212 |
+
# base class, CCompiler.
|
| 213 |
+
src_extensions = _c_extensions + _cpp_extensions + _rc_extensions + _mc_extensions
|
| 214 |
+
res_extension = '.res'
|
| 215 |
+
obj_extension = '.obj'
|
| 216 |
+
static_lib_extension = '.lib'
|
| 217 |
+
shared_lib_extension = '.dll'
|
| 218 |
+
static_lib_format = shared_lib_format = '%s%s'
|
| 219 |
+
exe_extension = '.exe'
|
| 220 |
+
|
| 221 |
+
def __init__(self, verbose=0, dry_run=0, force=0):
|
| 222 |
+
super().__init__(verbose, dry_run, force)
|
| 223 |
+
# target platform (.plat_name is consistent with 'bdist')
|
| 224 |
+
self.plat_name = None
|
| 225 |
+
self.initialized = False
|
| 226 |
+
|
| 227 |
+
@classmethod
|
| 228 |
+
def _configure(cls, vc_env):
|
| 229 |
+
"""
|
| 230 |
+
Set class-level include/lib dirs.
|
| 231 |
+
"""
|
| 232 |
+
cls.include_dirs = cls._parse_path(vc_env.get('include', ''))
|
| 233 |
+
cls.library_dirs = cls._parse_path(vc_env.get('lib', ''))
|
| 234 |
+
|
| 235 |
+
@staticmethod
|
| 236 |
+
def _parse_path(val):
|
| 237 |
+
return [dir.rstrip(os.sep) for dir in val.split(os.pathsep) if dir]
|
| 238 |
+
|
| 239 |
+
def initialize(self, plat_name=None):
|
| 240 |
+
# multi-init means we would need to check platform same each time...
|
| 241 |
+
assert not self.initialized, "don't init multiple times"
|
| 242 |
+
if plat_name is None:
|
| 243 |
+
plat_name = get_platform()
|
| 244 |
+
# sanity check for platforms to prevent obscure errors later.
|
| 245 |
+
if plat_name not in PLAT_TO_VCVARS:
|
| 246 |
+
raise DistutilsPlatformError(
|
| 247 |
+
f"--plat-name must be one of {tuple(PLAT_TO_VCVARS)}"
|
| 248 |
+
)
|
| 249 |
+
|
| 250 |
+
# Get the vcvarsall.bat spec for the requested platform.
|
| 251 |
+
plat_spec = PLAT_TO_VCVARS[plat_name]
|
| 252 |
+
|
| 253 |
+
vc_env = _get_vc_env(plat_spec)
|
| 254 |
+
if not vc_env:
|
| 255 |
+
raise DistutilsPlatformError(
|
| 256 |
+
"Unable to find a compatible " "Visual Studio installation."
|
| 257 |
+
)
|
| 258 |
+
self._configure(vc_env)
|
| 259 |
+
|
| 260 |
+
self._paths = vc_env.get('path', '')
|
| 261 |
+
paths = self._paths.split(os.pathsep)
|
| 262 |
+
self.cc = _find_exe("cl.exe", paths)
|
| 263 |
+
self.linker = _find_exe("link.exe", paths)
|
| 264 |
+
self.lib = _find_exe("lib.exe", paths)
|
| 265 |
+
self.rc = _find_exe("rc.exe", paths) # resource compiler
|
| 266 |
+
self.mc = _find_exe("mc.exe", paths) # message compiler
|
| 267 |
+
self.mt = _find_exe("mt.exe", paths) # message compiler
|
| 268 |
+
|
| 269 |
+
self.preprocess_options = None
|
| 270 |
+
# bpo-38597: Always compile with dynamic linking
|
| 271 |
+
# Future releases of Python 3.x will include all past
|
| 272 |
+
# versions of vcruntime*.dll for compatibility.
|
| 273 |
+
self.compile_options = ['/nologo', '/O2', '/W3', '/GL', '/DNDEBUG', '/MD']
|
| 274 |
+
|
| 275 |
+
self.compile_options_debug = [
|
| 276 |
+
'/nologo',
|
| 277 |
+
'/Od',
|
| 278 |
+
'/MDd',
|
| 279 |
+
'/Zi',
|
| 280 |
+
'/W3',
|
| 281 |
+
'/D_DEBUG',
|
| 282 |
+
]
|
| 283 |
+
|
| 284 |
+
ldflags = ['/nologo', '/INCREMENTAL:NO', '/LTCG']
|
| 285 |
+
|
| 286 |
+
ldflags_debug = ['/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL']
|
| 287 |
+
|
| 288 |
+
self.ldflags_exe = [*ldflags, '/MANIFEST:EMBED,ID=1']
|
| 289 |
+
self.ldflags_exe_debug = [*ldflags_debug, '/MANIFEST:EMBED,ID=1']
|
| 290 |
+
self.ldflags_shared = [
|
| 291 |
+
*ldflags,
|
| 292 |
+
'/DLL',
|
| 293 |
+
'/MANIFEST:EMBED,ID=2',
|
| 294 |
+
'/MANIFESTUAC:NO',
|
| 295 |
+
]
|
| 296 |
+
self.ldflags_shared_debug = [
|
| 297 |
+
*ldflags_debug,
|
| 298 |
+
'/DLL',
|
| 299 |
+
'/MANIFEST:EMBED,ID=2',
|
| 300 |
+
'/MANIFESTUAC:NO',
|
| 301 |
+
]
|
| 302 |
+
self.ldflags_static = [*ldflags]
|
| 303 |
+
self.ldflags_static_debug = [*ldflags_debug]
|
| 304 |
+
|
| 305 |
+
self._ldflags = {
|
| 306 |
+
(CCompiler.EXECUTABLE, None): self.ldflags_exe,
|
| 307 |
+
(CCompiler.EXECUTABLE, False): self.ldflags_exe,
|
| 308 |
+
(CCompiler.EXECUTABLE, True): self.ldflags_exe_debug,
|
| 309 |
+
(CCompiler.SHARED_OBJECT, None): self.ldflags_shared,
|
| 310 |
+
(CCompiler.SHARED_OBJECT, False): self.ldflags_shared,
|
| 311 |
+
(CCompiler.SHARED_OBJECT, True): self.ldflags_shared_debug,
|
| 312 |
+
(CCompiler.SHARED_LIBRARY, None): self.ldflags_static,
|
| 313 |
+
(CCompiler.SHARED_LIBRARY, False): self.ldflags_static,
|
| 314 |
+
(CCompiler.SHARED_LIBRARY, True): self.ldflags_static_debug,
|
| 315 |
+
}
|
| 316 |
+
|
| 317 |
+
self.initialized = True
|
| 318 |
+
|
| 319 |
+
# -- Worker methods ------------------------------------------------
|
| 320 |
+
|
| 321 |
+
@property
|
| 322 |
+
def out_extensions(self):
|
| 323 |
+
return {
|
| 324 |
+
**super().out_extensions,
|
| 325 |
+
**{
|
| 326 |
+
ext: self.res_extension
|
| 327 |
+
for ext in self._rc_extensions + self._mc_extensions
|
| 328 |
+
},
|
| 329 |
+
}
|
| 330 |
+
|
| 331 |
+
def compile( # noqa: C901
|
| 332 |
+
self,
|
| 333 |
+
sources,
|
| 334 |
+
output_dir=None,
|
| 335 |
+
macros=None,
|
| 336 |
+
include_dirs=None,
|
| 337 |
+
debug=0,
|
| 338 |
+
extra_preargs=None,
|
| 339 |
+
extra_postargs=None,
|
| 340 |
+
depends=None,
|
| 341 |
+
):
|
| 342 |
+
|
| 343 |
+
if not self.initialized:
|
| 344 |
+
self.initialize()
|
| 345 |
+
compile_info = self._setup_compile(
|
| 346 |
+
output_dir, macros, include_dirs, sources, depends, extra_postargs
|
| 347 |
+
)
|
| 348 |
+
macros, objects, extra_postargs, pp_opts, build = compile_info
|
| 349 |
+
|
| 350 |
+
compile_opts = extra_preargs or []
|
| 351 |
+
compile_opts.append('/c')
|
| 352 |
+
if debug:
|
| 353 |
+
compile_opts.extend(self.compile_options_debug)
|
| 354 |
+
else:
|
| 355 |
+
compile_opts.extend(self.compile_options)
|
| 356 |
+
|
| 357 |
+
add_cpp_opts = False
|
| 358 |
+
|
| 359 |
+
for obj in objects:
|
| 360 |
+
try:
|
| 361 |
+
src, ext = build[obj]
|
| 362 |
+
except KeyError:
|
| 363 |
+
continue
|
| 364 |
+
if debug:
|
| 365 |
+
# pass the full pathname to MSVC in debug mode,
|
| 366 |
+
# this allows the debugger to find the source file
|
| 367 |
+
# without asking the user to browse for it
|
| 368 |
+
src = os.path.abspath(src)
|
| 369 |
+
|
| 370 |
+
if ext in self._c_extensions:
|
| 371 |
+
input_opt = "/Tc" + src
|
| 372 |
+
elif ext in self._cpp_extensions:
|
| 373 |
+
input_opt = "/Tp" + src
|
| 374 |
+
add_cpp_opts = True
|
| 375 |
+
elif ext in self._rc_extensions:
|
| 376 |
+
# compile .RC to .RES file
|
| 377 |
+
input_opt = src
|
| 378 |
+
output_opt = "/fo" + obj
|
| 379 |
+
try:
|
| 380 |
+
self.spawn([self.rc] + pp_opts + [output_opt, input_opt])
|
| 381 |
+
except DistutilsExecError as msg:
|
| 382 |
+
raise CompileError(msg)
|
| 383 |
+
continue
|
| 384 |
+
elif ext in self._mc_extensions:
|
| 385 |
+
# Compile .MC to .RC file to .RES file.
|
| 386 |
+
# * '-h dir' specifies the directory for the
|
| 387 |
+
# generated include file
|
| 388 |
+
# * '-r dir' specifies the target directory of the
|
| 389 |
+
# generated RC file and the binary message resource
|
| 390 |
+
# it includes
|
| 391 |
+
#
|
| 392 |
+
# For now (since there are no options to change this),
|
| 393 |
+
# we use the source-directory for the include file and
|
| 394 |
+
# the build directory for the RC file and message
|
| 395 |
+
# resources. This works at least for win32all.
|
| 396 |
+
h_dir = os.path.dirname(src)
|
| 397 |
+
rc_dir = os.path.dirname(obj)
|
| 398 |
+
try:
|
| 399 |
+
# first compile .MC to .RC and .H file
|
| 400 |
+
self.spawn([self.mc, '-h', h_dir, '-r', rc_dir, src])
|
| 401 |
+
base, _ = os.path.splitext(os.path.basename(src))
|
| 402 |
+
rc_file = os.path.join(rc_dir, base + '.rc')
|
| 403 |
+
# then compile .RC to .RES file
|
| 404 |
+
self.spawn([self.rc, "/fo" + obj, rc_file])
|
| 405 |
+
|
| 406 |
+
except DistutilsExecError as msg:
|
| 407 |
+
raise CompileError(msg)
|
| 408 |
+
continue
|
| 409 |
+
else:
|
| 410 |
+
# how to handle this file?
|
| 411 |
+
raise CompileError(f"Don't know how to compile {src} to {obj}")
|
| 412 |
+
|
| 413 |
+
args = [self.cc] + compile_opts + pp_opts
|
| 414 |
+
if add_cpp_opts:
|
| 415 |
+
args.append('/EHsc')
|
| 416 |
+
args.append(input_opt)
|
| 417 |
+
args.append("/Fo" + obj)
|
| 418 |
+
args.extend(extra_postargs)
|
| 419 |
+
|
| 420 |
+
try:
|
| 421 |
+
self.spawn(args)
|
| 422 |
+
except DistutilsExecError as msg:
|
| 423 |
+
raise CompileError(msg)
|
| 424 |
+
|
| 425 |
+
return objects
|
| 426 |
+
|
| 427 |
+
def create_static_lib(
|
| 428 |
+
self, objects, output_libname, output_dir=None, debug=0, target_lang=None
|
| 429 |
+
):
|
| 430 |
+
|
| 431 |
+
if not self.initialized:
|
| 432 |
+
self.initialize()
|
| 433 |
+
objects, output_dir = self._fix_object_args(objects, output_dir)
|
| 434 |
+
output_filename = self.library_filename(output_libname, output_dir=output_dir)
|
| 435 |
+
|
| 436 |
+
if self._need_link(objects, output_filename):
|
| 437 |
+
lib_args = objects + ['/OUT:' + output_filename]
|
| 438 |
+
if debug:
|
| 439 |
+
pass # XXX what goes here?
|
| 440 |
+
try:
|
| 441 |
+
log.debug('Executing "%s" %s', self.lib, ' '.join(lib_args))
|
| 442 |
+
self.spawn([self.lib] + lib_args)
|
| 443 |
+
except DistutilsExecError as msg:
|
| 444 |
+
raise LibError(msg)
|
| 445 |
+
else:
|
| 446 |
+
log.debug("skipping %s (up-to-date)", output_filename)
|
| 447 |
+
|
| 448 |
+
def link(
|
| 449 |
+
self,
|
| 450 |
+
target_desc,
|
| 451 |
+
objects,
|
| 452 |
+
output_filename,
|
| 453 |
+
output_dir=None,
|
| 454 |
+
libraries=None,
|
| 455 |
+
library_dirs=None,
|
| 456 |
+
runtime_library_dirs=None,
|
| 457 |
+
export_symbols=None,
|
| 458 |
+
debug=0,
|
| 459 |
+
extra_preargs=None,
|
| 460 |
+
extra_postargs=None,
|
| 461 |
+
build_temp=None,
|
| 462 |
+
target_lang=None,
|
| 463 |
+
):
|
| 464 |
+
|
| 465 |
+
if not self.initialized:
|
| 466 |
+
self.initialize()
|
| 467 |
+
objects, output_dir = self._fix_object_args(objects, output_dir)
|
| 468 |
+
fixed_args = self._fix_lib_args(libraries, library_dirs, runtime_library_dirs)
|
| 469 |
+
libraries, library_dirs, runtime_library_dirs = fixed_args
|
| 470 |
+
|
| 471 |
+
if runtime_library_dirs:
|
| 472 |
+
self.warn(
|
| 473 |
+
"I don't know what to do with 'runtime_library_dirs': "
|
| 474 |
+
+ str(runtime_library_dirs)
|
| 475 |
+
)
|
| 476 |
+
|
| 477 |
+
lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs, libraries)
|
| 478 |
+
if output_dir is not None:
|
| 479 |
+
output_filename = os.path.join(output_dir, output_filename)
|
| 480 |
+
|
| 481 |
+
if self._need_link(objects, output_filename):
|
| 482 |
+
ldflags = self._ldflags[target_desc, debug]
|
| 483 |
+
|
| 484 |
+
export_opts = ["/EXPORT:" + sym for sym in (export_symbols or [])]
|
| 485 |
+
|
| 486 |
+
ld_args = (
|
| 487 |
+
ldflags + lib_opts + export_opts + objects + ['/OUT:' + output_filename]
|
| 488 |
+
)
|
| 489 |
+
|
| 490 |
+
# The MSVC linker generates .lib and .exp files, which cannot be
|
| 491 |
+
# suppressed by any linker switches. The .lib files may even be
|
| 492 |
+
# needed! Make sure they are generated in the temporary build
|
| 493 |
+
# directory. Since they have different names for debug and release
|
| 494 |
+
# builds, they can go into the same directory.
|
| 495 |
+
build_temp = os.path.dirname(objects[0])
|
| 496 |
+
if export_symbols is not None:
|
| 497 |
+
(dll_name, dll_ext) = os.path.splitext(
|
| 498 |
+
os.path.basename(output_filename)
|
| 499 |
+
)
|
| 500 |
+
implib_file = os.path.join(build_temp, self.library_filename(dll_name))
|
| 501 |
+
ld_args.append('/IMPLIB:' + implib_file)
|
| 502 |
+
|
| 503 |
+
if extra_preargs:
|
| 504 |
+
ld_args[:0] = extra_preargs
|
| 505 |
+
if extra_postargs:
|
| 506 |
+
ld_args.extend(extra_postargs)
|
| 507 |
+
|
| 508 |
+
output_dir = os.path.dirname(os.path.abspath(output_filename))
|
| 509 |
+
self.mkpath(output_dir)
|
| 510 |
+
try:
|
| 511 |
+
log.debug('Executing "%s" %s', self.linker, ' '.join(ld_args))
|
| 512 |
+
self.spawn([self.linker] + ld_args)
|
| 513 |
+
except DistutilsExecError as msg:
|
| 514 |
+
raise LinkError(msg)
|
| 515 |
+
else:
|
| 516 |
+
log.debug("skipping %s (up-to-date)", output_filename)
|
| 517 |
+
|
| 518 |
+
def spawn(self, cmd):
|
| 519 |
+
env = dict(os.environ, PATH=self._paths)
|
| 520 |
+
with self._fallback_spawn(cmd, env) as fallback:
|
| 521 |
+
return super().spawn(cmd, env=env)
|
| 522 |
+
return fallback.value
|
| 523 |
+
|
| 524 |
+
@contextlib.contextmanager
|
| 525 |
+
def _fallback_spawn(self, cmd, env):
|
| 526 |
+
"""
|
| 527 |
+
Discovered in pypa/distutils#15, some tools monkeypatch the compiler,
|
| 528 |
+
so the 'env' kwarg causes a TypeError. Detect this condition and
|
| 529 |
+
restore the legacy, unsafe behavior.
|
| 530 |
+
"""
|
| 531 |
+
bag = type('Bag', (), {})()
|
| 532 |
+
try:
|
| 533 |
+
yield bag
|
| 534 |
+
except TypeError as exc:
|
| 535 |
+
if "unexpected keyword argument 'env'" not in str(exc):
|
| 536 |
+
raise
|
| 537 |
+
else:
|
| 538 |
+
return
|
| 539 |
+
warnings.warn("Fallback spawn triggered. Please update distutils monkeypatch.")
|
| 540 |
+
with mock.patch.dict('os.environ', env):
|
| 541 |
+
bag.value = super().spawn(cmd)
|
| 542 |
+
|
| 543 |
+
# -- Miscellaneous methods -----------------------------------------
|
| 544 |
+
# These are all used by the 'gen_lib_options() function, in
|
| 545 |
+
# ccompiler.py.
|
| 546 |
+
|
| 547 |
+
def library_dir_option(self, dir):
|
| 548 |
+
return "/LIBPATH:" + dir
|
| 549 |
+
|
| 550 |
+
def runtime_library_dir_option(self, dir):
|
| 551 |
+
raise DistutilsPlatformError(
|
| 552 |
+
"don't know how to set runtime library search path for MSVC"
|
| 553 |
+
)
|
| 554 |
+
|
| 555 |
+
def library_option(self, lib):
|
| 556 |
+
return self.library_filename(lib)
|
| 557 |
+
|
| 558 |
+
def find_library_file(self, dirs, lib, debug=0):
|
| 559 |
+
# Prefer a debugging library if found (and requested), but deal
|
| 560 |
+
# with it if we don't have one.
|
| 561 |
+
if debug:
|
| 562 |
+
try_names = [lib + "_d", lib]
|
| 563 |
+
else:
|
| 564 |
+
try_names = [lib]
|
| 565 |
+
for dir in dirs:
|
| 566 |
+
for name in try_names:
|
| 567 |
+
libfile = os.path.join(dir, self.library_filename(name))
|
| 568 |
+
if os.path.isfile(libfile):
|
| 569 |
+
return libfile
|
| 570 |
+
else:
|
| 571 |
+
# Oops, didn't find it in *any* of 'dirs'
|
| 572 |
+
return None
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/archive_util.py
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""distutils.archive_util
|
| 2 |
+
|
| 3 |
+
Utility functions for creating archive files (tarballs, zip files,
|
| 4 |
+
that sort of thing)."""
|
| 5 |
+
|
| 6 |
+
import os
|
| 7 |
+
from warnings import warn
|
| 8 |
+
import sys
|
| 9 |
+
|
| 10 |
+
try:
|
| 11 |
+
import zipfile
|
| 12 |
+
except ImportError:
|
| 13 |
+
zipfile = None
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
from distutils.errors import DistutilsExecError
|
| 17 |
+
from distutils.spawn import spawn
|
| 18 |
+
from distutils.dir_util import mkpath
|
| 19 |
+
from distutils import log
|
| 20 |
+
|
| 21 |
+
try:
|
| 22 |
+
from pwd import getpwnam
|
| 23 |
+
except ImportError:
|
| 24 |
+
getpwnam = None
|
| 25 |
+
|
| 26 |
+
try:
|
| 27 |
+
from grp import getgrnam
|
| 28 |
+
except ImportError:
|
| 29 |
+
getgrnam = None
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def _get_gid(name):
|
| 33 |
+
"""Returns a gid, given a group name."""
|
| 34 |
+
if getgrnam is None or name is None:
|
| 35 |
+
return None
|
| 36 |
+
try:
|
| 37 |
+
result = getgrnam(name)
|
| 38 |
+
except KeyError:
|
| 39 |
+
result = None
|
| 40 |
+
if result is not None:
|
| 41 |
+
return result[2]
|
| 42 |
+
return None
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def _get_uid(name):
|
| 46 |
+
"""Returns an uid, given a user name."""
|
| 47 |
+
if getpwnam is None or name is None:
|
| 48 |
+
return None
|
| 49 |
+
try:
|
| 50 |
+
result = getpwnam(name)
|
| 51 |
+
except KeyError:
|
| 52 |
+
result = None
|
| 53 |
+
if result is not None:
|
| 54 |
+
return result[2]
|
| 55 |
+
return None
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def make_tarball(
|
| 59 |
+
base_name, base_dir, compress="gzip", verbose=0, dry_run=0, owner=None, group=None
|
| 60 |
+
):
|
| 61 |
+
"""Create a (possibly compressed) tar file from all the files under
|
| 62 |
+
'base_dir'.
|
| 63 |
+
|
| 64 |
+
'compress' must be "gzip" (the default), "bzip2", "xz", "compress", or
|
| 65 |
+
None. ("compress" will be deprecated in Python 3.2)
|
| 66 |
+
|
| 67 |
+
'owner' and 'group' can be used to define an owner and a group for the
|
| 68 |
+
archive that is being built. If not provided, the current owner and group
|
| 69 |
+
will be used.
|
| 70 |
+
|
| 71 |
+
The output tar file will be named 'base_dir' + ".tar", possibly plus
|
| 72 |
+
the appropriate compression extension (".gz", ".bz2", ".xz" or ".Z").
|
| 73 |
+
|
| 74 |
+
Returns the output filename.
|
| 75 |
+
"""
|
| 76 |
+
tar_compression = {
|
| 77 |
+
'gzip': 'gz',
|
| 78 |
+
'bzip2': 'bz2',
|
| 79 |
+
'xz': 'xz',
|
| 80 |
+
None: '',
|
| 81 |
+
'compress': '',
|
| 82 |
+
}
|
| 83 |
+
compress_ext = {'gzip': '.gz', 'bzip2': '.bz2', 'xz': '.xz', 'compress': '.Z'}
|
| 84 |
+
|
| 85 |
+
# flags for compression program, each element of list will be an argument
|
| 86 |
+
if compress is not None and compress not in compress_ext.keys():
|
| 87 |
+
raise ValueError(
|
| 88 |
+
"bad value for 'compress': must be None, 'gzip', 'bzip2', "
|
| 89 |
+
"'xz' or 'compress'"
|
| 90 |
+
)
|
| 91 |
+
|
| 92 |
+
archive_name = base_name + '.tar'
|
| 93 |
+
if compress != 'compress':
|
| 94 |
+
archive_name += compress_ext.get(compress, '')
|
| 95 |
+
|
| 96 |
+
mkpath(os.path.dirname(archive_name), dry_run=dry_run)
|
| 97 |
+
|
| 98 |
+
# creating the tarball
|
| 99 |
+
import tarfile # late import so Python build itself doesn't break
|
| 100 |
+
|
| 101 |
+
log.info('Creating tar archive')
|
| 102 |
+
|
| 103 |
+
uid = _get_uid(owner)
|
| 104 |
+
gid = _get_gid(group)
|
| 105 |
+
|
| 106 |
+
def _set_uid_gid(tarinfo):
|
| 107 |
+
if gid is not None:
|
| 108 |
+
tarinfo.gid = gid
|
| 109 |
+
tarinfo.gname = group
|
| 110 |
+
if uid is not None:
|
| 111 |
+
tarinfo.uid = uid
|
| 112 |
+
tarinfo.uname = owner
|
| 113 |
+
return tarinfo
|
| 114 |
+
|
| 115 |
+
if not dry_run:
|
| 116 |
+
tar = tarfile.open(archive_name, 'w|%s' % tar_compression[compress])
|
| 117 |
+
try:
|
| 118 |
+
tar.add(base_dir, filter=_set_uid_gid)
|
| 119 |
+
finally:
|
| 120 |
+
tar.close()
|
| 121 |
+
|
| 122 |
+
# compression using `compress`
|
| 123 |
+
if compress == 'compress':
|
| 124 |
+
warn("'compress' is deprecated.", DeprecationWarning)
|
| 125 |
+
# the option varies depending on the platform
|
| 126 |
+
compressed_name = archive_name + compress_ext[compress]
|
| 127 |
+
if sys.platform == 'win32':
|
| 128 |
+
cmd = [compress, archive_name, compressed_name]
|
| 129 |
+
else:
|
| 130 |
+
cmd = [compress, '-f', archive_name]
|
| 131 |
+
spawn(cmd, dry_run=dry_run)
|
| 132 |
+
return compressed_name
|
| 133 |
+
|
| 134 |
+
return archive_name
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
def make_zipfile(base_name, base_dir, verbose=0, dry_run=0): # noqa: C901
|
| 138 |
+
"""Create a zip file from all the files under 'base_dir'.
|
| 139 |
+
|
| 140 |
+
The output zip file will be named 'base_name' + ".zip". Uses either the
|
| 141 |
+
"zipfile" Python module (if available) or the InfoZIP "zip" utility
|
| 142 |
+
(if installed and found on the default search path). If neither tool is
|
| 143 |
+
available, raises DistutilsExecError. Returns the name of the output zip
|
| 144 |
+
file.
|
| 145 |
+
"""
|
| 146 |
+
zip_filename = base_name + ".zip"
|
| 147 |
+
mkpath(os.path.dirname(zip_filename), dry_run=dry_run)
|
| 148 |
+
|
| 149 |
+
# If zipfile module is not available, try spawning an external
|
| 150 |
+
# 'zip' command.
|
| 151 |
+
if zipfile is None:
|
| 152 |
+
if verbose:
|
| 153 |
+
zipoptions = "-r"
|
| 154 |
+
else:
|
| 155 |
+
zipoptions = "-rq"
|
| 156 |
+
|
| 157 |
+
try:
|
| 158 |
+
spawn(["zip", zipoptions, zip_filename, base_dir], dry_run=dry_run)
|
| 159 |
+
except DistutilsExecError:
|
| 160 |
+
# XXX really should distinguish between "couldn't find
|
| 161 |
+
# external 'zip' command" and "zip failed".
|
| 162 |
+
raise DistutilsExecError(
|
| 163 |
+
(
|
| 164 |
+
"unable to create zip file '%s': "
|
| 165 |
+
"could neither import the 'zipfile' module nor "
|
| 166 |
+
"find a standalone zip utility"
|
| 167 |
+
)
|
| 168 |
+
% zip_filename
|
| 169 |
+
)
|
| 170 |
+
|
| 171 |
+
else:
|
| 172 |
+
log.info("creating '%s' and adding '%s' to it", zip_filename, base_dir)
|
| 173 |
+
|
| 174 |
+
if not dry_run:
|
| 175 |
+
try:
|
| 176 |
+
zip = zipfile.ZipFile(
|
| 177 |
+
zip_filename, "w", compression=zipfile.ZIP_DEFLATED
|
| 178 |
+
)
|
| 179 |
+
except RuntimeError:
|
| 180 |
+
zip = zipfile.ZipFile(zip_filename, "w", compression=zipfile.ZIP_STORED)
|
| 181 |
+
|
| 182 |
+
with zip:
|
| 183 |
+
if base_dir != os.curdir:
|
| 184 |
+
path = os.path.normpath(os.path.join(base_dir, ''))
|
| 185 |
+
zip.write(path, path)
|
| 186 |
+
log.info("adding '%s'", path)
|
| 187 |
+
for dirpath, dirnames, filenames in os.walk(base_dir):
|
| 188 |
+
for name in dirnames:
|
| 189 |
+
path = os.path.normpath(os.path.join(dirpath, name, ''))
|
| 190 |
+
zip.write(path, path)
|
| 191 |
+
log.info("adding '%s'", path)
|
| 192 |
+
for name in filenames:
|
| 193 |
+
path = os.path.normpath(os.path.join(dirpath, name))
|
| 194 |
+
if os.path.isfile(path):
|
| 195 |
+
zip.write(path, path)
|
| 196 |
+
log.info("adding '%s'", path)
|
| 197 |
+
|
| 198 |
+
return zip_filename
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
ARCHIVE_FORMATS = {
|
| 202 |
+
'gztar': (make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"),
|
| 203 |
+
'bztar': (make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"),
|
| 204 |
+
'xztar': (make_tarball, [('compress', 'xz')], "xz'ed tar-file"),
|
| 205 |
+
'ztar': (make_tarball, [('compress', 'compress')], "compressed tar file"),
|
| 206 |
+
'tar': (make_tarball, [('compress', None)], "uncompressed tar file"),
|
| 207 |
+
'zip': (make_zipfile, [], "ZIP file"),
|
| 208 |
+
}
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
def check_archive_formats(formats):
|
| 212 |
+
"""Returns the first format from the 'format' list that is unknown.
|
| 213 |
+
|
| 214 |
+
If all formats are known, returns None
|
| 215 |
+
"""
|
| 216 |
+
for format in formats:
|
| 217 |
+
if format not in ARCHIVE_FORMATS:
|
| 218 |
+
return format
|
| 219 |
+
return None
|
| 220 |
+
|
| 221 |
+
|
| 222 |
+
def make_archive(
|
| 223 |
+
base_name,
|
| 224 |
+
format,
|
| 225 |
+
root_dir=None,
|
| 226 |
+
base_dir=None,
|
| 227 |
+
verbose=0,
|
| 228 |
+
dry_run=0,
|
| 229 |
+
owner=None,
|
| 230 |
+
group=None,
|
| 231 |
+
):
|
| 232 |
+
"""Create an archive file (eg. zip or tar).
|
| 233 |
+
|
| 234 |
+
'base_name' is the name of the file to create, minus any format-specific
|
| 235 |
+
extension; 'format' is the archive format: one of "zip", "tar", "gztar",
|
| 236 |
+
"bztar", "xztar", or "ztar".
|
| 237 |
+
|
| 238 |
+
'root_dir' is a directory that will be the root directory of the
|
| 239 |
+
archive; ie. we typically chdir into 'root_dir' before creating the
|
| 240 |
+
archive. 'base_dir' is the directory where we start archiving from;
|
| 241 |
+
ie. 'base_dir' will be the common prefix of all files and
|
| 242 |
+
directories in the archive. 'root_dir' and 'base_dir' both default
|
| 243 |
+
to the current directory. Returns the name of the archive file.
|
| 244 |
+
|
| 245 |
+
'owner' and 'group' are used when creating a tar archive. By default,
|
| 246 |
+
uses the current owner and group.
|
| 247 |
+
"""
|
| 248 |
+
save_cwd = os.getcwd()
|
| 249 |
+
if root_dir is not None:
|
| 250 |
+
log.debug("changing into '%s'", root_dir)
|
| 251 |
+
base_name = os.path.abspath(base_name)
|
| 252 |
+
if not dry_run:
|
| 253 |
+
os.chdir(root_dir)
|
| 254 |
+
|
| 255 |
+
if base_dir is None:
|
| 256 |
+
base_dir = os.curdir
|
| 257 |
+
|
| 258 |
+
kwargs = {'dry_run': dry_run}
|
| 259 |
+
|
| 260 |
+
try:
|
| 261 |
+
format_info = ARCHIVE_FORMATS[format]
|
| 262 |
+
except KeyError:
|
| 263 |
+
raise ValueError("unknown archive format '%s'" % format)
|
| 264 |
+
|
| 265 |
+
func = format_info[0]
|
| 266 |
+
for arg, val in format_info[1]:
|
| 267 |
+
kwargs[arg] = val
|
| 268 |
+
|
| 269 |
+
if format != 'zip':
|
| 270 |
+
kwargs['owner'] = owner
|
| 271 |
+
kwargs['group'] = group
|
| 272 |
+
|
| 273 |
+
try:
|
| 274 |
+
filename = func(base_name, base_dir, **kwargs)
|
| 275 |
+
finally:
|
| 276 |
+
if root_dir is not None:
|
| 277 |
+
log.debug("changing back to '%s'", save_cwd)
|
| 278 |
+
os.chdir(save_cwd)
|
| 279 |
+
|
| 280 |
+
return filename
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/bcppcompiler.py
ADDED
|
@@ -0,0 +1,408 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""distutils.bcppcompiler
|
| 2 |
+
|
| 3 |
+
Contains BorlandCCompiler, an implementation of the abstract CCompiler class
|
| 4 |
+
for the Borland C++ compiler.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
# This implementation by Lyle Johnson, based on the original msvccompiler.py
|
| 8 |
+
# module and using the directions originally published by Gordon Williams.
|
| 9 |
+
|
| 10 |
+
# XXX looks like there's a LOT of overlap between these two classes:
|
| 11 |
+
# someone should sit down and factor out the common code as
|
| 12 |
+
# WindowsCCompiler! --GPW
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
import os
|
| 16 |
+
import warnings
|
| 17 |
+
|
| 18 |
+
from distutils.errors import (
|
| 19 |
+
DistutilsExecError,
|
| 20 |
+
CompileError,
|
| 21 |
+
LibError,
|
| 22 |
+
LinkError,
|
| 23 |
+
UnknownFileError,
|
| 24 |
+
)
|
| 25 |
+
from distutils.ccompiler import CCompiler, gen_preprocess_options
|
| 26 |
+
from distutils.file_util import write_file
|
| 27 |
+
from distutils.dep_util import newer
|
| 28 |
+
from distutils import log
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
warnings.warn(
|
| 32 |
+
"bcppcompiler is deprecated and slated to be removed "
|
| 33 |
+
"in the future. Please discontinue use or file an issue "
|
| 34 |
+
"with pypa/distutils describing your use case.",
|
| 35 |
+
DeprecationWarning,
|
| 36 |
+
)
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
class BCPPCompiler(CCompiler):
|
| 40 |
+
"""Concrete class that implements an interface to the Borland C/C++
|
| 41 |
+
compiler, as defined by the CCompiler abstract class.
|
| 42 |
+
"""
|
| 43 |
+
|
| 44 |
+
compiler_type = 'bcpp'
|
| 45 |
+
|
| 46 |
+
# Just set this so CCompiler's constructor doesn't barf. We currently
|
| 47 |
+
# don't use the 'set_executables()' bureaucracy provided by CCompiler,
|
| 48 |
+
# as it really isn't necessary for this sort of single-compiler class.
|
| 49 |
+
# Would be nice to have a consistent interface with UnixCCompiler,
|
| 50 |
+
# though, so it's worth thinking about.
|
| 51 |
+
executables = {}
|
| 52 |
+
|
| 53 |
+
# Private class data (need to distinguish C from C++ source for compiler)
|
| 54 |
+
_c_extensions = ['.c']
|
| 55 |
+
_cpp_extensions = ['.cc', '.cpp', '.cxx']
|
| 56 |
+
|
| 57 |
+
# Needed for the filename generation methods provided by the
|
| 58 |
+
# base class, CCompiler.
|
| 59 |
+
src_extensions = _c_extensions + _cpp_extensions
|
| 60 |
+
obj_extension = '.obj'
|
| 61 |
+
static_lib_extension = '.lib'
|
| 62 |
+
shared_lib_extension = '.dll'
|
| 63 |
+
static_lib_format = shared_lib_format = '%s%s'
|
| 64 |
+
exe_extension = '.exe'
|
| 65 |
+
|
| 66 |
+
def __init__(self, verbose=0, dry_run=0, force=0):
|
| 67 |
+
|
| 68 |
+
super().__init__(verbose, dry_run, force)
|
| 69 |
+
|
| 70 |
+
# These executables are assumed to all be in the path.
|
| 71 |
+
# Borland doesn't seem to use any special registry settings to
|
| 72 |
+
# indicate their installation locations.
|
| 73 |
+
|
| 74 |
+
self.cc = "bcc32.exe"
|
| 75 |
+
self.linker = "ilink32.exe"
|
| 76 |
+
self.lib = "tlib.exe"
|
| 77 |
+
|
| 78 |
+
self.preprocess_options = None
|
| 79 |
+
self.compile_options = ['/tWM', '/O2', '/q', '/g0']
|
| 80 |
+
self.compile_options_debug = ['/tWM', '/Od', '/q', '/g0']
|
| 81 |
+
|
| 82 |
+
self.ldflags_shared = ['/Tpd', '/Gn', '/q', '/x']
|
| 83 |
+
self.ldflags_shared_debug = ['/Tpd', '/Gn', '/q', '/x']
|
| 84 |
+
self.ldflags_static = []
|
| 85 |
+
self.ldflags_exe = ['/Gn', '/q', '/x']
|
| 86 |
+
self.ldflags_exe_debug = ['/Gn', '/q', '/x', '/r']
|
| 87 |
+
|
| 88 |
+
# -- Worker methods ------------------------------------------------
|
| 89 |
+
|
| 90 |
+
def compile( # noqa: C901
|
| 91 |
+
self,
|
| 92 |
+
sources,
|
| 93 |
+
output_dir=None,
|
| 94 |
+
macros=None,
|
| 95 |
+
include_dirs=None,
|
| 96 |
+
debug=0,
|
| 97 |
+
extra_preargs=None,
|
| 98 |
+
extra_postargs=None,
|
| 99 |
+
depends=None,
|
| 100 |
+
):
|
| 101 |
+
|
| 102 |
+
macros, objects, extra_postargs, pp_opts, build = self._setup_compile(
|
| 103 |
+
output_dir, macros, include_dirs, sources, depends, extra_postargs
|
| 104 |
+
)
|
| 105 |
+
compile_opts = extra_preargs or []
|
| 106 |
+
compile_opts.append('-c')
|
| 107 |
+
if debug:
|
| 108 |
+
compile_opts.extend(self.compile_options_debug)
|
| 109 |
+
else:
|
| 110 |
+
compile_opts.extend(self.compile_options)
|
| 111 |
+
|
| 112 |
+
for obj in objects:
|
| 113 |
+
try:
|
| 114 |
+
src, ext = build[obj]
|
| 115 |
+
except KeyError:
|
| 116 |
+
continue
|
| 117 |
+
# XXX why do the normpath here?
|
| 118 |
+
src = os.path.normpath(src)
|
| 119 |
+
obj = os.path.normpath(obj)
|
| 120 |
+
# XXX _setup_compile() did a mkpath() too but before the normpath.
|
| 121 |
+
# Is it possible to skip the normpath?
|
| 122 |
+
self.mkpath(os.path.dirname(obj))
|
| 123 |
+
|
| 124 |
+
if ext == '.res':
|
| 125 |
+
# This is already a binary file -- skip it.
|
| 126 |
+
continue # the 'for' loop
|
| 127 |
+
if ext == '.rc':
|
| 128 |
+
# This needs to be compiled to a .res file -- do it now.
|
| 129 |
+
try:
|
| 130 |
+
self.spawn(["brcc32", "-fo", obj, src])
|
| 131 |
+
except DistutilsExecError as msg:
|
| 132 |
+
raise CompileError(msg)
|
| 133 |
+
continue # the 'for' loop
|
| 134 |
+
|
| 135 |
+
# The next two are both for the real compiler.
|
| 136 |
+
if ext in self._c_extensions:
|
| 137 |
+
input_opt = ""
|
| 138 |
+
elif ext in self._cpp_extensions:
|
| 139 |
+
input_opt = "-P"
|
| 140 |
+
else:
|
| 141 |
+
# Unknown file type -- no extra options. The compiler
|
| 142 |
+
# will probably fail, but let it just in case this is a
|
| 143 |
+
# file the compiler recognizes even if we don't.
|
| 144 |
+
input_opt = ""
|
| 145 |
+
|
| 146 |
+
output_opt = "-o" + obj
|
| 147 |
+
|
| 148 |
+
# Compiler command line syntax is: "bcc32 [options] file(s)".
|
| 149 |
+
# Note that the source file names must appear at the end of
|
| 150 |
+
# the command line.
|
| 151 |
+
try:
|
| 152 |
+
self.spawn(
|
| 153 |
+
[self.cc]
|
| 154 |
+
+ compile_opts
|
| 155 |
+
+ pp_opts
|
| 156 |
+
+ [input_opt, output_opt]
|
| 157 |
+
+ extra_postargs
|
| 158 |
+
+ [src]
|
| 159 |
+
)
|
| 160 |
+
except DistutilsExecError as msg:
|
| 161 |
+
raise CompileError(msg)
|
| 162 |
+
|
| 163 |
+
return objects
|
| 164 |
+
|
| 165 |
+
# compile ()
|
| 166 |
+
|
| 167 |
+
def create_static_lib(
|
| 168 |
+
self, objects, output_libname, output_dir=None, debug=0, target_lang=None
|
| 169 |
+
):
|
| 170 |
+
|
| 171 |
+
(objects, output_dir) = self._fix_object_args(objects, output_dir)
|
| 172 |
+
output_filename = self.library_filename(output_libname, output_dir=output_dir)
|
| 173 |
+
|
| 174 |
+
if self._need_link(objects, output_filename):
|
| 175 |
+
lib_args = [output_filename, '/u'] + objects
|
| 176 |
+
if debug:
|
| 177 |
+
pass # XXX what goes here?
|
| 178 |
+
try:
|
| 179 |
+
self.spawn([self.lib] + lib_args)
|
| 180 |
+
except DistutilsExecError as msg:
|
| 181 |
+
raise LibError(msg)
|
| 182 |
+
else:
|
| 183 |
+
log.debug("skipping %s (up-to-date)", output_filename)
|
| 184 |
+
|
| 185 |
+
# create_static_lib ()
|
| 186 |
+
|
| 187 |
+
def link( # noqa: C901
|
| 188 |
+
self,
|
| 189 |
+
target_desc,
|
| 190 |
+
objects,
|
| 191 |
+
output_filename,
|
| 192 |
+
output_dir=None,
|
| 193 |
+
libraries=None,
|
| 194 |
+
library_dirs=None,
|
| 195 |
+
runtime_library_dirs=None,
|
| 196 |
+
export_symbols=None,
|
| 197 |
+
debug=0,
|
| 198 |
+
extra_preargs=None,
|
| 199 |
+
extra_postargs=None,
|
| 200 |
+
build_temp=None,
|
| 201 |
+
target_lang=None,
|
| 202 |
+
):
|
| 203 |
+
|
| 204 |
+
# XXX this ignores 'build_temp'! should follow the lead of
|
| 205 |
+
# msvccompiler.py
|
| 206 |
+
|
| 207 |
+
(objects, output_dir) = self._fix_object_args(objects, output_dir)
|
| 208 |
+
(libraries, library_dirs, runtime_library_dirs) = self._fix_lib_args(
|
| 209 |
+
libraries, library_dirs, runtime_library_dirs
|
| 210 |
+
)
|
| 211 |
+
|
| 212 |
+
if runtime_library_dirs:
|
| 213 |
+
log.warn(
|
| 214 |
+
"I don't know what to do with 'runtime_library_dirs': %s",
|
| 215 |
+
str(runtime_library_dirs),
|
| 216 |
+
)
|
| 217 |
+
|
| 218 |
+
if output_dir is not None:
|
| 219 |
+
output_filename = os.path.join(output_dir, output_filename)
|
| 220 |
+
|
| 221 |
+
if self._need_link(objects, output_filename):
|
| 222 |
+
|
| 223 |
+
# Figure out linker args based on type of target.
|
| 224 |
+
if target_desc == CCompiler.EXECUTABLE:
|
| 225 |
+
startup_obj = 'c0w32'
|
| 226 |
+
if debug:
|
| 227 |
+
ld_args = self.ldflags_exe_debug[:]
|
| 228 |
+
else:
|
| 229 |
+
ld_args = self.ldflags_exe[:]
|
| 230 |
+
else:
|
| 231 |
+
startup_obj = 'c0d32'
|
| 232 |
+
if debug:
|
| 233 |
+
ld_args = self.ldflags_shared_debug[:]
|
| 234 |
+
else:
|
| 235 |
+
ld_args = self.ldflags_shared[:]
|
| 236 |
+
|
| 237 |
+
# Create a temporary exports file for use by the linker
|
| 238 |
+
if export_symbols is None:
|
| 239 |
+
def_file = ''
|
| 240 |
+
else:
|
| 241 |
+
head, tail = os.path.split(output_filename)
|
| 242 |
+
modname, ext = os.path.splitext(tail)
|
| 243 |
+
temp_dir = os.path.dirname(objects[0]) # preserve tree structure
|
| 244 |
+
def_file = os.path.join(temp_dir, '%s.def' % modname)
|
| 245 |
+
contents = ['EXPORTS']
|
| 246 |
+
for sym in export_symbols or []:
|
| 247 |
+
contents.append(' {}=_{}'.format(sym, sym))
|
| 248 |
+
self.execute(write_file, (def_file, contents), "writing %s" % def_file)
|
| 249 |
+
|
| 250 |
+
# Borland C++ has problems with '/' in paths
|
| 251 |
+
objects2 = map(os.path.normpath, objects)
|
| 252 |
+
# split objects in .obj and .res files
|
| 253 |
+
# Borland C++ needs them at different positions in the command line
|
| 254 |
+
objects = [startup_obj]
|
| 255 |
+
resources = []
|
| 256 |
+
for file in objects2:
|
| 257 |
+
(base, ext) = os.path.splitext(os.path.normcase(file))
|
| 258 |
+
if ext == '.res':
|
| 259 |
+
resources.append(file)
|
| 260 |
+
else:
|
| 261 |
+
objects.append(file)
|
| 262 |
+
|
| 263 |
+
for ell in library_dirs:
|
| 264 |
+
ld_args.append("/L%s" % os.path.normpath(ell))
|
| 265 |
+
ld_args.append("/L.") # we sometimes use relative paths
|
| 266 |
+
|
| 267 |
+
# list of object files
|
| 268 |
+
ld_args.extend(objects)
|
| 269 |
+
|
| 270 |
+
# XXX the command-line syntax for Borland C++ is a bit wonky;
|
| 271 |
+
# certain filenames are jammed together in one big string, but
|
| 272 |
+
# comma-delimited. This doesn't mesh too well with the
|
| 273 |
+
# Unix-centric attitude (with a DOS/Windows quoting hack) of
|
| 274 |
+
# 'spawn()', so constructing the argument list is a bit
|
| 275 |
+
# awkward. Note that doing the obvious thing and jamming all
|
| 276 |
+
# the filenames and commas into one argument would be wrong,
|
| 277 |
+
# because 'spawn()' would quote any filenames with spaces in
|
| 278 |
+
# them. Arghghh!. Apparently it works fine as coded...
|
| 279 |
+
|
| 280 |
+
# name of dll/exe file
|
| 281 |
+
ld_args.extend([',', output_filename])
|
| 282 |
+
# no map file and start libraries
|
| 283 |
+
ld_args.append(',,')
|
| 284 |
+
|
| 285 |
+
for lib in libraries:
|
| 286 |
+
# see if we find it and if there is a bcpp specific lib
|
| 287 |
+
# (xxx_bcpp.lib)
|
| 288 |
+
libfile = self.find_library_file(library_dirs, lib, debug)
|
| 289 |
+
if libfile is None:
|
| 290 |
+
ld_args.append(lib)
|
| 291 |
+
# probably a BCPP internal library -- don't warn
|
| 292 |
+
else:
|
| 293 |
+
# full name which prefers bcpp_xxx.lib over xxx.lib
|
| 294 |
+
ld_args.append(libfile)
|
| 295 |
+
|
| 296 |
+
# some default libraries
|
| 297 |
+
ld_args.append('import32')
|
| 298 |
+
ld_args.append('cw32mt')
|
| 299 |
+
|
| 300 |
+
# def file for export symbols
|
| 301 |
+
ld_args.extend([',', def_file])
|
| 302 |
+
# add resource files
|
| 303 |
+
ld_args.append(',')
|
| 304 |
+
ld_args.extend(resources)
|
| 305 |
+
|
| 306 |
+
if extra_preargs:
|
| 307 |
+
ld_args[:0] = extra_preargs
|
| 308 |
+
if extra_postargs:
|
| 309 |
+
ld_args.extend(extra_postargs)
|
| 310 |
+
|
| 311 |
+
self.mkpath(os.path.dirname(output_filename))
|
| 312 |
+
try:
|
| 313 |
+
self.spawn([self.linker] + ld_args)
|
| 314 |
+
except DistutilsExecError as msg:
|
| 315 |
+
raise LinkError(msg)
|
| 316 |
+
|
| 317 |
+
else:
|
| 318 |
+
log.debug("skipping %s (up-to-date)", output_filename)
|
| 319 |
+
|
| 320 |
+
# link ()
|
| 321 |
+
|
| 322 |
+
# -- Miscellaneous methods -----------------------------------------
|
| 323 |
+
|
| 324 |
+
def find_library_file(self, dirs, lib, debug=0):
|
| 325 |
+
# List of effective library names to try, in order of preference:
|
| 326 |
+
# xxx_bcpp.lib is better than xxx.lib
|
| 327 |
+
# and xxx_d.lib is better than xxx.lib if debug is set
|
| 328 |
+
#
|
| 329 |
+
# The "_bcpp" suffix is to handle a Python installation for people
|
| 330 |
+
# with multiple compilers (primarily Distutils hackers, I suspect
|
| 331 |
+
# ;-). The idea is they'd have one static library for each
|
| 332 |
+
# compiler they care about, since (almost?) every Windows compiler
|
| 333 |
+
# seems to have a different format for static libraries.
|
| 334 |
+
if debug:
|
| 335 |
+
dlib = lib + "_d"
|
| 336 |
+
try_names = (dlib + "_bcpp", lib + "_bcpp", dlib, lib)
|
| 337 |
+
else:
|
| 338 |
+
try_names = (lib + "_bcpp", lib)
|
| 339 |
+
|
| 340 |
+
for dir in dirs:
|
| 341 |
+
for name in try_names:
|
| 342 |
+
libfile = os.path.join(dir, self.library_filename(name))
|
| 343 |
+
if os.path.exists(libfile):
|
| 344 |
+
return libfile
|
| 345 |
+
else:
|
| 346 |
+
# Oops, didn't find it in *any* of 'dirs'
|
| 347 |
+
return None
|
| 348 |
+
|
| 349 |
+
# overwrite the one from CCompiler to support rc and res-files
|
| 350 |
+
def object_filenames(self, source_filenames, strip_dir=0, output_dir=''):
|
| 351 |
+
if output_dir is None:
|
| 352 |
+
output_dir = ''
|
| 353 |
+
obj_names = []
|
| 354 |
+
for src_name in source_filenames:
|
| 355 |
+
# use normcase to make sure '.rc' is really '.rc' and not '.RC'
|
| 356 |
+
(base, ext) = os.path.splitext(os.path.normcase(src_name))
|
| 357 |
+
if ext not in (self.src_extensions + ['.rc', '.res']):
|
| 358 |
+
raise UnknownFileError(
|
| 359 |
+
"unknown file type '{}' (from '{}')".format(ext, src_name)
|
| 360 |
+
)
|
| 361 |
+
if strip_dir:
|
| 362 |
+
base = os.path.basename(base)
|
| 363 |
+
if ext == '.res':
|
| 364 |
+
# these can go unchanged
|
| 365 |
+
obj_names.append(os.path.join(output_dir, base + ext))
|
| 366 |
+
elif ext == '.rc':
|
| 367 |
+
# these need to be compiled to .res-files
|
| 368 |
+
obj_names.append(os.path.join(output_dir, base + '.res'))
|
| 369 |
+
else:
|
| 370 |
+
obj_names.append(os.path.join(output_dir, base + self.obj_extension))
|
| 371 |
+
return obj_names
|
| 372 |
+
|
| 373 |
+
# object_filenames ()
|
| 374 |
+
|
| 375 |
+
def preprocess(
|
| 376 |
+
self,
|
| 377 |
+
source,
|
| 378 |
+
output_file=None,
|
| 379 |
+
macros=None,
|
| 380 |
+
include_dirs=None,
|
| 381 |
+
extra_preargs=None,
|
| 382 |
+
extra_postargs=None,
|
| 383 |
+
):
|
| 384 |
+
|
| 385 |
+
(_, macros, include_dirs) = self._fix_compile_args(None, macros, include_dirs)
|
| 386 |
+
pp_opts = gen_preprocess_options(macros, include_dirs)
|
| 387 |
+
pp_args = ['cpp32.exe'] + pp_opts
|
| 388 |
+
if output_file is not None:
|
| 389 |
+
pp_args.append('-o' + output_file)
|
| 390 |
+
if extra_preargs:
|
| 391 |
+
pp_args[:0] = extra_preargs
|
| 392 |
+
if extra_postargs:
|
| 393 |
+
pp_args.extend(extra_postargs)
|
| 394 |
+
pp_args.append(source)
|
| 395 |
+
|
| 396 |
+
# We need to preprocess: either we're being forced to, or the
|
| 397 |
+
# source file is newer than the target (or the target doesn't
|
| 398 |
+
# exist).
|
| 399 |
+
if self.force or output_file is None or newer(source, output_file):
|
| 400 |
+
if output_file:
|
| 401 |
+
self.mkpath(os.path.dirname(output_file))
|
| 402 |
+
try:
|
| 403 |
+
self.spawn(pp_args)
|
| 404 |
+
except DistutilsExecError as msg:
|
| 405 |
+
print(msg)
|
| 406 |
+
raise CompileError(msg)
|
| 407 |
+
|
| 408 |
+
# preprocess()
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/ccompiler.py
ADDED
|
@@ -0,0 +1,1220 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""distutils.ccompiler
|
| 2 |
+
|
| 3 |
+
Contains CCompiler, an abstract base class that defines the interface
|
| 4 |
+
for the Distutils compiler abstraction model."""
|
| 5 |
+
|
| 6 |
+
import sys
|
| 7 |
+
import os
|
| 8 |
+
import re
|
| 9 |
+
|
| 10 |
+
from distutils.errors import (
|
| 11 |
+
CompileError,
|
| 12 |
+
LinkError,
|
| 13 |
+
UnknownFileError,
|
| 14 |
+
DistutilsPlatformError,
|
| 15 |
+
DistutilsModuleError,
|
| 16 |
+
)
|
| 17 |
+
from distutils.spawn import spawn
|
| 18 |
+
from distutils.file_util import move_file
|
| 19 |
+
from distutils.dir_util import mkpath
|
| 20 |
+
from distutils.dep_util import newer_group
|
| 21 |
+
from distutils.util import split_quoted, execute
|
| 22 |
+
from distutils import log
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
class CCompiler:
|
| 26 |
+
"""Abstract base class to define the interface that must be implemented
|
| 27 |
+
by real compiler classes. Also has some utility methods used by
|
| 28 |
+
several compiler classes.
|
| 29 |
+
|
| 30 |
+
The basic idea behind a compiler abstraction class is that each
|
| 31 |
+
instance can be used for all the compile/link steps in building a
|
| 32 |
+
single project. Thus, attributes common to all of those compile and
|
| 33 |
+
link steps -- include directories, macros to define, libraries to link
|
| 34 |
+
against, etc. -- are attributes of the compiler instance. To allow for
|
| 35 |
+
variability in how individual files are treated, most of those
|
| 36 |
+
attributes may be varied on a per-compilation or per-link basis.
|
| 37 |
+
"""
|
| 38 |
+
|
| 39 |
+
# 'compiler_type' is a class attribute that identifies this class. It
|
| 40 |
+
# keeps code that wants to know what kind of compiler it's dealing with
|
| 41 |
+
# from having to import all possible compiler classes just to do an
|
| 42 |
+
# 'isinstance'. In concrete CCompiler subclasses, 'compiler_type'
|
| 43 |
+
# should really, really be one of the keys of the 'compiler_class'
|
| 44 |
+
# dictionary (see below -- used by the 'new_compiler()' factory
|
| 45 |
+
# function) -- authors of new compiler interface classes are
|
| 46 |
+
# responsible for updating 'compiler_class'!
|
| 47 |
+
compiler_type = None
|
| 48 |
+
|
| 49 |
+
# XXX things not handled by this compiler abstraction model:
|
| 50 |
+
# * client can't provide additional options for a compiler,
|
| 51 |
+
# e.g. warning, optimization, debugging flags. Perhaps this
|
| 52 |
+
# should be the domain of concrete compiler abstraction classes
|
| 53 |
+
# (UnixCCompiler, MSVCCompiler, etc.) -- or perhaps the base
|
| 54 |
+
# class should have methods for the common ones.
|
| 55 |
+
# * can't completely override the include or library searchg
|
| 56 |
+
# path, ie. no "cc -I -Idir1 -Idir2" or "cc -L -Ldir1 -Ldir2".
|
| 57 |
+
# I'm not sure how widely supported this is even by Unix
|
| 58 |
+
# compilers, much less on other platforms. And I'm even less
|
| 59 |
+
# sure how useful it is; maybe for cross-compiling, but
|
| 60 |
+
# support for that is a ways off. (And anyways, cross
|
| 61 |
+
# compilers probably have a dedicated binary with the
|
| 62 |
+
# right paths compiled in. I hope.)
|
| 63 |
+
# * can't do really freaky things with the library list/library
|
| 64 |
+
# dirs, e.g. "-Ldir1 -lfoo -Ldir2 -lfoo" to link against
|
| 65 |
+
# different versions of libfoo.a in different locations. I
|
| 66 |
+
# think this is useless without the ability to null out the
|
| 67 |
+
# library search path anyways.
|
| 68 |
+
|
| 69 |
+
# Subclasses that rely on the standard filename generation methods
|
| 70 |
+
# implemented below should override these; see the comment near
|
| 71 |
+
# those methods ('object_filenames()' et. al.) for details:
|
| 72 |
+
src_extensions = None # list of strings
|
| 73 |
+
obj_extension = None # string
|
| 74 |
+
static_lib_extension = None
|
| 75 |
+
shared_lib_extension = None # string
|
| 76 |
+
static_lib_format = None # format string
|
| 77 |
+
shared_lib_format = None # prob. same as static_lib_format
|
| 78 |
+
exe_extension = None # string
|
| 79 |
+
|
| 80 |
+
# Default language settings. language_map is used to detect a source
|
| 81 |
+
# file or Extension target language, checking source filenames.
|
| 82 |
+
# language_order is used to detect the language precedence, when deciding
|
| 83 |
+
# what language to use when mixing source types. For example, if some
|
| 84 |
+
# extension has two files with ".c" extension, and one with ".cpp", it
|
| 85 |
+
# is still linked as c++.
|
| 86 |
+
language_map = {
|
| 87 |
+
".c": "c",
|
| 88 |
+
".cc": "c++",
|
| 89 |
+
".cpp": "c++",
|
| 90 |
+
".cxx": "c++",
|
| 91 |
+
".m": "objc",
|
| 92 |
+
}
|
| 93 |
+
language_order = ["c++", "objc", "c"]
|
| 94 |
+
|
| 95 |
+
include_dirs = []
|
| 96 |
+
"""
|
| 97 |
+
include dirs specific to this compiler class
|
| 98 |
+
"""
|
| 99 |
+
|
| 100 |
+
library_dirs = []
|
| 101 |
+
"""
|
| 102 |
+
library dirs specific to this compiler class
|
| 103 |
+
"""
|
| 104 |
+
|
| 105 |
+
def __init__(self, verbose=0, dry_run=0, force=0):
|
| 106 |
+
self.dry_run = dry_run
|
| 107 |
+
self.force = force
|
| 108 |
+
self.verbose = verbose
|
| 109 |
+
|
| 110 |
+
# 'output_dir': a common output directory for object, library,
|
| 111 |
+
# shared object, and shared library files
|
| 112 |
+
self.output_dir = None
|
| 113 |
+
|
| 114 |
+
# 'macros': a list of macro definitions (or undefinitions). A
|
| 115 |
+
# macro definition is a 2-tuple (name, value), where the value is
|
| 116 |
+
# either a string or None (no explicit value). A macro
|
| 117 |
+
# undefinition is a 1-tuple (name,).
|
| 118 |
+
self.macros = []
|
| 119 |
+
|
| 120 |
+
# 'include_dirs': a list of directories to search for include files
|
| 121 |
+
self.include_dirs = []
|
| 122 |
+
|
| 123 |
+
# 'libraries': a list of libraries to include in any link
|
| 124 |
+
# (library names, not filenames: eg. "foo" not "libfoo.a")
|
| 125 |
+
self.libraries = []
|
| 126 |
+
|
| 127 |
+
# 'library_dirs': a list of directories to search for libraries
|
| 128 |
+
self.library_dirs = []
|
| 129 |
+
|
| 130 |
+
# 'runtime_library_dirs': a list of directories to search for
|
| 131 |
+
# shared libraries/objects at runtime
|
| 132 |
+
self.runtime_library_dirs = []
|
| 133 |
+
|
| 134 |
+
# 'objects': a list of object files (or similar, such as explicitly
|
| 135 |
+
# named library files) to include on any link
|
| 136 |
+
self.objects = []
|
| 137 |
+
|
| 138 |
+
for key in self.executables.keys():
|
| 139 |
+
self.set_executable(key, self.executables[key])
|
| 140 |
+
|
| 141 |
+
def set_executables(self, **kwargs):
|
| 142 |
+
"""Define the executables (and options for them) that will be run
|
| 143 |
+
to perform the various stages of compilation. The exact set of
|
| 144 |
+
executables that may be specified here depends on the compiler
|
| 145 |
+
class (via the 'executables' class attribute), but most will have:
|
| 146 |
+
compiler the C/C++ compiler
|
| 147 |
+
linker_so linker used to create shared objects and libraries
|
| 148 |
+
linker_exe linker used to create binary executables
|
| 149 |
+
archiver static library creator
|
| 150 |
+
|
| 151 |
+
On platforms with a command-line (Unix, DOS/Windows), each of these
|
| 152 |
+
is a string that will be split into executable name and (optional)
|
| 153 |
+
list of arguments. (Splitting the string is done similarly to how
|
| 154 |
+
Unix shells operate: words are delimited by spaces, but quotes and
|
| 155 |
+
backslashes can override this. See
|
| 156 |
+
'distutils.util.split_quoted()'.)
|
| 157 |
+
"""
|
| 158 |
+
|
| 159 |
+
# Note that some CCompiler implementation classes will define class
|
| 160 |
+
# attributes 'cpp', 'cc', etc. with hard-coded executable names;
|
| 161 |
+
# this is appropriate when a compiler class is for exactly one
|
| 162 |
+
# compiler/OS combination (eg. MSVCCompiler). Other compiler
|
| 163 |
+
# classes (UnixCCompiler, in particular) are driven by information
|
| 164 |
+
# discovered at run-time, since there are many different ways to do
|
| 165 |
+
# basically the same things with Unix C compilers.
|
| 166 |
+
|
| 167 |
+
for key in kwargs:
|
| 168 |
+
if key not in self.executables:
|
| 169 |
+
raise ValueError(
|
| 170 |
+
"unknown executable '%s' for class %s"
|
| 171 |
+
% (key, self.__class__.__name__)
|
| 172 |
+
)
|
| 173 |
+
self.set_executable(key, kwargs[key])
|
| 174 |
+
|
| 175 |
+
def set_executable(self, key, value):
|
| 176 |
+
if isinstance(value, str):
|
| 177 |
+
setattr(self, key, split_quoted(value))
|
| 178 |
+
else:
|
| 179 |
+
setattr(self, key, value)
|
| 180 |
+
|
| 181 |
+
def _find_macro(self, name):
|
| 182 |
+
i = 0
|
| 183 |
+
for defn in self.macros:
|
| 184 |
+
if defn[0] == name:
|
| 185 |
+
return i
|
| 186 |
+
i += 1
|
| 187 |
+
return None
|
| 188 |
+
|
| 189 |
+
def _check_macro_definitions(self, definitions):
|
| 190 |
+
"""Ensures that every element of 'definitions' is a valid macro
|
| 191 |
+
definition, ie. either (name,value) 2-tuple or a (name,) tuple. Do
|
| 192 |
+
nothing if all definitions are OK, raise TypeError otherwise.
|
| 193 |
+
"""
|
| 194 |
+
for defn in definitions:
|
| 195 |
+
if not (
|
| 196 |
+
isinstance(defn, tuple)
|
| 197 |
+
and (
|
| 198 |
+
len(defn) in (1, 2)
|
| 199 |
+
and (isinstance(defn[1], str) or defn[1] is None)
|
| 200 |
+
)
|
| 201 |
+
and isinstance(defn[0], str)
|
| 202 |
+
):
|
| 203 |
+
raise TypeError(
|
| 204 |
+
("invalid macro definition '%s': " % defn)
|
| 205 |
+
+ "must be tuple (string,), (string, string), or "
|
| 206 |
+
+ "(string, None)"
|
| 207 |
+
)
|
| 208 |
+
|
| 209 |
+
# -- Bookkeeping methods -------------------------------------------
|
| 210 |
+
|
| 211 |
+
def define_macro(self, name, value=None):
|
| 212 |
+
"""Define a preprocessor macro for all compilations driven by this
|
| 213 |
+
compiler object. The optional parameter 'value' should be a
|
| 214 |
+
string; if it is not supplied, then the macro will be defined
|
| 215 |
+
without an explicit value and the exact outcome depends on the
|
| 216 |
+
compiler used (XXX true? does ANSI say anything about this?)
|
| 217 |
+
"""
|
| 218 |
+
# Delete from the list of macro definitions/undefinitions if
|
| 219 |
+
# already there (so that this one will take precedence).
|
| 220 |
+
i = self._find_macro(name)
|
| 221 |
+
if i is not None:
|
| 222 |
+
del self.macros[i]
|
| 223 |
+
|
| 224 |
+
self.macros.append((name, value))
|
| 225 |
+
|
| 226 |
+
def undefine_macro(self, name):
|
| 227 |
+
"""Undefine a preprocessor macro for all compilations driven by
|
| 228 |
+
this compiler object. If the same macro is defined by
|
| 229 |
+
'define_macro()' and undefined by 'undefine_macro()' the last call
|
| 230 |
+
takes precedence (including multiple redefinitions or
|
| 231 |
+
undefinitions). If the macro is redefined/undefined on a
|
| 232 |
+
per-compilation basis (ie. in the call to 'compile()'), then that
|
| 233 |
+
takes precedence.
|
| 234 |
+
"""
|
| 235 |
+
# Delete from the list of macro definitions/undefinitions if
|
| 236 |
+
# already there (so that this one will take precedence).
|
| 237 |
+
i = self._find_macro(name)
|
| 238 |
+
if i is not None:
|
| 239 |
+
del self.macros[i]
|
| 240 |
+
|
| 241 |
+
undefn = (name,)
|
| 242 |
+
self.macros.append(undefn)
|
| 243 |
+
|
| 244 |
+
def add_include_dir(self, dir):
|
| 245 |
+
"""Add 'dir' to the list of directories that will be searched for
|
| 246 |
+
header files. The compiler is instructed to search directories in
|
| 247 |
+
the order in which they are supplied by successive calls to
|
| 248 |
+
'add_include_dir()'.
|
| 249 |
+
"""
|
| 250 |
+
self.include_dirs.append(dir)
|
| 251 |
+
|
| 252 |
+
def set_include_dirs(self, dirs):
|
| 253 |
+
"""Set the list of directories that will be searched to 'dirs' (a
|
| 254 |
+
list of strings). Overrides any preceding calls to
|
| 255 |
+
'add_include_dir()'; subsequence calls to 'add_include_dir()' add
|
| 256 |
+
to the list passed to 'set_include_dirs()'. This does not affect
|
| 257 |
+
any list of standard include directories that the compiler may
|
| 258 |
+
search by default.
|
| 259 |
+
"""
|
| 260 |
+
self.include_dirs = dirs[:]
|
| 261 |
+
|
| 262 |
+
def add_library(self, libname):
|
| 263 |
+
"""Add 'libname' to the list of libraries that will be included in
|
| 264 |
+
all links driven by this compiler object. Note that 'libname'
|
| 265 |
+
should *not* be the name of a file containing a library, but the
|
| 266 |
+
name of the library itself: the actual filename will be inferred by
|
| 267 |
+
the linker, the compiler, or the compiler class (depending on the
|
| 268 |
+
platform).
|
| 269 |
+
|
| 270 |
+
The linker will be instructed to link against libraries in the
|
| 271 |
+
order they were supplied to 'add_library()' and/or
|
| 272 |
+
'set_libraries()'. It is perfectly valid to duplicate library
|
| 273 |
+
names; the linker will be instructed to link against libraries as
|
| 274 |
+
many times as they are mentioned.
|
| 275 |
+
"""
|
| 276 |
+
self.libraries.append(libname)
|
| 277 |
+
|
| 278 |
+
def set_libraries(self, libnames):
|
| 279 |
+
"""Set the list of libraries to be included in all links driven by
|
| 280 |
+
this compiler object to 'libnames' (a list of strings). This does
|
| 281 |
+
not affect any standard system libraries that the linker may
|
| 282 |
+
include by default.
|
| 283 |
+
"""
|
| 284 |
+
self.libraries = libnames[:]
|
| 285 |
+
|
| 286 |
+
def add_library_dir(self, dir):
|
| 287 |
+
"""Add 'dir' to the list of directories that will be searched for
|
| 288 |
+
libraries specified to 'add_library()' and 'set_libraries()'. The
|
| 289 |
+
linker will be instructed to search for libraries in the order they
|
| 290 |
+
are supplied to 'add_library_dir()' and/or 'set_library_dirs()'.
|
| 291 |
+
"""
|
| 292 |
+
self.library_dirs.append(dir)
|
| 293 |
+
|
| 294 |
+
def set_library_dirs(self, dirs):
|
| 295 |
+
"""Set the list of library search directories to 'dirs' (a list of
|
| 296 |
+
strings). This does not affect any standard library search path
|
| 297 |
+
that the linker may search by default.
|
| 298 |
+
"""
|
| 299 |
+
self.library_dirs = dirs[:]
|
| 300 |
+
|
| 301 |
+
def add_runtime_library_dir(self, dir):
|
| 302 |
+
"""Add 'dir' to the list of directories that will be searched for
|
| 303 |
+
shared libraries at runtime.
|
| 304 |
+
"""
|
| 305 |
+
self.runtime_library_dirs.append(dir)
|
| 306 |
+
|
| 307 |
+
def set_runtime_library_dirs(self, dirs):
|
| 308 |
+
"""Set the list of directories to search for shared libraries at
|
| 309 |
+
runtime to 'dirs' (a list of strings). This does not affect any
|
| 310 |
+
standard search path that the runtime linker may search by
|
| 311 |
+
default.
|
| 312 |
+
"""
|
| 313 |
+
self.runtime_library_dirs = dirs[:]
|
| 314 |
+
|
| 315 |
+
def add_link_object(self, object):
|
| 316 |
+
"""Add 'object' to the list of object files (or analogues, such as
|
| 317 |
+
explicitly named library files or the output of "resource
|
| 318 |
+
compilers") to be included in every link driven by this compiler
|
| 319 |
+
object.
|
| 320 |
+
"""
|
| 321 |
+
self.objects.append(object)
|
| 322 |
+
|
| 323 |
+
def set_link_objects(self, objects):
|
| 324 |
+
"""Set the list of object files (or analogues) to be included in
|
| 325 |
+
every link to 'objects'. This does not affect any standard object
|
| 326 |
+
files that the linker may include by default (such as system
|
| 327 |
+
libraries).
|
| 328 |
+
"""
|
| 329 |
+
self.objects = objects[:]
|
| 330 |
+
|
| 331 |
+
# -- Private utility methods --------------------------------------
|
| 332 |
+
# (here for the convenience of subclasses)
|
| 333 |
+
|
| 334 |
+
# Helper method to prep compiler in subclass compile() methods
|
| 335 |
+
|
| 336 |
+
def _setup_compile(self, outdir, macros, incdirs, sources, depends, extra):
|
| 337 |
+
"""Process arguments and decide which source files to compile."""
|
| 338 |
+
outdir, macros, incdirs = self._fix_compile_args(outdir, macros, incdirs)
|
| 339 |
+
|
| 340 |
+
if extra is None:
|
| 341 |
+
extra = []
|
| 342 |
+
|
| 343 |
+
# Get the list of expected output (object) files
|
| 344 |
+
objects = self.object_filenames(sources, strip_dir=0, output_dir=outdir)
|
| 345 |
+
assert len(objects) == len(sources)
|
| 346 |
+
|
| 347 |
+
pp_opts = gen_preprocess_options(macros, incdirs)
|
| 348 |
+
|
| 349 |
+
build = {}
|
| 350 |
+
for i in range(len(sources)):
|
| 351 |
+
src = sources[i]
|
| 352 |
+
obj = objects[i]
|
| 353 |
+
ext = os.path.splitext(src)[1]
|
| 354 |
+
self.mkpath(os.path.dirname(obj))
|
| 355 |
+
build[obj] = (src, ext)
|
| 356 |
+
|
| 357 |
+
return macros, objects, extra, pp_opts, build
|
| 358 |
+
|
| 359 |
+
def _get_cc_args(self, pp_opts, debug, before):
|
| 360 |
+
# works for unixccompiler, cygwinccompiler
|
| 361 |
+
cc_args = pp_opts + ['-c']
|
| 362 |
+
if debug:
|
| 363 |
+
cc_args[:0] = ['-g']
|
| 364 |
+
if before:
|
| 365 |
+
cc_args[:0] = before
|
| 366 |
+
return cc_args
|
| 367 |
+
|
| 368 |
+
def _fix_compile_args(self, output_dir, macros, include_dirs):
|
| 369 |
+
"""Typecheck and fix-up some of the arguments to the 'compile()'
|
| 370 |
+
method, and return fixed-up values. Specifically: if 'output_dir'
|
| 371 |
+
is None, replaces it with 'self.output_dir'; ensures that 'macros'
|
| 372 |
+
is a list, and augments it with 'self.macros'; ensures that
|
| 373 |
+
'include_dirs' is a list, and augments it with 'self.include_dirs'.
|
| 374 |
+
Guarantees that the returned values are of the correct type,
|
| 375 |
+
i.e. for 'output_dir' either string or None, and for 'macros' and
|
| 376 |
+
'include_dirs' either list or None.
|
| 377 |
+
"""
|
| 378 |
+
if output_dir is None:
|
| 379 |
+
output_dir = self.output_dir
|
| 380 |
+
elif not isinstance(output_dir, str):
|
| 381 |
+
raise TypeError("'output_dir' must be a string or None")
|
| 382 |
+
|
| 383 |
+
if macros is None:
|
| 384 |
+
macros = self.macros
|
| 385 |
+
elif isinstance(macros, list):
|
| 386 |
+
macros = macros + (self.macros or [])
|
| 387 |
+
else:
|
| 388 |
+
raise TypeError("'macros' (if supplied) must be a list of tuples")
|
| 389 |
+
|
| 390 |
+
if include_dirs is None:
|
| 391 |
+
include_dirs = self.include_dirs
|
| 392 |
+
elif isinstance(include_dirs, (list, tuple)):
|
| 393 |
+
include_dirs = list(include_dirs) + (self.include_dirs or [])
|
| 394 |
+
else:
|
| 395 |
+
raise TypeError("'include_dirs' (if supplied) must be a list of strings")
|
| 396 |
+
|
| 397 |
+
# add include dirs for class
|
| 398 |
+
include_dirs += self.__class__.include_dirs
|
| 399 |
+
|
| 400 |
+
return output_dir, macros, include_dirs
|
| 401 |
+
|
| 402 |
+
def _prep_compile(self, sources, output_dir, depends=None):
|
| 403 |
+
"""Decide which source files must be recompiled.
|
| 404 |
+
|
| 405 |
+
Determine the list of object files corresponding to 'sources',
|
| 406 |
+
and figure out which ones really need to be recompiled.
|
| 407 |
+
Return a list of all object files and a dictionary telling
|
| 408 |
+
which source files can be skipped.
|
| 409 |
+
"""
|
| 410 |
+
# Get the list of expected output (object) files
|
| 411 |
+
objects = self.object_filenames(sources, output_dir=output_dir)
|
| 412 |
+
assert len(objects) == len(sources)
|
| 413 |
+
|
| 414 |
+
# Return an empty dict for the "which source files can be skipped"
|
| 415 |
+
# return value to preserve API compatibility.
|
| 416 |
+
return objects, {}
|
| 417 |
+
|
| 418 |
+
def _fix_object_args(self, objects, output_dir):
|
| 419 |
+
"""Typecheck and fix up some arguments supplied to various methods.
|
| 420 |
+
Specifically: ensure that 'objects' is a list; if output_dir is
|
| 421 |
+
None, replace with self.output_dir. Return fixed versions of
|
| 422 |
+
'objects' and 'output_dir'.
|
| 423 |
+
"""
|
| 424 |
+
if not isinstance(objects, (list, tuple)):
|
| 425 |
+
raise TypeError("'objects' must be a list or tuple of strings")
|
| 426 |
+
objects = list(objects)
|
| 427 |
+
|
| 428 |
+
if output_dir is None:
|
| 429 |
+
output_dir = self.output_dir
|
| 430 |
+
elif not isinstance(output_dir, str):
|
| 431 |
+
raise TypeError("'output_dir' must be a string or None")
|
| 432 |
+
|
| 433 |
+
return (objects, output_dir)
|
| 434 |
+
|
| 435 |
+
def _fix_lib_args(self, libraries, library_dirs, runtime_library_dirs):
|
| 436 |
+
"""Typecheck and fix up some of the arguments supplied to the
|
| 437 |
+
'link_*' methods. Specifically: ensure that all arguments are
|
| 438 |
+
lists, and augment them with their permanent versions
|
| 439 |
+
(eg. 'self.libraries' augments 'libraries'). Return a tuple with
|
| 440 |
+
fixed versions of all arguments.
|
| 441 |
+
"""
|
| 442 |
+
if libraries is None:
|
| 443 |
+
libraries = self.libraries
|
| 444 |
+
elif isinstance(libraries, (list, tuple)):
|
| 445 |
+
libraries = list(libraries) + (self.libraries or [])
|
| 446 |
+
else:
|
| 447 |
+
raise TypeError("'libraries' (if supplied) must be a list of strings")
|
| 448 |
+
|
| 449 |
+
if library_dirs is None:
|
| 450 |
+
library_dirs = self.library_dirs
|
| 451 |
+
elif isinstance(library_dirs, (list, tuple)):
|
| 452 |
+
library_dirs = list(library_dirs) + (self.library_dirs or [])
|
| 453 |
+
else:
|
| 454 |
+
raise TypeError("'library_dirs' (if supplied) must be a list of strings")
|
| 455 |
+
|
| 456 |
+
# add library dirs for class
|
| 457 |
+
library_dirs += self.__class__.library_dirs
|
| 458 |
+
|
| 459 |
+
if runtime_library_dirs is None:
|
| 460 |
+
runtime_library_dirs = self.runtime_library_dirs
|
| 461 |
+
elif isinstance(runtime_library_dirs, (list, tuple)):
|
| 462 |
+
runtime_library_dirs = list(runtime_library_dirs) + (
|
| 463 |
+
self.runtime_library_dirs or []
|
| 464 |
+
)
|
| 465 |
+
else:
|
| 466 |
+
raise TypeError(
|
| 467 |
+
"'runtime_library_dirs' (if supplied) " "must be a list of strings"
|
| 468 |
+
)
|
| 469 |
+
|
| 470 |
+
return (libraries, library_dirs, runtime_library_dirs)
|
| 471 |
+
|
| 472 |
+
def _need_link(self, objects, output_file):
|
| 473 |
+
"""Return true if we need to relink the files listed in 'objects'
|
| 474 |
+
to recreate 'output_file'.
|
| 475 |
+
"""
|
| 476 |
+
if self.force:
|
| 477 |
+
return True
|
| 478 |
+
else:
|
| 479 |
+
if self.dry_run:
|
| 480 |
+
newer = newer_group(objects, output_file, missing='newer')
|
| 481 |
+
else:
|
| 482 |
+
newer = newer_group(objects, output_file)
|
| 483 |
+
return newer
|
| 484 |
+
|
| 485 |
+
def detect_language(self, sources):
|
| 486 |
+
"""Detect the language of a given file, or list of files. Uses
|
| 487 |
+
language_map, and language_order to do the job.
|
| 488 |
+
"""
|
| 489 |
+
if not isinstance(sources, list):
|
| 490 |
+
sources = [sources]
|
| 491 |
+
lang = None
|
| 492 |
+
index = len(self.language_order)
|
| 493 |
+
for source in sources:
|
| 494 |
+
base, ext = os.path.splitext(source)
|
| 495 |
+
extlang = self.language_map.get(ext)
|
| 496 |
+
try:
|
| 497 |
+
extindex = self.language_order.index(extlang)
|
| 498 |
+
if extindex < index:
|
| 499 |
+
lang = extlang
|
| 500 |
+
index = extindex
|
| 501 |
+
except ValueError:
|
| 502 |
+
pass
|
| 503 |
+
return lang
|
| 504 |
+
|
| 505 |
+
# -- Worker methods ------------------------------------------------
|
| 506 |
+
# (must be implemented by subclasses)
|
| 507 |
+
|
| 508 |
+
def preprocess(
|
| 509 |
+
self,
|
| 510 |
+
source,
|
| 511 |
+
output_file=None,
|
| 512 |
+
macros=None,
|
| 513 |
+
include_dirs=None,
|
| 514 |
+
extra_preargs=None,
|
| 515 |
+
extra_postargs=None,
|
| 516 |
+
):
|
| 517 |
+
"""Preprocess a single C/C++ source file, named in 'source'.
|
| 518 |
+
Output will be written to file named 'output_file', or stdout if
|
| 519 |
+
'output_file' not supplied. 'macros' is a list of macro
|
| 520 |
+
definitions as for 'compile()', which will augment the macros set
|
| 521 |
+
with 'define_macro()' and 'undefine_macro()'. 'include_dirs' is a
|
| 522 |
+
list of directory names that will be added to the default list.
|
| 523 |
+
|
| 524 |
+
Raises PreprocessError on failure.
|
| 525 |
+
"""
|
| 526 |
+
pass
|
| 527 |
+
|
| 528 |
+
def compile(
|
| 529 |
+
self,
|
| 530 |
+
sources,
|
| 531 |
+
output_dir=None,
|
| 532 |
+
macros=None,
|
| 533 |
+
include_dirs=None,
|
| 534 |
+
debug=0,
|
| 535 |
+
extra_preargs=None,
|
| 536 |
+
extra_postargs=None,
|
| 537 |
+
depends=None,
|
| 538 |
+
):
|
| 539 |
+
"""Compile one or more source files.
|
| 540 |
+
|
| 541 |
+
'sources' must be a list of filenames, most likely C/C++
|
| 542 |
+
files, but in reality anything that can be handled by a
|
| 543 |
+
particular compiler and compiler class (eg. MSVCCompiler can
|
| 544 |
+
handle resource files in 'sources'). Return a list of object
|
| 545 |
+
filenames, one per source filename in 'sources'. Depending on
|
| 546 |
+
the implementation, not all source files will necessarily be
|
| 547 |
+
compiled, but all corresponding object filenames will be
|
| 548 |
+
returned.
|
| 549 |
+
|
| 550 |
+
If 'output_dir' is given, object files will be put under it, while
|
| 551 |
+
retaining their original path component. That is, "foo/bar.c"
|
| 552 |
+
normally compiles to "foo/bar.o" (for a Unix implementation); if
|
| 553 |
+
'output_dir' is "build", then it would compile to
|
| 554 |
+
"build/foo/bar.o".
|
| 555 |
+
|
| 556 |
+
'macros', if given, must be a list of macro definitions. A macro
|
| 557 |
+
definition is either a (name, value) 2-tuple or a (name,) 1-tuple.
|
| 558 |
+
The former defines a macro; if the value is None, the macro is
|
| 559 |
+
defined without an explicit value. The 1-tuple case undefines a
|
| 560 |
+
macro. Later definitions/redefinitions/ undefinitions take
|
| 561 |
+
precedence.
|
| 562 |
+
|
| 563 |
+
'include_dirs', if given, must be a list of strings, the
|
| 564 |
+
directories to add to the default include file search path for this
|
| 565 |
+
compilation only.
|
| 566 |
+
|
| 567 |
+
'debug' is a boolean; if true, the compiler will be instructed to
|
| 568 |
+
output debug symbols in (or alongside) the object file(s).
|
| 569 |
+
|
| 570 |
+
'extra_preargs' and 'extra_postargs' are implementation- dependent.
|
| 571 |
+
On platforms that have the notion of a command-line (e.g. Unix,
|
| 572 |
+
DOS/Windows), they are most likely lists of strings: extra
|
| 573 |
+
command-line arguments to prepend/append to the compiler command
|
| 574 |
+
line. On other platforms, consult the implementation class
|
| 575 |
+
documentation. In any event, they are intended as an escape hatch
|
| 576 |
+
for those occasions when the abstract compiler framework doesn't
|
| 577 |
+
cut the mustard.
|
| 578 |
+
|
| 579 |
+
'depends', if given, is a list of filenames that all targets
|
| 580 |
+
depend on. If a source file is older than any file in
|
| 581 |
+
depends, then the source file will be recompiled. This
|
| 582 |
+
supports dependency tracking, but only at a coarse
|
| 583 |
+
granularity.
|
| 584 |
+
|
| 585 |
+
Raises CompileError on failure.
|
| 586 |
+
"""
|
| 587 |
+
# A concrete compiler class can either override this method
|
| 588 |
+
# entirely or implement _compile().
|
| 589 |
+
macros, objects, extra_postargs, pp_opts, build = self._setup_compile(
|
| 590 |
+
output_dir, macros, include_dirs, sources, depends, extra_postargs
|
| 591 |
+
)
|
| 592 |
+
cc_args = self._get_cc_args(pp_opts, debug, extra_preargs)
|
| 593 |
+
|
| 594 |
+
for obj in objects:
|
| 595 |
+
try:
|
| 596 |
+
src, ext = build[obj]
|
| 597 |
+
except KeyError:
|
| 598 |
+
continue
|
| 599 |
+
self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts)
|
| 600 |
+
|
| 601 |
+
# Return *all* object filenames, not just the ones we just built.
|
| 602 |
+
return objects
|
| 603 |
+
|
| 604 |
+
def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
|
| 605 |
+
"""Compile 'src' to product 'obj'."""
|
| 606 |
+
# A concrete compiler class that does not override compile()
|
| 607 |
+
# should implement _compile().
|
| 608 |
+
pass
|
| 609 |
+
|
| 610 |
+
def create_static_lib(
|
| 611 |
+
self, objects, output_libname, output_dir=None, debug=0, target_lang=None
|
| 612 |
+
):
|
| 613 |
+
"""Link a bunch of stuff together to create a static library file.
|
| 614 |
+
The "bunch of stuff" consists of the list of object files supplied
|
| 615 |
+
as 'objects', the extra object files supplied to
|
| 616 |
+
'add_link_object()' and/or 'set_link_objects()', the libraries
|
| 617 |
+
supplied to 'add_library()' and/or 'set_libraries()', and the
|
| 618 |
+
libraries supplied as 'libraries' (if any).
|
| 619 |
+
|
| 620 |
+
'output_libname' should be a library name, not a filename; the
|
| 621 |
+
filename will be inferred from the library name. 'output_dir' is
|
| 622 |
+
the directory where the library file will be put.
|
| 623 |
+
|
| 624 |
+
'debug' is a boolean; if true, debugging information will be
|
| 625 |
+
included in the library (note that on most platforms, it is the
|
| 626 |
+
compile step where this matters: the 'debug' flag is included here
|
| 627 |
+
just for consistency).
|
| 628 |
+
|
| 629 |
+
'target_lang' is the target language for which the given objects
|
| 630 |
+
are being compiled. This allows specific linkage time treatment of
|
| 631 |
+
certain languages.
|
| 632 |
+
|
| 633 |
+
Raises LibError on failure.
|
| 634 |
+
"""
|
| 635 |
+
pass
|
| 636 |
+
|
| 637 |
+
# values for target_desc parameter in link()
|
| 638 |
+
SHARED_OBJECT = "shared_object"
|
| 639 |
+
SHARED_LIBRARY = "shared_library"
|
| 640 |
+
EXECUTABLE = "executable"
|
| 641 |
+
|
| 642 |
+
def link(
|
| 643 |
+
self,
|
| 644 |
+
target_desc,
|
| 645 |
+
objects,
|
| 646 |
+
output_filename,
|
| 647 |
+
output_dir=None,
|
| 648 |
+
libraries=None,
|
| 649 |
+
library_dirs=None,
|
| 650 |
+
runtime_library_dirs=None,
|
| 651 |
+
export_symbols=None,
|
| 652 |
+
debug=0,
|
| 653 |
+
extra_preargs=None,
|
| 654 |
+
extra_postargs=None,
|
| 655 |
+
build_temp=None,
|
| 656 |
+
target_lang=None,
|
| 657 |
+
):
|
| 658 |
+
"""Link a bunch of stuff together to create an executable or
|
| 659 |
+
shared library file.
|
| 660 |
+
|
| 661 |
+
The "bunch of stuff" consists of the list of object files supplied
|
| 662 |
+
as 'objects'. 'output_filename' should be a filename. If
|
| 663 |
+
'output_dir' is supplied, 'output_filename' is relative to it
|
| 664 |
+
(i.e. 'output_filename' can provide directory components if
|
| 665 |
+
needed).
|
| 666 |
+
|
| 667 |
+
'libraries' is a list of libraries to link against. These are
|
| 668 |
+
library names, not filenames, since they're translated into
|
| 669 |
+
filenames in a platform-specific way (eg. "foo" becomes "libfoo.a"
|
| 670 |
+
on Unix and "foo.lib" on DOS/Windows). However, they can include a
|
| 671 |
+
directory component, which means the linker will look in that
|
| 672 |
+
specific directory rather than searching all the normal locations.
|
| 673 |
+
|
| 674 |
+
'library_dirs', if supplied, should be a list of directories to
|
| 675 |
+
search for libraries that were specified as bare library names
|
| 676 |
+
(ie. no directory component). These are on top of the system
|
| 677 |
+
default and those supplied to 'add_library_dir()' and/or
|
| 678 |
+
'set_library_dirs()'. 'runtime_library_dirs' is a list of
|
| 679 |
+
directories that will be embedded into the shared library and used
|
| 680 |
+
to search for other shared libraries that *it* depends on at
|
| 681 |
+
run-time. (This may only be relevant on Unix.)
|
| 682 |
+
|
| 683 |
+
'export_symbols' is a list of symbols that the shared library will
|
| 684 |
+
export. (This appears to be relevant only on Windows.)
|
| 685 |
+
|
| 686 |
+
'debug' is as for 'compile()' and 'create_static_lib()', with the
|
| 687 |
+
slight distinction that it actually matters on most platforms (as
|
| 688 |
+
opposed to 'create_static_lib()', which includes a 'debug' flag
|
| 689 |
+
mostly for form's sake).
|
| 690 |
+
|
| 691 |
+
'extra_preargs' and 'extra_postargs' are as for 'compile()' (except
|
| 692 |
+
of course that they supply command-line arguments for the
|
| 693 |
+
particular linker being used).
|
| 694 |
+
|
| 695 |
+
'target_lang' is the target language for which the given objects
|
| 696 |
+
are being compiled. This allows specific linkage time treatment of
|
| 697 |
+
certain languages.
|
| 698 |
+
|
| 699 |
+
Raises LinkError on failure.
|
| 700 |
+
"""
|
| 701 |
+
raise NotImplementedError
|
| 702 |
+
|
| 703 |
+
# Old 'link_*()' methods, rewritten to use the new 'link()' method.
|
| 704 |
+
|
| 705 |
+
def link_shared_lib(
|
| 706 |
+
self,
|
| 707 |
+
objects,
|
| 708 |
+
output_libname,
|
| 709 |
+
output_dir=None,
|
| 710 |
+
libraries=None,
|
| 711 |
+
library_dirs=None,
|
| 712 |
+
runtime_library_dirs=None,
|
| 713 |
+
export_symbols=None,
|
| 714 |
+
debug=0,
|
| 715 |
+
extra_preargs=None,
|
| 716 |
+
extra_postargs=None,
|
| 717 |
+
build_temp=None,
|
| 718 |
+
target_lang=None,
|
| 719 |
+
):
|
| 720 |
+
self.link(
|
| 721 |
+
CCompiler.SHARED_LIBRARY,
|
| 722 |
+
objects,
|
| 723 |
+
self.library_filename(output_libname, lib_type='shared'),
|
| 724 |
+
output_dir,
|
| 725 |
+
libraries,
|
| 726 |
+
library_dirs,
|
| 727 |
+
runtime_library_dirs,
|
| 728 |
+
export_symbols,
|
| 729 |
+
debug,
|
| 730 |
+
extra_preargs,
|
| 731 |
+
extra_postargs,
|
| 732 |
+
build_temp,
|
| 733 |
+
target_lang,
|
| 734 |
+
)
|
| 735 |
+
|
| 736 |
+
def link_shared_object(
|
| 737 |
+
self,
|
| 738 |
+
objects,
|
| 739 |
+
output_filename,
|
| 740 |
+
output_dir=None,
|
| 741 |
+
libraries=None,
|
| 742 |
+
library_dirs=None,
|
| 743 |
+
runtime_library_dirs=None,
|
| 744 |
+
export_symbols=None,
|
| 745 |
+
debug=0,
|
| 746 |
+
extra_preargs=None,
|
| 747 |
+
extra_postargs=None,
|
| 748 |
+
build_temp=None,
|
| 749 |
+
target_lang=None,
|
| 750 |
+
):
|
| 751 |
+
self.link(
|
| 752 |
+
CCompiler.SHARED_OBJECT,
|
| 753 |
+
objects,
|
| 754 |
+
output_filename,
|
| 755 |
+
output_dir,
|
| 756 |
+
libraries,
|
| 757 |
+
library_dirs,
|
| 758 |
+
runtime_library_dirs,
|
| 759 |
+
export_symbols,
|
| 760 |
+
debug,
|
| 761 |
+
extra_preargs,
|
| 762 |
+
extra_postargs,
|
| 763 |
+
build_temp,
|
| 764 |
+
target_lang,
|
| 765 |
+
)
|
| 766 |
+
|
| 767 |
+
def link_executable(
|
| 768 |
+
self,
|
| 769 |
+
objects,
|
| 770 |
+
output_progname,
|
| 771 |
+
output_dir=None,
|
| 772 |
+
libraries=None,
|
| 773 |
+
library_dirs=None,
|
| 774 |
+
runtime_library_dirs=None,
|
| 775 |
+
debug=0,
|
| 776 |
+
extra_preargs=None,
|
| 777 |
+
extra_postargs=None,
|
| 778 |
+
target_lang=None,
|
| 779 |
+
):
|
| 780 |
+
self.link(
|
| 781 |
+
CCompiler.EXECUTABLE,
|
| 782 |
+
objects,
|
| 783 |
+
self.executable_filename(output_progname),
|
| 784 |
+
output_dir,
|
| 785 |
+
libraries,
|
| 786 |
+
library_dirs,
|
| 787 |
+
runtime_library_dirs,
|
| 788 |
+
None,
|
| 789 |
+
debug,
|
| 790 |
+
extra_preargs,
|
| 791 |
+
extra_postargs,
|
| 792 |
+
None,
|
| 793 |
+
target_lang,
|
| 794 |
+
)
|
| 795 |
+
|
| 796 |
+
# -- Miscellaneous methods -----------------------------------------
|
| 797 |
+
# These are all used by the 'gen_lib_options() function; there is
|
| 798 |
+
# no appropriate default implementation so subclasses should
|
| 799 |
+
# implement all of these.
|
| 800 |
+
|
| 801 |
+
def library_dir_option(self, dir):
|
| 802 |
+
"""Return the compiler option to add 'dir' to the list of
|
| 803 |
+
directories searched for libraries.
|
| 804 |
+
"""
|
| 805 |
+
raise NotImplementedError
|
| 806 |
+
|
| 807 |
+
def runtime_library_dir_option(self, dir):
|
| 808 |
+
"""Return the compiler option to add 'dir' to the list of
|
| 809 |
+
directories searched for runtime libraries.
|
| 810 |
+
"""
|
| 811 |
+
raise NotImplementedError
|
| 812 |
+
|
| 813 |
+
def library_option(self, lib):
|
| 814 |
+
"""Return the compiler option to add 'lib' to the list of libraries
|
| 815 |
+
linked into the shared library or executable.
|
| 816 |
+
"""
|
| 817 |
+
raise NotImplementedError
|
| 818 |
+
|
| 819 |
+
def has_function( # noqa: C901
|
| 820 |
+
self,
|
| 821 |
+
funcname,
|
| 822 |
+
includes=None,
|
| 823 |
+
include_dirs=None,
|
| 824 |
+
libraries=None,
|
| 825 |
+
library_dirs=None,
|
| 826 |
+
):
|
| 827 |
+
"""Return a boolean indicating whether funcname is supported on
|
| 828 |
+
the current platform. The optional arguments can be used to
|
| 829 |
+
augment the compilation environment.
|
| 830 |
+
"""
|
| 831 |
+
# this can't be included at module scope because it tries to
|
| 832 |
+
# import math which might not be available at that point - maybe
|
| 833 |
+
# the necessary logic should just be inlined?
|
| 834 |
+
import tempfile
|
| 835 |
+
|
| 836 |
+
if includes is None:
|
| 837 |
+
includes = []
|
| 838 |
+
if include_dirs is None:
|
| 839 |
+
include_dirs = []
|
| 840 |
+
if libraries is None:
|
| 841 |
+
libraries = []
|
| 842 |
+
if library_dirs is None:
|
| 843 |
+
library_dirs = []
|
| 844 |
+
fd, fname = tempfile.mkstemp(".c", funcname, text=True)
|
| 845 |
+
f = os.fdopen(fd, "w")
|
| 846 |
+
try:
|
| 847 |
+
for incl in includes:
|
| 848 |
+
f.write("""#include "%s"\n""" % incl)
|
| 849 |
+
f.write(
|
| 850 |
+
"""\
|
| 851 |
+
int main (int argc, char **argv) {
|
| 852 |
+
%s();
|
| 853 |
+
return 0;
|
| 854 |
+
}
|
| 855 |
+
"""
|
| 856 |
+
% funcname
|
| 857 |
+
)
|
| 858 |
+
finally:
|
| 859 |
+
f.close()
|
| 860 |
+
try:
|
| 861 |
+
objects = self.compile([fname], include_dirs=include_dirs)
|
| 862 |
+
except CompileError:
|
| 863 |
+
return False
|
| 864 |
+
finally:
|
| 865 |
+
os.remove(fname)
|
| 866 |
+
|
| 867 |
+
try:
|
| 868 |
+
self.link_executable(
|
| 869 |
+
objects, "a.out", libraries=libraries, library_dirs=library_dirs
|
| 870 |
+
)
|
| 871 |
+
except (LinkError, TypeError):
|
| 872 |
+
return False
|
| 873 |
+
else:
|
| 874 |
+
os.remove(os.path.join(self.output_dir or '', "a.out"))
|
| 875 |
+
finally:
|
| 876 |
+
for fn in objects:
|
| 877 |
+
os.remove(fn)
|
| 878 |
+
return True
|
| 879 |
+
|
| 880 |
+
def find_library_file(self, dirs, lib, debug=0):
|
| 881 |
+
"""Search the specified list of directories for a static or shared
|
| 882 |
+
library file 'lib' and return the full path to that file. If
|
| 883 |
+
'debug' true, look for a debugging version (if that makes sense on
|
| 884 |
+
the current platform). Return None if 'lib' wasn't found in any of
|
| 885 |
+
the specified directories.
|
| 886 |
+
"""
|
| 887 |
+
raise NotImplementedError
|
| 888 |
+
|
| 889 |
+
# -- Filename generation methods -----------------------------------
|
| 890 |
+
|
| 891 |
+
# The default implementation of the filename generating methods are
|
| 892 |
+
# prejudiced towards the Unix/DOS/Windows view of the world:
|
| 893 |
+
# * object files are named by replacing the source file extension
|
| 894 |
+
# (eg. .c/.cpp -> .o/.obj)
|
| 895 |
+
# * library files (shared or static) are named by plugging the
|
| 896 |
+
# library name and extension into a format string, eg.
|
| 897 |
+
# "lib%s.%s" % (lib_name, ".a") for Unix static libraries
|
| 898 |
+
# * executables are named by appending an extension (possibly
|
| 899 |
+
# empty) to the program name: eg. progname + ".exe" for
|
| 900 |
+
# Windows
|
| 901 |
+
#
|
| 902 |
+
# To reduce redundant code, these methods expect to find
|
| 903 |
+
# several attributes in the current object (presumably defined
|
| 904 |
+
# as class attributes):
|
| 905 |
+
# * src_extensions -
|
| 906 |
+
# list of C/C++ source file extensions, eg. ['.c', '.cpp']
|
| 907 |
+
# * obj_extension -
|
| 908 |
+
# object file extension, eg. '.o' or '.obj'
|
| 909 |
+
# * static_lib_extension -
|
| 910 |
+
# extension for static library files, eg. '.a' or '.lib'
|
| 911 |
+
# * shared_lib_extension -
|
| 912 |
+
# extension for shared library/object files, eg. '.so', '.dll'
|
| 913 |
+
# * static_lib_format -
|
| 914 |
+
# format string for generating static library filenames,
|
| 915 |
+
# eg. 'lib%s.%s' or '%s.%s'
|
| 916 |
+
# * shared_lib_format
|
| 917 |
+
# format string for generating shared library filenames
|
| 918 |
+
# (probably same as static_lib_format, since the extension
|
| 919 |
+
# is one of the intended parameters to the format string)
|
| 920 |
+
# * exe_extension -
|
| 921 |
+
# extension for executable files, eg. '' or '.exe'
|
| 922 |
+
|
| 923 |
+
def object_filenames(self, source_filenames, strip_dir=0, output_dir=''):
|
| 924 |
+
if output_dir is None:
|
| 925 |
+
output_dir = ''
|
| 926 |
+
return list(
|
| 927 |
+
self._make_out_path(output_dir, strip_dir, src_name)
|
| 928 |
+
for src_name in source_filenames
|
| 929 |
+
)
|
| 930 |
+
|
| 931 |
+
@property
|
| 932 |
+
def out_extensions(self):
|
| 933 |
+
return dict.fromkeys(self.src_extensions, self.obj_extension)
|
| 934 |
+
|
| 935 |
+
def _make_out_path(self, output_dir, strip_dir, src_name):
|
| 936 |
+
base, ext = os.path.splitext(src_name)
|
| 937 |
+
base = self._make_relative(base)
|
| 938 |
+
try:
|
| 939 |
+
new_ext = self.out_extensions[ext]
|
| 940 |
+
except LookupError:
|
| 941 |
+
raise UnknownFileError(
|
| 942 |
+
"unknown file type '{}' (from '{}')".format(ext, src_name)
|
| 943 |
+
)
|
| 944 |
+
if strip_dir:
|
| 945 |
+
base = os.path.basename(base)
|
| 946 |
+
return os.path.join(output_dir, base + new_ext)
|
| 947 |
+
|
| 948 |
+
@staticmethod
|
| 949 |
+
def _make_relative(base):
|
| 950 |
+
"""
|
| 951 |
+
In order to ensure that a filename always honors the
|
| 952 |
+
indicated output_dir, make sure it's relative.
|
| 953 |
+
Ref python/cpython#37775.
|
| 954 |
+
"""
|
| 955 |
+
# Chop off the drive
|
| 956 |
+
no_drive = os.path.splitdrive(base)[1]
|
| 957 |
+
# If abs, chop off leading /
|
| 958 |
+
return no_drive[os.path.isabs(no_drive) :]
|
| 959 |
+
|
| 960 |
+
def shared_object_filename(self, basename, strip_dir=0, output_dir=''):
|
| 961 |
+
assert output_dir is not None
|
| 962 |
+
if strip_dir:
|
| 963 |
+
basename = os.path.basename(basename)
|
| 964 |
+
return os.path.join(output_dir, basename + self.shared_lib_extension)
|
| 965 |
+
|
| 966 |
+
def executable_filename(self, basename, strip_dir=0, output_dir=''):
|
| 967 |
+
assert output_dir is not None
|
| 968 |
+
if strip_dir:
|
| 969 |
+
basename = os.path.basename(basename)
|
| 970 |
+
return os.path.join(output_dir, basename + (self.exe_extension or ''))
|
| 971 |
+
|
| 972 |
+
def library_filename(
|
| 973 |
+
self, libname, lib_type='static', strip_dir=0, output_dir='' # or 'shared'
|
| 974 |
+
):
|
| 975 |
+
assert output_dir is not None
|
| 976 |
+
expected = '"static", "shared", "dylib", "xcode_stub"'
|
| 977 |
+
if lib_type not in eval(expected):
|
| 978 |
+
raise ValueError(f"'lib_type' must be {expected}")
|
| 979 |
+
fmt = getattr(self, lib_type + "_lib_format")
|
| 980 |
+
ext = getattr(self, lib_type + "_lib_extension")
|
| 981 |
+
|
| 982 |
+
dir, base = os.path.split(libname)
|
| 983 |
+
filename = fmt % (base, ext)
|
| 984 |
+
if strip_dir:
|
| 985 |
+
dir = ''
|
| 986 |
+
|
| 987 |
+
return os.path.join(output_dir, dir, filename)
|
| 988 |
+
|
| 989 |
+
# -- Utility methods -----------------------------------------------
|
| 990 |
+
|
| 991 |
+
def announce(self, msg, level=1):
|
| 992 |
+
log.debug(msg)
|
| 993 |
+
|
| 994 |
+
def debug_print(self, msg):
|
| 995 |
+
from distutils.debug import DEBUG
|
| 996 |
+
|
| 997 |
+
if DEBUG:
|
| 998 |
+
print(msg)
|
| 999 |
+
|
| 1000 |
+
def warn(self, msg):
|
| 1001 |
+
sys.stderr.write("warning: %s\n" % msg)
|
| 1002 |
+
|
| 1003 |
+
def execute(self, func, args, msg=None, level=1):
|
| 1004 |
+
execute(func, args, msg, self.dry_run)
|
| 1005 |
+
|
| 1006 |
+
def spawn(self, cmd, **kwargs):
|
| 1007 |
+
spawn(cmd, dry_run=self.dry_run, **kwargs)
|
| 1008 |
+
|
| 1009 |
+
def move_file(self, src, dst):
|
| 1010 |
+
return move_file(src, dst, dry_run=self.dry_run)
|
| 1011 |
+
|
| 1012 |
+
def mkpath(self, name, mode=0o777):
|
| 1013 |
+
mkpath(name, mode, dry_run=self.dry_run)
|
| 1014 |
+
|
| 1015 |
+
|
| 1016 |
+
# Map a sys.platform/os.name ('posix', 'nt') to the default compiler
|
| 1017 |
+
# type for that platform. Keys are interpreted as re match
|
| 1018 |
+
# patterns. Order is important; platform mappings are preferred over
|
| 1019 |
+
# OS names.
|
| 1020 |
+
_default_compilers = (
|
| 1021 |
+
# Platform string mappings
|
| 1022 |
+
# on a cygwin built python we can use gcc like an ordinary UNIXish
|
| 1023 |
+
# compiler
|
| 1024 |
+
('cygwin.*', 'unix'),
|
| 1025 |
+
# OS name mappings
|
| 1026 |
+
('posix', 'unix'),
|
| 1027 |
+
('nt', 'msvc'),
|
| 1028 |
+
)
|
| 1029 |
+
|
| 1030 |
+
|
| 1031 |
+
def get_default_compiler(osname=None, platform=None):
|
| 1032 |
+
"""Determine the default compiler to use for the given platform.
|
| 1033 |
+
|
| 1034 |
+
osname should be one of the standard Python OS names (i.e. the
|
| 1035 |
+
ones returned by os.name) and platform the common value
|
| 1036 |
+
returned by sys.platform for the platform in question.
|
| 1037 |
+
|
| 1038 |
+
The default values are os.name and sys.platform in case the
|
| 1039 |
+
parameters are not given.
|
| 1040 |
+
"""
|
| 1041 |
+
if osname is None:
|
| 1042 |
+
osname = os.name
|
| 1043 |
+
if platform is None:
|
| 1044 |
+
platform = sys.platform
|
| 1045 |
+
for pattern, compiler in _default_compilers:
|
| 1046 |
+
if (
|
| 1047 |
+
re.match(pattern, platform) is not None
|
| 1048 |
+
or re.match(pattern, osname) is not None
|
| 1049 |
+
):
|
| 1050 |
+
return compiler
|
| 1051 |
+
# Default to Unix compiler
|
| 1052 |
+
return 'unix'
|
| 1053 |
+
|
| 1054 |
+
|
| 1055 |
+
# Map compiler types to (module_name, class_name) pairs -- ie. where to
|
| 1056 |
+
# find the code that implements an interface to this compiler. (The module
|
| 1057 |
+
# is assumed to be in the 'distutils' package.)
|
| 1058 |
+
compiler_class = {
|
| 1059 |
+
'unix': ('unixccompiler', 'UnixCCompiler', "standard UNIX-style compiler"),
|
| 1060 |
+
'msvc': ('_msvccompiler', 'MSVCCompiler', "Microsoft Visual C++"),
|
| 1061 |
+
'cygwin': (
|
| 1062 |
+
'cygwinccompiler',
|
| 1063 |
+
'CygwinCCompiler',
|
| 1064 |
+
"Cygwin port of GNU C Compiler for Win32",
|
| 1065 |
+
),
|
| 1066 |
+
'mingw32': (
|
| 1067 |
+
'cygwinccompiler',
|
| 1068 |
+
'Mingw32CCompiler',
|
| 1069 |
+
"Mingw32 port of GNU C Compiler for Win32",
|
| 1070 |
+
),
|
| 1071 |
+
'bcpp': ('bcppcompiler', 'BCPPCompiler', "Borland C++ Compiler"),
|
| 1072 |
+
}
|
| 1073 |
+
|
| 1074 |
+
|
| 1075 |
+
def show_compilers():
|
| 1076 |
+
"""Print list of available compilers (used by the "--help-compiler"
|
| 1077 |
+
options to "build", "build_ext", "build_clib").
|
| 1078 |
+
"""
|
| 1079 |
+
# XXX this "knows" that the compiler option it's describing is
|
| 1080 |
+
# "--compiler", which just happens to be the case for the three
|
| 1081 |
+
# commands that use it.
|
| 1082 |
+
from distutils.fancy_getopt import FancyGetopt
|
| 1083 |
+
|
| 1084 |
+
compilers = []
|
| 1085 |
+
for compiler in compiler_class.keys():
|
| 1086 |
+
compilers.append(("compiler=" + compiler, None, compiler_class[compiler][2]))
|
| 1087 |
+
compilers.sort()
|
| 1088 |
+
pretty_printer = FancyGetopt(compilers)
|
| 1089 |
+
pretty_printer.print_help("List of available compilers:")
|
| 1090 |
+
|
| 1091 |
+
|
| 1092 |
+
def new_compiler(plat=None, compiler=None, verbose=0, dry_run=0, force=0):
|
| 1093 |
+
"""Generate an instance of some CCompiler subclass for the supplied
|
| 1094 |
+
platform/compiler combination. 'plat' defaults to 'os.name'
|
| 1095 |
+
(eg. 'posix', 'nt'), and 'compiler' defaults to the default compiler
|
| 1096 |
+
for that platform. Currently only 'posix' and 'nt' are supported, and
|
| 1097 |
+
the default compilers are "traditional Unix interface" (UnixCCompiler
|
| 1098 |
+
class) and Visual C++ (MSVCCompiler class). Note that it's perfectly
|
| 1099 |
+
possible to ask for a Unix compiler object under Windows, and a
|
| 1100 |
+
Microsoft compiler object under Unix -- if you supply a value for
|
| 1101 |
+
'compiler', 'plat' is ignored.
|
| 1102 |
+
"""
|
| 1103 |
+
if plat is None:
|
| 1104 |
+
plat = os.name
|
| 1105 |
+
|
| 1106 |
+
try:
|
| 1107 |
+
if compiler is None:
|
| 1108 |
+
compiler = get_default_compiler(plat)
|
| 1109 |
+
|
| 1110 |
+
(module_name, class_name, long_description) = compiler_class[compiler]
|
| 1111 |
+
except KeyError:
|
| 1112 |
+
msg = "don't know how to compile C/C++ code on platform '%s'" % plat
|
| 1113 |
+
if compiler is not None:
|
| 1114 |
+
msg = msg + " with '%s' compiler" % compiler
|
| 1115 |
+
raise DistutilsPlatformError(msg)
|
| 1116 |
+
|
| 1117 |
+
try:
|
| 1118 |
+
module_name = "distutils." + module_name
|
| 1119 |
+
__import__(module_name)
|
| 1120 |
+
module = sys.modules[module_name]
|
| 1121 |
+
klass = vars(module)[class_name]
|
| 1122 |
+
except ImportError:
|
| 1123 |
+
raise DistutilsModuleError(
|
| 1124 |
+
"can't compile C/C++ code: unable to load module '%s'" % module_name
|
| 1125 |
+
)
|
| 1126 |
+
except KeyError:
|
| 1127 |
+
raise DistutilsModuleError(
|
| 1128 |
+
"can't compile C/C++ code: unable to find class '%s' "
|
| 1129 |
+
"in module '%s'" % (class_name, module_name)
|
| 1130 |
+
)
|
| 1131 |
+
|
| 1132 |
+
# XXX The None is necessary to preserve backwards compatibility
|
| 1133 |
+
# with classes that expect verbose to be the first positional
|
| 1134 |
+
# argument.
|
| 1135 |
+
return klass(None, dry_run, force)
|
| 1136 |
+
|
| 1137 |
+
|
| 1138 |
+
def gen_preprocess_options(macros, include_dirs):
|
| 1139 |
+
"""Generate C pre-processor options (-D, -U, -I) as used by at least
|
| 1140 |
+
two types of compilers: the typical Unix compiler and Visual C++.
|
| 1141 |
+
'macros' is the usual thing, a list of 1- or 2-tuples, where (name,)
|
| 1142 |
+
means undefine (-U) macro 'name', and (name,value) means define (-D)
|
| 1143 |
+
macro 'name' to 'value'. 'include_dirs' is just a list of directory
|
| 1144 |
+
names to be added to the header file search path (-I). Returns a list
|
| 1145 |
+
of command-line options suitable for either Unix compilers or Visual
|
| 1146 |
+
C++.
|
| 1147 |
+
"""
|
| 1148 |
+
# XXX it would be nice (mainly aesthetic, and so we don't generate
|
| 1149 |
+
# stupid-looking command lines) to go over 'macros' and eliminate
|
| 1150 |
+
# redundant definitions/undefinitions (ie. ensure that only the
|
| 1151 |
+
# latest mention of a particular macro winds up on the command
|
| 1152 |
+
# line). I don't think it's essential, though, since most (all?)
|
| 1153 |
+
# Unix C compilers only pay attention to the latest -D or -U
|
| 1154 |
+
# mention of a macro on their command line. Similar situation for
|
| 1155 |
+
# 'include_dirs'. I'm punting on both for now. Anyways, weeding out
|
| 1156 |
+
# redundancies like this should probably be the province of
|
| 1157 |
+
# CCompiler, since the data structures used are inherited from it
|
| 1158 |
+
# and therefore common to all CCompiler classes.
|
| 1159 |
+
pp_opts = []
|
| 1160 |
+
for macro in macros:
|
| 1161 |
+
if not (isinstance(macro, tuple) and 1 <= len(macro) <= 2):
|
| 1162 |
+
raise TypeError(
|
| 1163 |
+
"bad macro definition '%s': "
|
| 1164 |
+
"each element of 'macros' list must be a 1- or 2-tuple" % macro
|
| 1165 |
+
)
|
| 1166 |
+
|
| 1167 |
+
if len(macro) == 1: # undefine this macro
|
| 1168 |
+
pp_opts.append("-U%s" % macro[0])
|
| 1169 |
+
elif len(macro) == 2:
|
| 1170 |
+
if macro[1] is None: # define with no explicit value
|
| 1171 |
+
pp_opts.append("-D%s" % macro[0])
|
| 1172 |
+
else:
|
| 1173 |
+
# XXX *don't* need to be clever about quoting the
|
| 1174 |
+
# macro value here, because we're going to avoid the
|
| 1175 |
+
# shell at all costs when we spawn the command!
|
| 1176 |
+
pp_opts.append("-D%s=%s" % macro)
|
| 1177 |
+
|
| 1178 |
+
for dir in include_dirs:
|
| 1179 |
+
pp_opts.append("-I%s" % dir)
|
| 1180 |
+
return pp_opts
|
| 1181 |
+
|
| 1182 |
+
|
| 1183 |
+
def gen_lib_options(compiler, library_dirs, runtime_library_dirs, libraries):
|
| 1184 |
+
"""Generate linker options for searching library directories and
|
| 1185 |
+
linking with specific libraries. 'libraries' and 'library_dirs' are,
|
| 1186 |
+
respectively, lists of library names (not filenames!) and search
|
| 1187 |
+
directories. Returns a list of command-line options suitable for use
|
| 1188 |
+
with some compiler (depending on the two format strings passed in).
|
| 1189 |
+
"""
|
| 1190 |
+
lib_opts = []
|
| 1191 |
+
|
| 1192 |
+
for dir in library_dirs:
|
| 1193 |
+
lib_opts.append(compiler.library_dir_option(dir))
|
| 1194 |
+
|
| 1195 |
+
for dir in runtime_library_dirs:
|
| 1196 |
+
opt = compiler.runtime_library_dir_option(dir)
|
| 1197 |
+
if isinstance(opt, list):
|
| 1198 |
+
lib_opts = lib_opts + opt
|
| 1199 |
+
else:
|
| 1200 |
+
lib_opts.append(opt)
|
| 1201 |
+
|
| 1202 |
+
# XXX it's important that we *not* remove redundant library mentions!
|
| 1203 |
+
# sometimes you really do have to say "-lfoo -lbar -lfoo" in order to
|
| 1204 |
+
# resolve all symbols. I just hope we never have to say "-lfoo obj.o
|
| 1205 |
+
# -lbar" to get things to work -- that's certainly a possibility, but a
|
| 1206 |
+
# pretty nasty way to arrange your C code.
|
| 1207 |
+
|
| 1208 |
+
for lib in libraries:
|
| 1209 |
+
(lib_dir, lib_name) = os.path.split(lib)
|
| 1210 |
+
if lib_dir:
|
| 1211 |
+
lib_file = compiler.find_library_file([lib_dir], lib_name)
|
| 1212 |
+
if lib_file:
|
| 1213 |
+
lib_opts.append(lib_file)
|
| 1214 |
+
else:
|
| 1215 |
+
compiler.warn(
|
| 1216 |
+
"no library file corresponding to " "'%s' found (skipping)" % lib
|
| 1217 |
+
)
|
| 1218 |
+
else:
|
| 1219 |
+
lib_opts.append(compiler.library_option(lib))
|
| 1220 |
+
return lib_opts
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/cmd.py
ADDED
|
@@ -0,0 +1,436 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""distutils.cmd
|
| 2 |
+
|
| 3 |
+
Provides the Command class, the base class for the command classes
|
| 4 |
+
in the distutils.command package.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import sys
|
| 8 |
+
import os
|
| 9 |
+
import re
|
| 10 |
+
from distutils.errors import DistutilsOptionError
|
| 11 |
+
from distutils import util, dir_util, file_util, archive_util, dep_util
|
| 12 |
+
from distutils import log
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
class Command:
|
| 16 |
+
"""Abstract base class for defining command classes, the "worker bees"
|
| 17 |
+
of the Distutils. A useful analogy for command classes is to think of
|
| 18 |
+
them as subroutines with local variables called "options". The options
|
| 19 |
+
are "declared" in 'initialize_options()' and "defined" (given their
|
| 20 |
+
final values, aka "finalized") in 'finalize_options()', both of which
|
| 21 |
+
must be defined by every command class. The distinction between the
|
| 22 |
+
two is necessary because option values might come from the outside
|
| 23 |
+
world (command line, config file, ...), and any options dependent on
|
| 24 |
+
other options must be computed *after* these outside influences have
|
| 25 |
+
been processed -- hence 'finalize_options()'. The "body" of the
|
| 26 |
+
subroutine, where it does all its work based on the values of its
|
| 27 |
+
options, is the 'run()' method, which must also be implemented by every
|
| 28 |
+
command class.
|
| 29 |
+
"""
|
| 30 |
+
|
| 31 |
+
# 'sub_commands' formalizes the notion of a "family" of commands,
|
| 32 |
+
# eg. "install" as the parent with sub-commands "install_lib",
|
| 33 |
+
# "install_headers", etc. The parent of a family of commands
|
| 34 |
+
# defines 'sub_commands' as a class attribute; it's a list of
|
| 35 |
+
# (command_name : string, predicate : unbound_method | string | None)
|
| 36 |
+
# tuples, where 'predicate' is a method of the parent command that
|
| 37 |
+
# determines whether the corresponding command is applicable in the
|
| 38 |
+
# current situation. (Eg. we "install_headers" is only applicable if
|
| 39 |
+
# we have any C header files to install.) If 'predicate' is None,
|
| 40 |
+
# that command is always applicable.
|
| 41 |
+
#
|
| 42 |
+
# 'sub_commands' is usually defined at the *end* of a class, because
|
| 43 |
+
# predicates can be unbound methods, so they must already have been
|
| 44 |
+
# defined. The canonical example is the "install" command.
|
| 45 |
+
sub_commands = []
|
| 46 |
+
|
| 47 |
+
# -- Creation/initialization methods -------------------------------
|
| 48 |
+
|
| 49 |
+
def __init__(self, dist):
|
| 50 |
+
"""Create and initialize a new Command object. Most importantly,
|
| 51 |
+
invokes the 'initialize_options()' method, which is the real
|
| 52 |
+
initializer and depends on the actual command being
|
| 53 |
+
instantiated.
|
| 54 |
+
"""
|
| 55 |
+
# late import because of mutual dependence between these classes
|
| 56 |
+
from distutils.dist import Distribution
|
| 57 |
+
|
| 58 |
+
if not isinstance(dist, Distribution):
|
| 59 |
+
raise TypeError("dist must be a Distribution instance")
|
| 60 |
+
if self.__class__ is Command:
|
| 61 |
+
raise RuntimeError("Command is an abstract class")
|
| 62 |
+
|
| 63 |
+
self.distribution = dist
|
| 64 |
+
self.initialize_options()
|
| 65 |
+
|
| 66 |
+
# Per-command versions of the global flags, so that the user can
|
| 67 |
+
# customize Distutils' behaviour command-by-command and let some
|
| 68 |
+
# commands fall back on the Distribution's behaviour. None means
|
| 69 |
+
# "not defined, check self.distribution's copy", while 0 or 1 mean
|
| 70 |
+
# false and true (duh). Note that this means figuring out the real
|
| 71 |
+
# value of each flag is a touch complicated -- hence "self._dry_run"
|
| 72 |
+
# will be handled by __getattr__, below.
|
| 73 |
+
# XXX This needs to be fixed.
|
| 74 |
+
self._dry_run = None
|
| 75 |
+
|
| 76 |
+
# verbose is largely ignored, but needs to be set for
|
| 77 |
+
# backwards compatibility (I think)?
|
| 78 |
+
self.verbose = dist.verbose
|
| 79 |
+
|
| 80 |
+
# Some commands define a 'self.force' option to ignore file
|
| 81 |
+
# timestamps, but methods defined *here* assume that
|
| 82 |
+
# 'self.force' exists for all commands. So define it here
|
| 83 |
+
# just to be safe.
|
| 84 |
+
self.force = None
|
| 85 |
+
|
| 86 |
+
# The 'help' flag is just used for command-line parsing, so
|
| 87 |
+
# none of that complicated bureaucracy is needed.
|
| 88 |
+
self.help = 0
|
| 89 |
+
|
| 90 |
+
# 'finalized' records whether or not 'finalize_options()' has been
|
| 91 |
+
# called. 'finalize_options()' itself should not pay attention to
|
| 92 |
+
# this flag: it is the business of 'ensure_finalized()', which
|
| 93 |
+
# always calls 'finalize_options()', to respect/update it.
|
| 94 |
+
self.finalized = 0
|
| 95 |
+
|
| 96 |
+
# XXX A more explicit way to customize dry_run would be better.
|
| 97 |
+
def __getattr__(self, attr):
|
| 98 |
+
if attr == 'dry_run':
|
| 99 |
+
myval = getattr(self, "_" + attr)
|
| 100 |
+
if myval is None:
|
| 101 |
+
return getattr(self.distribution, attr)
|
| 102 |
+
else:
|
| 103 |
+
return myval
|
| 104 |
+
else:
|
| 105 |
+
raise AttributeError(attr)
|
| 106 |
+
|
| 107 |
+
def ensure_finalized(self):
|
| 108 |
+
if not self.finalized:
|
| 109 |
+
self.finalize_options()
|
| 110 |
+
self.finalized = 1
|
| 111 |
+
|
| 112 |
+
# Subclasses must define:
|
| 113 |
+
# initialize_options()
|
| 114 |
+
# provide default values for all options; may be customized by
|
| 115 |
+
# setup script, by options from config file(s), or by command-line
|
| 116 |
+
# options
|
| 117 |
+
# finalize_options()
|
| 118 |
+
# decide on the final values for all options; this is called
|
| 119 |
+
# after all possible intervention from the outside world
|
| 120 |
+
# (command-line, option file, etc.) has been processed
|
| 121 |
+
# run()
|
| 122 |
+
# run the command: do whatever it is we're here to do,
|
| 123 |
+
# controlled by the command's various option values
|
| 124 |
+
|
| 125 |
+
def initialize_options(self):
|
| 126 |
+
"""Set default values for all the options that this command
|
| 127 |
+
supports. Note that these defaults may be overridden by other
|
| 128 |
+
commands, by the setup script, by config files, or by the
|
| 129 |
+
command-line. Thus, this is not the place to code dependencies
|
| 130 |
+
between options; generally, 'initialize_options()' implementations
|
| 131 |
+
are just a bunch of "self.foo = None" assignments.
|
| 132 |
+
|
| 133 |
+
This method must be implemented by all command classes.
|
| 134 |
+
"""
|
| 135 |
+
raise RuntimeError(
|
| 136 |
+
"abstract method -- subclass %s must override" % self.__class__
|
| 137 |
+
)
|
| 138 |
+
|
| 139 |
+
def finalize_options(self):
|
| 140 |
+
"""Set final values for all the options that this command supports.
|
| 141 |
+
This is always called as late as possible, ie. after any option
|
| 142 |
+
assignments from the command-line or from other commands have been
|
| 143 |
+
done. Thus, this is the place to code option dependencies: if
|
| 144 |
+
'foo' depends on 'bar', then it is safe to set 'foo' from 'bar' as
|
| 145 |
+
long as 'foo' still has the same value it was assigned in
|
| 146 |
+
'initialize_options()'.
|
| 147 |
+
|
| 148 |
+
This method must be implemented by all command classes.
|
| 149 |
+
"""
|
| 150 |
+
raise RuntimeError(
|
| 151 |
+
"abstract method -- subclass %s must override" % self.__class__
|
| 152 |
+
)
|
| 153 |
+
|
| 154 |
+
def dump_options(self, header=None, indent=""):
|
| 155 |
+
from distutils.fancy_getopt import longopt_xlate
|
| 156 |
+
|
| 157 |
+
if header is None:
|
| 158 |
+
header = "command options for '%s':" % self.get_command_name()
|
| 159 |
+
self.announce(indent + header, level=log.INFO)
|
| 160 |
+
indent = indent + " "
|
| 161 |
+
for (option, _, _) in self.user_options:
|
| 162 |
+
option = option.translate(longopt_xlate)
|
| 163 |
+
if option[-1] == "=":
|
| 164 |
+
option = option[:-1]
|
| 165 |
+
value = getattr(self, option)
|
| 166 |
+
self.announce(indent + "{} = {}".format(option, value), level=log.INFO)
|
| 167 |
+
|
| 168 |
+
def run(self):
|
| 169 |
+
"""A command's raison d'etre: carry out the action it exists to
|
| 170 |
+
perform, controlled by the options initialized in
|
| 171 |
+
'initialize_options()', customized by other commands, the setup
|
| 172 |
+
script, the command-line, and config files, and finalized in
|
| 173 |
+
'finalize_options()'. All terminal output and filesystem
|
| 174 |
+
interaction should be done by 'run()'.
|
| 175 |
+
|
| 176 |
+
This method must be implemented by all command classes.
|
| 177 |
+
"""
|
| 178 |
+
raise RuntimeError(
|
| 179 |
+
"abstract method -- subclass %s must override" % self.__class__
|
| 180 |
+
)
|
| 181 |
+
|
| 182 |
+
def announce(self, msg, level=1):
|
| 183 |
+
"""If the current verbosity level is of greater than or equal to
|
| 184 |
+
'level' print 'msg' to stdout.
|
| 185 |
+
"""
|
| 186 |
+
log.log(level, msg)
|
| 187 |
+
|
| 188 |
+
def debug_print(self, msg):
|
| 189 |
+
"""Print 'msg' to stdout if the global DEBUG (taken from the
|
| 190 |
+
DISTUTILS_DEBUG environment variable) flag is true.
|
| 191 |
+
"""
|
| 192 |
+
from distutils.debug import DEBUG
|
| 193 |
+
|
| 194 |
+
if DEBUG:
|
| 195 |
+
print(msg)
|
| 196 |
+
sys.stdout.flush()
|
| 197 |
+
|
| 198 |
+
# -- Option validation methods -------------------------------------
|
| 199 |
+
# (these are very handy in writing the 'finalize_options()' method)
|
| 200 |
+
#
|
| 201 |
+
# NB. the general philosophy here is to ensure that a particular option
|
| 202 |
+
# value meets certain type and value constraints. If not, we try to
|
| 203 |
+
# force it into conformance (eg. if we expect a list but have a string,
|
| 204 |
+
# split the string on comma and/or whitespace). If we can't force the
|
| 205 |
+
# option into conformance, raise DistutilsOptionError. Thus, command
|
| 206 |
+
# classes need do nothing more than (eg.)
|
| 207 |
+
# self.ensure_string_list('foo')
|
| 208 |
+
# and they can be guaranteed that thereafter, self.foo will be
|
| 209 |
+
# a list of strings.
|
| 210 |
+
|
| 211 |
+
def _ensure_stringlike(self, option, what, default=None):
|
| 212 |
+
val = getattr(self, option)
|
| 213 |
+
if val is None:
|
| 214 |
+
setattr(self, option, default)
|
| 215 |
+
return default
|
| 216 |
+
elif not isinstance(val, str):
|
| 217 |
+
raise DistutilsOptionError(
|
| 218 |
+
"'{}' must be a {} (got `{}`)".format(option, what, val)
|
| 219 |
+
)
|
| 220 |
+
return val
|
| 221 |
+
|
| 222 |
+
def ensure_string(self, option, default=None):
|
| 223 |
+
"""Ensure that 'option' is a string; if not defined, set it to
|
| 224 |
+
'default'.
|
| 225 |
+
"""
|
| 226 |
+
self._ensure_stringlike(option, "string", default)
|
| 227 |
+
|
| 228 |
+
def ensure_string_list(self, option):
|
| 229 |
+
r"""Ensure that 'option' is a list of strings. If 'option' is
|
| 230 |
+
currently a string, we split it either on /,\s*/ or /\s+/, so
|
| 231 |
+
"foo bar baz", "foo,bar,baz", and "foo, bar baz" all become
|
| 232 |
+
["foo", "bar", "baz"].
|
| 233 |
+
"""
|
| 234 |
+
val = getattr(self, option)
|
| 235 |
+
if val is None:
|
| 236 |
+
return
|
| 237 |
+
elif isinstance(val, str):
|
| 238 |
+
setattr(self, option, re.split(r',\s*|\s+', val))
|
| 239 |
+
else:
|
| 240 |
+
if isinstance(val, list):
|
| 241 |
+
ok = all(isinstance(v, str) for v in val)
|
| 242 |
+
else:
|
| 243 |
+
ok = False
|
| 244 |
+
if not ok:
|
| 245 |
+
raise DistutilsOptionError(
|
| 246 |
+
"'{}' must be a list of strings (got {!r})".format(option, val)
|
| 247 |
+
)
|
| 248 |
+
|
| 249 |
+
def _ensure_tested_string(self, option, tester, what, error_fmt, default=None):
|
| 250 |
+
val = self._ensure_stringlike(option, what, default)
|
| 251 |
+
if val is not None and not tester(val):
|
| 252 |
+
raise DistutilsOptionError(
|
| 253 |
+
("error in '%s' option: " + error_fmt) % (option, val)
|
| 254 |
+
)
|
| 255 |
+
|
| 256 |
+
def ensure_filename(self, option):
|
| 257 |
+
"""Ensure that 'option' is the name of an existing file."""
|
| 258 |
+
self._ensure_tested_string(
|
| 259 |
+
option, os.path.isfile, "filename", "'%s' does not exist or is not a file"
|
| 260 |
+
)
|
| 261 |
+
|
| 262 |
+
def ensure_dirname(self, option):
|
| 263 |
+
self._ensure_tested_string(
|
| 264 |
+
option,
|
| 265 |
+
os.path.isdir,
|
| 266 |
+
"directory name",
|
| 267 |
+
"'%s' does not exist or is not a directory",
|
| 268 |
+
)
|
| 269 |
+
|
| 270 |
+
# -- Convenience methods for commands ------------------------------
|
| 271 |
+
|
| 272 |
+
def get_command_name(self):
|
| 273 |
+
if hasattr(self, 'command_name'):
|
| 274 |
+
return self.command_name
|
| 275 |
+
else:
|
| 276 |
+
return self.__class__.__name__
|
| 277 |
+
|
| 278 |
+
def set_undefined_options(self, src_cmd, *option_pairs):
|
| 279 |
+
"""Set the values of any "undefined" options from corresponding
|
| 280 |
+
option values in some other command object. "Undefined" here means
|
| 281 |
+
"is None", which is the convention used to indicate that an option
|
| 282 |
+
has not been changed between 'initialize_options()' and
|
| 283 |
+
'finalize_options()'. Usually called from 'finalize_options()' for
|
| 284 |
+
options that depend on some other command rather than another
|
| 285 |
+
option of the same command. 'src_cmd' is the other command from
|
| 286 |
+
which option values will be taken (a command object will be created
|
| 287 |
+
for it if necessary); the remaining arguments are
|
| 288 |
+
'(src_option,dst_option)' tuples which mean "take the value of
|
| 289 |
+
'src_option' in the 'src_cmd' command object, and copy it to
|
| 290 |
+
'dst_option' in the current command object".
|
| 291 |
+
"""
|
| 292 |
+
# Option_pairs: list of (src_option, dst_option) tuples
|
| 293 |
+
src_cmd_obj = self.distribution.get_command_obj(src_cmd)
|
| 294 |
+
src_cmd_obj.ensure_finalized()
|
| 295 |
+
for (src_option, dst_option) in option_pairs:
|
| 296 |
+
if getattr(self, dst_option) is None:
|
| 297 |
+
setattr(self, dst_option, getattr(src_cmd_obj, src_option))
|
| 298 |
+
|
| 299 |
+
def get_finalized_command(self, command, create=1):
|
| 300 |
+
"""Wrapper around Distribution's 'get_command_obj()' method: find
|
| 301 |
+
(create if necessary and 'create' is true) the command object for
|
| 302 |
+
'command', call its 'ensure_finalized()' method, and return the
|
| 303 |
+
finalized command object.
|
| 304 |
+
"""
|
| 305 |
+
cmd_obj = self.distribution.get_command_obj(command, create)
|
| 306 |
+
cmd_obj.ensure_finalized()
|
| 307 |
+
return cmd_obj
|
| 308 |
+
|
| 309 |
+
# XXX rename to 'get_reinitialized_command()'? (should do the
|
| 310 |
+
# same in dist.py, if so)
|
| 311 |
+
def reinitialize_command(self, command, reinit_subcommands=0):
|
| 312 |
+
return self.distribution.reinitialize_command(command, reinit_subcommands)
|
| 313 |
+
|
| 314 |
+
def run_command(self, command):
|
| 315 |
+
"""Run some other command: uses the 'run_command()' method of
|
| 316 |
+
Distribution, which creates and finalizes the command object if
|
| 317 |
+
necessary and then invokes its 'run()' method.
|
| 318 |
+
"""
|
| 319 |
+
self.distribution.run_command(command)
|
| 320 |
+
|
| 321 |
+
def get_sub_commands(self):
|
| 322 |
+
"""Determine the sub-commands that are relevant in the current
|
| 323 |
+
distribution (ie., that need to be run). This is based on the
|
| 324 |
+
'sub_commands' class attribute: each tuple in that list may include
|
| 325 |
+
a method that we call to determine if the subcommand needs to be
|
| 326 |
+
run for the current distribution. Return a list of command names.
|
| 327 |
+
"""
|
| 328 |
+
commands = []
|
| 329 |
+
for (cmd_name, method) in self.sub_commands:
|
| 330 |
+
if method is None or method(self):
|
| 331 |
+
commands.append(cmd_name)
|
| 332 |
+
return commands
|
| 333 |
+
|
| 334 |
+
# -- External world manipulation -----------------------------------
|
| 335 |
+
|
| 336 |
+
def warn(self, msg):
|
| 337 |
+
log.warn("warning: %s: %s\n", self.get_command_name(), msg)
|
| 338 |
+
|
| 339 |
+
def execute(self, func, args, msg=None, level=1):
|
| 340 |
+
util.execute(func, args, msg, dry_run=self.dry_run)
|
| 341 |
+
|
| 342 |
+
def mkpath(self, name, mode=0o777):
|
| 343 |
+
dir_util.mkpath(name, mode, dry_run=self.dry_run)
|
| 344 |
+
|
| 345 |
+
def copy_file(
|
| 346 |
+
self, infile, outfile, preserve_mode=1, preserve_times=1, link=None, level=1
|
| 347 |
+
):
|
| 348 |
+
"""Copy a file respecting verbose, dry-run and force flags. (The
|
| 349 |
+
former two default to whatever is in the Distribution object, and
|
| 350 |
+
the latter defaults to false for commands that don't define it.)"""
|
| 351 |
+
return file_util.copy_file(
|
| 352 |
+
infile,
|
| 353 |
+
outfile,
|
| 354 |
+
preserve_mode,
|
| 355 |
+
preserve_times,
|
| 356 |
+
not self.force,
|
| 357 |
+
link,
|
| 358 |
+
dry_run=self.dry_run,
|
| 359 |
+
)
|
| 360 |
+
|
| 361 |
+
def copy_tree(
|
| 362 |
+
self,
|
| 363 |
+
infile,
|
| 364 |
+
outfile,
|
| 365 |
+
preserve_mode=1,
|
| 366 |
+
preserve_times=1,
|
| 367 |
+
preserve_symlinks=0,
|
| 368 |
+
level=1,
|
| 369 |
+
):
|
| 370 |
+
"""Copy an entire directory tree respecting verbose, dry-run,
|
| 371 |
+
and force flags.
|
| 372 |
+
"""
|
| 373 |
+
return dir_util.copy_tree(
|
| 374 |
+
infile,
|
| 375 |
+
outfile,
|
| 376 |
+
preserve_mode,
|
| 377 |
+
preserve_times,
|
| 378 |
+
preserve_symlinks,
|
| 379 |
+
not self.force,
|
| 380 |
+
dry_run=self.dry_run,
|
| 381 |
+
)
|
| 382 |
+
|
| 383 |
+
def move_file(self, src, dst, level=1):
|
| 384 |
+
"""Move a file respecting dry-run flag."""
|
| 385 |
+
return file_util.move_file(src, dst, dry_run=self.dry_run)
|
| 386 |
+
|
| 387 |
+
def spawn(self, cmd, search_path=1, level=1):
|
| 388 |
+
"""Spawn an external command respecting dry-run flag."""
|
| 389 |
+
from distutils.spawn import spawn
|
| 390 |
+
|
| 391 |
+
spawn(cmd, search_path, dry_run=self.dry_run)
|
| 392 |
+
|
| 393 |
+
def make_archive(
|
| 394 |
+
self, base_name, format, root_dir=None, base_dir=None, owner=None, group=None
|
| 395 |
+
):
|
| 396 |
+
return archive_util.make_archive(
|
| 397 |
+
base_name,
|
| 398 |
+
format,
|
| 399 |
+
root_dir,
|
| 400 |
+
base_dir,
|
| 401 |
+
dry_run=self.dry_run,
|
| 402 |
+
owner=owner,
|
| 403 |
+
group=group,
|
| 404 |
+
)
|
| 405 |
+
|
| 406 |
+
def make_file(
|
| 407 |
+
self, infiles, outfile, func, args, exec_msg=None, skip_msg=None, level=1
|
| 408 |
+
):
|
| 409 |
+
"""Special case of 'execute()' for operations that process one or
|
| 410 |
+
more input files and generate one output file. Works just like
|
| 411 |
+
'execute()', except the operation is skipped and a different
|
| 412 |
+
message printed if 'outfile' already exists and is newer than all
|
| 413 |
+
files listed in 'infiles'. If the command defined 'self.force',
|
| 414 |
+
and it is true, then the command is unconditionally run -- does no
|
| 415 |
+
timestamp checks.
|
| 416 |
+
"""
|
| 417 |
+
if skip_msg is None:
|
| 418 |
+
skip_msg = "skipping %s (inputs unchanged)" % outfile
|
| 419 |
+
|
| 420 |
+
# Allow 'infiles' to be a single string
|
| 421 |
+
if isinstance(infiles, str):
|
| 422 |
+
infiles = (infiles,)
|
| 423 |
+
elif not isinstance(infiles, (list, tuple)):
|
| 424 |
+
raise TypeError("'infiles' must be a string, or a list or tuple of strings")
|
| 425 |
+
|
| 426 |
+
if exec_msg is None:
|
| 427 |
+
exec_msg = "generating {} from {}".format(outfile, ', '.join(infiles))
|
| 428 |
+
|
| 429 |
+
# If 'outfile' must be regenerated (either because it doesn't
|
| 430 |
+
# exist, is out-of-date, or the 'force' flag is true) then
|
| 431 |
+
# perform the action that presumably regenerates it
|
| 432 |
+
if self.force or dep_util.newer_group(infiles, outfile):
|
| 433 |
+
self.execute(func, args, exec_msg, level)
|
| 434 |
+
# Otherwise, print the "skip" message
|
| 435 |
+
else:
|
| 436 |
+
log.debug(skip_msg)
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/_framework_compat.cpython-311.pyc
ADDED
|
Binary file (2.78 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/bdist_dumb.cpython-311.pyc
ADDED
|
Binary file (5.76 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/bdist_rpm.cpython-311.pyc
ADDED
|
Binary file (23.3 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/build.cpython-311.pyc
ADDED
|
Binary file (6.09 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/build_clib.cpython-311.pyc
ADDED
|
Binary file (7.79 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/build_scripts.cpython-311.pyc
ADDED
|
Binary file (7.86 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/clean.cpython-311.pyc
ADDED
|
Binary file (3.19 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/install.cpython-311.pyc
ADDED
|
Binary file (29.4 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/install_data.cpython-311.pyc
ADDED
|
Binary file (3.78 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/install_headers.cpython-311.pyc
ADDED
|
Binary file (2.36 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/install_lib.cpython-311.pyc
ADDED
|
Binary file (8.69 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/install_scripts.cpython-311.pyc
ADDED
|
Binary file (3.16 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/py37compat.cpython-311.pyc
ADDED
|
Binary file (1.54 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/register.cpython-311.pyc
ADDED
|
Binary file (15.5 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/__pycache__/sdist.cpython-311.pyc
ADDED
|
Binary file (23.8 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/bdist_dumb.py
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""distutils.command.bdist_dumb
|
| 2 |
+
|
| 3 |
+
Implements the Distutils 'bdist_dumb' command (create a "dumb" built
|
| 4 |
+
distribution -- i.e., just an archive to be unpacked under $prefix or
|
| 5 |
+
$exec_prefix)."""
|
| 6 |
+
|
| 7 |
+
import os
|
| 8 |
+
from distutils.core import Command
|
| 9 |
+
from distutils.util import get_platform
|
| 10 |
+
from distutils.dir_util import remove_tree, ensure_relative
|
| 11 |
+
from distutils.errors import DistutilsPlatformError
|
| 12 |
+
from distutils.sysconfig import get_python_version
|
| 13 |
+
from distutils import log
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
class bdist_dumb(Command):
|
| 17 |
+
|
| 18 |
+
description = "create a \"dumb\" built distribution"
|
| 19 |
+
|
| 20 |
+
user_options = [
|
| 21 |
+
('bdist-dir=', 'd', "temporary directory for creating the distribution"),
|
| 22 |
+
(
|
| 23 |
+
'plat-name=',
|
| 24 |
+
'p',
|
| 25 |
+
"platform name to embed in generated filenames "
|
| 26 |
+
"(default: %s)" % get_platform(),
|
| 27 |
+
),
|
| 28 |
+
(
|
| 29 |
+
'format=',
|
| 30 |
+
'f',
|
| 31 |
+
"archive format to create (tar, gztar, bztar, xztar, " "ztar, zip)",
|
| 32 |
+
),
|
| 33 |
+
(
|
| 34 |
+
'keep-temp',
|
| 35 |
+
'k',
|
| 36 |
+
"keep the pseudo-installation tree around after "
|
| 37 |
+
+ "creating the distribution archive",
|
| 38 |
+
),
|
| 39 |
+
('dist-dir=', 'd', "directory to put final built distributions in"),
|
| 40 |
+
('skip-build', None, "skip rebuilding everything (for testing/debugging)"),
|
| 41 |
+
(
|
| 42 |
+
'relative',
|
| 43 |
+
None,
|
| 44 |
+
"build the archive using relative paths " "(default: false)",
|
| 45 |
+
),
|
| 46 |
+
(
|
| 47 |
+
'owner=',
|
| 48 |
+
'u',
|
| 49 |
+
"Owner name used when creating a tar file" " [default: current user]",
|
| 50 |
+
),
|
| 51 |
+
(
|
| 52 |
+
'group=',
|
| 53 |
+
'g',
|
| 54 |
+
"Group name used when creating a tar file" " [default: current group]",
|
| 55 |
+
),
|
| 56 |
+
]
|
| 57 |
+
|
| 58 |
+
boolean_options = ['keep-temp', 'skip-build', 'relative']
|
| 59 |
+
|
| 60 |
+
default_format = {'posix': 'gztar', 'nt': 'zip'}
|
| 61 |
+
|
| 62 |
+
def initialize_options(self):
|
| 63 |
+
self.bdist_dir = None
|
| 64 |
+
self.plat_name = None
|
| 65 |
+
self.format = None
|
| 66 |
+
self.keep_temp = 0
|
| 67 |
+
self.dist_dir = None
|
| 68 |
+
self.skip_build = None
|
| 69 |
+
self.relative = 0
|
| 70 |
+
self.owner = None
|
| 71 |
+
self.group = None
|
| 72 |
+
|
| 73 |
+
def finalize_options(self):
|
| 74 |
+
if self.bdist_dir is None:
|
| 75 |
+
bdist_base = self.get_finalized_command('bdist').bdist_base
|
| 76 |
+
self.bdist_dir = os.path.join(bdist_base, 'dumb')
|
| 77 |
+
|
| 78 |
+
if self.format is None:
|
| 79 |
+
try:
|
| 80 |
+
self.format = self.default_format[os.name]
|
| 81 |
+
except KeyError:
|
| 82 |
+
raise DistutilsPlatformError(
|
| 83 |
+
"don't know how to create dumb built distributions "
|
| 84 |
+
"on platform %s" % os.name
|
| 85 |
+
)
|
| 86 |
+
|
| 87 |
+
self.set_undefined_options(
|
| 88 |
+
'bdist',
|
| 89 |
+
('dist_dir', 'dist_dir'),
|
| 90 |
+
('plat_name', 'plat_name'),
|
| 91 |
+
('skip_build', 'skip_build'),
|
| 92 |
+
)
|
| 93 |
+
|
| 94 |
+
def run(self):
|
| 95 |
+
if not self.skip_build:
|
| 96 |
+
self.run_command('build')
|
| 97 |
+
|
| 98 |
+
install = self.reinitialize_command('install', reinit_subcommands=1)
|
| 99 |
+
install.root = self.bdist_dir
|
| 100 |
+
install.skip_build = self.skip_build
|
| 101 |
+
install.warn_dir = 0
|
| 102 |
+
|
| 103 |
+
log.info("installing to %s", self.bdist_dir)
|
| 104 |
+
self.run_command('install')
|
| 105 |
+
|
| 106 |
+
# And make an archive relative to the root of the
|
| 107 |
+
# pseudo-installation tree.
|
| 108 |
+
archive_basename = "{}.{}".format(
|
| 109 |
+
self.distribution.get_fullname(), self.plat_name
|
| 110 |
+
)
|
| 111 |
+
|
| 112 |
+
pseudoinstall_root = os.path.join(self.dist_dir, archive_basename)
|
| 113 |
+
if not self.relative:
|
| 114 |
+
archive_root = self.bdist_dir
|
| 115 |
+
else:
|
| 116 |
+
if self.distribution.has_ext_modules() and (
|
| 117 |
+
install.install_base != install.install_platbase
|
| 118 |
+
):
|
| 119 |
+
raise DistutilsPlatformError(
|
| 120 |
+
"can't make a dumb built distribution where "
|
| 121 |
+
"base and platbase are different (%s, %s)"
|
| 122 |
+
% (repr(install.install_base), repr(install.install_platbase))
|
| 123 |
+
)
|
| 124 |
+
else:
|
| 125 |
+
archive_root = os.path.join(
|
| 126 |
+
self.bdist_dir, ensure_relative(install.install_base)
|
| 127 |
+
)
|
| 128 |
+
|
| 129 |
+
# Make the archive
|
| 130 |
+
filename = self.make_archive(
|
| 131 |
+
pseudoinstall_root,
|
| 132 |
+
self.format,
|
| 133 |
+
root_dir=archive_root,
|
| 134 |
+
owner=self.owner,
|
| 135 |
+
group=self.group,
|
| 136 |
+
)
|
| 137 |
+
if self.distribution.has_ext_modules():
|
| 138 |
+
pyversion = get_python_version()
|
| 139 |
+
else:
|
| 140 |
+
pyversion = 'any'
|
| 141 |
+
self.distribution.dist_files.append(('bdist_dumb', pyversion, filename))
|
| 142 |
+
|
| 143 |
+
if not self.keep_temp:
|
| 144 |
+
remove_tree(self.bdist_dir, dry_run=self.dry_run)
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/build.py
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""distutils.command.build
|
| 2 |
+
|
| 3 |
+
Implements the Distutils 'build' command."""
|
| 4 |
+
|
| 5 |
+
import sys
|
| 6 |
+
import os
|
| 7 |
+
from distutils.core import Command
|
| 8 |
+
from distutils.errors import DistutilsOptionError
|
| 9 |
+
from distutils.util import get_platform
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def show_compilers():
|
| 13 |
+
from distutils.ccompiler import show_compilers
|
| 14 |
+
|
| 15 |
+
show_compilers()
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class build(Command):
|
| 19 |
+
|
| 20 |
+
description = "build everything needed to install"
|
| 21 |
+
|
| 22 |
+
user_options = [
|
| 23 |
+
('build-base=', 'b', "base directory for build library"),
|
| 24 |
+
('build-purelib=', None, "build directory for platform-neutral distributions"),
|
| 25 |
+
('build-platlib=', None, "build directory for platform-specific distributions"),
|
| 26 |
+
(
|
| 27 |
+
'build-lib=',
|
| 28 |
+
None,
|
| 29 |
+
"build directory for all distribution (defaults to either "
|
| 30 |
+
+ "build-purelib or build-platlib",
|
| 31 |
+
),
|
| 32 |
+
('build-scripts=', None, "build directory for scripts"),
|
| 33 |
+
('build-temp=', 't', "temporary build directory"),
|
| 34 |
+
(
|
| 35 |
+
'plat-name=',
|
| 36 |
+
'p',
|
| 37 |
+
"platform name to build for, if supported "
|
| 38 |
+
"(default: %s)" % get_platform(),
|
| 39 |
+
),
|
| 40 |
+
('compiler=', 'c', "specify the compiler type"),
|
| 41 |
+
('parallel=', 'j', "number of parallel build jobs"),
|
| 42 |
+
('debug', 'g', "compile extensions and libraries with debugging information"),
|
| 43 |
+
('force', 'f', "forcibly build everything (ignore file timestamps)"),
|
| 44 |
+
('executable=', 'e', "specify final destination interpreter path (build.py)"),
|
| 45 |
+
]
|
| 46 |
+
|
| 47 |
+
boolean_options = ['debug', 'force']
|
| 48 |
+
|
| 49 |
+
help_options = [
|
| 50 |
+
('help-compiler', None, "list available compilers", show_compilers),
|
| 51 |
+
]
|
| 52 |
+
|
| 53 |
+
def initialize_options(self):
|
| 54 |
+
self.build_base = 'build'
|
| 55 |
+
# these are decided only after 'build_base' has its final value
|
| 56 |
+
# (unless overridden by the user or client)
|
| 57 |
+
self.build_purelib = None
|
| 58 |
+
self.build_platlib = None
|
| 59 |
+
self.build_lib = None
|
| 60 |
+
self.build_temp = None
|
| 61 |
+
self.build_scripts = None
|
| 62 |
+
self.compiler = None
|
| 63 |
+
self.plat_name = None
|
| 64 |
+
self.debug = None
|
| 65 |
+
self.force = 0
|
| 66 |
+
self.executable = None
|
| 67 |
+
self.parallel = None
|
| 68 |
+
|
| 69 |
+
def finalize_options(self): # noqa: C901
|
| 70 |
+
if self.plat_name is None:
|
| 71 |
+
self.plat_name = get_platform()
|
| 72 |
+
else:
|
| 73 |
+
# plat-name only supported for windows (other platforms are
|
| 74 |
+
# supported via ./configure flags, if at all). Avoid misleading
|
| 75 |
+
# other platforms.
|
| 76 |
+
if os.name != 'nt':
|
| 77 |
+
raise DistutilsOptionError(
|
| 78 |
+
"--plat-name only supported on Windows (try "
|
| 79 |
+
"using './configure --help' on your platform)"
|
| 80 |
+
)
|
| 81 |
+
|
| 82 |
+
plat_specifier = ".{}-{}".format(self.plat_name, sys.implementation.cache_tag)
|
| 83 |
+
|
| 84 |
+
# Make it so Python 2.x and Python 2.x with --with-pydebug don't
|
| 85 |
+
# share the same build directories. Doing so confuses the build
|
| 86 |
+
# process for C modules
|
| 87 |
+
if hasattr(sys, 'gettotalrefcount'):
|
| 88 |
+
plat_specifier += '-pydebug'
|
| 89 |
+
|
| 90 |
+
# 'build_purelib' and 'build_platlib' just default to 'lib' and
|
| 91 |
+
# 'lib.<plat>' under the base build directory. We only use one of
|
| 92 |
+
# them for a given distribution, though --
|
| 93 |
+
if self.build_purelib is None:
|
| 94 |
+
self.build_purelib = os.path.join(self.build_base, 'lib')
|
| 95 |
+
if self.build_platlib is None:
|
| 96 |
+
self.build_platlib = os.path.join(self.build_base, 'lib' + plat_specifier)
|
| 97 |
+
|
| 98 |
+
# 'build_lib' is the actual directory that we will use for this
|
| 99 |
+
# particular module distribution -- if user didn't supply it, pick
|
| 100 |
+
# one of 'build_purelib' or 'build_platlib'.
|
| 101 |
+
if self.build_lib is None:
|
| 102 |
+
if self.distribution.has_ext_modules():
|
| 103 |
+
self.build_lib = self.build_platlib
|
| 104 |
+
else:
|
| 105 |
+
self.build_lib = self.build_purelib
|
| 106 |
+
|
| 107 |
+
# 'build_temp' -- temporary directory for compiler turds,
|
| 108 |
+
# "build/temp.<plat>"
|
| 109 |
+
if self.build_temp is None:
|
| 110 |
+
self.build_temp = os.path.join(self.build_base, 'temp' + plat_specifier)
|
| 111 |
+
if self.build_scripts is None:
|
| 112 |
+
self.build_scripts = os.path.join(
|
| 113 |
+
self.build_base, 'scripts-%d.%d' % sys.version_info[:2]
|
| 114 |
+
)
|
| 115 |
+
|
| 116 |
+
if self.executable is None and sys.executable:
|
| 117 |
+
self.executable = os.path.normpath(sys.executable)
|
| 118 |
+
|
| 119 |
+
if isinstance(self.parallel, str):
|
| 120 |
+
try:
|
| 121 |
+
self.parallel = int(self.parallel)
|
| 122 |
+
except ValueError:
|
| 123 |
+
raise DistutilsOptionError("parallel should be an integer")
|
| 124 |
+
|
| 125 |
+
def run(self):
|
| 126 |
+
# Run all relevant sub-commands. This will be some subset of:
|
| 127 |
+
# - build_py - pure Python modules
|
| 128 |
+
# - build_clib - standalone C libraries
|
| 129 |
+
# - build_ext - Python extensions
|
| 130 |
+
# - build_scripts - (Python) scripts
|
| 131 |
+
for cmd_name in self.get_sub_commands():
|
| 132 |
+
self.run_command(cmd_name)
|
| 133 |
+
|
| 134 |
+
# -- Predicates for the sub-command list ---------------------------
|
| 135 |
+
|
| 136 |
+
def has_pure_modules(self):
|
| 137 |
+
return self.distribution.has_pure_modules()
|
| 138 |
+
|
| 139 |
+
def has_c_libraries(self):
|
| 140 |
+
return self.distribution.has_c_libraries()
|
| 141 |
+
|
| 142 |
+
def has_ext_modules(self):
|
| 143 |
+
return self.distribution.has_ext_modules()
|
| 144 |
+
|
| 145 |
+
def has_scripts(self):
|
| 146 |
+
return self.distribution.has_scripts()
|
| 147 |
+
|
| 148 |
+
sub_commands = [
|
| 149 |
+
('build_py', has_pure_modules),
|
| 150 |
+
('build_clib', has_c_libraries),
|
| 151 |
+
('build_ext', has_ext_modules),
|
| 152 |
+
('build_scripts', has_scripts),
|
| 153 |
+
]
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/build_ext.py
ADDED
|
@@ -0,0 +1,787 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""distutils.command.build_ext
|
| 2 |
+
|
| 3 |
+
Implements the Distutils 'build_ext' command, for building extension
|
| 4 |
+
modules (currently limited to C extensions, should accommodate C++
|
| 5 |
+
extensions ASAP)."""
|
| 6 |
+
|
| 7 |
+
import contextlib
|
| 8 |
+
import os
|
| 9 |
+
import re
|
| 10 |
+
import sys
|
| 11 |
+
from distutils.core import Command
|
| 12 |
+
from distutils.errors import (
|
| 13 |
+
DistutilsOptionError,
|
| 14 |
+
DistutilsSetupError,
|
| 15 |
+
CCompilerError,
|
| 16 |
+
DistutilsError,
|
| 17 |
+
CompileError,
|
| 18 |
+
DistutilsPlatformError,
|
| 19 |
+
)
|
| 20 |
+
from distutils.sysconfig import customize_compiler, get_python_version
|
| 21 |
+
from distutils.sysconfig import get_config_h_filename
|
| 22 |
+
from distutils.dep_util import newer_group
|
| 23 |
+
from distutils.extension import Extension
|
| 24 |
+
from distutils.util import get_platform
|
| 25 |
+
from distutils import log
|
| 26 |
+
from . import py37compat
|
| 27 |
+
|
| 28 |
+
from site import USER_BASE
|
| 29 |
+
|
| 30 |
+
# An extension name is just a dot-separated list of Python NAMEs (ie.
|
| 31 |
+
# the same as a fully-qualified module name).
|
| 32 |
+
extension_name_re = re.compile(r'^[a-zA-Z_][a-zA-Z_0-9]*(\.[a-zA-Z_][a-zA-Z_0-9]*)*$')
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def show_compilers():
|
| 36 |
+
from distutils.ccompiler import show_compilers
|
| 37 |
+
|
| 38 |
+
show_compilers()
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
class build_ext(Command):
|
| 42 |
+
|
| 43 |
+
description = "build C/C++ extensions (compile/link to build directory)"
|
| 44 |
+
|
| 45 |
+
# XXX thoughts on how to deal with complex command-line options like
|
| 46 |
+
# these, i.e. how to make it so fancy_getopt can suck them off the
|
| 47 |
+
# command line and make it look like setup.py defined the appropriate
|
| 48 |
+
# lists of tuples of what-have-you.
|
| 49 |
+
# - each command needs a callback to process its command-line options
|
| 50 |
+
# - Command.__init__() needs access to its share of the whole
|
| 51 |
+
# command line (must ultimately come from
|
| 52 |
+
# Distribution.parse_command_line())
|
| 53 |
+
# - it then calls the current command class' option-parsing
|
| 54 |
+
# callback to deal with weird options like -D, which have to
|
| 55 |
+
# parse the option text and churn out some custom data
|
| 56 |
+
# structure
|
| 57 |
+
# - that data structure (in this case, a list of 2-tuples)
|
| 58 |
+
# will then be present in the command object by the time
|
| 59 |
+
# we get to finalize_options() (i.e. the constructor
|
| 60 |
+
# takes care of both command-line and client options
|
| 61 |
+
# in between initialize_options() and finalize_options())
|
| 62 |
+
|
| 63 |
+
sep_by = " (separated by '%s')" % os.pathsep
|
| 64 |
+
user_options = [
|
| 65 |
+
('build-lib=', 'b', "directory for compiled extension modules"),
|
| 66 |
+
('build-temp=', 't', "directory for temporary files (build by-products)"),
|
| 67 |
+
(
|
| 68 |
+
'plat-name=',
|
| 69 |
+
'p',
|
| 70 |
+
"platform name to cross-compile for, if supported "
|
| 71 |
+
"(default: %s)" % get_platform(),
|
| 72 |
+
),
|
| 73 |
+
(
|
| 74 |
+
'inplace',
|
| 75 |
+
'i',
|
| 76 |
+
"ignore build-lib and put compiled extensions into the source "
|
| 77 |
+
+ "directory alongside your pure Python modules",
|
| 78 |
+
),
|
| 79 |
+
(
|
| 80 |
+
'include-dirs=',
|
| 81 |
+
'I',
|
| 82 |
+
"list of directories to search for header files" + sep_by,
|
| 83 |
+
),
|
| 84 |
+
('define=', 'D', "C preprocessor macros to define"),
|
| 85 |
+
('undef=', 'U', "C preprocessor macros to undefine"),
|
| 86 |
+
('libraries=', 'l', "external C libraries to link with"),
|
| 87 |
+
(
|
| 88 |
+
'library-dirs=',
|
| 89 |
+
'L',
|
| 90 |
+
"directories to search for external C libraries" + sep_by,
|
| 91 |
+
),
|
| 92 |
+
('rpath=', 'R', "directories to search for shared C libraries at runtime"),
|
| 93 |
+
('link-objects=', 'O', "extra explicit link objects to include in the link"),
|
| 94 |
+
('debug', 'g', "compile/link with debugging information"),
|
| 95 |
+
('force', 'f', "forcibly build everything (ignore file timestamps)"),
|
| 96 |
+
('compiler=', 'c', "specify the compiler type"),
|
| 97 |
+
('parallel=', 'j', "number of parallel build jobs"),
|
| 98 |
+
('swig-cpp', None, "make SWIG create C++ files (default is C)"),
|
| 99 |
+
('swig-opts=', None, "list of SWIG command line options"),
|
| 100 |
+
('swig=', None, "path to the SWIG executable"),
|
| 101 |
+
('user', None, "add user include, library and rpath"),
|
| 102 |
+
]
|
| 103 |
+
|
| 104 |
+
boolean_options = ['inplace', 'debug', 'force', 'swig-cpp', 'user']
|
| 105 |
+
|
| 106 |
+
help_options = [
|
| 107 |
+
('help-compiler', None, "list available compilers", show_compilers),
|
| 108 |
+
]
|
| 109 |
+
|
| 110 |
+
def initialize_options(self):
|
| 111 |
+
self.extensions = None
|
| 112 |
+
self.build_lib = None
|
| 113 |
+
self.plat_name = None
|
| 114 |
+
self.build_temp = None
|
| 115 |
+
self.inplace = 0
|
| 116 |
+
self.package = None
|
| 117 |
+
|
| 118 |
+
self.include_dirs = None
|
| 119 |
+
self.define = None
|
| 120 |
+
self.undef = None
|
| 121 |
+
self.libraries = None
|
| 122 |
+
self.library_dirs = None
|
| 123 |
+
self.rpath = None
|
| 124 |
+
self.link_objects = None
|
| 125 |
+
self.debug = None
|
| 126 |
+
self.force = None
|
| 127 |
+
self.compiler = None
|
| 128 |
+
self.swig = None
|
| 129 |
+
self.swig_cpp = None
|
| 130 |
+
self.swig_opts = None
|
| 131 |
+
self.user = None
|
| 132 |
+
self.parallel = None
|
| 133 |
+
|
| 134 |
+
def finalize_options(self): # noqa: C901
|
| 135 |
+
from distutils import sysconfig
|
| 136 |
+
|
| 137 |
+
self.set_undefined_options(
|
| 138 |
+
'build',
|
| 139 |
+
('build_lib', 'build_lib'),
|
| 140 |
+
('build_temp', 'build_temp'),
|
| 141 |
+
('compiler', 'compiler'),
|
| 142 |
+
('debug', 'debug'),
|
| 143 |
+
('force', 'force'),
|
| 144 |
+
('parallel', 'parallel'),
|
| 145 |
+
('plat_name', 'plat_name'),
|
| 146 |
+
)
|
| 147 |
+
|
| 148 |
+
if self.package is None:
|
| 149 |
+
self.package = self.distribution.ext_package
|
| 150 |
+
|
| 151 |
+
self.extensions = self.distribution.ext_modules
|
| 152 |
+
|
| 153 |
+
# Make sure Python's include directories (for Python.h, pyconfig.h,
|
| 154 |
+
# etc.) are in the include search path.
|
| 155 |
+
py_include = sysconfig.get_python_inc()
|
| 156 |
+
plat_py_include = sysconfig.get_python_inc(plat_specific=1)
|
| 157 |
+
if self.include_dirs is None:
|
| 158 |
+
self.include_dirs = self.distribution.include_dirs or []
|
| 159 |
+
if isinstance(self.include_dirs, str):
|
| 160 |
+
self.include_dirs = self.include_dirs.split(os.pathsep)
|
| 161 |
+
|
| 162 |
+
# If in a virtualenv, add its include directory
|
| 163 |
+
# Issue 16116
|
| 164 |
+
if sys.exec_prefix != sys.base_exec_prefix:
|
| 165 |
+
self.include_dirs.append(os.path.join(sys.exec_prefix, 'include'))
|
| 166 |
+
|
| 167 |
+
# Put the Python "system" include dir at the end, so that
|
| 168 |
+
# any local include dirs take precedence.
|
| 169 |
+
self.include_dirs.extend(py_include.split(os.path.pathsep))
|
| 170 |
+
if plat_py_include != py_include:
|
| 171 |
+
self.include_dirs.extend(plat_py_include.split(os.path.pathsep))
|
| 172 |
+
|
| 173 |
+
self.ensure_string_list('libraries')
|
| 174 |
+
self.ensure_string_list('link_objects')
|
| 175 |
+
|
| 176 |
+
# Life is easier if we're not forever checking for None, so
|
| 177 |
+
# simplify these options to empty lists if unset
|
| 178 |
+
if self.libraries is None:
|
| 179 |
+
self.libraries = []
|
| 180 |
+
if self.library_dirs is None:
|
| 181 |
+
self.library_dirs = []
|
| 182 |
+
elif isinstance(self.library_dirs, str):
|
| 183 |
+
self.library_dirs = self.library_dirs.split(os.pathsep)
|
| 184 |
+
|
| 185 |
+
if self.rpath is None:
|
| 186 |
+
self.rpath = []
|
| 187 |
+
elif isinstance(self.rpath, str):
|
| 188 |
+
self.rpath = self.rpath.split(os.pathsep)
|
| 189 |
+
|
| 190 |
+
# for extensions under windows use different directories
|
| 191 |
+
# for Release and Debug builds.
|
| 192 |
+
# also Python's library directory must be appended to library_dirs
|
| 193 |
+
if os.name == 'nt':
|
| 194 |
+
# the 'libs' directory is for binary installs - we assume that
|
| 195 |
+
# must be the *native* platform. But we don't really support
|
| 196 |
+
# cross-compiling via a binary install anyway, so we let it go.
|
| 197 |
+
self.library_dirs.append(os.path.join(sys.exec_prefix, 'libs'))
|
| 198 |
+
if sys.base_exec_prefix != sys.prefix: # Issue 16116
|
| 199 |
+
self.library_dirs.append(os.path.join(sys.base_exec_prefix, 'libs'))
|
| 200 |
+
if self.debug:
|
| 201 |
+
self.build_temp = os.path.join(self.build_temp, "Debug")
|
| 202 |
+
else:
|
| 203 |
+
self.build_temp = os.path.join(self.build_temp, "Release")
|
| 204 |
+
|
| 205 |
+
# Append the source distribution include and library directories,
|
| 206 |
+
# this allows distutils on windows to work in the source tree
|
| 207 |
+
self.include_dirs.append(os.path.dirname(get_config_h_filename()))
|
| 208 |
+
self.library_dirs.append(sys.base_exec_prefix)
|
| 209 |
+
|
| 210 |
+
# Use the .lib files for the correct architecture
|
| 211 |
+
if self.plat_name == 'win32':
|
| 212 |
+
suffix = 'win32'
|
| 213 |
+
else:
|
| 214 |
+
# win-amd64
|
| 215 |
+
suffix = self.plat_name[4:]
|
| 216 |
+
new_lib = os.path.join(sys.exec_prefix, 'PCbuild')
|
| 217 |
+
if suffix:
|
| 218 |
+
new_lib = os.path.join(new_lib, suffix)
|
| 219 |
+
self.library_dirs.append(new_lib)
|
| 220 |
+
|
| 221 |
+
# For extensions under Cygwin, Python's library directory must be
|
| 222 |
+
# appended to library_dirs
|
| 223 |
+
if sys.platform[:6] == 'cygwin':
|
| 224 |
+
if not sysconfig.python_build:
|
| 225 |
+
# building third party extensions
|
| 226 |
+
self.library_dirs.append(
|
| 227 |
+
os.path.join(
|
| 228 |
+
sys.prefix, "lib", "python" + get_python_version(), "config"
|
| 229 |
+
)
|
| 230 |
+
)
|
| 231 |
+
else:
|
| 232 |
+
# building python standard extensions
|
| 233 |
+
self.library_dirs.append('.')
|
| 234 |
+
|
| 235 |
+
# For building extensions with a shared Python library,
|
| 236 |
+
# Python's library directory must be appended to library_dirs
|
| 237 |
+
# See Issues: #1600860, #4366
|
| 238 |
+
if sysconfig.get_config_var('Py_ENABLE_SHARED'):
|
| 239 |
+
if not sysconfig.python_build:
|
| 240 |
+
# building third party extensions
|
| 241 |
+
self.library_dirs.append(sysconfig.get_config_var('LIBDIR'))
|
| 242 |
+
else:
|
| 243 |
+
# building python standard extensions
|
| 244 |
+
self.library_dirs.append('.')
|
| 245 |
+
|
| 246 |
+
# The argument parsing will result in self.define being a string, but
|
| 247 |
+
# it has to be a list of 2-tuples. All the preprocessor symbols
|
| 248 |
+
# specified by the 'define' option will be set to '1'. Multiple
|
| 249 |
+
# symbols can be separated with commas.
|
| 250 |
+
|
| 251 |
+
if self.define:
|
| 252 |
+
defines = self.define.split(',')
|
| 253 |
+
self.define = [(symbol, '1') for symbol in defines]
|
| 254 |
+
|
| 255 |
+
# The option for macros to undefine is also a string from the
|
| 256 |
+
# option parsing, but has to be a list. Multiple symbols can also
|
| 257 |
+
# be separated with commas here.
|
| 258 |
+
if self.undef:
|
| 259 |
+
self.undef = self.undef.split(',')
|
| 260 |
+
|
| 261 |
+
if self.swig_opts is None:
|
| 262 |
+
self.swig_opts = []
|
| 263 |
+
else:
|
| 264 |
+
self.swig_opts = self.swig_opts.split(' ')
|
| 265 |
+
|
| 266 |
+
# Finally add the user include and library directories if requested
|
| 267 |
+
if self.user:
|
| 268 |
+
user_include = os.path.join(USER_BASE, "include")
|
| 269 |
+
user_lib = os.path.join(USER_BASE, "lib")
|
| 270 |
+
if os.path.isdir(user_include):
|
| 271 |
+
self.include_dirs.append(user_include)
|
| 272 |
+
if os.path.isdir(user_lib):
|
| 273 |
+
self.library_dirs.append(user_lib)
|
| 274 |
+
self.rpath.append(user_lib)
|
| 275 |
+
|
| 276 |
+
if isinstance(self.parallel, str):
|
| 277 |
+
try:
|
| 278 |
+
self.parallel = int(self.parallel)
|
| 279 |
+
except ValueError:
|
| 280 |
+
raise DistutilsOptionError("parallel should be an integer")
|
| 281 |
+
|
| 282 |
+
def run(self): # noqa: C901
|
| 283 |
+
from distutils.ccompiler import new_compiler
|
| 284 |
+
|
| 285 |
+
# 'self.extensions', as supplied by setup.py, is a list of
|
| 286 |
+
# Extension instances. See the documentation for Extension (in
|
| 287 |
+
# distutils.extension) for details.
|
| 288 |
+
#
|
| 289 |
+
# For backwards compatibility with Distutils 0.8.2 and earlier, we
|
| 290 |
+
# also allow the 'extensions' list to be a list of tuples:
|
| 291 |
+
# (ext_name, build_info)
|
| 292 |
+
# where build_info is a dictionary containing everything that
|
| 293 |
+
# Extension instances do except the name, with a few things being
|
| 294 |
+
# differently named. We convert these 2-tuples to Extension
|
| 295 |
+
# instances as needed.
|
| 296 |
+
|
| 297 |
+
if not self.extensions:
|
| 298 |
+
return
|
| 299 |
+
|
| 300 |
+
# If we were asked to build any C/C++ libraries, make sure that the
|
| 301 |
+
# directory where we put them is in the library search path for
|
| 302 |
+
# linking extensions.
|
| 303 |
+
if self.distribution.has_c_libraries():
|
| 304 |
+
build_clib = self.get_finalized_command('build_clib')
|
| 305 |
+
self.libraries.extend(build_clib.get_library_names() or [])
|
| 306 |
+
self.library_dirs.append(build_clib.build_clib)
|
| 307 |
+
|
| 308 |
+
# Setup the CCompiler object that we'll use to do all the
|
| 309 |
+
# compiling and linking
|
| 310 |
+
self.compiler = new_compiler(
|
| 311 |
+
compiler=self.compiler,
|
| 312 |
+
verbose=self.verbose,
|
| 313 |
+
dry_run=self.dry_run,
|
| 314 |
+
force=self.force,
|
| 315 |
+
)
|
| 316 |
+
customize_compiler(self.compiler)
|
| 317 |
+
# If we are cross-compiling, init the compiler now (if we are not
|
| 318 |
+
# cross-compiling, init would not hurt, but people may rely on
|
| 319 |
+
# late initialization of compiler even if they shouldn't...)
|
| 320 |
+
if os.name == 'nt' and self.plat_name != get_platform():
|
| 321 |
+
self.compiler.initialize(self.plat_name)
|
| 322 |
+
|
| 323 |
+
# And make sure that any compile/link-related options (which might
|
| 324 |
+
# come from the command-line or from the setup script) are set in
|
| 325 |
+
# that CCompiler object -- that way, they automatically apply to
|
| 326 |
+
# all compiling and linking done here.
|
| 327 |
+
if self.include_dirs is not None:
|
| 328 |
+
self.compiler.set_include_dirs(self.include_dirs)
|
| 329 |
+
if self.define is not None:
|
| 330 |
+
# 'define' option is a list of (name,value) tuples
|
| 331 |
+
for (name, value) in self.define:
|
| 332 |
+
self.compiler.define_macro(name, value)
|
| 333 |
+
if self.undef is not None:
|
| 334 |
+
for macro in self.undef:
|
| 335 |
+
self.compiler.undefine_macro(macro)
|
| 336 |
+
if self.libraries is not None:
|
| 337 |
+
self.compiler.set_libraries(self.libraries)
|
| 338 |
+
if self.library_dirs is not None:
|
| 339 |
+
self.compiler.set_library_dirs(self.library_dirs)
|
| 340 |
+
if self.rpath is not None:
|
| 341 |
+
self.compiler.set_runtime_library_dirs(self.rpath)
|
| 342 |
+
if self.link_objects is not None:
|
| 343 |
+
self.compiler.set_link_objects(self.link_objects)
|
| 344 |
+
|
| 345 |
+
# Now actually compile and link everything.
|
| 346 |
+
self.build_extensions()
|
| 347 |
+
|
| 348 |
+
def check_extensions_list(self, extensions): # noqa: C901
|
| 349 |
+
"""Ensure that the list of extensions (presumably provided as a
|
| 350 |
+
command option 'extensions') is valid, i.e. it is a list of
|
| 351 |
+
Extension objects. We also support the old-style list of 2-tuples,
|
| 352 |
+
where the tuples are (ext_name, build_info), which are converted to
|
| 353 |
+
Extension instances here.
|
| 354 |
+
|
| 355 |
+
Raise DistutilsSetupError if the structure is invalid anywhere;
|
| 356 |
+
just returns otherwise.
|
| 357 |
+
"""
|
| 358 |
+
if not isinstance(extensions, list):
|
| 359 |
+
raise DistutilsSetupError(
|
| 360 |
+
"'ext_modules' option must be a list of Extension instances"
|
| 361 |
+
)
|
| 362 |
+
|
| 363 |
+
for i, ext in enumerate(extensions):
|
| 364 |
+
if isinstance(ext, Extension):
|
| 365 |
+
continue # OK! (assume type-checking done
|
| 366 |
+
# by Extension constructor)
|
| 367 |
+
|
| 368 |
+
if not isinstance(ext, tuple) or len(ext) != 2:
|
| 369 |
+
raise DistutilsSetupError(
|
| 370 |
+
"each element of 'ext_modules' option must be an "
|
| 371 |
+
"Extension instance or 2-tuple"
|
| 372 |
+
)
|
| 373 |
+
|
| 374 |
+
ext_name, build_info = ext
|
| 375 |
+
|
| 376 |
+
log.warn(
|
| 377 |
+
"old-style (ext_name, build_info) tuple found in "
|
| 378 |
+
"ext_modules for extension '%s' "
|
| 379 |
+
"-- please convert to Extension instance",
|
| 380 |
+
ext_name,
|
| 381 |
+
)
|
| 382 |
+
|
| 383 |
+
if not (isinstance(ext_name, str) and extension_name_re.match(ext_name)):
|
| 384 |
+
raise DistutilsSetupError(
|
| 385 |
+
"first element of each tuple in 'ext_modules' "
|
| 386 |
+
"must be the extension name (a string)"
|
| 387 |
+
)
|
| 388 |
+
|
| 389 |
+
if not isinstance(build_info, dict):
|
| 390 |
+
raise DistutilsSetupError(
|
| 391 |
+
"second element of each tuple in 'ext_modules' "
|
| 392 |
+
"must be a dictionary (build info)"
|
| 393 |
+
)
|
| 394 |
+
|
| 395 |
+
# OK, the (ext_name, build_info) dict is type-safe: convert it
|
| 396 |
+
# to an Extension instance.
|
| 397 |
+
ext = Extension(ext_name, build_info['sources'])
|
| 398 |
+
|
| 399 |
+
# Easy stuff: one-to-one mapping from dict elements to
|
| 400 |
+
# instance attributes.
|
| 401 |
+
for key in (
|
| 402 |
+
'include_dirs',
|
| 403 |
+
'library_dirs',
|
| 404 |
+
'libraries',
|
| 405 |
+
'extra_objects',
|
| 406 |
+
'extra_compile_args',
|
| 407 |
+
'extra_link_args',
|
| 408 |
+
):
|
| 409 |
+
val = build_info.get(key)
|
| 410 |
+
if val is not None:
|
| 411 |
+
setattr(ext, key, val)
|
| 412 |
+
|
| 413 |
+
# Medium-easy stuff: same syntax/semantics, different names.
|
| 414 |
+
ext.runtime_library_dirs = build_info.get('rpath')
|
| 415 |
+
if 'def_file' in build_info:
|
| 416 |
+
log.warn("'def_file' element of build info dict " "no longer supported")
|
| 417 |
+
|
| 418 |
+
# Non-trivial stuff: 'macros' split into 'define_macros'
|
| 419 |
+
# and 'undef_macros'.
|
| 420 |
+
macros = build_info.get('macros')
|
| 421 |
+
if macros:
|
| 422 |
+
ext.define_macros = []
|
| 423 |
+
ext.undef_macros = []
|
| 424 |
+
for macro in macros:
|
| 425 |
+
if not (isinstance(macro, tuple) and len(macro) in (1, 2)):
|
| 426 |
+
raise DistutilsSetupError(
|
| 427 |
+
"'macros' element of build info dict "
|
| 428 |
+
"must be 1- or 2-tuple"
|
| 429 |
+
)
|
| 430 |
+
if len(macro) == 1:
|
| 431 |
+
ext.undef_macros.append(macro[0])
|
| 432 |
+
elif len(macro) == 2:
|
| 433 |
+
ext.define_macros.append(macro)
|
| 434 |
+
|
| 435 |
+
extensions[i] = ext
|
| 436 |
+
|
| 437 |
+
def get_source_files(self):
|
| 438 |
+
self.check_extensions_list(self.extensions)
|
| 439 |
+
filenames = []
|
| 440 |
+
|
| 441 |
+
# Wouldn't it be neat if we knew the names of header files too...
|
| 442 |
+
for ext in self.extensions:
|
| 443 |
+
filenames.extend(ext.sources)
|
| 444 |
+
return filenames
|
| 445 |
+
|
| 446 |
+
def get_outputs(self):
|
| 447 |
+
# Sanity check the 'extensions' list -- can't assume this is being
|
| 448 |
+
# done in the same run as a 'build_extensions()' call (in fact, we
|
| 449 |
+
# can probably assume that it *isn't*!).
|
| 450 |
+
self.check_extensions_list(self.extensions)
|
| 451 |
+
|
| 452 |
+
# And build the list of output (built) filenames. Note that this
|
| 453 |
+
# ignores the 'inplace' flag, and assumes everything goes in the
|
| 454 |
+
# "build" tree.
|
| 455 |
+
outputs = []
|
| 456 |
+
for ext in self.extensions:
|
| 457 |
+
outputs.append(self.get_ext_fullpath(ext.name))
|
| 458 |
+
return outputs
|
| 459 |
+
|
| 460 |
+
def build_extensions(self):
|
| 461 |
+
# First, sanity-check the 'extensions' list
|
| 462 |
+
self.check_extensions_list(self.extensions)
|
| 463 |
+
if self.parallel:
|
| 464 |
+
self._build_extensions_parallel()
|
| 465 |
+
else:
|
| 466 |
+
self._build_extensions_serial()
|
| 467 |
+
|
| 468 |
+
def _build_extensions_parallel(self):
|
| 469 |
+
workers = self.parallel
|
| 470 |
+
if self.parallel is True:
|
| 471 |
+
workers = os.cpu_count() # may return None
|
| 472 |
+
try:
|
| 473 |
+
from concurrent.futures import ThreadPoolExecutor
|
| 474 |
+
except ImportError:
|
| 475 |
+
workers = None
|
| 476 |
+
|
| 477 |
+
if workers is None:
|
| 478 |
+
self._build_extensions_serial()
|
| 479 |
+
return
|
| 480 |
+
|
| 481 |
+
with ThreadPoolExecutor(max_workers=workers) as executor:
|
| 482 |
+
futures = [
|
| 483 |
+
executor.submit(self.build_extension, ext) for ext in self.extensions
|
| 484 |
+
]
|
| 485 |
+
for ext, fut in zip(self.extensions, futures):
|
| 486 |
+
with self._filter_build_errors(ext):
|
| 487 |
+
fut.result()
|
| 488 |
+
|
| 489 |
+
def _build_extensions_serial(self):
|
| 490 |
+
for ext in self.extensions:
|
| 491 |
+
with self._filter_build_errors(ext):
|
| 492 |
+
self.build_extension(ext)
|
| 493 |
+
|
| 494 |
+
@contextlib.contextmanager
|
| 495 |
+
def _filter_build_errors(self, ext):
|
| 496 |
+
try:
|
| 497 |
+
yield
|
| 498 |
+
except (CCompilerError, DistutilsError, CompileError) as e:
|
| 499 |
+
if not ext.optional:
|
| 500 |
+
raise
|
| 501 |
+
self.warn('building extension "{}" failed: {}'.format(ext.name, e))
|
| 502 |
+
|
| 503 |
+
def build_extension(self, ext):
|
| 504 |
+
sources = ext.sources
|
| 505 |
+
if sources is None or not isinstance(sources, (list, tuple)):
|
| 506 |
+
raise DistutilsSetupError(
|
| 507 |
+
"in 'ext_modules' option (extension '%s'), "
|
| 508 |
+
"'sources' must be present and must be "
|
| 509 |
+
"a list of source filenames" % ext.name
|
| 510 |
+
)
|
| 511 |
+
# sort to make the resulting .so file build reproducible
|
| 512 |
+
sources = sorted(sources)
|
| 513 |
+
|
| 514 |
+
ext_path = self.get_ext_fullpath(ext.name)
|
| 515 |
+
depends = sources + ext.depends
|
| 516 |
+
if not (self.force or newer_group(depends, ext_path, 'newer')):
|
| 517 |
+
log.debug("skipping '%s' extension (up-to-date)", ext.name)
|
| 518 |
+
return
|
| 519 |
+
else:
|
| 520 |
+
log.info("building '%s' extension", ext.name)
|
| 521 |
+
|
| 522 |
+
# First, scan the sources for SWIG definition files (.i), run
|
| 523 |
+
# SWIG on 'em to create .c files, and modify the sources list
|
| 524 |
+
# accordingly.
|
| 525 |
+
sources = self.swig_sources(sources, ext)
|
| 526 |
+
|
| 527 |
+
# Next, compile the source code to object files.
|
| 528 |
+
|
| 529 |
+
# XXX not honouring 'define_macros' or 'undef_macros' -- the
|
| 530 |
+
# CCompiler API needs to change to accommodate this, and I
|
| 531 |
+
# want to do one thing at a time!
|
| 532 |
+
|
| 533 |
+
# Two possible sources for extra compiler arguments:
|
| 534 |
+
# - 'extra_compile_args' in Extension object
|
| 535 |
+
# - CFLAGS environment variable (not particularly
|
| 536 |
+
# elegant, but people seem to expect it and I
|
| 537 |
+
# guess it's useful)
|
| 538 |
+
# The environment variable should take precedence, and
|
| 539 |
+
# any sensible compiler will give precedence to later
|
| 540 |
+
# command line args. Hence we combine them in order:
|
| 541 |
+
extra_args = ext.extra_compile_args or []
|
| 542 |
+
|
| 543 |
+
macros = ext.define_macros[:]
|
| 544 |
+
for undef in ext.undef_macros:
|
| 545 |
+
macros.append((undef,))
|
| 546 |
+
|
| 547 |
+
objects = self.compiler.compile(
|
| 548 |
+
sources,
|
| 549 |
+
output_dir=self.build_temp,
|
| 550 |
+
macros=macros,
|
| 551 |
+
include_dirs=ext.include_dirs,
|
| 552 |
+
debug=self.debug,
|
| 553 |
+
extra_postargs=extra_args,
|
| 554 |
+
depends=ext.depends,
|
| 555 |
+
)
|
| 556 |
+
|
| 557 |
+
# XXX outdated variable, kept here in case third-part code
|
| 558 |
+
# needs it.
|
| 559 |
+
self._built_objects = objects[:]
|
| 560 |
+
|
| 561 |
+
# Now link the object files together into a "shared object" --
|
| 562 |
+
# of course, first we have to figure out all the other things
|
| 563 |
+
# that go into the mix.
|
| 564 |
+
if ext.extra_objects:
|
| 565 |
+
objects.extend(ext.extra_objects)
|
| 566 |
+
extra_args = ext.extra_link_args or []
|
| 567 |
+
|
| 568 |
+
# Detect target language, if not provided
|
| 569 |
+
language = ext.language or self.compiler.detect_language(sources)
|
| 570 |
+
|
| 571 |
+
self.compiler.link_shared_object(
|
| 572 |
+
objects,
|
| 573 |
+
ext_path,
|
| 574 |
+
libraries=self.get_libraries(ext),
|
| 575 |
+
library_dirs=ext.library_dirs,
|
| 576 |
+
runtime_library_dirs=ext.runtime_library_dirs,
|
| 577 |
+
extra_postargs=extra_args,
|
| 578 |
+
export_symbols=self.get_export_symbols(ext),
|
| 579 |
+
debug=self.debug,
|
| 580 |
+
build_temp=self.build_temp,
|
| 581 |
+
target_lang=language,
|
| 582 |
+
)
|
| 583 |
+
|
| 584 |
+
def swig_sources(self, sources, extension):
|
| 585 |
+
"""Walk the list of source files in 'sources', looking for SWIG
|
| 586 |
+
interface (.i) files. Run SWIG on all that are found, and
|
| 587 |
+
return a modified 'sources' list with SWIG source files replaced
|
| 588 |
+
by the generated C (or C++) files.
|
| 589 |
+
"""
|
| 590 |
+
new_sources = []
|
| 591 |
+
swig_sources = []
|
| 592 |
+
swig_targets = {}
|
| 593 |
+
|
| 594 |
+
# XXX this drops generated C/C++ files into the source tree, which
|
| 595 |
+
# is fine for developers who want to distribute the generated
|
| 596 |
+
# source -- but there should be an option to put SWIG output in
|
| 597 |
+
# the temp dir.
|
| 598 |
+
|
| 599 |
+
if self.swig_cpp:
|
| 600 |
+
log.warn("--swig-cpp is deprecated - use --swig-opts=-c++")
|
| 601 |
+
|
| 602 |
+
if (
|
| 603 |
+
self.swig_cpp
|
| 604 |
+
or ('-c++' in self.swig_opts)
|
| 605 |
+
or ('-c++' in extension.swig_opts)
|
| 606 |
+
):
|
| 607 |
+
target_ext = '.cpp'
|
| 608 |
+
else:
|
| 609 |
+
target_ext = '.c'
|
| 610 |
+
|
| 611 |
+
for source in sources:
|
| 612 |
+
(base, ext) = os.path.splitext(source)
|
| 613 |
+
if ext == ".i": # SWIG interface file
|
| 614 |
+
new_sources.append(base + '_wrap' + target_ext)
|
| 615 |
+
swig_sources.append(source)
|
| 616 |
+
swig_targets[source] = new_sources[-1]
|
| 617 |
+
else:
|
| 618 |
+
new_sources.append(source)
|
| 619 |
+
|
| 620 |
+
if not swig_sources:
|
| 621 |
+
return new_sources
|
| 622 |
+
|
| 623 |
+
swig = self.swig or self.find_swig()
|
| 624 |
+
swig_cmd = [swig, "-python"]
|
| 625 |
+
swig_cmd.extend(self.swig_opts)
|
| 626 |
+
if self.swig_cpp:
|
| 627 |
+
swig_cmd.append("-c++")
|
| 628 |
+
|
| 629 |
+
# Do not override commandline arguments
|
| 630 |
+
if not self.swig_opts:
|
| 631 |
+
for o in extension.swig_opts:
|
| 632 |
+
swig_cmd.append(o)
|
| 633 |
+
|
| 634 |
+
for source in swig_sources:
|
| 635 |
+
target = swig_targets[source]
|
| 636 |
+
log.info("swigging %s to %s", source, target)
|
| 637 |
+
self.spawn(swig_cmd + ["-o", target, source])
|
| 638 |
+
|
| 639 |
+
return new_sources
|
| 640 |
+
|
| 641 |
+
def find_swig(self):
|
| 642 |
+
"""Return the name of the SWIG executable. On Unix, this is
|
| 643 |
+
just "swig" -- it should be in the PATH. Tries a bit harder on
|
| 644 |
+
Windows.
|
| 645 |
+
"""
|
| 646 |
+
if os.name == "posix":
|
| 647 |
+
return "swig"
|
| 648 |
+
elif os.name == "nt":
|
| 649 |
+
# Look for SWIG in its standard installation directory on
|
| 650 |
+
# Windows (or so I presume!). If we find it there, great;
|
| 651 |
+
# if not, act like Unix and assume it's in the PATH.
|
| 652 |
+
for vers in ("1.3", "1.2", "1.1"):
|
| 653 |
+
fn = os.path.join("c:\\swig%s" % vers, "swig.exe")
|
| 654 |
+
if os.path.isfile(fn):
|
| 655 |
+
return fn
|
| 656 |
+
else:
|
| 657 |
+
return "swig.exe"
|
| 658 |
+
else:
|
| 659 |
+
raise DistutilsPlatformError(
|
| 660 |
+
"I don't know how to find (much less run) SWIG "
|
| 661 |
+
"on platform '%s'" % os.name
|
| 662 |
+
)
|
| 663 |
+
|
| 664 |
+
# -- Name generators -----------------------------------------------
|
| 665 |
+
# (extension names, filenames, whatever)
|
| 666 |
+
def get_ext_fullpath(self, ext_name):
|
| 667 |
+
"""Returns the path of the filename for a given extension.
|
| 668 |
+
|
| 669 |
+
The file is located in `build_lib` or directly in the package
|
| 670 |
+
(inplace option).
|
| 671 |
+
"""
|
| 672 |
+
fullname = self.get_ext_fullname(ext_name)
|
| 673 |
+
modpath = fullname.split('.')
|
| 674 |
+
filename = self.get_ext_filename(modpath[-1])
|
| 675 |
+
|
| 676 |
+
if not self.inplace:
|
| 677 |
+
# no further work needed
|
| 678 |
+
# returning :
|
| 679 |
+
# build_dir/package/path/filename
|
| 680 |
+
filename = os.path.join(*modpath[:-1] + [filename])
|
| 681 |
+
return os.path.join(self.build_lib, filename)
|
| 682 |
+
|
| 683 |
+
# the inplace option requires to find the package directory
|
| 684 |
+
# using the build_py command for that
|
| 685 |
+
package = '.'.join(modpath[0:-1])
|
| 686 |
+
build_py = self.get_finalized_command('build_py')
|
| 687 |
+
package_dir = os.path.abspath(build_py.get_package_dir(package))
|
| 688 |
+
|
| 689 |
+
# returning
|
| 690 |
+
# package_dir/filename
|
| 691 |
+
return os.path.join(package_dir, filename)
|
| 692 |
+
|
| 693 |
+
def get_ext_fullname(self, ext_name):
|
| 694 |
+
"""Returns the fullname of a given extension name.
|
| 695 |
+
|
| 696 |
+
Adds the `package.` prefix"""
|
| 697 |
+
if self.package is None:
|
| 698 |
+
return ext_name
|
| 699 |
+
else:
|
| 700 |
+
return self.package + '.' + ext_name
|
| 701 |
+
|
| 702 |
+
def get_ext_filename(self, ext_name):
|
| 703 |
+
r"""Convert the name of an extension (eg. "foo.bar") into the name
|
| 704 |
+
of the file from which it will be loaded (eg. "foo/bar.so", or
|
| 705 |
+
"foo\bar.pyd").
|
| 706 |
+
"""
|
| 707 |
+
from distutils.sysconfig import get_config_var
|
| 708 |
+
|
| 709 |
+
ext_path = ext_name.split('.')
|
| 710 |
+
ext_suffix = get_config_var('EXT_SUFFIX')
|
| 711 |
+
return os.path.join(*ext_path) + ext_suffix
|
| 712 |
+
|
| 713 |
+
def get_export_symbols(self, ext):
|
| 714 |
+
"""Return the list of symbols that a shared extension has to
|
| 715 |
+
export. This either uses 'ext.export_symbols' or, if it's not
|
| 716 |
+
provided, "PyInit_" + module_name. Only relevant on Windows, where
|
| 717 |
+
the .pyd file (DLL) must export the module "PyInit_" function.
|
| 718 |
+
"""
|
| 719 |
+
name = ext.name.split('.')[-1]
|
| 720 |
+
try:
|
| 721 |
+
# Unicode module name support as defined in PEP-489
|
| 722 |
+
# https://www.python.org/dev/peps/pep-0489/#export-hook-name
|
| 723 |
+
name.encode('ascii')
|
| 724 |
+
except UnicodeEncodeError:
|
| 725 |
+
suffix = 'U_' + name.encode('punycode').replace(b'-', b'_').decode('ascii')
|
| 726 |
+
else:
|
| 727 |
+
suffix = "_" + name
|
| 728 |
+
|
| 729 |
+
initfunc_name = "PyInit" + suffix
|
| 730 |
+
if initfunc_name not in ext.export_symbols:
|
| 731 |
+
ext.export_symbols.append(initfunc_name)
|
| 732 |
+
return ext.export_symbols
|
| 733 |
+
|
| 734 |
+
def get_libraries(self, ext): # noqa: C901
|
| 735 |
+
"""Return the list of libraries to link against when building a
|
| 736 |
+
shared extension. On most platforms, this is just 'ext.libraries';
|
| 737 |
+
on Windows, we add the Python library (eg. python20.dll).
|
| 738 |
+
"""
|
| 739 |
+
# The python library is always needed on Windows. For MSVC, this
|
| 740 |
+
# is redundant, since the library is mentioned in a pragma in
|
| 741 |
+
# pyconfig.h that MSVC groks. The other Windows compilers all seem
|
| 742 |
+
# to need it mentioned explicitly, though, so that's what we do.
|
| 743 |
+
# Append '_d' to the python import library on debug builds.
|
| 744 |
+
if sys.platform == "win32":
|
| 745 |
+
from distutils._msvccompiler import MSVCCompiler
|
| 746 |
+
|
| 747 |
+
if not isinstance(self.compiler, MSVCCompiler):
|
| 748 |
+
template = "python%d%d"
|
| 749 |
+
if self.debug:
|
| 750 |
+
template = template + '_d'
|
| 751 |
+
pythonlib = template % (
|
| 752 |
+
sys.hexversion >> 24,
|
| 753 |
+
(sys.hexversion >> 16) & 0xFF,
|
| 754 |
+
)
|
| 755 |
+
# don't extend ext.libraries, it may be shared with other
|
| 756 |
+
# extensions, it is a reference to the original list
|
| 757 |
+
return ext.libraries + [pythonlib]
|
| 758 |
+
else:
|
| 759 |
+
# On Android only the main executable and LD_PRELOADs are considered
|
| 760 |
+
# to be RTLD_GLOBAL, all the dependencies of the main executable
|
| 761 |
+
# remain RTLD_LOCAL and so the shared libraries must be linked with
|
| 762 |
+
# libpython when python is built with a shared python library (issue
|
| 763 |
+
# bpo-21536).
|
| 764 |
+
# On Cygwin (and if required, other POSIX-like platforms based on
|
| 765 |
+
# Windows like MinGW) it is simply necessary that all symbols in
|
| 766 |
+
# shared libraries are resolved at link time.
|
| 767 |
+
from distutils.sysconfig import get_config_var
|
| 768 |
+
|
| 769 |
+
link_libpython = False
|
| 770 |
+
if get_config_var('Py_ENABLE_SHARED'):
|
| 771 |
+
# A native build on an Android device or on Cygwin
|
| 772 |
+
if hasattr(sys, 'getandroidapilevel'):
|
| 773 |
+
link_libpython = True
|
| 774 |
+
elif sys.platform == 'cygwin':
|
| 775 |
+
link_libpython = True
|
| 776 |
+
elif '_PYTHON_HOST_PLATFORM' in os.environ:
|
| 777 |
+
# We are cross-compiling for one of the relevant platforms
|
| 778 |
+
if get_config_var('ANDROID_API_LEVEL') != 0:
|
| 779 |
+
link_libpython = True
|
| 780 |
+
elif get_config_var('MACHDEP') == 'cygwin':
|
| 781 |
+
link_libpython = True
|
| 782 |
+
|
| 783 |
+
if link_libpython:
|
| 784 |
+
ldversion = get_config_var('LDVERSION')
|
| 785 |
+
return ext.libraries + ['python' + ldversion]
|
| 786 |
+
|
| 787 |
+
return ext.libraries + py37compat.pythonlib()
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/build_py.py
ADDED
|
@@ -0,0 +1,407 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""distutils.command.build_py
|
| 2 |
+
|
| 3 |
+
Implements the Distutils 'build_py' command."""
|
| 4 |
+
|
| 5 |
+
import os
|
| 6 |
+
import importlib.util
|
| 7 |
+
import sys
|
| 8 |
+
import glob
|
| 9 |
+
|
| 10 |
+
from distutils.core import Command
|
| 11 |
+
from distutils.errors import DistutilsOptionError, DistutilsFileError
|
| 12 |
+
from distutils.util import convert_path
|
| 13 |
+
from distutils import log
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
class build_py(Command):
|
| 17 |
+
|
| 18 |
+
description = "\"build\" pure Python modules (copy to build directory)"
|
| 19 |
+
|
| 20 |
+
user_options = [
|
| 21 |
+
('build-lib=', 'd', "directory to \"build\" (copy) to"),
|
| 22 |
+
('compile', 'c', "compile .py to .pyc"),
|
| 23 |
+
('no-compile', None, "don't compile .py files [default]"),
|
| 24 |
+
(
|
| 25 |
+
'optimize=',
|
| 26 |
+
'O',
|
| 27 |
+
"also compile with optimization: -O1 for \"python -O\", "
|
| 28 |
+
"-O2 for \"python -OO\", and -O0 to disable [default: -O0]",
|
| 29 |
+
),
|
| 30 |
+
('force', 'f', "forcibly build everything (ignore file timestamps)"),
|
| 31 |
+
]
|
| 32 |
+
|
| 33 |
+
boolean_options = ['compile', 'force']
|
| 34 |
+
negative_opt = {'no-compile': 'compile'}
|
| 35 |
+
|
| 36 |
+
def initialize_options(self):
|
| 37 |
+
self.build_lib = None
|
| 38 |
+
self.py_modules = None
|
| 39 |
+
self.package = None
|
| 40 |
+
self.package_data = None
|
| 41 |
+
self.package_dir = None
|
| 42 |
+
self.compile = 0
|
| 43 |
+
self.optimize = 0
|
| 44 |
+
self.force = None
|
| 45 |
+
|
| 46 |
+
def finalize_options(self):
|
| 47 |
+
self.set_undefined_options(
|
| 48 |
+
'build', ('build_lib', 'build_lib'), ('force', 'force')
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
# Get the distribution options that are aliases for build_py
|
| 52 |
+
# options -- list of packages and list of modules.
|
| 53 |
+
self.packages = self.distribution.packages
|
| 54 |
+
self.py_modules = self.distribution.py_modules
|
| 55 |
+
self.package_data = self.distribution.package_data
|
| 56 |
+
self.package_dir = {}
|
| 57 |
+
if self.distribution.package_dir:
|
| 58 |
+
for name, path in self.distribution.package_dir.items():
|
| 59 |
+
self.package_dir[name] = convert_path(path)
|
| 60 |
+
self.data_files = self.get_data_files()
|
| 61 |
+
|
| 62 |
+
# Ick, copied straight from install_lib.py (fancy_getopt needs a
|
| 63 |
+
# type system! Hell, *everything* needs a type system!!!)
|
| 64 |
+
if not isinstance(self.optimize, int):
|
| 65 |
+
try:
|
| 66 |
+
self.optimize = int(self.optimize)
|
| 67 |
+
assert 0 <= self.optimize <= 2
|
| 68 |
+
except (ValueError, AssertionError):
|
| 69 |
+
raise DistutilsOptionError("optimize must be 0, 1, or 2")
|
| 70 |
+
|
| 71 |
+
def run(self):
|
| 72 |
+
# XXX copy_file by default preserves atime and mtime. IMHO this is
|
| 73 |
+
# the right thing to do, but perhaps it should be an option -- in
|
| 74 |
+
# particular, a site administrator might want installed files to
|
| 75 |
+
# reflect the time of installation rather than the last
|
| 76 |
+
# modification time before the installed release.
|
| 77 |
+
|
| 78 |
+
# XXX copy_file by default preserves mode, which appears to be the
|
| 79 |
+
# wrong thing to do: if a file is read-only in the working
|
| 80 |
+
# directory, we want it to be installed read/write so that the next
|
| 81 |
+
# installation of the same module distribution can overwrite it
|
| 82 |
+
# without problems. (This might be a Unix-specific issue.) Thus
|
| 83 |
+
# we turn off 'preserve_mode' when copying to the build directory,
|
| 84 |
+
# since the build directory is supposed to be exactly what the
|
| 85 |
+
# installation will look like (ie. we preserve mode when
|
| 86 |
+
# installing).
|
| 87 |
+
|
| 88 |
+
# Two options control which modules will be installed: 'packages'
|
| 89 |
+
# and 'py_modules'. The former lets us work with whole packages, not
|
| 90 |
+
# specifying individual modules at all; the latter is for
|
| 91 |
+
# specifying modules one-at-a-time.
|
| 92 |
+
|
| 93 |
+
if self.py_modules:
|
| 94 |
+
self.build_modules()
|
| 95 |
+
if self.packages:
|
| 96 |
+
self.build_packages()
|
| 97 |
+
self.build_package_data()
|
| 98 |
+
|
| 99 |
+
self.byte_compile(self.get_outputs(include_bytecode=0))
|
| 100 |
+
|
| 101 |
+
def get_data_files(self):
|
| 102 |
+
"""Generate list of '(package,src_dir,build_dir,filenames)' tuples"""
|
| 103 |
+
data = []
|
| 104 |
+
if not self.packages:
|
| 105 |
+
return data
|
| 106 |
+
for package in self.packages:
|
| 107 |
+
# Locate package source directory
|
| 108 |
+
src_dir = self.get_package_dir(package)
|
| 109 |
+
|
| 110 |
+
# Compute package build directory
|
| 111 |
+
build_dir = os.path.join(*([self.build_lib] + package.split('.')))
|
| 112 |
+
|
| 113 |
+
# Length of path to strip from found files
|
| 114 |
+
plen = 0
|
| 115 |
+
if src_dir:
|
| 116 |
+
plen = len(src_dir) + 1
|
| 117 |
+
|
| 118 |
+
# Strip directory from globbed filenames
|
| 119 |
+
filenames = [file[plen:] for file in self.find_data_files(package, src_dir)]
|
| 120 |
+
data.append((package, src_dir, build_dir, filenames))
|
| 121 |
+
return data
|
| 122 |
+
|
| 123 |
+
def find_data_files(self, package, src_dir):
|
| 124 |
+
"""Return filenames for package's data files in 'src_dir'"""
|
| 125 |
+
globs = self.package_data.get('', []) + self.package_data.get(package, [])
|
| 126 |
+
files = []
|
| 127 |
+
for pattern in globs:
|
| 128 |
+
# Each pattern has to be converted to a platform-specific path
|
| 129 |
+
filelist = glob.glob(
|
| 130 |
+
os.path.join(glob.escape(src_dir), convert_path(pattern))
|
| 131 |
+
)
|
| 132 |
+
# Files that match more than one pattern are only added once
|
| 133 |
+
files.extend(
|
| 134 |
+
[fn for fn in filelist if fn not in files and os.path.isfile(fn)]
|
| 135 |
+
)
|
| 136 |
+
return files
|
| 137 |
+
|
| 138 |
+
def build_package_data(self):
|
| 139 |
+
"""Copy data files into build directory"""
|
| 140 |
+
for package, src_dir, build_dir, filenames in self.data_files:
|
| 141 |
+
for filename in filenames:
|
| 142 |
+
target = os.path.join(build_dir, filename)
|
| 143 |
+
self.mkpath(os.path.dirname(target))
|
| 144 |
+
self.copy_file(
|
| 145 |
+
os.path.join(src_dir, filename), target, preserve_mode=False
|
| 146 |
+
)
|
| 147 |
+
|
| 148 |
+
def get_package_dir(self, package):
|
| 149 |
+
"""Return the directory, relative to the top of the source
|
| 150 |
+
distribution, where package 'package' should be found
|
| 151 |
+
(at least according to the 'package_dir' option, if any)."""
|
| 152 |
+
path = package.split('.')
|
| 153 |
+
|
| 154 |
+
if not self.package_dir:
|
| 155 |
+
if path:
|
| 156 |
+
return os.path.join(*path)
|
| 157 |
+
else:
|
| 158 |
+
return ''
|
| 159 |
+
else:
|
| 160 |
+
tail = []
|
| 161 |
+
while path:
|
| 162 |
+
try:
|
| 163 |
+
pdir = self.package_dir['.'.join(path)]
|
| 164 |
+
except KeyError:
|
| 165 |
+
tail.insert(0, path[-1])
|
| 166 |
+
del path[-1]
|
| 167 |
+
else:
|
| 168 |
+
tail.insert(0, pdir)
|
| 169 |
+
return os.path.join(*tail)
|
| 170 |
+
else:
|
| 171 |
+
# Oops, got all the way through 'path' without finding a
|
| 172 |
+
# match in package_dir. If package_dir defines a directory
|
| 173 |
+
# for the root (nameless) package, then fallback on it;
|
| 174 |
+
# otherwise, we might as well have not consulted
|
| 175 |
+
# package_dir at all, as we just use the directory implied
|
| 176 |
+
# by 'tail' (which should be the same as the original value
|
| 177 |
+
# of 'path' at this point).
|
| 178 |
+
pdir = self.package_dir.get('')
|
| 179 |
+
if pdir is not None:
|
| 180 |
+
tail.insert(0, pdir)
|
| 181 |
+
|
| 182 |
+
if tail:
|
| 183 |
+
return os.path.join(*tail)
|
| 184 |
+
else:
|
| 185 |
+
return ''
|
| 186 |
+
|
| 187 |
+
def check_package(self, package, package_dir):
|
| 188 |
+
# Empty dir name means current directory, which we can probably
|
| 189 |
+
# assume exists. Also, os.path.exists and isdir don't know about
|
| 190 |
+
# my "empty string means current dir" convention, so we have to
|
| 191 |
+
# circumvent them.
|
| 192 |
+
if package_dir != "":
|
| 193 |
+
if not os.path.exists(package_dir):
|
| 194 |
+
raise DistutilsFileError(
|
| 195 |
+
"package directory '%s' does not exist" % package_dir
|
| 196 |
+
)
|
| 197 |
+
if not os.path.isdir(package_dir):
|
| 198 |
+
raise DistutilsFileError(
|
| 199 |
+
"supposed package directory '%s' exists, "
|
| 200 |
+
"but is not a directory" % package_dir
|
| 201 |
+
)
|
| 202 |
+
|
| 203 |
+
# Directories without __init__.py are namespace packages (PEP 420).
|
| 204 |
+
if package:
|
| 205 |
+
init_py = os.path.join(package_dir, "__init__.py")
|
| 206 |
+
if os.path.isfile(init_py):
|
| 207 |
+
return init_py
|
| 208 |
+
|
| 209 |
+
# Either not in a package at all (__init__.py not expected), or
|
| 210 |
+
# __init__.py doesn't exist -- so don't return the filename.
|
| 211 |
+
return None
|
| 212 |
+
|
| 213 |
+
def check_module(self, module, module_file):
|
| 214 |
+
if not os.path.isfile(module_file):
|
| 215 |
+
log.warn("file %s (for module %s) not found", module_file, module)
|
| 216 |
+
return False
|
| 217 |
+
else:
|
| 218 |
+
return True
|
| 219 |
+
|
| 220 |
+
def find_package_modules(self, package, package_dir):
|
| 221 |
+
self.check_package(package, package_dir)
|
| 222 |
+
module_files = glob.glob(os.path.join(glob.escape(package_dir), "*.py"))
|
| 223 |
+
modules = []
|
| 224 |
+
setup_script = os.path.abspath(self.distribution.script_name)
|
| 225 |
+
|
| 226 |
+
for f in module_files:
|
| 227 |
+
abs_f = os.path.abspath(f)
|
| 228 |
+
if abs_f != setup_script:
|
| 229 |
+
module = os.path.splitext(os.path.basename(f))[0]
|
| 230 |
+
modules.append((package, module, f))
|
| 231 |
+
else:
|
| 232 |
+
self.debug_print("excluding %s" % setup_script)
|
| 233 |
+
return modules
|
| 234 |
+
|
| 235 |
+
def find_modules(self):
|
| 236 |
+
"""Finds individually-specified Python modules, ie. those listed by
|
| 237 |
+
module name in 'self.py_modules'. Returns a list of tuples (package,
|
| 238 |
+
module_base, filename): 'package' is a tuple of the path through
|
| 239 |
+
package-space to the module; 'module_base' is the bare (no
|
| 240 |
+
packages, no dots) module name, and 'filename' is the path to the
|
| 241 |
+
".py" file (relative to the distribution root) that implements the
|
| 242 |
+
module.
|
| 243 |
+
"""
|
| 244 |
+
# Map package names to tuples of useful info about the package:
|
| 245 |
+
# (package_dir, checked)
|
| 246 |
+
# package_dir - the directory where we'll find source files for
|
| 247 |
+
# this package
|
| 248 |
+
# checked - true if we have checked that the package directory
|
| 249 |
+
# is valid (exists, contains __init__.py, ... ?)
|
| 250 |
+
packages = {}
|
| 251 |
+
|
| 252 |
+
# List of (package, module, filename) tuples to return
|
| 253 |
+
modules = []
|
| 254 |
+
|
| 255 |
+
# We treat modules-in-packages almost the same as toplevel modules,
|
| 256 |
+
# just the "package" for a toplevel is empty (either an empty
|
| 257 |
+
# string or empty list, depending on context). Differences:
|
| 258 |
+
# - don't check for __init__.py in directory for empty package
|
| 259 |
+
for module in self.py_modules:
|
| 260 |
+
path = module.split('.')
|
| 261 |
+
package = '.'.join(path[0:-1])
|
| 262 |
+
module_base = path[-1]
|
| 263 |
+
|
| 264 |
+
try:
|
| 265 |
+
(package_dir, checked) = packages[package]
|
| 266 |
+
except KeyError:
|
| 267 |
+
package_dir = self.get_package_dir(package)
|
| 268 |
+
checked = 0
|
| 269 |
+
|
| 270 |
+
if not checked:
|
| 271 |
+
init_py = self.check_package(package, package_dir)
|
| 272 |
+
packages[package] = (package_dir, 1)
|
| 273 |
+
if init_py:
|
| 274 |
+
modules.append((package, "__init__", init_py))
|
| 275 |
+
|
| 276 |
+
# XXX perhaps we should also check for just .pyc files
|
| 277 |
+
# (so greedy closed-source bastards can distribute Python
|
| 278 |
+
# modules too)
|
| 279 |
+
module_file = os.path.join(package_dir, module_base + ".py")
|
| 280 |
+
if not self.check_module(module, module_file):
|
| 281 |
+
continue
|
| 282 |
+
|
| 283 |
+
modules.append((package, module_base, module_file))
|
| 284 |
+
|
| 285 |
+
return modules
|
| 286 |
+
|
| 287 |
+
def find_all_modules(self):
|
| 288 |
+
"""Compute the list of all modules that will be built, whether
|
| 289 |
+
they are specified one-module-at-a-time ('self.py_modules') or
|
| 290 |
+
by whole packages ('self.packages'). Return a list of tuples
|
| 291 |
+
(package, module, module_file), just like 'find_modules()' and
|
| 292 |
+
'find_package_modules()' do."""
|
| 293 |
+
modules = []
|
| 294 |
+
if self.py_modules:
|
| 295 |
+
modules.extend(self.find_modules())
|
| 296 |
+
if self.packages:
|
| 297 |
+
for package in self.packages:
|
| 298 |
+
package_dir = self.get_package_dir(package)
|
| 299 |
+
m = self.find_package_modules(package, package_dir)
|
| 300 |
+
modules.extend(m)
|
| 301 |
+
return modules
|
| 302 |
+
|
| 303 |
+
def get_source_files(self):
|
| 304 |
+
return [module[-1] for module in self.find_all_modules()]
|
| 305 |
+
|
| 306 |
+
def get_module_outfile(self, build_dir, package, module):
|
| 307 |
+
outfile_path = [build_dir] + list(package) + [module + ".py"]
|
| 308 |
+
return os.path.join(*outfile_path)
|
| 309 |
+
|
| 310 |
+
def get_outputs(self, include_bytecode=1):
|
| 311 |
+
modules = self.find_all_modules()
|
| 312 |
+
outputs = []
|
| 313 |
+
for (package, module, module_file) in modules:
|
| 314 |
+
package = package.split('.')
|
| 315 |
+
filename = self.get_module_outfile(self.build_lib, package, module)
|
| 316 |
+
outputs.append(filename)
|
| 317 |
+
if include_bytecode:
|
| 318 |
+
if self.compile:
|
| 319 |
+
outputs.append(
|
| 320 |
+
importlib.util.cache_from_source(filename, optimization='')
|
| 321 |
+
)
|
| 322 |
+
if self.optimize > 0:
|
| 323 |
+
outputs.append(
|
| 324 |
+
importlib.util.cache_from_source(
|
| 325 |
+
filename, optimization=self.optimize
|
| 326 |
+
)
|
| 327 |
+
)
|
| 328 |
+
|
| 329 |
+
outputs += [
|
| 330 |
+
os.path.join(build_dir, filename)
|
| 331 |
+
for package, src_dir, build_dir, filenames in self.data_files
|
| 332 |
+
for filename in filenames
|
| 333 |
+
]
|
| 334 |
+
|
| 335 |
+
return outputs
|
| 336 |
+
|
| 337 |
+
def build_module(self, module, module_file, package):
|
| 338 |
+
if isinstance(package, str):
|
| 339 |
+
package = package.split('.')
|
| 340 |
+
elif not isinstance(package, (list, tuple)):
|
| 341 |
+
raise TypeError(
|
| 342 |
+
"'package' must be a string (dot-separated), list, or tuple"
|
| 343 |
+
)
|
| 344 |
+
|
| 345 |
+
# Now put the module source file into the "build" area -- this is
|
| 346 |
+
# easy, we just copy it somewhere under self.build_lib (the build
|
| 347 |
+
# directory for Python source).
|
| 348 |
+
outfile = self.get_module_outfile(self.build_lib, package, module)
|
| 349 |
+
dir = os.path.dirname(outfile)
|
| 350 |
+
self.mkpath(dir)
|
| 351 |
+
return self.copy_file(module_file, outfile, preserve_mode=0)
|
| 352 |
+
|
| 353 |
+
def build_modules(self):
|
| 354 |
+
modules = self.find_modules()
|
| 355 |
+
for (package, module, module_file) in modules:
|
| 356 |
+
# Now "build" the module -- ie. copy the source file to
|
| 357 |
+
# self.build_lib (the build directory for Python source).
|
| 358 |
+
# (Actually, it gets copied to the directory for this package
|
| 359 |
+
# under self.build_lib.)
|
| 360 |
+
self.build_module(module, module_file, package)
|
| 361 |
+
|
| 362 |
+
def build_packages(self):
|
| 363 |
+
for package in self.packages:
|
| 364 |
+
# Get list of (package, module, module_file) tuples based on
|
| 365 |
+
# scanning the package directory. 'package' is only included
|
| 366 |
+
# in the tuple so that 'find_modules()' and
|
| 367 |
+
# 'find_package_tuples()' have a consistent interface; it's
|
| 368 |
+
# ignored here (apart from a sanity check). Also, 'module' is
|
| 369 |
+
# the *unqualified* module name (ie. no dots, no package -- we
|
| 370 |
+
# already know its package!), and 'module_file' is the path to
|
| 371 |
+
# the .py file, relative to the current directory
|
| 372 |
+
# (ie. including 'package_dir').
|
| 373 |
+
package_dir = self.get_package_dir(package)
|
| 374 |
+
modules = self.find_package_modules(package, package_dir)
|
| 375 |
+
|
| 376 |
+
# Now loop over the modules we found, "building" each one (just
|
| 377 |
+
# copy it to self.build_lib).
|
| 378 |
+
for (package_, module, module_file) in modules:
|
| 379 |
+
assert package == package_
|
| 380 |
+
self.build_module(module, module_file, package)
|
| 381 |
+
|
| 382 |
+
def byte_compile(self, files):
|
| 383 |
+
if sys.dont_write_bytecode:
|
| 384 |
+
self.warn('byte-compiling is disabled, skipping.')
|
| 385 |
+
return
|
| 386 |
+
|
| 387 |
+
from distutils.util import byte_compile
|
| 388 |
+
|
| 389 |
+
prefix = self.build_lib
|
| 390 |
+
if prefix[-1] != os.sep:
|
| 391 |
+
prefix = prefix + os.sep
|
| 392 |
+
|
| 393 |
+
# XXX this code is essentially the same as the 'byte_compile()
|
| 394 |
+
# method of the "install_lib" command, except for the determination
|
| 395 |
+
# of the 'prefix' string. Hmmm.
|
| 396 |
+
if self.compile:
|
| 397 |
+
byte_compile(
|
| 398 |
+
files, optimize=0, force=self.force, prefix=prefix, dry_run=self.dry_run
|
| 399 |
+
)
|
| 400 |
+
if self.optimize > 0:
|
| 401 |
+
byte_compile(
|
| 402 |
+
files,
|
| 403 |
+
optimize=self.optimize,
|
| 404 |
+
force=self.force,
|
| 405 |
+
prefix=prefix,
|
| 406 |
+
dry_run=self.dry_run,
|
| 407 |
+
)
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/build_scripts.py
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""distutils.command.build_scripts
|
| 2 |
+
|
| 3 |
+
Implements the Distutils 'build_scripts' command."""
|
| 4 |
+
|
| 5 |
+
import os
|
| 6 |
+
import re
|
| 7 |
+
from stat import ST_MODE
|
| 8 |
+
from distutils import sysconfig
|
| 9 |
+
from distutils.core import Command
|
| 10 |
+
from distutils.dep_util import newer
|
| 11 |
+
from distutils.util import convert_path
|
| 12 |
+
from distutils import log
|
| 13 |
+
import tokenize
|
| 14 |
+
|
| 15 |
+
shebang_pattern = re.compile('^#!.*python[0-9.]*([ \t].*)?$')
|
| 16 |
+
"""
|
| 17 |
+
Pattern matching a Python interpreter indicated in first line of a script.
|
| 18 |
+
"""
|
| 19 |
+
|
| 20 |
+
# for Setuptools compatibility
|
| 21 |
+
first_line_re = shebang_pattern
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class build_scripts(Command):
|
| 25 |
+
|
| 26 |
+
description = "\"build\" scripts (copy and fixup #! line)"
|
| 27 |
+
|
| 28 |
+
user_options = [
|
| 29 |
+
('build-dir=', 'd', "directory to \"build\" (copy) to"),
|
| 30 |
+
('force', 'f', "forcibly build everything (ignore file timestamps"),
|
| 31 |
+
('executable=', 'e', "specify final destination interpreter path"),
|
| 32 |
+
]
|
| 33 |
+
|
| 34 |
+
boolean_options = ['force']
|
| 35 |
+
|
| 36 |
+
def initialize_options(self):
|
| 37 |
+
self.build_dir = None
|
| 38 |
+
self.scripts = None
|
| 39 |
+
self.force = None
|
| 40 |
+
self.executable = None
|
| 41 |
+
|
| 42 |
+
def finalize_options(self):
|
| 43 |
+
self.set_undefined_options(
|
| 44 |
+
'build',
|
| 45 |
+
('build_scripts', 'build_dir'),
|
| 46 |
+
('force', 'force'),
|
| 47 |
+
('executable', 'executable'),
|
| 48 |
+
)
|
| 49 |
+
self.scripts = self.distribution.scripts
|
| 50 |
+
|
| 51 |
+
def get_source_files(self):
|
| 52 |
+
return self.scripts
|
| 53 |
+
|
| 54 |
+
def run(self):
|
| 55 |
+
if not self.scripts:
|
| 56 |
+
return
|
| 57 |
+
self.copy_scripts()
|
| 58 |
+
|
| 59 |
+
def copy_scripts(self):
|
| 60 |
+
"""
|
| 61 |
+
Copy each script listed in ``self.scripts``.
|
| 62 |
+
|
| 63 |
+
If a script is marked as a Python script (first line matches
|
| 64 |
+
'shebang_pattern', i.e. starts with ``#!`` and contains
|
| 65 |
+
"python"), then adjust in the copy the first line to refer to
|
| 66 |
+
the current Python interpreter.
|
| 67 |
+
"""
|
| 68 |
+
self.mkpath(self.build_dir)
|
| 69 |
+
outfiles = []
|
| 70 |
+
updated_files = []
|
| 71 |
+
for script in self.scripts:
|
| 72 |
+
self._copy_script(script, outfiles, updated_files)
|
| 73 |
+
|
| 74 |
+
self._change_modes(outfiles)
|
| 75 |
+
|
| 76 |
+
return outfiles, updated_files
|
| 77 |
+
|
| 78 |
+
def _copy_script(self, script, outfiles, updated_files): # noqa: C901
|
| 79 |
+
shebang_match = None
|
| 80 |
+
script = convert_path(script)
|
| 81 |
+
outfile = os.path.join(self.build_dir, os.path.basename(script))
|
| 82 |
+
outfiles.append(outfile)
|
| 83 |
+
|
| 84 |
+
if not self.force and not newer(script, outfile):
|
| 85 |
+
log.debug("not copying %s (up-to-date)", script)
|
| 86 |
+
return
|
| 87 |
+
|
| 88 |
+
# Always open the file, but ignore failures in dry-run mode
|
| 89 |
+
# in order to attempt to copy directly.
|
| 90 |
+
try:
|
| 91 |
+
f = tokenize.open(script)
|
| 92 |
+
except OSError:
|
| 93 |
+
if not self.dry_run:
|
| 94 |
+
raise
|
| 95 |
+
f = None
|
| 96 |
+
else:
|
| 97 |
+
first_line = f.readline()
|
| 98 |
+
if not first_line:
|
| 99 |
+
self.warn("%s is an empty file (skipping)" % script)
|
| 100 |
+
return
|
| 101 |
+
|
| 102 |
+
shebang_match = shebang_pattern.match(first_line)
|
| 103 |
+
|
| 104 |
+
updated_files.append(outfile)
|
| 105 |
+
if shebang_match:
|
| 106 |
+
log.info("copying and adjusting %s -> %s", script, self.build_dir)
|
| 107 |
+
if not self.dry_run:
|
| 108 |
+
if not sysconfig.python_build:
|
| 109 |
+
executable = self.executable
|
| 110 |
+
else:
|
| 111 |
+
executable = os.path.join(
|
| 112 |
+
sysconfig.get_config_var("BINDIR"),
|
| 113 |
+
"python%s%s"
|
| 114 |
+
% (
|
| 115 |
+
sysconfig.get_config_var("VERSION"),
|
| 116 |
+
sysconfig.get_config_var("EXE"),
|
| 117 |
+
),
|
| 118 |
+
)
|
| 119 |
+
post_interp = shebang_match.group(1) or ''
|
| 120 |
+
shebang = "#!" + executable + post_interp + "\n"
|
| 121 |
+
self._validate_shebang(shebang, f.encoding)
|
| 122 |
+
with open(outfile, "w", encoding=f.encoding) as outf:
|
| 123 |
+
outf.write(shebang)
|
| 124 |
+
outf.writelines(f.readlines())
|
| 125 |
+
if f:
|
| 126 |
+
f.close()
|
| 127 |
+
else:
|
| 128 |
+
if f:
|
| 129 |
+
f.close()
|
| 130 |
+
self.copy_file(script, outfile)
|
| 131 |
+
|
| 132 |
+
def _change_modes(self, outfiles):
|
| 133 |
+
if os.name != 'posix':
|
| 134 |
+
return
|
| 135 |
+
|
| 136 |
+
for file in outfiles:
|
| 137 |
+
self._change_mode(file)
|
| 138 |
+
|
| 139 |
+
def _change_mode(self, file):
|
| 140 |
+
if self.dry_run:
|
| 141 |
+
log.info("changing mode of %s", file)
|
| 142 |
+
return
|
| 143 |
+
|
| 144 |
+
oldmode = os.stat(file)[ST_MODE] & 0o7777
|
| 145 |
+
newmode = (oldmode | 0o555) & 0o7777
|
| 146 |
+
if newmode != oldmode:
|
| 147 |
+
log.info("changing mode of %s from %o to %o", file, oldmode, newmode)
|
| 148 |
+
os.chmod(file, newmode)
|
| 149 |
+
|
| 150 |
+
@staticmethod
|
| 151 |
+
def _validate_shebang(shebang, encoding):
|
| 152 |
+
# Python parser starts to read a script using UTF-8 until
|
| 153 |
+
# it gets a #coding:xxx cookie. The shebang has to be the
|
| 154 |
+
# first line of a file, the #coding:xxx cookie cannot be
|
| 155 |
+
# written before. So the shebang has to be encodable to
|
| 156 |
+
# UTF-8.
|
| 157 |
+
try:
|
| 158 |
+
shebang.encode('utf-8')
|
| 159 |
+
except UnicodeEncodeError:
|
| 160 |
+
raise ValueError(
|
| 161 |
+
"The shebang ({!r}) is not encodable " "to utf-8".format(shebang)
|
| 162 |
+
)
|
| 163 |
+
|
| 164 |
+
# If the script is encoded to a custom encoding (use a
|
| 165 |
+
# #coding:xxx cookie), the shebang has to be encodable to
|
| 166 |
+
# the script encoding too.
|
| 167 |
+
try:
|
| 168 |
+
shebang.encode(encoding)
|
| 169 |
+
except UnicodeEncodeError:
|
| 170 |
+
raise ValueError(
|
| 171 |
+
"The shebang ({!r}) is not encodable "
|
| 172 |
+
"to the script encoding ({})".format(shebang, encoding)
|
| 173 |
+
)
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/config.py
ADDED
|
@@ -0,0 +1,377 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""distutils.command.config
|
| 2 |
+
|
| 3 |
+
Implements the Distutils 'config' command, a (mostly) empty command class
|
| 4 |
+
that exists mainly to be sub-classed by specific module distributions and
|
| 5 |
+
applications. The idea is that while every "config" command is different,
|
| 6 |
+
at least they're all named the same, and users always see "config" in the
|
| 7 |
+
list of standard commands. Also, this is a good place to put common
|
| 8 |
+
configure-like tasks: "try to compile this C code", or "figure out where
|
| 9 |
+
this header file lives".
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
import os
|
| 13 |
+
import re
|
| 14 |
+
|
| 15 |
+
from distutils.core import Command
|
| 16 |
+
from distutils.errors import DistutilsExecError
|
| 17 |
+
from distutils.sysconfig import customize_compiler
|
| 18 |
+
from distutils import log
|
| 19 |
+
|
| 20 |
+
LANG_EXT = {"c": ".c", "c++": ".cxx"}
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
class config(Command):
|
| 24 |
+
|
| 25 |
+
description = "prepare to build"
|
| 26 |
+
|
| 27 |
+
user_options = [
|
| 28 |
+
('compiler=', None, "specify the compiler type"),
|
| 29 |
+
('cc=', None, "specify the compiler executable"),
|
| 30 |
+
('include-dirs=', 'I', "list of directories to search for header files"),
|
| 31 |
+
('define=', 'D', "C preprocessor macros to define"),
|
| 32 |
+
('undef=', 'U', "C preprocessor macros to undefine"),
|
| 33 |
+
('libraries=', 'l', "external C libraries to link with"),
|
| 34 |
+
('library-dirs=', 'L', "directories to search for external C libraries"),
|
| 35 |
+
('noisy', None, "show every action (compile, link, run, ...) taken"),
|
| 36 |
+
(
|
| 37 |
+
'dump-source',
|
| 38 |
+
None,
|
| 39 |
+
"dump generated source files before attempting to compile them",
|
| 40 |
+
),
|
| 41 |
+
]
|
| 42 |
+
|
| 43 |
+
# The three standard command methods: since the "config" command
|
| 44 |
+
# does nothing by default, these are empty.
|
| 45 |
+
|
| 46 |
+
def initialize_options(self):
|
| 47 |
+
self.compiler = None
|
| 48 |
+
self.cc = None
|
| 49 |
+
self.include_dirs = None
|
| 50 |
+
self.libraries = None
|
| 51 |
+
self.library_dirs = None
|
| 52 |
+
|
| 53 |
+
# maximal output for now
|
| 54 |
+
self.noisy = 1
|
| 55 |
+
self.dump_source = 1
|
| 56 |
+
|
| 57 |
+
# list of temporary files generated along-the-way that we have
|
| 58 |
+
# to clean at some point
|
| 59 |
+
self.temp_files = []
|
| 60 |
+
|
| 61 |
+
def finalize_options(self):
|
| 62 |
+
if self.include_dirs is None:
|
| 63 |
+
self.include_dirs = self.distribution.include_dirs or []
|
| 64 |
+
elif isinstance(self.include_dirs, str):
|
| 65 |
+
self.include_dirs = self.include_dirs.split(os.pathsep)
|
| 66 |
+
|
| 67 |
+
if self.libraries is None:
|
| 68 |
+
self.libraries = []
|
| 69 |
+
elif isinstance(self.libraries, str):
|
| 70 |
+
self.libraries = [self.libraries]
|
| 71 |
+
|
| 72 |
+
if self.library_dirs is None:
|
| 73 |
+
self.library_dirs = []
|
| 74 |
+
elif isinstance(self.library_dirs, str):
|
| 75 |
+
self.library_dirs = self.library_dirs.split(os.pathsep)
|
| 76 |
+
|
| 77 |
+
def run(self):
|
| 78 |
+
pass
|
| 79 |
+
|
| 80 |
+
# Utility methods for actual "config" commands. The interfaces are
|
| 81 |
+
# loosely based on Autoconf macros of similar names. Sub-classes
|
| 82 |
+
# may use these freely.
|
| 83 |
+
|
| 84 |
+
def _check_compiler(self):
|
| 85 |
+
"""Check that 'self.compiler' really is a CCompiler object;
|
| 86 |
+
if not, make it one.
|
| 87 |
+
"""
|
| 88 |
+
# We do this late, and only on-demand, because this is an expensive
|
| 89 |
+
# import.
|
| 90 |
+
from distutils.ccompiler import CCompiler, new_compiler
|
| 91 |
+
|
| 92 |
+
if not isinstance(self.compiler, CCompiler):
|
| 93 |
+
self.compiler = new_compiler(
|
| 94 |
+
compiler=self.compiler, dry_run=self.dry_run, force=1
|
| 95 |
+
)
|
| 96 |
+
customize_compiler(self.compiler)
|
| 97 |
+
if self.include_dirs:
|
| 98 |
+
self.compiler.set_include_dirs(self.include_dirs)
|
| 99 |
+
if self.libraries:
|
| 100 |
+
self.compiler.set_libraries(self.libraries)
|
| 101 |
+
if self.library_dirs:
|
| 102 |
+
self.compiler.set_library_dirs(self.library_dirs)
|
| 103 |
+
|
| 104 |
+
def _gen_temp_sourcefile(self, body, headers, lang):
|
| 105 |
+
filename = "_configtest" + LANG_EXT[lang]
|
| 106 |
+
with open(filename, "w") as file:
|
| 107 |
+
if headers:
|
| 108 |
+
for header in headers:
|
| 109 |
+
file.write("#include <%s>\n" % header)
|
| 110 |
+
file.write("\n")
|
| 111 |
+
file.write(body)
|
| 112 |
+
if body[-1] != "\n":
|
| 113 |
+
file.write("\n")
|
| 114 |
+
return filename
|
| 115 |
+
|
| 116 |
+
def _preprocess(self, body, headers, include_dirs, lang):
|
| 117 |
+
src = self._gen_temp_sourcefile(body, headers, lang)
|
| 118 |
+
out = "_configtest.i"
|
| 119 |
+
self.temp_files.extend([src, out])
|
| 120 |
+
self.compiler.preprocess(src, out, include_dirs=include_dirs)
|
| 121 |
+
return (src, out)
|
| 122 |
+
|
| 123 |
+
def _compile(self, body, headers, include_dirs, lang):
|
| 124 |
+
src = self._gen_temp_sourcefile(body, headers, lang)
|
| 125 |
+
if self.dump_source:
|
| 126 |
+
dump_file(src, "compiling '%s':" % src)
|
| 127 |
+
(obj,) = self.compiler.object_filenames([src])
|
| 128 |
+
self.temp_files.extend([src, obj])
|
| 129 |
+
self.compiler.compile([src], include_dirs=include_dirs)
|
| 130 |
+
return (src, obj)
|
| 131 |
+
|
| 132 |
+
def _link(self, body, headers, include_dirs, libraries, library_dirs, lang):
|
| 133 |
+
(src, obj) = self._compile(body, headers, include_dirs, lang)
|
| 134 |
+
prog = os.path.splitext(os.path.basename(src))[0]
|
| 135 |
+
self.compiler.link_executable(
|
| 136 |
+
[obj],
|
| 137 |
+
prog,
|
| 138 |
+
libraries=libraries,
|
| 139 |
+
library_dirs=library_dirs,
|
| 140 |
+
target_lang=lang,
|
| 141 |
+
)
|
| 142 |
+
|
| 143 |
+
if self.compiler.exe_extension is not None:
|
| 144 |
+
prog = prog + self.compiler.exe_extension
|
| 145 |
+
self.temp_files.append(prog)
|
| 146 |
+
|
| 147 |
+
return (src, obj, prog)
|
| 148 |
+
|
| 149 |
+
def _clean(self, *filenames):
|
| 150 |
+
if not filenames:
|
| 151 |
+
filenames = self.temp_files
|
| 152 |
+
self.temp_files = []
|
| 153 |
+
log.info("removing: %s", ' '.join(filenames))
|
| 154 |
+
for filename in filenames:
|
| 155 |
+
try:
|
| 156 |
+
os.remove(filename)
|
| 157 |
+
except OSError:
|
| 158 |
+
pass
|
| 159 |
+
|
| 160 |
+
# XXX these ignore the dry-run flag: what to do, what to do? even if
|
| 161 |
+
# you want a dry-run build, you still need some sort of configuration
|
| 162 |
+
# info. My inclination is to make it up to the real config command to
|
| 163 |
+
# consult 'dry_run', and assume a default (minimal) configuration if
|
| 164 |
+
# true. The problem with trying to do it here is that you'd have to
|
| 165 |
+
# return either true or false from all the 'try' methods, neither of
|
| 166 |
+
# which is correct.
|
| 167 |
+
|
| 168 |
+
# XXX need access to the header search path and maybe default macros.
|
| 169 |
+
|
| 170 |
+
def try_cpp(self, body=None, headers=None, include_dirs=None, lang="c"):
|
| 171 |
+
"""Construct a source file from 'body' (a string containing lines
|
| 172 |
+
of C/C++ code) and 'headers' (a list of header files to include)
|
| 173 |
+
and run it through the preprocessor. Return true if the
|
| 174 |
+
preprocessor succeeded, false if there were any errors.
|
| 175 |
+
('body' probably isn't of much use, but what the heck.)
|
| 176 |
+
"""
|
| 177 |
+
from distutils.ccompiler import CompileError
|
| 178 |
+
|
| 179 |
+
self._check_compiler()
|
| 180 |
+
ok = True
|
| 181 |
+
try:
|
| 182 |
+
self._preprocess(body, headers, include_dirs, lang)
|
| 183 |
+
except CompileError:
|
| 184 |
+
ok = False
|
| 185 |
+
|
| 186 |
+
self._clean()
|
| 187 |
+
return ok
|
| 188 |
+
|
| 189 |
+
def search_cpp(self, pattern, body=None, headers=None, include_dirs=None, lang="c"):
|
| 190 |
+
"""Construct a source file (just like 'try_cpp()'), run it through
|
| 191 |
+
the preprocessor, and return true if any line of the output matches
|
| 192 |
+
'pattern'. 'pattern' should either be a compiled regex object or a
|
| 193 |
+
string containing a regex. If both 'body' and 'headers' are None,
|
| 194 |
+
preprocesses an empty file -- which can be useful to determine the
|
| 195 |
+
symbols the preprocessor and compiler set by default.
|
| 196 |
+
"""
|
| 197 |
+
self._check_compiler()
|
| 198 |
+
src, out = self._preprocess(body, headers, include_dirs, lang)
|
| 199 |
+
|
| 200 |
+
if isinstance(pattern, str):
|
| 201 |
+
pattern = re.compile(pattern)
|
| 202 |
+
|
| 203 |
+
with open(out) as file:
|
| 204 |
+
match = False
|
| 205 |
+
while True:
|
| 206 |
+
line = file.readline()
|
| 207 |
+
if line == '':
|
| 208 |
+
break
|
| 209 |
+
if pattern.search(line):
|
| 210 |
+
match = True
|
| 211 |
+
break
|
| 212 |
+
|
| 213 |
+
self._clean()
|
| 214 |
+
return match
|
| 215 |
+
|
| 216 |
+
def try_compile(self, body, headers=None, include_dirs=None, lang="c"):
|
| 217 |
+
"""Try to compile a source file built from 'body' and 'headers'.
|
| 218 |
+
Return true on success, false otherwise.
|
| 219 |
+
"""
|
| 220 |
+
from distutils.ccompiler import CompileError
|
| 221 |
+
|
| 222 |
+
self._check_compiler()
|
| 223 |
+
try:
|
| 224 |
+
self._compile(body, headers, include_dirs, lang)
|
| 225 |
+
ok = True
|
| 226 |
+
except CompileError:
|
| 227 |
+
ok = False
|
| 228 |
+
|
| 229 |
+
log.info(ok and "success!" or "failure.")
|
| 230 |
+
self._clean()
|
| 231 |
+
return ok
|
| 232 |
+
|
| 233 |
+
def try_link(
|
| 234 |
+
self,
|
| 235 |
+
body,
|
| 236 |
+
headers=None,
|
| 237 |
+
include_dirs=None,
|
| 238 |
+
libraries=None,
|
| 239 |
+
library_dirs=None,
|
| 240 |
+
lang="c",
|
| 241 |
+
):
|
| 242 |
+
"""Try to compile and link a source file, built from 'body' and
|
| 243 |
+
'headers', to executable form. Return true on success, false
|
| 244 |
+
otherwise.
|
| 245 |
+
"""
|
| 246 |
+
from distutils.ccompiler import CompileError, LinkError
|
| 247 |
+
|
| 248 |
+
self._check_compiler()
|
| 249 |
+
try:
|
| 250 |
+
self._link(body, headers, include_dirs, libraries, library_dirs, lang)
|
| 251 |
+
ok = True
|
| 252 |
+
except (CompileError, LinkError):
|
| 253 |
+
ok = False
|
| 254 |
+
|
| 255 |
+
log.info(ok and "success!" or "failure.")
|
| 256 |
+
self._clean()
|
| 257 |
+
return ok
|
| 258 |
+
|
| 259 |
+
def try_run(
|
| 260 |
+
self,
|
| 261 |
+
body,
|
| 262 |
+
headers=None,
|
| 263 |
+
include_dirs=None,
|
| 264 |
+
libraries=None,
|
| 265 |
+
library_dirs=None,
|
| 266 |
+
lang="c",
|
| 267 |
+
):
|
| 268 |
+
"""Try to compile, link to an executable, and run a program
|
| 269 |
+
built from 'body' and 'headers'. Return true on success, false
|
| 270 |
+
otherwise.
|
| 271 |
+
"""
|
| 272 |
+
from distutils.ccompiler import CompileError, LinkError
|
| 273 |
+
|
| 274 |
+
self._check_compiler()
|
| 275 |
+
try:
|
| 276 |
+
src, obj, exe = self._link(
|
| 277 |
+
body, headers, include_dirs, libraries, library_dirs, lang
|
| 278 |
+
)
|
| 279 |
+
self.spawn([exe])
|
| 280 |
+
ok = True
|
| 281 |
+
except (CompileError, LinkError, DistutilsExecError):
|
| 282 |
+
ok = False
|
| 283 |
+
|
| 284 |
+
log.info(ok and "success!" or "failure.")
|
| 285 |
+
self._clean()
|
| 286 |
+
return ok
|
| 287 |
+
|
| 288 |
+
# -- High-level methods --------------------------------------------
|
| 289 |
+
# (these are the ones that are actually likely to be useful
|
| 290 |
+
# when implementing a real-world config command!)
|
| 291 |
+
|
| 292 |
+
def check_func(
|
| 293 |
+
self,
|
| 294 |
+
func,
|
| 295 |
+
headers=None,
|
| 296 |
+
include_dirs=None,
|
| 297 |
+
libraries=None,
|
| 298 |
+
library_dirs=None,
|
| 299 |
+
decl=0,
|
| 300 |
+
call=0,
|
| 301 |
+
):
|
| 302 |
+
"""Determine if function 'func' is available by constructing a
|
| 303 |
+
source file that refers to 'func', and compiles and links it.
|
| 304 |
+
If everything succeeds, returns true; otherwise returns false.
|
| 305 |
+
|
| 306 |
+
The constructed source file starts out by including the header
|
| 307 |
+
files listed in 'headers'. If 'decl' is true, it then declares
|
| 308 |
+
'func' (as "int func()"); you probably shouldn't supply 'headers'
|
| 309 |
+
and set 'decl' true in the same call, or you might get errors about
|
| 310 |
+
a conflicting declarations for 'func'. Finally, the constructed
|
| 311 |
+
'main()' function either references 'func' or (if 'call' is true)
|
| 312 |
+
calls it. 'libraries' and 'library_dirs' are used when
|
| 313 |
+
linking.
|
| 314 |
+
"""
|
| 315 |
+
self._check_compiler()
|
| 316 |
+
body = []
|
| 317 |
+
if decl:
|
| 318 |
+
body.append("int %s ();" % func)
|
| 319 |
+
body.append("int main () {")
|
| 320 |
+
if call:
|
| 321 |
+
body.append(" %s();" % func)
|
| 322 |
+
else:
|
| 323 |
+
body.append(" %s;" % func)
|
| 324 |
+
body.append("}")
|
| 325 |
+
body = "\n".join(body) + "\n"
|
| 326 |
+
|
| 327 |
+
return self.try_link(body, headers, include_dirs, libraries, library_dirs)
|
| 328 |
+
|
| 329 |
+
def check_lib(
|
| 330 |
+
self,
|
| 331 |
+
library,
|
| 332 |
+
library_dirs=None,
|
| 333 |
+
headers=None,
|
| 334 |
+
include_dirs=None,
|
| 335 |
+
other_libraries=[],
|
| 336 |
+
):
|
| 337 |
+
"""Determine if 'library' is available to be linked against,
|
| 338 |
+
without actually checking that any particular symbols are provided
|
| 339 |
+
by it. 'headers' will be used in constructing the source file to
|
| 340 |
+
be compiled, but the only effect of this is to check if all the
|
| 341 |
+
header files listed are available. Any libraries listed in
|
| 342 |
+
'other_libraries' will be included in the link, in case 'library'
|
| 343 |
+
has symbols that depend on other libraries.
|
| 344 |
+
"""
|
| 345 |
+
self._check_compiler()
|
| 346 |
+
return self.try_link(
|
| 347 |
+
"int main (void) { }",
|
| 348 |
+
headers,
|
| 349 |
+
include_dirs,
|
| 350 |
+
[library] + other_libraries,
|
| 351 |
+
library_dirs,
|
| 352 |
+
)
|
| 353 |
+
|
| 354 |
+
def check_header(self, header, include_dirs=None, library_dirs=None, lang="c"):
|
| 355 |
+
"""Determine if the system header file named by 'header_file'
|
| 356 |
+
exists and can be found by the preprocessor; return true if so,
|
| 357 |
+
false otherwise.
|
| 358 |
+
"""
|
| 359 |
+
return self.try_cpp(
|
| 360 |
+
body="/* No body */", headers=[header], include_dirs=include_dirs
|
| 361 |
+
)
|
| 362 |
+
|
| 363 |
+
|
| 364 |
+
def dump_file(filename, head=None):
|
| 365 |
+
"""Dumps a file content into log.info.
|
| 366 |
+
|
| 367 |
+
If head is not None, will be dumped before the file content.
|
| 368 |
+
"""
|
| 369 |
+
if head is None:
|
| 370 |
+
log.info('%s', filename)
|
| 371 |
+
else:
|
| 372 |
+
log.info(head)
|
| 373 |
+
file = open(filename)
|
| 374 |
+
try:
|
| 375 |
+
log.info(file.read())
|
| 376 |
+
finally:
|
| 377 |
+
file.close()
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/install.py
ADDED
|
@@ -0,0 +1,814 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""distutils.command.install
|
| 2 |
+
|
| 3 |
+
Implements the Distutils 'install' command."""
|
| 4 |
+
|
| 5 |
+
import sys
|
| 6 |
+
import os
|
| 7 |
+
import contextlib
|
| 8 |
+
import sysconfig
|
| 9 |
+
import itertools
|
| 10 |
+
|
| 11 |
+
from distutils import log
|
| 12 |
+
from distutils.core import Command
|
| 13 |
+
from distutils.debug import DEBUG
|
| 14 |
+
from distutils.sysconfig import get_config_vars
|
| 15 |
+
from distutils.file_util import write_file
|
| 16 |
+
from distutils.util import convert_path, subst_vars, change_root
|
| 17 |
+
from distutils.util import get_platform
|
| 18 |
+
from distutils.errors import DistutilsOptionError, DistutilsPlatformError
|
| 19 |
+
from . import _framework_compat as fw
|
| 20 |
+
from .. import _collections
|
| 21 |
+
|
| 22 |
+
from site import USER_BASE
|
| 23 |
+
from site import USER_SITE
|
| 24 |
+
|
| 25 |
+
HAS_USER_SITE = True
|
| 26 |
+
|
| 27 |
+
WINDOWS_SCHEME = {
|
| 28 |
+
'purelib': '{base}/Lib/site-packages',
|
| 29 |
+
'platlib': '{base}/Lib/site-packages',
|
| 30 |
+
'headers': '{base}/Include/{dist_name}',
|
| 31 |
+
'scripts': '{base}/Scripts',
|
| 32 |
+
'data': '{base}',
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
INSTALL_SCHEMES = {
|
| 36 |
+
'posix_prefix': {
|
| 37 |
+
'purelib': '{base}/lib/{implementation_lower}{py_version_short}/site-packages',
|
| 38 |
+
'platlib': '{platbase}/{platlibdir}/{implementation_lower}'
|
| 39 |
+
'{py_version_short}/site-packages',
|
| 40 |
+
'headers': '{base}/include/{implementation_lower}'
|
| 41 |
+
'{py_version_short}{abiflags}/{dist_name}',
|
| 42 |
+
'scripts': '{base}/bin',
|
| 43 |
+
'data': '{base}',
|
| 44 |
+
},
|
| 45 |
+
'posix_home': {
|
| 46 |
+
'purelib': '{base}/lib/{implementation_lower}',
|
| 47 |
+
'platlib': '{base}/{platlibdir}/{implementation_lower}',
|
| 48 |
+
'headers': '{base}/include/{implementation_lower}/{dist_name}',
|
| 49 |
+
'scripts': '{base}/bin',
|
| 50 |
+
'data': '{base}',
|
| 51 |
+
},
|
| 52 |
+
'nt': WINDOWS_SCHEME,
|
| 53 |
+
'pypy': {
|
| 54 |
+
'purelib': '{base}/site-packages',
|
| 55 |
+
'platlib': '{base}/site-packages',
|
| 56 |
+
'headers': '{base}/include/{dist_name}',
|
| 57 |
+
'scripts': '{base}/bin',
|
| 58 |
+
'data': '{base}',
|
| 59 |
+
},
|
| 60 |
+
'pypy_nt': {
|
| 61 |
+
'purelib': '{base}/site-packages',
|
| 62 |
+
'platlib': '{base}/site-packages',
|
| 63 |
+
'headers': '{base}/include/{dist_name}',
|
| 64 |
+
'scripts': '{base}/Scripts',
|
| 65 |
+
'data': '{base}',
|
| 66 |
+
},
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
# user site schemes
|
| 70 |
+
if HAS_USER_SITE:
|
| 71 |
+
INSTALL_SCHEMES['nt_user'] = {
|
| 72 |
+
'purelib': '{usersite}',
|
| 73 |
+
'platlib': '{usersite}',
|
| 74 |
+
'headers': '{userbase}/{implementation}{py_version_nodot_plat}'
|
| 75 |
+
'/Include/{dist_name}',
|
| 76 |
+
'scripts': '{userbase}/{implementation}{py_version_nodot_plat}/Scripts',
|
| 77 |
+
'data': '{userbase}',
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
INSTALL_SCHEMES['posix_user'] = {
|
| 81 |
+
'purelib': '{usersite}',
|
| 82 |
+
'platlib': '{usersite}',
|
| 83 |
+
'headers': '{userbase}/include/{implementation_lower}'
|
| 84 |
+
'{py_version_short}{abiflags}/{dist_name}',
|
| 85 |
+
'scripts': '{userbase}/bin',
|
| 86 |
+
'data': '{userbase}',
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
INSTALL_SCHEMES.update(fw.schemes)
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
# The keys to an installation scheme; if any new types of files are to be
|
| 94 |
+
# installed, be sure to add an entry to every installation scheme above,
|
| 95 |
+
# and to SCHEME_KEYS here.
|
| 96 |
+
SCHEME_KEYS = ('purelib', 'platlib', 'headers', 'scripts', 'data')
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
def _load_sysconfig_schemes():
|
| 100 |
+
with contextlib.suppress(AttributeError):
|
| 101 |
+
return {
|
| 102 |
+
scheme: sysconfig.get_paths(scheme, expand=False)
|
| 103 |
+
for scheme in sysconfig.get_scheme_names()
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
def _load_schemes():
|
| 108 |
+
"""
|
| 109 |
+
Extend default schemes with schemes from sysconfig.
|
| 110 |
+
"""
|
| 111 |
+
|
| 112 |
+
sysconfig_schemes = _load_sysconfig_schemes() or {}
|
| 113 |
+
|
| 114 |
+
return {
|
| 115 |
+
scheme: {
|
| 116 |
+
**INSTALL_SCHEMES.get(scheme, {}),
|
| 117 |
+
**sysconfig_schemes.get(scheme, {}),
|
| 118 |
+
}
|
| 119 |
+
for scheme in set(itertools.chain(INSTALL_SCHEMES, sysconfig_schemes))
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
def _get_implementation():
|
| 124 |
+
if hasattr(sys, 'pypy_version_info'):
|
| 125 |
+
return 'PyPy'
|
| 126 |
+
else:
|
| 127 |
+
return 'Python'
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
def _select_scheme(ob, name):
|
| 131 |
+
scheme = _inject_headers(name, _load_scheme(_resolve_scheme(name)))
|
| 132 |
+
vars(ob).update(_remove_set(ob, _scheme_attrs(scheme)))
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
def _remove_set(ob, attrs):
|
| 136 |
+
"""
|
| 137 |
+
Include only attrs that are None in ob.
|
| 138 |
+
"""
|
| 139 |
+
return {key: value for key, value in attrs.items() if getattr(ob, key) is None}
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
def _resolve_scheme(name):
|
| 143 |
+
os_name, sep, key = name.partition('_')
|
| 144 |
+
try:
|
| 145 |
+
resolved = sysconfig.get_preferred_scheme(key)
|
| 146 |
+
except Exception:
|
| 147 |
+
resolved = fw.scheme(_pypy_hack(name))
|
| 148 |
+
return resolved
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
def _load_scheme(name):
|
| 152 |
+
return _load_schemes()[name]
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
def _inject_headers(name, scheme):
|
| 156 |
+
"""
|
| 157 |
+
Given a scheme name and the resolved scheme,
|
| 158 |
+
if the scheme does not include headers, resolve
|
| 159 |
+
the fallback scheme for the name and use headers
|
| 160 |
+
from it. pypa/distutils#88
|
| 161 |
+
"""
|
| 162 |
+
# Bypass the preferred scheme, which may not
|
| 163 |
+
# have defined headers.
|
| 164 |
+
fallback = _load_scheme(_pypy_hack(name))
|
| 165 |
+
scheme.setdefault('headers', fallback['headers'])
|
| 166 |
+
return scheme
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
def _scheme_attrs(scheme):
|
| 170 |
+
"""Resolve install directories by applying the install schemes."""
|
| 171 |
+
return {f'install_{key}': scheme[key] for key in SCHEME_KEYS}
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
def _pypy_hack(name):
|
| 175 |
+
PY37 = sys.version_info < (3, 8)
|
| 176 |
+
old_pypy = hasattr(sys, 'pypy_version_info') and PY37
|
| 177 |
+
prefix = not name.endswith(('_user', '_home'))
|
| 178 |
+
pypy_name = 'pypy' + '_nt' * (os.name == 'nt')
|
| 179 |
+
return pypy_name if old_pypy and prefix else name
|
| 180 |
+
|
| 181 |
+
|
| 182 |
+
class install(Command):
|
| 183 |
+
|
| 184 |
+
description = "install everything from build directory"
|
| 185 |
+
|
| 186 |
+
user_options = [
|
| 187 |
+
# Select installation scheme and set base director(y|ies)
|
| 188 |
+
('prefix=', None, "installation prefix"),
|
| 189 |
+
('exec-prefix=', None, "(Unix only) prefix for platform-specific files"),
|
| 190 |
+
('home=', None, "(Unix only) home directory to install under"),
|
| 191 |
+
# Or, just set the base director(y|ies)
|
| 192 |
+
(
|
| 193 |
+
'install-base=',
|
| 194 |
+
None,
|
| 195 |
+
"base installation directory (instead of --prefix or --home)",
|
| 196 |
+
),
|
| 197 |
+
(
|
| 198 |
+
'install-platbase=',
|
| 199 |
+
None,
|
| 200 |
+
"base installation directory for platform-specific files "
|
| 201 |
+
+ "(instead of --exec-prefix or --home)",
|
| 202 |
+
),
|
| 203 |
+
('root=', None, "install everything relative to this alternate root directory"),
|
| 204 |
+
# Or, explicitly set the installation scheme
|
| 205 |
+
(
|
| 206 |
+
'install-purelib=',
|
| 207 |
+
None,
|
| 208 |
+
"installation directory for pure Python module distributions",
|
| 209 |
+
),
|
| 210 |
+
(
|
| 211 |
+
'install-platlib=',
|
| 212 |
+
None,
|
| 213 |
+
"installation directory for non-pure module distributions",
|
| 214 |
+
),
|
| 215 |
+
(
|
| 216 |
+
'install-lib=',
|
| 217 |
+
None,
|
| 218 |
+
"installation directory for all module distributions "
|
| 219 |
+
+ "(overrides --install-purelib and --install-platlib)",
|
| 220 |
+
),
|
| 221 |
+
('install-headers=', None, "installation directory for C/C++ headers"),
|
| 222 |
+
('install-scripts=', None, "installation directory for Python scripts"),
|
| 223 |
+
('install-data=', None, "installation directory for data files"),
|
| 224 |
+
# Byte-compilation options -- see install_lib.py for details, as
|
| 225 |
+
# these are duplicated from there (but only install_lib does
|
| 226 |
+
# anything with them).
|
| 227 |
+
('compile', 'c', "compile .py to .pyc [default]"),
|
| 228 |
+
('no-compile', None, "don't compile .py files"),
|
| 229 |
+
(
|
| 230 |
+
'optimize=',
|
| 231 |
+
'O',
|
| 232 |
+
"also compile with optimization: -O1 for \"python -O\", "
|
| 233 |
+
"-O2 for \"python -OO\", and -O0 to disable [default: -O0]",
|
| 234 |
+
),
|
| 235 |
+
# Miscellaneous control options
|
| 236 |
+
('force', 'f', "force installation (overwrite any existing files)"),
|
| 237 |
+
('skip-build', None, "skip rebuilding everything (for testing/debugging)"),
|
| 238 |
+
# Where to install documentation (eventually!)
|
| 239 |
+
# ('doc-format=', None, "format of documentation to generate"),
|
| 240 |
+
# ('install-man=', None, "directory for Unix man pages"),
|
| 241 |
+
# ('install-html=', None, "directory for HTML documentation"),
|
| 242 |
+
# ('install-info=', None, "directory for GNU info files"),
|
| 243 |
+
('record=', None, "filename in which to record list of installed files"),
|
| 244 |
+
]
|
| 245 |
+
|
| 246 |
+
boolean_options = ['compile', 'force', 'skip-build']
|
| 247 |
+
|
| 248 |
+
if HAS_USER_SITE:
|
| 249 |
+
user_options.append(
|
| 250 |
+
('user', None, "install in user site-package '%s'" % USER_SITE)
|
| 251 |
+
)
|
| 252 |
+
boolean_options.append('user')
|
| 253 |
+
|
| 254 |
+
negative_opt = {'no-compile': 'compile'}
|
| 255 |
+
|
| 256 |
+
def initialize_options(self):
|
| 257 |
+
"""Initializes options."""
|
| 258 |
+
# High-level options: these select both an installation base
|
| 259 |
+
# and scheme.
|
| 260 |
+
self.prefix = None
|
| 261 |
+
self.exec_prefix = None
|
| 262 |
+
self.home = None
|
| 263 |
+
self.user = 0
|
| 264 |
+
|
| 265 |
+
# These select only the installation base; it's up to the user to
|
| 266 |
+
# specify the installation scheme (currently, that means supplying
|
| 267 |
+
# the --install-{platlib,purelib,scripts,data} options).
|
| 268 |
+
self.install_base = None
|
| 269 |
+
self.install_platbase = None
|
| 270 |
+
self.root = None
|
| 271 |
+
|
| 272 |
+
# These options are the actual installation directories; if not
|
| 273 |
+
# supplied by the user, they are filled in using the installation
|
| 274 |
+
# scheme implied by prefix/exec-prefix/home and the contents of
|
| 275 |
+
# that installation scheme.
|
| 276 |
+
self.install_purelib = None # for pure module distributions
|
| 277 |
+
self.install_platlib = None # non-pure (dists w/ extensions)
|
| 278 |
+
self.install_headers = None # for C/C++ headers
|
| 279 |
+
self.install_lib = None # set to either purelib or platlib
|
| 280 |
+
self.install_scripts = None
|
| 281 |
+
self.install_data = None
|
| 282 |
+
self.install_userbase = USER_BASE
|
| 283 |
+
self.install_usersite = USER_SITE
|
| 284 |
+
|
| 285 |
+
self.compile = None
|
| 286 |
+
self.optimize = None
|
| 287 |
+
|
| 288 |
+
# Deprecated
|
| 289 |
+
# These two are for putting non-packagized distributions into their
|
| 290 |
+
# own directory and creating a .pth file if it makes sense.
|
| 291 |
+
# 'extra_path' comes from the setup file; 'install_path_file' can
|
| 292 |
+
# be turned off if it makes no sense to install a .pth file. (But
|
| 293 |
+
# better to install it uselessly than to guess wrong and not
|
| 294 |
+
# install it when it's necessary and would be used!) Currently,
|
| 295 |
+
# 'install_path_file' is always true unless some outsider meddles
|
| 296 |
+
# with it.
|
| 297 |
+
self.extra_path = None
|
| 298 |
+
self.install_path_file = 1
|
| 299 |
+
|
| 300 |
+
# 'force' forces installation, even if target files are not
|
| 301 |
+
# out-of-date. 'skip_build' skips running the "build" command,
|
| 302 |
+
# handy if you know it's not necessary. 'warn_dir' (which is *not*
|
| 303 |
+
# a user option, it's just there so the bdist_* commands can turn
|
| 304 |
+
# it off) determines whether we warn about installing to a
|
| 305 |
+
# directory not in sys.path.
|
| 306 |
+
self.force = 0
|
| 307 |
+
self.skip_build = 0
|
| 308 |
+
self.warn_dir = 1
|
| 309 |
+
|
| 310 |
+
# These are only here as a conduit from the 'build' command to the
|
| 311 |
+
# 'install_*' commands that do the real work. ('build_base' isn't
|
| 312 |
+
# actually used anywhere, but it might be useful in future.) They
|
| 313 |
+
# are not user options, because if the user told the install
|
| 314 |
+
# command where the build directory is, that wouldn't affect the
|
| 315 |
+
# build command.
|
| 316 |
+
self.build_base = None
|
| 317 |
+
self.build_lib = None
|
| 318 |
+
|
| 319 |
+
# Not defined yet because we don't know anything about
|
| 320 |
+
# documentation yet.
|
| 321 |
+
# self.install_man = None
|
| 322 |
+
# self.install_html = None
|
| 323 |
+
# self.install_info = None
|
| 324 |
+
|
| 325 |
+
self.record = None
|
| 326 |
+
|
| 327 |
+
# -- Option finalizing methods -------------------------------------
|
| 328 |
+
# (This is rather more involved than for most commands,
|
| 329 |
+
# because this is where the policy for installing third-
|
| 330 |
+
# party Python modules on various platforms given a wide
|
| 331 |
+
# array of user input is decided. Yes, it's quite complex!)
|
| 332 |
+
|
| 333 |
+
def finalize_options(self): # noqa: C901
|
| 334 |
+
"""Finalizes options."""
|
| 335 |
+
# This method (and its helpers, like 'finalize_unix()',
|
| 336 |
+
# 'finalize_other()', and 'select_scheme()') is where the default
|
| 337 |
+
# installation directories for modules, extension modules, and
|
| 338 |
+
# anything else we care to install from a Python module
|
| 339 |
+
# distribution. Thus, this code makes a pretty important policy
|
| 340 |
+
# statement about how third-party stuff is added to a Python
|
| 341 |
+
# installation! Note that the actual work of installation is done
|
| 342 |
+
# by the relatively simple 'install_*' commands; they just take
|
| 343 |
+
# their orders from the installation directory options determined
|
| 344 |
+
# here.
|
| 345 |
+
|
| 346 |
+
# Check for errors/inconsistencies in the options; first, stuff
|
| 347 |
+
# that's wrong on any platform.
|
| 348 |
+
|
| 349 |
+
if (self.prefix or self.exec_prefix or self.home) and (
|
| 350 |
+
self.install_base or self.install_platbase
|
| 351 |
+
):
|
| 352 |
+
raise DistutilsOptionError(
|
| 353 |
+
"must supply either prefix/exec-prefix/home or "
|
| 354 |
+
+ "install-base/install-platbase -- not both"
|
| 355 |
+
)
|
| 356 |
+
|
| 357 |
+
if self.home and (self.prefix or self.exec_prefix):
|
| 358 |
+
raise DistutilsOptionError(
|
| 359 |
+
"must supply either home or prefix/exec-prefix -- not both"
|
| 360 |
+
)
|
| 361 |
+
|
| 362 |
+
if self.user and (
|
| 363 |
+
self.prefix
|
| 364 |
+
or self.exec_prefix
|
| 365 |
+
or self.home
|
| 366 |
+
or self.install_base
|
| 367 |
+
or self.install_platbase
|
| 368 |
+
):
|
| 369 |
+
raise DistutilsOptionError(
|
| 370 |
+
"can't combine user with prefix, "
|
| 371 |
+
"exec_prefix/home, or install_(plat)base"
|
| 372 |
+
)
|
| 373 |
+
|
| 374 |
+
# Next, stuff that's wrong (or dubious) only on certain platforms.
|
| 375 |
+
if os.name != "posix":
|
| 376 |
+
if self.exec_prefix:
|
| 377 |
+
self.warn("exec-prefix option ignored on this platform")
|
| 378 |
+
self.exec_prefix = None
|
| 379 |
+
|
| 380 |
+
# Now the interesting logic -- so interesting that we farm it out
|
| 381 |
+
# to other methods. The goal of these methods is to set the final
|
| 382 |
+
# values for the install_{lib,scripts,data,...} options, using as
|
| 383 |
+
# input a heady brew of prefix, exec_prefix, home, install_base,
|
| 384 |
+
# install_platbase, user-supplied versions of
|
| 385 |
+
# install_{purelib,platlib,lib,scripts,data,...}, and the
|
| 386 |
+
# install schemes. Phew!
|
| 387 |
+
|
| 388 |
+
self.dump_dirs("pre-finalize_{unix,other}")
|
| 389 |
+
|
| 390 |
+
if os.name == 'posix':
|
| 391 |
+
self.finalize_unix()
|
| 392 |
+
else:
|
| 393 |
+
self.finalize_other()
|
| 394 |
+
|
| 395 |
+
self.dump_dirs("post-finalize_{unix,other}()")
|
| 396 |
+
|
| 397 |
+
# Expand configuration variables, tilde, etc. in self.install_base
|
| 398 |
+
# and self.install_platbase -- that way, we can use $base or
|
| 399 |
+
# $platbase in the other installation directories and not worry
|
| 400 |
+
# about needing recursive variable expansion (shudder).
|
| 401 |
+
|
| 402 |
+
py_version = sys.version.split()[0]
|
| 403 |
+
(prefix, exec_prefix) = get_config_vars('prefix', 'exec_prefix')
|
| 404 |
+
try:
|
| 405 |
+
abiflags = sys.abiflags
|
| 406 |
+
except AttributeError:
|
| 407 |
+
# sys.abiflags may not be defined on all platforms.
|
| 408 |
+
abiflags = ''
|
| 409 |
+
local_vars = {
|
| 410 |
+
'dist_name': self.distribution.get_name(),
|
| 411 |
+
'dist_version': self.distribution.get_version(),
|
| 412 |
+
'dist_fullname': self.distribution.get_fullname(),
|
| 413 |
+
'py_version': py_version,
|
| 414 |
+
'py_version_short': '%d.%d' % sys.version_info[:2],
|
| 415 |
+
'py_version_nodot': '%d%d' % sys.version_info[:2],
|
| 416 |
+
'sys_prefix': prefix,
|
| 417 |
+
'prefix': prefix,
|
| 418 |
+
'sys_exec_prefix': exec_prefix,
|
| 419 |
+
'exec_prefix': exec_prefix,
|
| 420 |
+
'abiflags': abiflags,
|
| 421 |
+
'platlibdir': getattr(sys, 'platlibdir', 'lib'),
|
| 422 |
+
'implementation_lower': _get_implementation().lower(),
|
| 423 |
+
'implementation': _get_implementation(),
|
| 424 |
+
}
|
| 425 |
+
|
| 426 |
+
# vars for compatibility on older Pythons
|
| 427 |
+
compat_vars = dict(
|
| 428 |
+
# Python 3.9 and earlier
|
| 429 |
+
py_version_nodot_plat=getattr(sys, 'winver', '').replace('.', ''),
|
| 430 |
+
)
|
| 431 |
+
|
| 432 |
+
if HAS_USER_SITE:
|
| 433 |
+
local_vars['userbase'] = self.install_userbase
|
| 434 |
+
local_vars['usersite'] = self.install_usersite
|
| 435 |
+
|
| 436 |
+
self.config_vars = _collections.DictStack(
|
| 437 |
+
[fw.vars(), compat_vars, sysconfig.get_config_vars(), local_vars]
|
| 438 |
+
)
|
| 439 |
+
|
| 440 |
+
self.expand_basedirs()
|
| 441 |
+
|
| 442 |
+
self.dump_dirs("post-expand_basedirs()")
|
| 443 |
+
|
| 444 |
+
# Now define config vars for the base directories so we can expand
|
| 445 |
+
# everything else.
|
| 446 |
+
local_vars['base'] = self.install_base
|
| 447 |
+
local_vars['platbase'] = self.install_platbase
|
| 448 |
+
|
| 449 |
+
if DEBUG:
|
| 450 |
+
from pprint import pprint
|
| 451 |
+
|
| 452 |
+
print("config vars:")
|
| 453 |
+
pprint(dict(self.config_vars))
|
| 454 |
+
|
| 455 |
+
# Expand "~" and configuration variables in the installation
|
| 456 |
+
# directories.
|
| 457 |
+
self.expand_dirs()
|
| 458 |
+
|
| 459 |
+
self.dump_dirs("post-expand_dirs()")
|
| 460 |
+
|
| 461 |
+
# Create directories in the home dir:
|
| 462 |
+
if self.user:
|
| 463 |
+
self.create_home_path()
|
| 464 |
+
|
| 465 |
+
# Pick the actual directory to install all modules to: either
|
| 466 |
+
# install_purelib or install_platlib, depending on whether this
|
| 467 |
+
# module distribution is pure or not. Of course, if the user
|
| 468 |
+
# already specified install_lib, use their selection.
|
| 469 |
+
if self.install_lib is None:
|
| 470 |
+
if self.distribution.has_ext_modules(): # has extensions: non-pure
|
| 471 |
+
self.install_lib = self.install_platlib
|
| 472 |
+
else:
|
| 473 |
+
self.install_lib = self.install_purelib
|
| 474 |
+
|
| 475 |
+
# Convert directories from Unix /-separated syntax to the local
|
| 476 |
+
# convention.
|
| 477 |
+
self.convert_paths(
|
| 478 |
+
'lib',
|
| 479 |
+
'purelib',
|
| 480 |
+
'platlib',
|
| 481 |
+
'scripts',
|
| 482 |
+
'data',
|
| 483 |
+
'headers',
|
| 484 |
+
'userbase',
|
| 485 |
+
'usersite',
|
| 486 |
+
)
|
| 487 |
+
|
| 488 |
+
# Deprecated
|
| 489 |
+
# Well, we're not actually fully completely finalized yet: we still
|
| 490 |
+
# have to deal with 'extra_path', which is the hack for allowing
|
| 491 |
+
# non-packagized module distributions (hello, Numerical Python!) to
|
| 492 |
+
# get their own directories.
|
| 493 |
+
self.handle_extra_path()
|
| 494 |
+
self.install_libbase = self.install_lib # needed for .pth file
|
| 495 |
+
self.install_lib = os.path.join(self.install_lib, self.extra_dirs)
|
| 496 |
+
|
| 497 |
+
# If a new root directory was supplied, make all the installation
|
| 498 |
+
# dirs relative to it.
|
| 499 |
+
if self.root is not None:
|
| 500 |
+
self.change_roots(
|
| 501 |
+
'libbase', 'lib', 'purelib', 'platlib', 'scripts', 'data', 'headers'
|
| 502 |
+
)
|
| 503 |
+
|
| 504 |
+
self.dump_dirs("after prepending root")
|
| 505 |
+
|
| 506 |
+
# Find out the build directories, ie. where to install from.
|
| 507 |
+
self.set_undefined_options(
|
| 508 |
+
'build', ('build_base', 'build_base'), ('build_lib', 'build_lib')
|
| 509 |
+
)
|
| 510 |
+
|
| 511 |
+
# Punt on doc directories for now -- after all, we're punting on
|
| 512 |
+
# documentation completely!
|
| 513 |
+
|
| 514 |
+
def dump_dirs(self, msg):
|
| 515 |
+
"""Dumps the list of user options."""
|
| 516 |
+
if not DEBUG:
|
| 517 |
+
return
|
| 518 |
+
from distutils.fancy_getopt import longopt_xlate
|
| 519 |
+
|
| 520 |
+
log.debug(msg + ":")
|
| 521 |
+
for opt in self.user_options:
|
| 522 |
+
opt_name = opt[0]
|
| 523 |
+
if opt_name[-1] == "=":
|
| 524 |
+
opt_name = opt_name[0:-1]
|
| 525 |
+
if opt_name in self.negative_opt:
|
| 526 |
+
opt_name = self.negative_opt[opt_name]
|
| 527 |
+
opt_name = opt_name.translate(longopt_xlate)
|
| 528 |
+
val = not getattr(self, opt_name)
|
| 529 |
+
else:
|
| 530 |
+
opt_name = opt_name.translate(longopt_xlate)
|
| 531 |
+
val = getattr(self, opt_name)
|
| 532 |
+
log.debug(" %s: %s", opt_name, val)
|
| 533 |
+
|
| 534 |
+
def finalize_unix(self):
|
| 535 |
+
"""Finalizes options for posix platforms."""
|
| 536 |
+
if self.install_base is not None or self.install_platbase is not None:
|
| 537 |
+
incomplete_scheme = (
|
| 538 |
+
(
|
| 539 |
+
self.install_lib is None
|
| 540 |
+
and self.install_purelib is None
|
| 541 |
+
and self.install_platlib is None
|
| 542 |
+
)
|
| 543 |
+
or self.install_headers is None
|
| 544 |
+
or self.install_scripts is None
|
| 545 |
+
or self.install_data is None
|
| 546 |
+
)
|
| 547 |
+
if incomplete_scheme:
|
| 548 |
+
raise DistutilsOptionError(
|
| 549 |
+
"install-base or install-platbase supplied, but "
|
| 550 |
+
"installation scheme is incomplete"
|
| 551 |
+
)
|
| 552 |
+
return
|
| 553 |
+
|
| 554 |
+
if self.user:
|
| 555 |
+
if self.install_userbase is None:
|
| 556 |
+
raise DistutilsPlatformError("User base directory is not specified")
|
| 557 |
+
self.install_base = self.install_platbase = self.install_userbase
|
| 558 |
+
self.select_scheme("posix_user")
|
| 559 |
+
elif self.home is not None:
|
| 560 |
+
self.install_base = self.install_platbase = self.home
|
| 561 |
+
self.select_scheme("posix_home")
|
| 562 |
+
else:
|
| 563 |
+
if self.prefix is None:
|
| 564 |
+
if self.exec_prefix is not None:
|
| 565 |
+
raise DistutilsOptionError(
|
| 566 |
+
"must not supply exec-prefix without prefix"
|
| 567 |
+
)
|
| 568 |
+
|
| 569 |
+
# Allow Fedora to add components to the prefix
|
| 570 |
+
_prefix_addition = getattr(sysconfig, '_prefix_addition', "")
|
| 571 |
+
|
| 572 |
+
self.prefix = os.path.normpath(sys.prefix) + _prefix_addition
|
| 573 |
+
self.exec_prefix = os.path.normpath(sys.exec_prefix) + _prefix_addition
|
| 574 |
+
|
| 575 |
+
else:
|
| 576 |
+
if self.exec_prefix is None:
|
| 577 |
+
self.exec_prefix = self.prefix
|
| 578 |
+
|
| 579 |
+
self.install_base = self.prefix
|
| 580 |
+
self.install_platbase = self.exec_prefix
|
| 581 |
+
self.select_scheme("posix_prefix")
|
| 582 |
+
|
| 583 |
+
def finalize_other(self):
|
| 584 |
+
"""Finalizes options for non-posix platforms"""
|
| 585 |
+
if self.user:
|
| 586 |
+
if self.install_userbase is None:
|
| 587 |
+
raise DistutilsPlatformError("User base directory is not specified")
|
| 588 |
+
self.install_base = self.install_platbase = self.install_userbase
|
| 589 |
+
self.select_scheme(os.name + "_user")
|
| 590 |
+
elif self.home is not None:
|
| 591 |
+
self.install_base = self.install_platbase = self.home
|
| 592 |
+
self.select_scheme("posix_home")
|
| 593 |
+
else:
|
| 594 |
+
if self.prefix is None:
|
| 595 |
+
self.prefix = os.path.normpath(sys.prefix)
|
| 596 |
+
|
| 597 |
+
self.install_base = self.install_platbase = self.prefix
|
| 598 |
+
try:
|
| 599 |
+
self.select_scheme(os.name)
|
| 600 |
+
except KeyError:
|
| 601 |
+
raise DistutilsPlatformError(
|
| 602 |
+
"I don't know how to install stuff on '%s'" % os.name
|
| 603 |
+
)
|
| 604 |
+
|
| 605 |
+
def select_scheme(self, name):
|
| 606 |
+
_select_scheme(self, name)
|
| 607 |
+
|
| 608 |
+
def _expand_attrs(self, attrs):
|
| 609 |
+
for attr in attrs:
|
| 610 |
+
val = getattr(self, attr)
|
| 611 |
+
if val is not None:
|
| 612 |
+
if os.name == 'posix' or os.name == 'nt':
|
| 613 |
+
val = os.path.expanduser(val)
|
| 614 |
+
val = subst_vars(val, self.config_vars)
|
| 615 |
+
setattr(self, attr, val)
|
| 616 |
+
|
| 617 |
+
def expand_basedirs(self):
|
| 618 |
+
"""Calls `os.path.expanduser` on install_base, install_platbase and
|
| 619 |
+
root."""
|
| 620 |
+
self._expand_attrs(['install_base', 'install_platbase', 'root'])
|
| 621 |
+
|
| 622 |
+
def expand_dirs(self):
|
| 623 |
+
"""Calls `os.path.expanduser` on install dirs."""
|
| 624 |
+
self._expand_attrs(
|
| 625 |
+
[
|
| 626 |
+
'install_purelib',
|
| 627 |
+
'install_platlib',
|
| 628 |
+
'install_lib',
|
| 629 |
+
'install_headers',
|
| 630 |
+
'install_scripts',
|
| 631 |
+
'install_data',
|
| 632 |
+
]
|
| 633 |
+
)
|
| 634 |
+
|
| 635 |
+
def convert_paths(self, *names):
|
| 636 |
+
"""Call `convert_path` over `names`."""
|
| 637 |
+
for name in names:
|
| 638 |
+
attr = "install_" + name
|
| 639 |
+
setattr(self, attr, convert_path(getattr(self, attr)))
|
| 640 |
+
|
| 641 |
+
def handle_extra_path(self):
|
| 642 |
+
"""Set `path_file` and `extra_dirs` using `extra_path`."""
|
| 643 |
+
if self.extra_path is None:
|
| 644 |
+
self.extra_path = self.distribution.extra_path
|
| 645 |
+
|
| 646 |
+
if self.extra_path is not None:
|
| 647 |
+
log.warn(
|
| 648 |
+
"Distribution option extra_path is deprecated. "
|
| 649 |
+
"See issue27919 for details."
|
| 650 |
+
)
|
| 651 |
+
if isinstance(self.extra_path, str):
|
| 652 |
+
self.extra_path = self.extra_path.split(',')
|
| 653 |
+
|
| 654 |
+
if len(self.extra_path) == 1:
|
| 655 |
+
path_file = extra_dirs = self.extra_path[0]
|
| 656 |
+
elif len(self.extra_path) == 2:
|
| 657 |
+
path_file, extra_dirs = self.extra_path
|
| 658 |
+
else:
|
| 659 |
+
raise DistutilsOptionError(
|
| 660 |
+
"'extra_path' option must be a list, tuple, or "
|
| 661 |
+
"comma-separated string with 1 or 2 elements"
|
| 662 |
+
)
|
| 663 |
+
|
| 664 |
+
# convert to local form in case Unix notation used (as it
|
| 665 |
+
# should be in setup scripts)
|
| 666 |
+
extra_dirs = convert_path(extra_dirs)
|
| 667 |
+
else:
|
| 668 |
+
path_file = None
|
| 669 |
+
extra_dirs = ''
|
| 670 |
+
|
| 671 |
+
# XXX should we warn if path_file and not extra_dirs? (in which
|
| 672 |
+
# case the path file would be harmless but pointless)
|
| 673 |
+
self.path_file = path_file
|
| 674 |
+
self.extra_dirs = extra_dirs
|
| 675 |
+
|
| 676 |
+
def change_roots(self, *names):
|
| 677 |
+
"""Change the install directories pointed by name using root."""
|
| 678 |
+
for name in names:
|
| 679 |
+
attr = "install_" + name
|
| 680 |
+
setattr(self, attr, change_root(self.root, getattr(self, attr)))
|
| 681 |
+
|
| 682 |
+
def create_home_path(self):
|
| 683 |
+
"""Create directories under ~."""
|
| 684 |
+
if not self.user:
|
| 685 |
+
return
|
| 686 |
+
home = convert_path(os.path.expanduser("~"))
|
| 687 |
+
for name, path in self.config_vars.items():
|
| 688 |
+
if str(path).startswith(home) and not os.path.isdir(path):
|
| 689 |
+
self.debug_print("os.makedirs('%s', 0o700)" % path)
|
| 690 |
+
os.makedirs(path, 0o700)
|
| 691 |
+
|
| 692 |
+
# -- Command execution methods -------------------------------------
|
| 693 |
+
|
| 694 |
+
def run(self):
|
| 695 |
+
"""Runs the command."""
|
| 696 |
+
# Obviously have to build before we can install
|
| 697 |
+
if not self.skip_build:
|
| 698 |
+
self.run_command('build')
|
| 699 |
+
# If we built for any other platform, we can't install.
|
| 700 |
+
build_plat = self.distribution.get_command_obj('build').plat_name
|
| 701 |
+
# check warn_dir - it is a clue that the 'install' is happening
|
| 702 |
+
# internally, and not to sys.path, so we don't check the platform
|
| 703 |
+
# matches what we are running.
|
| 704 |
+
if self.warn_dir and build_plat != get_platform():
|
| 705 |
+
raise DistutilsPlatformError("Can't install when " "cross-compiling")
|
| 706 |
+
|
| 707 |
+
# Run all sub-commands (at least those that need to be run)
|
| 708 |
+
for cmd_name in self.get_sub_commands():
|
| 709 |
+
self.run_command(cmd_name)
|
| 710 |
+
|
| 711 |
+
if self.path_file:
|
| 712 |
+
self.create_path_file()
|
| 713 |
+
|
| 714 |
+
# write list of installed files, if requested.
|
| 715 |
+
if self.record:
|
| 716 |
+
outputs = self.get_outputs()
|
| 717 |
+
if self.root: # strip any package prefix
|
| 718 |
+
root_len = len(self.root)
|
| 719 |
+
for counter in range(len(outputs)):
|
| 720 |
+
outputs[counter] = outputs[counter][root_len:]
|
| 721 |
+
self.execute(
|
| 722 |
+
write_file,
|
| 723 |
+
(self.record, outputs),
|
| 724 |
+
"writing list of installed files to '%s'" % self.record,
|
| 725 |
+
)
|
| 726 |
+
|
| 727 |
+
sys_path = map(os.path.normpath, sys.path)
|
| 728 |
+
sys_path = map(os.path.normcase, sys_path)
|
| 729 |
+
install_lib = os.path.normcase(os.path.normpath(self.install_lib))
|
| 730 |
+
if (
|
| 731 |
+
self.warn_dir
|
| 732 |
+
and not (self.path_file and self.install_path_file)
|
| 733 |
+
and install_lib not in sys_path
|
| 734 |
+
):
|
| 735 |
+
log.debug(
|
| 736 |
+
(
|
| 737 |
+
"modules installed to '%s', which is not in "
|
| 738 |
+
"Python's module search path (sys.path) -- "
|
| 739 |
+
"you'll have to change the search path yourself"
|
| 740 |
+
),
|
| 741 |
+
self.install_lib,
|
| 742 |
+
)
|
| 743 |
+
|
| 744 |
+
def create_path_file(self):
|
| 745 |
+
"""Creates the .pth file"""
|
| 746 |
+
filename = os.path.join(self.install_libbase, self.path_file + ".pth")
|
| 747 |
+
if self.install_path_file:
|
| 748 |
+
self.execute(
|
| 749 |
+
write_file, (filename, [self.extra_dirs]), "creating %s" % filename
|
| 750 |
+
)
|
| 751 |
+
else:
|
| 752 |
+
self.warn("path file '%s' not created" % filename)
|
| 753 |
+
|
| 754 |
+
# -- Reporting methods ---------------------------------------------
|
| 755 |
+
|
| 756 |
+
def get_outputs(self):
|
| 757 |
+
"""Assembles the outputs of all the sub-commands."""
|
| 758 |
+
outputs = []
|
| 759 |
+
for cmd_name in self.get_sub_commands():
|
| 760 |
+
cmd = self.get_finalized_command(cmd_name)
|
| 761 |
+
# Add the contents of cmd.get_outputs(), ensuring
|
| 762 |
+
# that outputs doesn't contain duplicate entries
|
| 763 |
+
for filename in cmd.get_outputs():
|
| 764 |
+
if filename not in outputs:
|
| 765 |
+
outputs.append(filename)
|
| 766 |
+
|
| 767 |
+
if self.path_file and self.install_path_file:
|
| 768 |
+
outputs.append(os.path.join(self.install_libbase, self.path_file + ".pth"))
|
| 769 |
+
|
| 770 |
+
return outputs
|
| 771 |
+
|
| 772 |
+
def get_inputs(self):
|
| 773 |
+
"""Returns the inputs of all the sub-commands"""
|
| 774 |
+
# XXX gee, this looks familiar ;-(
|
| 775 |
+
inputs = []
|
| 776 |
+
for cmd_name in self.get_sub_commands():
|
| 777 |
+
cmd = self.get_finalized_command(cmd_name)
|
| 778 |
+
inputs.extend(cmd.get_inputs())
|
| 779 |
+
|
| 780 |
+
return inputs
|
| 781 |
+
|
| 782 |
+
# -- Predicates for sub-command list -------------------------------
|
| 783 |
+
|
| 784 |
+
def has_lib(self):
|
| 785 |
+
"""Returns true if the current distribution has any Python
|
| 786 |
+
modules to install."""
|
| 787 |
+
return (
|
| 788 |
+
self.distribution.has_pure_modules() or self.distribution.has_ext_modules()
|
| 789 |
+
)
|
| 790 |
+
|
| 791 |
+
def has_headers(self):
|
| 792 |
+
"""Returns true if the current distribution has any headers to
|
| 793 |
+
install."""
|
| 794 |
+
return self.distribution.has_headers()
|
| 795 |
+
|
| 796 |
+
def has_scripts(self):
|
| 797 |
+
"""Returns true if the current distribution has any scripts to.
|
| 798 |
+
install."""
|
| 799 |
+
return self.distribution.has_scripts()
|
| 800 |
+
|
| 801 |
+
def has_data(self):
|
| 802 |
+
"""Returns true if the current distribution has any data to.
|
| 803 |
+
install."""
|
| 804 |
+
return self.distribution.has_data_files()
|
| 805 |
+
|
| 806 |
+
# 'sub_commands': a list of commands this command might have to run to
|
| 807 |
+
# get its work done. See cmd.py for more info.
|
| 808 |
+
sub_commands = [
|
| 809 |
+
('install_lib', has_lib),
|
| 810 |
+
('install_headers', has_headers),
|
| 811 |
+
('install_scripts', has_scripts),
|
| 812 |
+
('install_data', has_data),
|
| 813 |
+
('install_egg_info', lambda self: True),
|
| 814 |
+
]
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/install_data.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""distutils.command.install_data
|
| 2 |
+
|
| 3 |
+
Implements the Distutils 'install_data' command, for installing
|
| 4 |
+
platform-independent data files."""
|
| 5 |
+
|
| 6 |
+
# contributed by Bastian Kleineidam
|
| 7 |
+
|
| 8 |
+
import os
|
| 9 |
+
from distutils.core import Command
|
| 10 |
+
from distutils.util import change_root, convert_path
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
class install_data(Command):
|
| 14 |
+
|
| 15 |
+
description = "install data files"
|
| 16 |
+
|
| 17 |
+
user_options = [
|
| 18 |
+
(
|
| 19 |
+
'install-dir=',
|
| 20 |
+
'd',
|
| 21 |
+
"base directory for installing data files "
|
| 22 |
+
"(default: installation base dir)",
|
| 23 |
+
),
|
| 24 |
+
('root=', None, "install everything relative to this alternate root directory"),
|
| 25 |
+
('force', 'f', "force installation (overwrite existing files)"),
|
| 26 |
+
]
|
| 27 |
+
|
| 28 |
+
boolean_options = ['force']
|
| 29 |
+
|
| 30 |
+
def initialize_options(self):
|
| 31 |
+
self.install_dir = None
|
| 32 |
+
self.outfiles = []
|
| 33 |
+
self.root = None
|
| 34 |
+
self.force = 0
|
| 35 |
+
self.data_files = self.distribution.data_files
|
| 36 |
+
self.warn_dir = 1
|
| 37 |
+
|
| 38 |
+
def finalize_options(self):
|
| 39 |
+
self.set_undefined_options(
|
| 40 |
+
'install',
|
| 41 |
+
('install_data', 'install_dir'),
|
| 42 |
+
('root', 'root'),
|
| 43 |
+
('force', 'force'),
|
| 44 |
+
)
|
| 45 |
+
|
| 46 |
+
def run(self):
|
| 47 |
+
self.mkpath(self.install_dir)
|
| 48 |
+
for f in self.data_files:
|
| 49 |
+
if isinstance(f, str):
|
| 50 |
+
# it's a simple file, so copy it
|
| 51 |
+
f = convert_path(f)
|
| 52 |
+
if self.warn_dir:
|
| 53 |
+
self.warn(
|
| 54 |
+
"setup script did not provide a directory for "
|
| 55 |
+
"'%s' -- installing right in '%s'" % (f, self.install_dir)
|
| 56 |
+
)
|
| 57 |
+
(out, _) = self.copy_file(f, self.install_dir)
|
| 58 |
+
self.outfiles.append(out)
|
| 59 |
+
else:
|
| 60 |
+
# it's a tuple with path to install to and a list of files
|
| 61 |
+
dir = convert_path(f[0])
|
| 62 |
+
if not os.path.isabs(dir):
|
| 63 |
+
dir = os.path.join(self.install_dir, dir)
|
| 64 |
+
elif self.root:
|
| 65 |
+
dir = change_root(self.root, dir)
|
| 66 |
+
self.mkpath(dir)
|
| 67 |
+
|
| 68 |
+
if f[1] == []:
|
| 69 |
+
# If there are no files listed, the user must be
|
| 70 |
+
# trying to create an empty directory, so add the
|
| 71 |
+
# directory to the list of output files.
|
| 72 |
+
self.outfiles.append(dir)
|
| 73 |
+
else:
|
| 74 |
+
# Copy files, adding them to the list of output files.
|
| 75 |
+
for data in f[1]:
|
| 76 |
+
data = convert_path(data)
|
| 77 |
+
(out, _) = self.copy_file(data, dir)
|
| 78 |
+
self.outfiles.append(out)
|
| 79 |
+
|
| 80 |
+
def get_inputs(self):
|
| 81 |
+
return self.data_files or []
|
| 82 |
+
|
| 83 |
+
def get_outputs(self):
|
| 84 |
+
return self.outfiles
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/install_egg_info.py
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
distutils.command.install_egg_info
|
| 3 |
+
|
| 4 |
+
Implements the Distutils 'install_egg_info' command, for installing
|
| 5 |
+
a package's PKG-INFO metadata.
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
import os
|
| 9 |
+
import sys
|
| 10 |
+
import re
|
| 11 |
+
|
| 12 |
+
from distutils.cmd import Command
|
| 13 |
+
from distutils import log, dir_util
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
class install_egg_info(Command):
|
| 17 |
+
"""Install an .egg-info file for the package"""
|
| 18 |
+
|
| 19 |
+
description = "Install package's PKG-INFO metadata as an .egg-info file"
|
| 20 |
+
user_options = [
|
| 21 |
+
('install-dir=', 'd', "directory to install to"),
|
| 22 |
+
]
|
| 23 |
+
|
| 24 |
+
def initialize_options(self):
|
| 25 |
+
self.install_dir = None
|
| 26 |
+
|
| 27 |
+
@property
|
| 28 |
+
def basename(self):
|
| 29 |
+
"""
|
| 30 |
+
Allow basename to be overridden by child class.
|
| 31 |
+
Ref pypa/distutils#2.
|
| 32 |
+
"""
|
| 33 |
+
return "%s-%s-py%d.%d.egg-info" % (
|
| 34 |
+
to_filename(safe_name(self.distribution.get_name())),
|
| 35 |
+
to_filename(safe_version(self.distribution.get_version())),
|
| 36 |
+
*sys.version_info[:2],
|
| 37 |
+
)
|
| 38 |
+
|
| 39 |
+
def finalize_options(self):
|
| 40 |
+
self.set_undefined_options('install_lib', ('install_dir', 'install_dir'))
|
| 41 |
+
self.target = os.path.join(self.install_dir, self.basename)
|
| 42 |
+
self.outputs = [self.target]
|
| 43 |
+
|
| 44 |
+
def run(self):
|
| 45 |
+
target = self.target
|
| 46 |
+
if os.path.isdir(target) and not os.path.islink(target):
|
| 47 |
+
dir_util.remove_tree(target, dry_run=self.dry_run)
|
| 48 |
+
elif os.path.exists(target):
|
| 49 |
+
self.execute(os.unlink, (self.target,), "Removing " + target)
|
| 50 |
+
elif not os.path.isdir(self.install_dir):
|
| 51 |
+
self.execute(
|
| 52 |
+
os.makedirs, (self.install_dir,), "Creating " + self.install_dir
|
| 53 |
+
)
|
| 54 |
+
log.info("Writing %s", target)
|
| 55 |
+
if not self.dry_run:
|
| 56 |
+
with open(target, 'w', encoding='UTF-8') as f:
|
| 57 |
+
self.distribution.metadata.write_pkg_file(f)
|
| 58 |
+
|
| 59 |
+
def get_outputs(self):
|
| 60 |
+
return self.outputs
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
# The following routines are taken from setuptools' pkg_resources module and
|
| 64 |
+
# can be replaced by importing them from pkg_resources once it is included
|
| 65 |
+
# in the stdlib.
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
def safe_name(name):
|
| 69 |
+
"""Convert an arbitrary string to a standard distribution name
|
| 70 |
+
|
| 71 |
+
Any runs of non-alphanumeric/. characters are replaced with a single '-'.
|
| 72 |
+
"""
|
| 73 |
+
return re.sub('[^A-Za-z0-9.]+', '-', name)
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def safe_version(version):
|
| 77 |
+
"""Convert an arbitrary string to a standard version string
|
| 78 |
+
|
| 79 |
+
Spaces become dots, and all other non-alphanumeric characters become
|
| 80 |
+
dashes, with runs of multiple dashes condensed to a single dash.
|
| 81 |
+
"""
|
| 82 |
+
version = version.replace(' ', '.')
|
| 83 |
+
return re.sub('[^A-Za-z0-9.]+', '-', version)
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
def to_filename(name):
|
| 87 |
+
"""Convert a project or version name to its filename-escaped form
|
| 88 |
+
|
| 89 |
+
Any '-' characters are currently replaced with '_'.
|
| 90 |
+
"""
|
| 91 |
+
return name.replace('-', '_')
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/install_headers.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""distutils.command.install_headers
|
| 2 |
+
|
| 3 |
+
Implements the Distutils 'install_headers' command, to install C/C++ header
|
| 4 |
+
files to the Python include directory."""
|
| 5 |
+
|
| 6 |
+
from distutils.core import Command
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
# XXX force is never used
|
| 10 |
+
class install_headers(Command):
|
| 11 |
+
|
| 12 |
+
description = "install C/C++ header files"
|
| 13 |
+
|
| 14 |
+
user_options = [
|
| 15 |
+
('install-dir=', 'd', "directory to install header files to"),
|
| 16 |
+
('force', 'f', "force installation (overwrite existing files)"),
|
| 17 |
+
]
|
| 18 |
+
|
| 19 |
+
boolean_options = ['force']
|
| 20 |
+
|
| 21 |
+
def initialize_options(self):
|
| 22 |
+
self.install_dir = None
|
| 23 |
+
self.force = 0
|
| 24 |
+
self.outfiles = []
|
| 25 |
+
|
| 26 |
+
def finalize_options(self):
|
| 27 |
+
self.set_undefined_options(
|
| 28 |
+
'install', ('install_headers', 'install_dir'), ('force', 'force')
|
| 29 |
+
)
|
| 30 |
+
|
| 31 |
+
def run(self):
|
| 32 |
+
headers = self.distribution.headers
|
| 33 |
+
if not headers:
|
| 34 |
+
return
|
| 35 |
+
|
| 36 |
+
self.mkpath(self.install_dir)
|
| 37 |
+
for header in headers:
|
| 38 |
+
(out, _) = self.copy_file(header, self.install_dir)
|
| 39 |
+
self.outfiles.append(out)
|
| 40 |
+
|
| 41 |
+
def get_inputs(self):
|
| 42 |
+
return self.distribution.headers or []
|
| 43 |
+
|
| 44 |
+
def get_outputs(self):
|
| 45 |
+
return self.outfiles
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/install_lib.py
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""distutils.command.install_lib
|
| 2 |
+
|
| 3 |
+
Implements the Distutils 'install_lib' command
|
| 4 |
+
(install all Python modules)."""
|
| 5 |
+
|
| 6 |
+
import os
|
| 7 |
+
import importlib.util
|
| 8 |
+
import sys
|
| 9 |
+
|
| 10 |
+
from distutils.core import Command
|
| 11 |
+
from distutils.errors import DistutilsOptionError
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
# Extension for Python source files.
|
| 15 |
+
PYTHON_SOURCE_EXTENSION = ".py"
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class install_lib(Command):
|
| 19 |
+
|
| 20 |
+
description = "install all Python modules (extensions and pure Python)"
|
| 21 |
+
|
| 22 |
+
# The byte-compilation options are a tad confusing. Here are the
|
| 23 |
+
# possible scenarios:
|
| 24 |
+
# 1) no compilation at all (--no-compile --no-optimize)
|
| 25 |
+
# 2) compile .pyc only (--compile --no-optimize; default)
|
| 26 |
+
# 3) compile .pyc and "opt-1" .pyc (--compile --optimize)
|
| 27 |
+
# 4) compile "opt-1" .pyc only (--no-compile --optimize)
|
| 28 |
+
# 5) compile .pyc and "opt-2" .pyc (--compile --optimize-more)
|
| 29 |
+
# 6) compile "opt-2" .pyc only (--no-compile --optimize-more)
|
| 30 |
+
#
|
| 31 |
+
# The UI for this is two options, 'compile' and 'optimize'.
|
| 32 |
+
# 'compile' is strictly boolean, and only decides whether to
|
| 33 |
+
# generate .pyc files. 'optimize' is three-way (0, 1, or 2), and
|
| 34 |
+
# decides both whether to generate .pyc files and what level of
|
| 35 |
+
# optimization to use.
|
| 36 |
+
|
| 37 |
+
user_options = [
|
| 38 |
+
('install-dir=', 'd', "directory to install to"),
|
| 39 |
+
('build-dir=', 'b', "build directory (where to install from)"),
|
| 40 |
+
('force', 'f', "force installation (overwrite existing files)"),
|
| 41 |
+
('compile', 'c', "compile .py to .pyc [default]"),
|
| 42 |
+
('no-compile', None, "don't compile .py files"),
|
| 43 |
+
(
|
| 44 |
+
'optimize=',
|
| 45 |
+
'O',
|
| 46 |
+
"also compile with optimization: -O1 for \"python -O\", "
|
| 47 |
+
"-O2 for \"python -OO\", and -O0 to disable [default: -O0]",
|
| 48 |
+
),
|
| 49 |
+
('skip-build', None, "skip the build steps"),
|
| 50 |
+
]
|
| 51 |
+
|
| 52 |
+
boolean_options = ['force', 'compile', 'skip-build']
|
| 53 |
+
negative_opt = {'no-compile': 'compile'}
|
| 54 |
+
|
| 55 |
+
def initialize_options(self):
|
| 56 |
+
# let the 'install' command dictate our installation directory
|
| 57 |
+
self.install_dir = None
|
| 58 |
+
self.build_dir = None
|
| 59 |
+
self.force = 0
|
| 60 |
+
self.compile = None
|
| 61 |
+
self.optimize = None
|
| 62 |
+
self.skip_build = None
|
| 63 |
+
|
| 64 |
+
def finalize_options(self):
|
| 65 |
+
# Get all the information we need to install pure Python modules
|
| 66 |
+
# from the umbrella 'install' command -- build (source) directory,
|
| 67 |
+
# install (target) directory, and whether to compile .py files.
|
| 68 |
+
self.set_undefined_options(
|
| 69 |
+
'install',
|
| 70 |
+
('build_lib', 'build_dir'),
|
| 71 |
+
('install_lib', 'install_dir'),
|
| 72 |
+
('force', 'force'),
|
| 73 |
+
('compile', 'compile'),
|
| 74 |
+
('optimize', 'optimize'),
|
| 75 |
+
('skip_build', 'skip_build'),
|
| 76 |
+
)
|
| 77 |
+
|
| 78 |
+
if self.compile is None:
|
| 79 |
+
self.compile = True
|
| 80 |
+
if self.optimize is None:
|
| 81 |
+
self.optimize = False
|
| 82 |
+
|
| 83 |
+
if not isinstance(self.optimize, int):
|
| 84 |
+
try:
|
| 85 |
+
self.optimize = int(self.optimize)
|
| 86 |
+
if self.optimize not in (0, 1, 2):
|
| 87 |
+
raise AssertionError
|
| 88 |
+
except (ValueError, AssertionError):
|
| 89 |
+
raise DistutilsOptionError("optimize must be 0, 1, or 2")
|
| 90 |
+
|
| 91 |
+
def run(self):
|
| 92 |
+
# Make sure we have built everything we need first
|
| 93 |
+
self.build()
|
| 94 |
+
|
| 95 |
+
# Install everything: simply dump the entire contents of the build
|
| 96 |
+
# directory to the installation directory (that's the beauty of
|
| 97 |
+
# having a build directory!)
|
| 98 |
+
outfiles = self.install()
|
| 99 |
+
|
| 100 |
+
# (Optionally) compile .py to .pyc
|
| 101 |
+
if outfiles is not None and self.distribution.has_pure_modules():
|
| 102 |
+
self.byte_compile(outfiles)
|
| 103 |
+
|
| 104 |
+
# -- Top-level worker functions ------------------------------------
|
| 105 |
+
# (called from 'run()')
|
| 106 |
+
|
| 107 |
+
def build(self):
|
| 108 |
+
if not self.skip_build:
|
| 109 |
+
if self.distribution.has_pure_modules():
|
| 110 |
+
self.run_command('build_py')
|
| 111 |
+
if self.distribution.has_ext_modules():
|
| 112 |
+
self.run_command('build_ext')
|
| 113 |
+
|
| 114 |
+
def install(self):
|
| 115 |
+
if os.path.isdir(self.build_dir):
|
| 116 |
+
outfiles = self.copy_tree(self.build_dir, self.install_dir)
|
| 117 |
+
else:
|
| 118 |
+
self.warn(
|
| 119 |
+
"'%s' does not exist -- no Python modules to install" % self.build_dir
|
| 120 |
+
)
|
| 121 |
+
return
|
| 122 |
+
return outfiles
|
| 123 |
+
|
| 124 |
+
def byte_compile(self, files):
|
| 125 |
+
if sys.dont_write_bytecode:
|
| 126 |
+
self.warn('byte-compiling is disabled, skipping.')
|
| 127 |
+
return
|
| 128 |
+
|
| 129 |
+
from distutils.util import byte_compile
|
| 130 |
+
|
| 131 |
+
# Get the "--root" directory supplied to the "install" command,
|
| 132 |
+
# and use it as a prefix to strip off the purported filename
|
| 133 |
+
# encoded in bytecode files. This is far from complete, but it
|
| 134 |
+
# should at least generate usable bytecode in RPM distributions.
|
| 135 |
+
install_root = self.get_finalized_command('install').root
|
| 136 |
+
|
| 137 |
+
if self.compile:
|
| 138 |
+
byte_compile(
|
| 139 |
+
files,
|
| 140 |
+
optimize=0,
|
| 141 |
+
force=self.force,
|
| 142 |
+
prefix=install_root,
|
| 143 |
+
dry_run=self.dry_run,
|
| 144 |
+
)
|
| 145 |
+
if self.optimize > 0:
|
| 146 |
+
byte_compile(
|
| 147 |
+
files,
|
| 148 |
+
optimize=self.optimize,
|
| 149 |
+
force=self.force,
|
| 150 |
+
prefix=install_root,
|
| 151 |
+
verbose=self.verbose,
|
| 152 |
+
dry_run=self.dry_run,
|
| 153 |
+
)
|
| 154 |
+
|
| 155 |
+
# -- Utility methods -----------------------------------------------
|
| 156 |
+
|
| 157 |
+
def _mutate_outputs(self, has_any, build_cmd, cmd_option, output_dir):
|
| 158 |
+
if not has_any:
|
| 159 |
+
return []
|
| 160 |
+
|
| 161 |
+
build_cmd = self.get_finalized_command(build_cmd)
|
| 162 |
+
build_files = build_cmd.get_outputs()
|
| 163 |
+
build_dir = getattr(build_cmd, cmd_option)
|
| 164 |
+
|
| 165 |
+
prefix_len = len(build_dir) + len(os.sep)
|
| 166 |
+
outputs = []
|
| 167 |
+
for file in build_files:
|
| 168 |
+
outputs.append(os.path.join(output_dir, file[prefix_len:]))
|
| 169 |
+
|
| 170 |
+
return outputs
|
| 171 |
+
|
| 172 |
+
def _bytecode_filenames(self, py_filenames):
|
| 173 |
+
bytecode_files = []
|
| 174 |
+
for py_file in py_filenames:
|
| 175 |
+
# Since build_py handles package data installation, the
|
| 176 |
+
# list of outputs can contain more than just .py files.
|
| 177 |
+
# Make sure we only report bytecode for the .py files.
|
| 178 |
+
ext = os.path.splitext(os.path.normcase(py_file))[1]
|
| 179 |
+
if ext != PYTHON_SOURCE_EXTENSION:
|
| 180 |
+
continue
|
| 181 |
+
if self.compile:
|
| 182 |
+
bytecode_files.append(
|
| 183 |
+
importlib.util.cache_from_source(py_file, optimization='')
|
| 184 |
+
)
|
| 185 |
+
if self.optimize > 0:
|
| 186 |
+
bytecode_files.append(
|
| 187 |
+
importlib.util.cache_from_source(
|
| 188 |
+
py_file, optimization=self.optimize
|
| 189 |
+
)
|
| 190 |
+
)
|
| 191 |
+
|
| 192 |
+
return bytecode_files
|
| 193 |
+
|
| 194 |
+
# -- External interface --------------------------------------------
|
| 195 |
+
# (called by outsiders)
|
| 196 |
+
|
| 197 |
+
def get_outputs(self):
|
| 198 |
+
"""Return the list of files that would be installed if this command
|
| 199 |
+
were actually run. Not affected by the "dry-run" flag or whether
|
| 200 |
+
modules have actually been built yet.
|
| 201 |
+
"""
|
| 202 |
+
pure_outputs = self._mutate_outputs(
|
| 203 |
+
self.distribution.has_pure_modules(),
|
| 204 |
+
'build_py',
|
| 205 |
+
'build_lib',
|
| 206 |
+
self.install_dir,
|
| 207 |
+
)
|
| 208 |
+
if self.compile:
|
| 209 |
+
bytecode_outputs = self._bytecode_filenames(pure_outputs)
|
| 210 |
+
else:
|
| 211 |
+
bytecode_outputs = []
|
| 212 |
+
|
| 213 |
+
ext_outputs = self._mutate_outputs(
|
| 214 |
+
self.distribution.has_ext_modules(),
|
| 215 |
+
'build_ext',
|
| 216 |
+
'build_lib',
|
| 217 |
+
self.install_dir,
|
| 218 |
+
)
|
| 219 |
+
|
| 220 |
+
return pure_outputs + bytecode_outputs + ext_outputs
|
| 221 |
+
|
| 222 |
+
def get_inputs(self):
|
| 223 |
+
"""Get the list of files that are input to this command, ie. the
|
| 224 |
+
files that get installed as they are named in the build tree.
|
| 225 |
+
The files in this list correspond one-to-one to the output
|
| 226 |
+
filenames returned by 'get_outputs()'.
|
| 227 |
+
"""
|
| 228 |
+
inputs = []
|
| 229 |
+
|
| 230 |
+
if self.distribution.has_pure_modules():
|
| 231 |
+
build_py = self.get_finalized_command('build_py')
|
| 232 |
+
inputs.extend(build_py.get_outputs())
|
| 233 |
+
|
| 234 |
+
if self.distribution.has_ext_modules():
|
| 235 |
+
build_ext = self.get_finalized_command('build_ext')
|
| 236 |
+
inputs.extend(build_ext.get_outputs())
|
| 237 |
+
|
| 238 |
+
return inputs
|
.venv/lib/python3.11/site-packages/setuptools/_distutils/command/install_scripts.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""distutils.command.install_scripts
|
| 2 |
+
|
| 3 |
+
Implements the Distutils 'install_scripts' command, for installing
|
| 4 |
+
Python scripts."""
|
| 5 |
+
|
| 6 |
+
# contributed by Bastian Kleineidam
|
| 7 |
+
|
| 8 |
+
import os
|
| 9 |
+
from distutils.core import Command
|
| 10 |
+
from distutils import log
|
| 11 |
+
from stat import ST_MODE
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
class install_scripts(Command):
|
| 15 |
+
|
| 16 |
+
description = "install scripts (Python or otherwise)"
|
| 17 |
+
|
| 18 |
+
user_options = [
|
| 19 |
+
('install-dir=', 'd', "directory to install scripts to"),
|
| 20 |
+
('build-dir=', 'b', "build directory (where to install from)"),
|
| 21 |
+
('force', 'f', "force installation (overwrite existing files)"),
|
| 22 |
+
('skip-build', None, "skip the build steps"),
|
| 23 |
+
]
|
| 24 |
+
|
| 25 |
+
boolean_options = ['force', 'skip-build']
|
| 26 |
+
|
| 27 |
+
def initialize_options(self):
|
| 28 |
+
self.install_dir = None
|
| 29 |
+
self.force = 0
|
| 30 |
+
self.build_dir = None
|
| 31 |
+
self.skip_build = None
|
| 32 |
+
|
| 33 |
+
def finalize_options(self):
|
| 34 |
+
self.set_undefined_options('build', ('build_scripts', 'build_dir'))
|
| 35 |
+
self.set_undefined_options(
|
| 36 |
+
'install',
|
| 37 |
+
('install_scripts', 'install_dir'),
|
| 38 |
+
('force', 'force'),
|
| 39 |
+
('skip_build', 'skip_build'),
|
| 40 |
+
)
|
| 41 |
+
|
| 42 |
+
def run(self):
|
| 43 |
+
if not self.skip_build:
|
| 44 |
+
self.run_command('build_scripts')
|
| 45 |
+
self.outfiles = self.copy_tree(self.build_dir, self.install_dir)
|
| 46 |
+
if os.name == 'posix':
|
| 47 |
+
# Set the executable bits (owner, group, and world) on
|
| 48 |
+
# all the scripts we just installed.
|
| 49 |
+
for file in self.get_outputs():
|
| 50 |
+
if self.dry_run:
|
| 51 |
+
log.info("changing mode of %s", file)
|
| 52 |
+
else:
|
| 53 |
+
mode = ((os.stat(file)[ST_MODE]) | 0o555) & 0o7777
|
| 54 |
+
log.info("changing mode of %s to %o", file, mode)
|
| 55 |
+
os.chmod(file, mode)
|
| 56 |
+
|
| 57 |
+
def get_inputs(self):
|
| 58 |
+
return self.distribution.scripts or []
|
| 59 |
+
|
| 60 |
+
def get_outputs(self):
|
| 61 |
+
return self.outfiles or []
|