passagemath-environment 10.4.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_environment-10.4.1.data/scripts/sage +1140 -0
- passagemath_environment-10.4.1.data/scripts/sage-env +667 -0
- passagemath_environment-10.4.1.data/scripts/sage-num-threads.py +105 -0
- passagemath_environment-10.4.1.data/scripts/sage-python +2 -0
- passagemath_environment-10.4.1.data/scripts/sage-venv-config +42 -0
- passagemath_environment-10.4.1.data/scripts/sage-version.sh +9 -0
- passagemath_environment-10.4.1.dist-info/METADATA +76 -0
- passagemath_environment-10.4.1.dist-info/RECORD +70 -0
- passagemath_environment-10.4.1.dist-info/WHEEL +5 -0
- passagemath_environment-10.4.1.dist-info/top_level.txt +1 -0
- sage/all__sagemath_environment.py +4 -0
- sage/env.py +496 -0
- sage/features/__init__.py +981 -0
- sage/features/all.py +126 -0
- sage/features/bliss.py +85 -0
- sage/features/cddlib.py +38 -0
- sage/features/coxeter3.py +45 -0
- sage/features/csdp.py +83 -0
- sage/features/cython.py +38 -0
- sage/features/databases.py +302 -0
- sage/features/dvipng.py +40 -0
- sage/features/ecm.py +42 -0
- sage/features/ffmpeg.py +119 -0
- sage/features/four_ti_2.py +55 -0
- sage/features/fricas.py +66 -0
- sage/features/gap.py +86 -0
- sage/features/gfan.py +38 -0
- sage/features/giac.py +30 -0
- sage/features/graph_generators.py +171 -0
- sage/features/graphviz.py +117 -0
- sage/features/igraph.py +44 -0
- sage/features/imagemagick.py +138 -0
- sage/features/interfaces.py +256 -0
- sage/features/internet.py +65 -0
- sage/features/jmol.py +44 -0
- sage/features/join_feature.py +146 -0
- sage/features/kenzo.py +77 -0
- sage/features/latex.py +300 -0
- sage/features/latte.py +85 -0
- sage/features/lrs.py +164 -0
- sage/features/mcqd.py +45 -0
- sage/features/meataxe.py +46 -0
- sage/features/mip_backends.py +114 -0
- sage/features/msolve.py +68 -0
- sage/features/nauty.py +70 -0
- sage/features/normaliz.py +43 -0
- sage/features/palp.py +65 -0
- sage/features/pandoc.py +42 -0
- sage/features/pdf2svg.py +41 -0
- sage/features/phitigra.py +42 -0
- sage/features/pkg_systems.py +195 -0
- sage/features/polymake.py +43 -0
- sage/features/poppler.py +58 -0
- sage/features/rubiks.py +180 -0
- sage/features/sagemath.py +1205 -0
- sage/features/sat.py +103 -0
- sage/features/singular.py +48 -0
- sage/features/sirocco.py +45 -0
- sage/features/sphinx.py +71 -0
- sage/features/standard.py +38 -0
- sage/features/symengine_py.py +44 -0
- sage/features/tdlib.py +38 -0
- sage/features/threejs.py +75 -0
- sage/features/topcom.py +67 -0
- sage/misc/all__sagemath_environment.py +2 -0
- sage/misc/package.py +570 -0
- sage/misc/package_dir.py +621 -0
- sage/misc/temporary_file.py +546 -0
- sage/misc/viewer.py +369 -0
- sage/version.py +5 -0
sage/env.py
ADDED
@@ -0,0 +1,496 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-environment
|
2
|
+
r"""
|
3
|
+
Sage Runtime Environment
|
4
|
+
|
5
|
+
Verify that importing ``sage.all`` works in Sage's Python without any ``SAGE_``
|
6
|
+
environment variables, and has the same ``SAGE_ROOT`` and ``SAGE_LOCAL``
|
7
|
+
(see also :issue:`29446`)::
|
8
|
+
|
9
|
+
sage: env = {k:v for (k,v) in os.environ.items() if not k.startswith("SAGE_")}
|
10
|
+
sage: from subprocess import check_output
|
11
|
+
sage: environment = "sage.all"
|
12
|
+
sage: cmd = f"from {environment} import SAGE_ROOT, SAGE_LOCAL; print((SAGE_ROOT, SAGE_LOCAL))"
|
13
|
+
sage: out = check_output([sys.executable, "-c", cmd], env=env).decode().strip() # long time
|
14
|
+
sage: out == repr((SAGE_ROOT, SAGE_LOCAL)) # long time
|
15
|
+
True
|
16
|
+
|
17
|
+
AUTHORS:
|
18
|
+
|
19
|
+
- \R. Andrew Ohana (2012): initial version
|
20
|
+
"""
|
21
|
+
|
22
|
+
# ****************************************************************************
|
23
|
+
# Copyright (C) 2013 R. Andrew Ohana <andrew.ohana@gmail.com>
|
24
|
+
# Copyright (C) 2019 Jeroen Demeyer <J.Demeyer@UGent.be>
|
25
|
+
#
|
26
|
+
# This program is free software: you can redistribute it and/or modify
|
27
|
+
# it under the terms of the GNU General Public License as published by
|
28
|
+
# the Free Software Foundation, either version 2 of the License, or
|
29
|
+
# (at your option) any later version.
|
30
|
+
# https://www.gnu.org/licenses/
|
31
|
+
# ****************************************************************************
|
32
|
+
|
33
|
+
from typing import Optional
|
34
|
+
import sage
|
35
|
+
import os
|
36
|
+
import socket
|
37
|
+
import sys
|
38
|
+
import sysconfig
|
39
|
+
from . import version
|
40
|
+
from pathlib import Path
|
41
|
+
import subprocess
|
42
|
+
|
43
|
+
|
44
|
+
# All variables set by var() appear in this SAGE_ENV dict
|
45
|
+
SAGE_ENV = dict()
|
46
|
+
|
47
|
+
|
48
|
+
def join(*args):
|
49
|
+
"""
|
50
|
+
Join paths like ``os.path.join`` except that the result is ``None``
|
51
|
+
if any of the components is ``None``.
|
52
|
+
|
53
|
+
EXAMPLES::
|
54
|
+
|
55
|
+
sage: from sage.env import join
|
56
|
+
sage: print(join("hello", "world"))
|
57
|
+
hello/world
|
58
|
+
sage: print(join("hello", None))
|
59
|
+
None
|
60
|
+
"""
|
61
|
+
if any(a is None for a in args):
|
62
|
+
return None
|
63
|
+
return os.path.join(*args)
|
64
|
+
|
65
|
+
|
66
|
+
def var(key: str, *fallbacks: Optional[str], force: bool = False) -> Optional[str]:
|
67
|
+
"""
|
68
|
+
Set ``SAGE_ENV[key]`` and return the value.
|
69
|
+
|
70
|
+
If ``key`` is an environment variable, this is the value.
|
71
|
+
Otherwise, the ``fallbacks`` are tried until one is found which
|
72
|
+
is not ``None``. If the environment variable is not set and all
|
73
|
+
fallbacks are ``None``, then the final value is ``None``.
|
74
|
+
|
75
|
+
INPUT:
|
76
|
+
|
77
|
+
- ``key`` -- string
|
78
|
+
|
79
|
+
- ``fallbacks`` -- tuple containing ``str`` or ``None`` values
|
80
|
+
|
81
|
+
- ``force`` -- boolean (default: ``False``); if
|
82
|
+
``True``, skip the environment variable and only use the
|
83
|
+
fallbacks
|
84
|
+
|
85
|
+
OUTPUT: the value of the environment variable or its fallbacks
|
86
|
+
|
87
|
+
EXAMPLES::
|
88
|
+
|
89
|
+
sage: import os, sage.env
|
90
|
+
sage: sage.env.SAGE_ENV = dict()
|
91
|
+
sage: os.environ['SAGE_FOO'] = 'foo'
|
92
|
+
sage: sage.env.var('SAGE_FOO', 'unused')
|
93
|
+
'foo'
|
94
|
+
sage: sage.env.SAGE_FOO
|
95
|
+
'foo'
|
96
|
+
sage: sage.env.SAGE_ENV['SAGE_FOO']
|
97
|
+
'foo'
|
98
|
+
|
99
|
+
If the environment variable does not exist, the fallbacks (if any)
|
100
|
+
are used. In most typical uses, there is exactly one fallback::
|
101
|
+
|
102
|
+
sage: _ = os.environ.pop('SAGE_BAR', None) # ensure that SAGE_BAR does not exist
|
103
|
+
sage: sage.env.var('SAGE_BAR', 'bar')
|
104
|
+
'bar'
|
105
|
+
sage: sage.env.SAGE_BAR
|
106
|
+
'bar'
|
107
|
+
sage: sage.env.SAGE_ENV['SAGE_BAR']
|
108
|
+
'bar'
|
109
|
+
|
110
|
+
Test multiple fallbacks::
|
111
|
+
|
112
|
+
sage: sage.env.var('SAGE_BAR', None, 'yes', 'no')
|
113
|
+
'yes'
|
114
|
+
sage: sage.env.SAGE_BAR
|
115
|
+
'yes'
|
116
|
+
|
117
|
+
If all fallbacks are ``None``, the result is ``None``::
|
118
|
+
|
119
|
+
sage: sage.env.var('SAGE_BAR')
|
120
|
+
sage: print(sage.env.SAGE_BAR)
|
121
|
+
None
|
122
|
+
sage: sage.env.var('SAGE_BAR', None)
|
123
|
+
sage: print(sage.env.SAGE_BAR)
|
124
|
+
None
|
125
|
+
|
126
|
+
Test the ``force`` keyword::
|
127
|
+
|
128
|
+
sage: os.environ['SAGE_FOO'] = 'foo'
|
129
|
+
sage: sage.env.var('SAGE_FOO', 'forced', force=True)
|
130
|
+
'forced'
|
131
|
+
sage: sage.env.SAGE_FOO
|
132
|
+
'forced'
|
133
|
+
sage: sage.env.var('SAGE_FOO', 'forced', force=False)
|
134
|
+
'foo'
|
135
|
+
sage: sage.env.SAGE_FOO
|
136
|
+
'foo'
|
137
|
+
"""
|
138
|
+
if force:
|
139
|
+
value = None
|
140
|
+
else:
|
141
|
+
value = os.environ.get(key)
|
142
|
+
if value is None:
|
143
|
+
try:
|
144
|
+
import sage_conf
|
145
|
+
value = getattr(sage_conf, key, None)
|
146
|
+
except ImportError:
|
147
|
+
pass
|
148
|
+
# Try all fallbacks in order as long as we don't have a value
|
149
|
+
for f in fallbacks:
|
150
|
+
if value is not None:
|
151
|
+
break
|
152
|
+
value = f
|
153
|
+
SAGE_ENV[key] = value
|
154
|
+
globals()[key] = value
|
155
|
+
return value
|
156
|
+
|
157
|
+
|
158
|
+
# system info
|
159
|
+
UNAME = var("UNAME", os.uname()[0])
|
160
|
+
HOSTNAME = var("HOSTNAME", socket.gethostname())
|
161
|
+
LOCAL_IDENTIFIER = var("LOCAL_IDENTIFIER", "{}.{}".format(HOSTNAME, os.getpid()))
|
162
|
+
|
163
|
+
# version info
|
164
|
+
SAGE_VERSION = var("SAGE_VERSION", version.version)
|
165
|
+
SAGE_DATE = var("SAGE_DATE", version.date)
|
166
|
+
SAGE_VERSION_BANNER = var("SAGE_VERSION_BANNER", version.banner)
|
167
|
+
|
168
|
+
# virtual environment where sagelib is installed
|
169
|
+
SAGE_VENV = var("SAGE_VENV", os.path.abspath(sys.prefix))
|
170
|
+
SAGE_LIB = var("SAGE_LIB", os.path.dirname(os.path.dirname(__file__)))
|
171
|
+
SAGE_EXTCODE = var("SAGE_EXTCODE", join(SAGE_LIB, "sage", "ext_data"))
|
172
|
+
SAGE_VENV_SPKG_INST = var("SAGE_VENV_SPKG_INST", join(SAGE_VENV, "var", "lib", "sage", "installed"))
|
173
|
+
|
174
|
+
# prefix hierarchy where non-Python packages are installed
|
175
|
+
SAGE_LOCAL = var("SAGE_LOCAL", SAGE_VENV)
|
176
|
+
SAGE_SHARE = var("SAGE_SHARE", join(SAGE_LOCAL, "share"))
|
177
|
+
SAGE_DOC = var("SAGE_DOC", join(SAGE_SHARE, "doc", "sage"))
|
178
|
+
SAGE_LOCAL_SPKG_INST = var("SAGE_LOCAL_SPKG_INST", join(SAGE_LOCAL, "var", "lib", "sage", "installed"))
|
179
|
+
SAGE_SPKG_INST = var("SAGE_SPKG_INST", join(SAGE_LOCAL, "var", "lib", "sage", "installed")) # deprecated
|
180
|
+
|
181
|
+
# source tree of the Sage distribution
|
182
|
+
SAGE_ROOT = var("SAGE_ROOT") # no fallback for SAGE_ROOT
|
183
|
+
SAGE_SRC = var("SAGE_SRC", join(SAGE_ROOT, "src"), SAGE_LIB)
|
184
|
+
SAGE_DOC_SRC = var("SAGE_DOC_SRC", join(SAGE_ROOT, "src", "doc"), SAGE_DOC)
|
185
|
+
SAGE_PKGS = var("SAGE_PKGS", join(SAGE_ROOT, "build", "pkgs"))
|
186
|
+
SAGE_ROOT_GIT = var("SAGE_ROOT_GIT", join(SAGE_ROOT, ".git"))
|
187
|
+
|
188
|
+
# Sage doc server (local server with PORT if URL is not given)
|
189
|
+
SAGE_DOC_SERVER_URL = var("SAGE_DOC_SERVER_URL")
|
190
|
+
# The default port is 0 so that the system will assign a random unused port > 1024
|
191
|
+
SAGE_DOC_LOCAL_PORT = var("SAGE_DOC_LOCAL_PORT", "0")
|
192
|
+
|
193
|
+
# ~/.sage
|
194
|
+
DOT_SAGE = var("DOT_SAGE", join(os.environ.get("HOME"), ".sage"))
|
195
|
+
SAGE_STARTUP_FILE = var("SAGE_STARTUP_FILE", join(DOT_SAGE, "init.sage"))
|
196
|
+
|
197
|
+
# for sage_setup.setenv
|
198
|
+
SAGE_ARCHFLAGS = var("SAGE_ARCHFLAGS", "unset")
|
199
|
+
SAGE_PKG_CONFIG_PATH = var("SAGE_PKG_CONFIG_PATH")
|
200
|
+
|
201
|
+
# colon-separated search path for databases.
|
202
|
+
SAGE_DATA_PATH = var("SAGE_DATA_PATH",
|
203
|
+
os.pathsep.join(filter(None, [
|
204
|
+
join(DOT_SAGE, "db"),
|
205
|
+
join(SAGE_SHARE, "sagemath"),
|
206
|
+
SAGE_SHARE,
|
207
|
+
])))
|
208
|
+
|
209
|
+
# database directories, the default is to search in SAGE_DATA_PATH
|
210
|
+
CREMONA_LARGE_DATA_DIR = var("CREMONA_LARGE_DATA_DIR")
|
211
|
+
CREMONA_MINI_DATA_DIR = var("CREMONA_MINI_DATA_DIR")
|
212
|
+
ELLCURVE_DATA_DIR = var("ELLCURVE_DATA_DIR")
|
213
|
+
GRAPHS_DATA_DIR = var("GRAPHS_DATA_DIR")
|
214
|
+
POLYTOPE_DATA_DIR = var("POLYTOPE_DATA_DIR")
|
215
|
+
|
216
|
+
# installation directories for various packages
|
217
|
+
JMOL_DIR = var("JMOL_DIR")
|
218
|
+
MATHJAX_DIR = var("MATHJAX_DIR", join(SAGE_SHARE, "mathjax"))
|
219
|
+
MTXLIB = var("MTXLIB", join(SAGE_SHARE, "meataxe"))
|
220
|
+
THREEJS_DIR = var("THREEJS_DIR")
|
221
|
+
PPLPY_DOCS = var("PPLPY_DOCS", join(SAGE_SHARE, "doc", "pplpy"))
|
222
|
+
MAXIMA = var("MAXIMA", "maxima")
|
223
|
+
MAXIMA_FAS = var("MAXIMA_FAS")
|
224
|
+
KENZO_FAS = var("KENZO_FAS")
|
225
|
+
SAGE_NAUTY_BINS_PREFIX = var("SAGE_NAUTY_BINS_PREFIX", "")
|
226
|
+
SAGE_ECMBIN = var("SAGE_ECMBIN", "ecm")
|
227
|
+
RUBIKS_BINS_PREFIX = var("RUBIKS_BINS_PREFIX", "")
|
228
|
+
FOURTITWO_HILBERT = var("FOURTITWO_HILBERT")
|
229
|
+
FOURTITWO_MARKOV = var("FOURTITWO_MARKOV")
|
230
|
+
FOURTITWO_GRAVER = var("FOURTITWO_GRAVER")
|
231
|
+
FOURTITWO_ZSOLVE = var("FOURTITWO_ZSOLVE")
|
232
|
+
FOURTITWO_QSOLVE = var("FOURTITWO_QSOLVE")
|
233
|
+
FOURTITWO_RAYS = var("FOURTITWO_RAYS")
|
234
|
+
FOURTITWO_PPI = var("FOURTITWO_PPI")
|
235
|
+
FOURTITWO_CIRCUITS = var("FOURTITWO_CIRCUITS")
|
236
|
+
FOURTITWO_GROEBNER = var("FOURTITWO_GROEBNER")
|
237
|
+
CBLAS_PC_MODULES = var("CBLAS_PC_MODULES", "cblas:openblas:blas")
|
238
|
+
ECL_CONFIG = var("ECL_CONFIG", "ecl-config")
|
239
|
+
NTL_INCDIR = var("NTL_INCDIR")
|
240
|
+
NTL_LIBDIR = var("NTL_LIBDIR")
|
241
|
+
LIE_INFO_DIR = var("LIE_INFO_DIR", join(SAGE_LOCAL, "lib", "LiE"))
|
242
|
+
SINGULAR_BIN = var("SINGULAR_BIN") or "Singular"
|
243
|
+
|
244
|
+
# OpenMP
|
245
|
+
OPENMP_CFLAGS = var("OPENMP_CFLAGS", "")
|
246
|
+
OPENMP_CXXFLAGS = var("OPENMP_CXXFLAGS", "")
|
247
|
+
|
248
|
+
# Make sure mpmath uses Sage types
|
249
|
+
os.environ['MPMATH_SAGE'] = '1'
|
250
|
+
|
251
|
+
# misc
|
252
|
+
SAGE_BANNER = var("SAGE_BANNER", "")
|
253
|
+
SAGE_IMPORTALL = var("SAGE_IMPORTALL", "yes")
|
254
|
+
|
255
|
+
# GAP memory and args
|
256
|
+
|
257
|
+
SAGE_GAP_MEMORY = var('SAGE_GAP_MEMORY', None)
|
258
|
+
SAGE_GAP_COMMAND = var('SAGE_GAP_COMMAND', None)
|
259
|
+
|
260
|
+
# The semicolon-separated search path for GAP packages. It is passed
|
261
|
+
# directly to GAP via the -l flag.
|
262
|
+
GAP_ROOT_PATHS = var("GAP_ROOT_PATHS",
|
263
|
+
";".join([join(SAGE_LOCAL, "lib", "gap"),
|
264
|
+
join(SAGE_LOCAL, "share", "gap")]))
|
265
|
+
|
266
|
+
# post process
|
267
|
+
if DOT_SAGE is not None and ' ' in DOT_SAGE:
|
268
|
+
print("Your home directory has a space in it. This")
|
269
|
+
print("will probably break some functionality of Sage. E.g.,")
|
270
|
+
print("the GAP interface will not work. A workaround")
|
271
|
+
print("is to set the environment variable HOME to a")
|
272
|
+
print("directory with no spaces that you have write")
|
273
|
+
print("permissions to before you start sage.")
|
274
|
+
|
275
|
+
|
276
|
+
def sage_include_directories(use_sources=False):
|
277
|
+
"""
|
278
|
+
Return the list of include directories for compiling Sage extension modules.
|
279
|
+
|
280
|
+
INPUT:
|
281
|
+
|
282
|
+
- ``use_sources`` -- boolean (default: ``False``)
|
283
|
+
|
284
|
+
OUTPUT:
|
285
|
+
|
286
|
+
a list of include directories to be used to compile sage code
|
287
|
+
1. while building sage (use_sources='True')
|
288
|
+
2. while using sage (use_sources='False')
|
289
|
+
|
290
|
+
EXAMPLES:
|
291
|
+
|
292
|
+
Expected output while using Sage::
|
293
|
+
|
294
|
+
sage: import sage.env
|
295
|
+
sage: sage.env.sage_include_directories()
|
296
|
+
['...',
|
297
|
+
'.../numpy/...core/include',
|
298
|
+
'.../include/python...']
|
299
|
+
|
300
|
+
To check that C/C++ files are correctly found, we verify that we can
|
301
|
+
always find the include file ``sage/cpython/cython_metaclass.h``,
|
302
|
+
with both values for ``use_sources``::
|
303
|
+
|
304
|
+
sage: file = os.path.join("sage", "cpython", "cython_metaclass.h")
|
305
|
+
sage: dirs = sage.env.sage_include_directories(use_sources=True)
|
306
|
+
sage: any(os.path.isfile(os.path.join(d, file)) for d in dirs)
|
307
|
+
True
|
308
|
+
sage: dirs = sage.env.sage_include_directories(use_sources=False)
|
309
|
+
sage: any(os.path.isfile(os.path.join(d, file)) for d in dirs)
|
310
|
+
True
|
311
|
+
"""
|
312
|
+
if use_sources:
|
313
|
+
dirs = [SAGE_SRC]
|
314
|
+
else:
|
315
|
+
import sage
|
316
|
+
dirs = [os.path.dirname(directory)
|
317
|
+
for directory in sage.__path__]
|
318
|
+
try:
|
319
|
+
import numpy
|
320
|
+
dirs.append(numpy.get_include())
|
321
|
+
except ModuleNotFoundError:
|
322
|
+
pass
|
323
|
+
|
324
|
+
dirs.append(sysconfig.get_config_var('INCLUDEPY'))
|
325
|
+
|
326
|
+
return dirs
|
327
|
+
|
328
|
+
|
329
|
+
def get_cblas_pc_module_name() -> str:
|
330
|
+
"""
|
331
|
+
Return the name of the BLAS libraries to be used.
|
332
|
+
"""
|
333
|
+
import pkgconfig
|
334
|
+
cblas_pc_modules = CBLAS_PC_MODULES.split(':')
|
335
|
+
return next((blas_lib for blas_lib in cblas_pc_modules if pkgconfig.exists(blas_lib)))
|
336
|
+
|
337
|
+
|
338
|
+
default_required_modules = ('fflas-ffpack', 'givaro', 'gsl', 'linbox', 'Singular',
|
339
|
+
'libpng', 'gdlib', 'm4ri', 'zlib', 'cblas', 'ecl')
|
340
|
+
|
341
|
+
|
342
|
+
default_optional_modules = ('lapack',)
|
343
|
+
|
344
|
+
|
345
|
+
def cython_aliases(required_modules=None, optional_modules=None):
|
346
|
+
"""
|
347
|
+
Return the aliases for compiling Cython code. These aliases are
|
348
|
+
macros which can occur in ``# distutils`` headers.
|
349
|
+
|
350
|
+
INPUT:
|
351
|
+
|
352
|
+
- ``required_modules`` -- (default: taken from ``default_required_modules``)
|
353
|
+
iterable of string values
|
354
|
+
|
355
|
+
- ``optional_modules`` -- (default: taken from ``default_optional_modules``)
|
356
|
+
iterable of string values
|
357
|
+
|
358
|
+
EXAMPLES::
|
359
|
+
|
360
|
+
sage: from sage.env import cython_aliases
|
361
|
+
sage: cython_aliases()
|
362
|
+
{...}
|
363
|
+
sage: sorted(cython_aliases().keys())
|
364
|
+
['CBLAS_CFLAGS',
|
365
|
+
...,
|
366
|
+
'ZLIB_LIBRARIES']
|
367
|
+
sage: cython_aliases(required_modules=('module-that-is-assumed-to-not-exist'))
|
368
|
+
Traceback (most recent call last):
|
369
|
+
...
|
370
|
+
PackageNotFoundError: ...
|
371
|
+
sage: cython_aliases(required_modules=(), optional_modules=('module-that-is-assumed-to-not-exist'))
|
372
|
+
{...}
|
373
|
+
|
374
|
+
TESTS:
|
375
|
+
|
376
|
+
We can use ``cython.parallel`` regardless of whether OpenMP is supported.
|
377
|
+
This will run in parallel, if OpenMP is supported::
|
378
|
+
|
379
|
+
sage: cython( # optional - sage.misc.cython
|
380
|
+
....: '''
|
381
|
+
....: #distutils: extra_compile_args = OPENMP_CFLAGS
|
382
|
+
....: #distutils: extra_link_args = OPENMP_CFLAGS
|
383
|
+
....: from cython.parallel import prange
|
384
|
+
....:
|
385
|
+
....: cdef int i
|
386
|
+
....: cdef int n = 30
|
387
|
+
....: cdef int sum = 0
|
388
|
+
....:
|
389
|
+
....: for i in prange(n, num_threads=4, nogil=True):
|
390
|
+
....: sum += i
|
391
|
+
....:
|
392
|
+
....: print(sum)
|
393
|
+
....: ''')
|
394
|
+
435
|
395
|
+
"""
|
396
|
+
import pkgconfig
|
397
|
+
import itertools
|
398
|
+
|
399
|
+
if required_modules is None:
|
400
|
+
required_modules = default_required_modules
|
401
|
+
|
402
|
+
if optional_modules is None:
|
403
|
+
optional_modules = default_optional_modules
|
404
|
+
|
405
|
+
aliases = {}
|
406
|
+
|
407
|
+
for lib, required in itertools.chain(((lib, True) for lib in required_modules),
|
408
|
+
((lib, False) for lib in optional_modules)):
|
409
|
+
var = lib.upper().replace("-", "") + "_"
|
410
|
+
if lib == 'cblas':
|
411
|
+
lib = get_cblas_pc_module_name()
|
412
|
+
if lib == 'zlib':
|
413
|
+
aliases[var + "CFLAGS"] = ""
|
414
|
+
try:
|
415
|
+
pc = pkgconfig.parse('zlib')
|
416
|
+
libs = pkgconfig.libs(lib)
|
417
|
+
except pkgconfig.PackageNotFoundError:
|
418
|
+
from collections import defaultdict
|
419
|
+
pc = defaultdict(list, {'libraries': ['z']})
|
420
|
+
libs = "-lz"
|
421
|
+
elif lib == 'ecl':
|
422
|
+
try:
|
423
|
+
# Determine ecl-specific compiler arguments using the ecl-config script
|
424
|
+
ecl_cflags = subprocess.run([ECL_CONFIG, "--cflags"], check=True, capture_output=True, text=True).stdout.split()
|
425
|
+
ecl_libs = subprocess.run([ECL_CONFIG, "--libs"], check=True, capture_output=True, text=True).stdout.split()
|
426
|
+
except subprocess.CalledProcessError:
|
427
|
+
if required:
|
428
|
+
raise
|
429
|
+
else:
|
430
|
+
continue
|
431
|
+
aliases["ECL_CFLAGS"] = list(filter(lambda s: not s.startswith('-I'), ecl_cflags))
|
432
|
+
aliases["ECL_INCDIR"] = [s[2:] for s in filter(lambda s: s.startswith('-I'), ecl_cflags)]
|
433
|
+
aliases["ECL_LIBDIR"] = [s[2:] for s in filter(lambda s: s.startswith('-L'), ecl_libs)]
|
434
|
+
aliases["ECL_LIBRARIES"] = [s[2:] for s in filter(lambda s: s.startswith('-l'), ecl_libs)]
|
435
|
+
aliases["ECL_LIBEXTRA"] = list(filter(lambda s: not s.startswith(('-l', '-L')), ecl_libs))
|
436
|
+
continue
|
437
|
+
else:
|
438
|
+
try:
|
439
|
+
aliases[var + "CFLAGS"] = pkgconfig.cflags(lib).split()
|
440
|
+
pc = pkgconfig.parse(lib)
|
441
|
+
libs = pkgconfig.libs(lib)
|
442
|
+
except pkgconfig.PackageNotFoundError:
|
443
|
+
if required:
|
444
|
+
raise
|
445
|
+
else:
|
446
|
+
continue
|
447
|
+
|
448
|
+
# It may seem that INCDIR is redundant because the -I options are also
|
449
|
+
# passed in CFLAGS. However, "extra_compile_args" are put at the end
|
450
|
+
# of the compiler command line. "include_dirs" go to the front; the
|
451
|
+
# include search order matters.
|
452
|
+
aliases[var + "INCDIR"] = pc['include_dirs']
|
453
|
+
aliases[var + "LIBDIR"] = pc['library_dirs']
|
454
|
+
aliases[var + "LIBEXTRA"] = list(filter(lambda s: not s.startswith(('-l', '-L')), libs.split()))
|
455
|
+
aliases[var + "LIBRARIES"] = pc['libraries']
|
456
|
+
|
457
|
+
# uname-specific flags
|
458
|
+
UNAME = os.uname()
|
459
|
+
|
460
|
+
def uname_specific(name, value, alternative):
|
461
|
+
if name in UNAME[0]:
|
462
|
+
return value
|
463
|
+
else:
|
464
|
+
return alternative
|
465
|
+
|
466
|
+
aliases["LINUX_NOEXECSTACK"] = uname_specific("Linux", ["-Wl,-z,noexecstack"],
|
467
|
+
[])
|
468
|
+
|
469
|
+
# LinBox needs special care because it actually requires C++11 with
|
470
|
+
# GNU extensions: -std=c++11 does not work, you need -std=gnu++11
|
471
|
+
# (this is true at least with GCC 7.2.0).
|
472
|
+
#
|
473
|
+
# Further, note that LinBox does not add any C++11 flag in its .pc
|
474
|
+
# file (possibly because of confusion between CFLAGS and CXXFLAGS?).
|
475
|
+
# This is not a problem in practice since LinBox depends on
|
476
|
+
# fflas-ffpack and fflas-ffpack does add such a C++11 flag.
|
477
|
+
if "LINBOX_CFLAGS" in aliases:
|
478
|
+
aliases["LINBOX_CFLAGS"].append("-std=gnu++11")
|
479
|
+
|
480
|
+
try:
|
481
|
+
aliases["M4RI_CFLAGS"].remove("-pedantic")
|
482
|
+
except (ValueError, KeyError):
|
483
|
+
pass
|
484
|
+
|
485
|
+
# NTL
|
486
|
+
aliases["NTL_CFLAGS"] = ['-std=c++11']
|
487
|
+
aliases["NTL_INCDIR"] = [NTL_INCDIR] if NTL_INCDIR else []
|
488
|
+
aliases["NTL_LIBDIR"] = [NTL_LIBDIR] if NTL_LIBDIR else []
|
489
|
+
aliases["NTL_LIBRARIES"] = ['ntl']
|
490
|
+
aliases["NTL_LIBEXTRA"] = []
|
491
|
+
|
492
|
+
# OpenMP
|
493
|
+
aliases["OPENMP_CFLAGS"] = OPENMP_CFLAGS.split()
|
494
|
+
aliases["OPENMP_CXXFLAGS"] = OPENMP_CXXFLAGS.split()
|
495
|
+
|
496
|
+
return aliases
|