Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sage
Path: blob/develop/pkgs/sage-conf_pypi/setup.py
4081 views
1
import os
2
import sys
3
import shutil
4
import sysconfig
5
import platform
6
import fnmatch
7
8
from setuptools import setup
9
from setuptools.dist import Distribution
10
from distutils.command.build_scripts import build_scripts as distutils_build_scripts
11
from setuptools.command.build_py import build_py as setuptools_build_py
12
from setuptools.command.editable_wheel import editable_wheel as setuptools_editable_wheel
13
from setuptools.errors import SetupError
14
15
16
# setuptools plugins considered harmful:
17
# If build isolation is not in use and setuptools_scm is installed,
18
# then its file_finders entry point is invoked, which we don't need.
19
# And with setuptools_scm 8, we get more trouble:
20
# LookupError: pyproject.toml does not contain a tool.setuptools_scm section
21
# LookupError: setuptools-scm was unable to detect version ...
22
# We just remove all handling of "setuptools.finalize_distribution_options" entry points.
23
Distribution._removed = staticmethod(lambda ep: True)
24
25
26
class build_py(setuptools_build_py):
27
28
def run(self):
29
HERE = os.path.dirname(__file__)
30
if self.editable_mode:
31
SAGE_ROOT = os.path.join(HERE, 'sage_root')
32
else:
33
SAGE_ROOT = self._create_writable_sage_root()
34
35
# For convenience, set up the homebrew env automatically. This is a no-op if homebrew is not present.
36
if os.environ.get('CONDA_PREFIX', ''):
37
SETENV = ':'
38
else:
39
SETENV = '. ./.homebrew-build-env 2> /dev/null'
40
41
SAGE_LOCAL = os.path.join(SAGE_ROOT, 'local')
42
43
if os.path.exists(os.path.join(SAGE_ROOT, 'config.status')):
44
print(f'Reusing configured SAGE_ROOT={SAGE_ROOT}')
45
else:
46
cmd = f"cd {SAGE_ROOT} && ({SETENV}; ./configure --prefix={SAGE_LOCAL} --with-python={sys.executable} --enable-build-as-root --enable-download-from-upstream-url --with-system-python3=force --with-sage-venv --disable-notebook --disable-sagelib --disable-sage_conf --disable-doc)"
47
print(f"Running {cmd}")
48
sys.stdout.flush()
49
if os.system(cmd) != 0:
50
print("configure failed; this may be caused by missing build prerequisites.")
51
sys.stdout.flush()
52
PREREQ_SPKG = "_prereq bzip2 xz libffi" # includes python3 SPKG_DEPCHECK packages
53
os.system(f'cd {SAGE_ROOT} && export SYSTEM=$(build/bin/sage-guess-package-system 2>/dev/null) && export PACKAGES="$(build/bin/sage-get-system-packages $SYSTEM {PREREQ_SPKG})" && [ -n "$PACKAGES" ] && echo "You can install the required build prerequisites using the following shell command" && echo "" && build/bin/sage-print-system-package-command $SYSTEM --verbose --sudo install $PACKAGES && echo ""')
54
raise SetupError("configure failed")
55
56
# Copy over files generated by the configure script
57
# (see configure.ac AC_CONFIG_FILES)
58
if self.editable_mode:
59
pass # same file
60
else:
61
shutil.copyfile(os.path.join(SAGE_ROOT, 'pkgs', 'sage-conf', '_sage_conf', '_conf.py'),
62
os.path.join(HERE, '_sage_conf', '_conf.py'))
63
shutil.copyfile(os.path.join(SAGE_ROOT, 'src', 'bin', 'sage-env-config'),
64
os.path.join(HERE, 'bin', 'sage-env-config'))
65
66
# Here we run "make build" -- which builds everything except for sagelib because we
67
# used configure --disable-sagelib
68
# Alternative:
69
# "make build-local" only builds the non-Python packages of the Sage distribution.
70
# It still makes an (empty) venv in SAGE_VENV, which is unused by default;
71
# but then a user could use "make build-venv" to build compatible wheels for all Python packages.
72
# TODO: A target to only build wheels of tricky packages
73
# (that use native libraries shared with other packages).
74
SETMAKE = 'if [ -z "$MAKE" ]; then export MAKE="make -j$(PATH=build/bin:$PATH build/bin/sage-build-num-threads | cut -d" " -f 2)"; fi'
75
TARGETS = 'build'
76
cmd = f'cd {SAGE_ROOT} && ({SETENV}; {SETMAKE} && $MAKE V=0 ${{SAGE_CONF_TARGETS-{TARGETS}}})'
77
print(f"Running {cmd}", flush=True)
78
if os.system(cmd) != 0:
79
raise SetupError(f"make ${{SAGE_CONF_TARGETS-{TARGETS}}} failed")
80
81
setuptools_build_py.run(self)
82
83
def _create_writable_sage_root(self):
84
HERE = os.path.dirname(__file__)
85
DOT_SAGE = os.environ.get('DOT_SAGE', os.path.join(os.environ.get('HOME'), '.sage'))
86
with open(os.path.join(HERE, 'VERSION.txt')) as f:
87
sage_version = f.read().strip()
88
# After #30534, SAGE_LOCAL no longer contains any Python. So we key the SAGE_ROOT only to Sage version
89
# and architecture.
90
system = platform.system()
91
machine = platform.machine()
92
arch_tag = f'{system}-{machine}'
93
# TODO: Should be user-configurable with config settings
94
SAGE_ROOT = os.path.join(DOT_SAGE, f'sage-{sage_version}-{arch_tag}')
95
96
def ignore(path, names):
97
# exclude all embedded src trees
98
if fnmatch.fnmatch(path, '*/build/pkgs/*'):
99
return ['src']
100
### ignore more stuff --- .tox etc.
101
return [name for name in names
102
if name in ('.tox', '.git', '__pycache__',
103
'prefix', 'local', 'venv', 'upstream',
104
'config.status', 'config.log', 'logs')]
105
106
if not os.path.exists(os.path.join(SAGE_ROOT, 'config.status')):
107
# config.status and other configure output has to be writable.
108
# So (until the Sage distribution supports VPATH builds - #21469), we have to make a copy of sage_root.
109
try:
110
shutil.copytree('sage_root', SAGE_ROOT,
111
ignore=ignore) # will fail if already exists
112
except Exception as e:
113
raise SetupError(f"the directory SAGE_ROOT={SAGE_ROOT} already exists but it is not configured ({e}). "
114
"Please either remove it and try again, or install in editable mode (pip install -e).")
115
116
return SAGE_ROOT
117
118
119
class build_scripts(distutils_build_scripts):
120
121
def run(self):
122
self.distribution.scripts.append(os.path.join('bin', 'sage-env-config'))
123
if not self.distribution.entry_points:
124
self.entry_points = self.distribution.entry_points = dict()
125
distutils_build_scripts.run(self)
126
127
128
class editable_wheel(setuptools_editable_wheel):
129
r"""
130
Customized so that exceptions raised by our build_py
131
do not lead to the "Customization incompatible with editable install" message
132
"""
133
_safely_run = setuptools_editable_wheel.run_command
134
135
136
setup(
137
cmdclass=dict(build_py=build_py,
138
build_scripts=build_scripts,
139
editable_wheel=editable_wheel)
140
)
141
142