/usr/share/sagemath/bin/sage-location is in sagemath-common 7.4-9.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 | #!/usr/bin/env python
from __future__ import print_function
import os, sys, re
SAGE_ROOT = os.path.realpath(os.environ['SAGE_ROOT'])
SAGE_LOCAL = os.environ['SAGE_LOCAL']
location_file = os.path.join(SAGE_LOCAL, 'lib', 'sage-current-location.txt')
force_file = os.path.join(SAGE_LOCAL, 'lib', 'sage-force-relocate.txt')
flags_file = os.path.join(SAGE_LOCAL, 'lib', 'sage-flags.txt')
# The flags we care about recording in the local/lib/sage-flags.txt file.
# In SAGE_FAT_BINARY mode we only require that ['sse', 'sse2', '3d',
# 'mmx', 'cmov'] be available, and in particular, we don't require pni
# (Prescott New Instructions, including SSE3) or ssse3.
SAGE_FAT_BINARY = os.environ.get('SAGE_FAT_BINARY',"")
if SAGE_FAT_BINARY == "yes":
FLAGS = ['sse', 'sse2', '3d', 'mmx', 'cmov']
else:
FLAGS = ['sse', 'sse2', 'ssse3', '3d', 'mmx', 'pni', 'cmov']
def write_location_file():
"""
Write the location file with the current value of ``SAGE_ROOT``.
"""
O = open(location_file, 'w')
O.write(SAGE_ROOT)
O.close()
def read_location_file():
"""
If the location file exists, return the path contained in it.
Otherwise return ``None``.
"""
try:
f = open(location_file)
except IOError:
return None
path = f.read().strip()
f.close()
# Make the path absolute, even though this should not be needed.
return os.path.abspath(path)
def get_flags_info():
"""
Return a space-separated string that lists the flags indicating what's
supported by this CPU by reading ``/proc/cpuinfo``.
"""
try:
r = open('/proc/cpuinfo').read()
i = r.find('flags')
r = r[i:]
i = r.find(':')
r = r[i+1:]
i = r.find('\n')
r = r[:i]
# This line restricts the flags to just ones that start with sse, 3d or mmx.
# We do not want *all* flags, since some like "up" are not relevant (up = uniprocessor).
return ' '.join(set(x for x in r.split() if x in FLAGS))
except IOError:
# On a system without /proc/cpuinfo, so don't bother. In
# particular, for non-Linux systems I have no clue how to get
# the processor flags, and we so far have never ever had any
# problem with processor flags on such machines. So we don't
# bother.
return ''
def check_processor_flags():
"""
Make sure all processor flags from the build machine are on this machine.
If the ``sage-flags.txt`` file is missing, create it.
"""
# Write the flags file if it isn't there:
if not os.path.isfile(flags_file):
f = open(flags_file, 'w')
f.write(get_flags_info())
f.close()
return
# We check that the processor flags of the original build are a
# subset of the new machine. If not, we print a massive warning.
X = set(open(flags_file).read().split()).intersection(FLAGS)
X.difference_update(get_flags_info().split())
if X:
print("")
print("*"*70)
print("WARNING! This Sage install was built on a machine that supports")
print("instructions that are not available on this computer. Sage will")
print("likely fail with ILLEGAL INSTRUCTION errors! The following processor")
print("flags were on the build machine but are not on this computer:\n")
print(*X)
print("")
print("Email http://groups.google.com/group/sage-support for help.")
print("To remove this warning and make Sage start, just delete")
print(" %s"%flags_file)
print("*"*70)
sys.exit(1)
def update_library_files():
"""
Manually change the paths in all ``.la`` libtool archives.
"""
for libdir in ["lib", "lib32", "lib64"]:
LIB = os.path.join(SAGE_LOCAL, libdir)
if not os.path.isdir(LIB):
continue
# The .la files hardcode path info, so we manually fix the path info:
for F in os.listdir(LIB):
if os.path.splitext(F)[-1] == ".la":
G = open(os.path.join(LIB,F)).read()
i = G.find('libdir=')
j = i+8 + G[i+8:].find("'")
z = G[i+8:j].strip().strip("'")
i = z.rfind('local/')
if i != -1:
z = z[:i]
H = G.replace(z, SAGE_ROOT + '/')
open(os.path.join(LIB, F),'w').write(H)
def update_pkgconfig_files():
"""
Call ``update_pkgconfig_file()`` for every ``pkg-config`` file in
``$SAGE_LOCAL/lib``.
"""
PKG = os.path.join(SAGE_LOCAL, 'lib', 'pkgconfig')
for name in os.listdir(PKG):
filename = os.path.join(PKG, name)
if os.path.splitext(filename)[1] == ".pc":
update_pkgconfig_file(filename)
def update_pkgconfig_file(filename):
"""
Edit the ``pkg-config`` file ``filename`` such that it contains
a definition of a ``SAGE_ROOT`` variable, and replace occurrences of
its current and previous value by references ``${SAGE_ROOT}`` to
that variable.
"""
# Pattern matching a *definition* of SAGE_ROOT:
def_pat = re.compile(r"^SAGE_ROOT=.*\n", re.MULTILINE)
with open(filename, 'r+') as f:
config = f.read()
# Delete old definition(s) of SAGE_ROOT
config = def_pat.sub("", config)
# Replace all occurrences of the current value of SAGE_ROOT
# by references to the pkg-config variable SAGE_ROOT.
# This is needed for the initial install of Sage.
config = config.replace(SAGE_ROOT, "${SAGE_ROOT}")
if OLD_SAGE_ROOT is not None:
# Also replace old values of SAGE_ROOT, this is needed for
# manually installed packages after the initial
# sage-location run.
config = config.replace(OLD_SAGE_ROOT, "${SAGE_ROOT}")
# New definition of SAGE_ROOT:
definition = "SAGE_ROOT=%s\n" % SAGE_ROOT
# Re-write the file
f.seek(0)
f.truncate()
f.write(definition + config)
def make_scripts_relative():
"""
For all interpreter scripts in ``$SAGE_LOCAL/bin`` running python,
replace first line by "#!/usr/bin/env python"
"""
os.chdir(os.path.join(SAGE_LOCAL, 'bin'))
for filename in os.listdir('.'):
# Only ordinary files
if not os.path.isfile(filename):
continue
try:
with open(filename, 'rb+') as f:
# Read at most 512 bytes, this should be more than enough.
# If we don't find '\n' in the first 512 bytes, we most likely
# have a binary file.
L = f.readline(512)
# Make sure we read a complete line
if len(L) < 1 or L[-1] != '\n':
continue
# Is the first line "#!.../python"?
if L.startswith("#!") and L.find("/python") >= 0:
# Read the rest of the file
script = f.read()
# Write the file again with a proper interpreter line
f.seek(0)
f.truncate()
f.write("#!/usr/bin/env python\n" + script)
except IOError:
pass
def write_config_files():
"""
Write various configuration files which contain the ``SAGE_ROOT``
path.
"""
# Currently only one file (for the experimental package qepcad):
# $SAGE_LOCAL/default.qepcadrc
f = open(os.path.join(SAGE_LOCAL, 'default.qepcadrc'), 'w')
text = \
"""# THIS FILE IS AUTOMATICALLY GENERATED by sage-location -- DO NOT EDIT
#####################################################
# QEPCAD rc file.
# This file allows for some customization of QEPCAD.
# Right now, the ability to give a path to Singular,
# so that it gets used for some computer algebra
# computations is the only feature.
#####################################################
SINGULAR %s
""" % os.path.join(SAGE_LOCAL, 'bin')
f.write(text)
f.close()
def remove_files(path, remove_extensions):
"""
Walk the tree starting at ``path``, and remove all files with
extensions in ``remove_extensions``.
The extensions in ``remove_extensions`` should start with a period, i.e.,
e.g. use ``remove_files(path, ('.pyc', '.pyo'))``.
"""
for root, dirs, files in os.walk(path):
for file in files:
filename = os.path.join(root, file)
if os.path.splitext(filename)[1] in remove_extensions:
try:
os.unlink(filename)
except OSError as msg:
print(msg)
def sage_relocate():
"""
High-level function which calls various functions to handle
relocation. To be called either for the initial install or when
the Sage tree has moved.
These operations should all be idempotent: executing them more than
once should be equivalent to executing them once.
"""
check_processor_flags()
update_library_files()
update_pkgconfig_files()
make_scripts_relative()
write_config_files()
# Compiled python files need to be regenerated, so we remove them:
remove_files(os.path.join(SAGE_LOCAL, 'lib', 'python'),
remove_extensions=('.pyc', '.pyo'))
# Write the new location file as last thing in this script,
# such that it only gets written if there were no exceptions.
write_location_file()
RELOCATION_ERROR = """
ERROR: The Sage installation tree has moved
from {OLD_SAGE_ROOT}
to {SAGE_ROOT}
This is not supported, and Sage will not work. To install Sage from a
binary package:
1. Open the .tar.bz2 archive (or .dmg on OSX)
2. Move the SageMath folder/app to where you want it to be. You can
also rename the directory now.
3. Start sage for the first time. This will then automatically patch
paths in binaries.
After starting Sage for the first time you cannot change the
installation any more. To install Sage elsewhere, start over from the
binary package. Or recompile Sage from scratch in the new location
("make distclean && make")
"""
if __name__ == '__main__':
if SAGE_ROOT is None:
print('You must run this script from within a Sage shell')
sys.exit(1)
# Previous SAGE_ROOT, read from "sage-location.txt".
# OLD_SAGE_ROOT is None if this is a first-time install.
OLD_SAGE_ROOT = read_location_file()
# If the force file exists (test that by deleting it),
# then always run sage_locate().
try:
os.unlink(force_file)
force_relocate = True
except OSError:
force_relocate = False
if OLD_SAGE_ROOT != SAGE_ROOT or force_relocate:
if OLD_SAGE_ROOT is None:
print("This looks like the first time you are running Sage.")
elif OLD_SAGE_ROOT != SAGE_ROOT:
print(RELOCATION_ERROR.format(OLD_SAGE_ROOT=OLD_SAGE_ROOT, SAGE_ROOT=SAGE_ROOT))
sys.exit(1)
elif force_relocate:
print("Forcing sage-location, probably because a new package was installed.")
else:
print("The Sage installation tree has moved")
print("from %s" % OLD_SAGE_ROOT)
print(" to %s" % SAGE_ROOT)
assert(False)
print("Updating various hardcoded paths...")
print("(Please wait at most a few minutes.)")
print("DO NOT INTERRUPT THIS.")
sys.stdout.flush() # One never knows...
sage_relocate()
print("Done updating paths.")
|