1 |
|
2 |
############################################################################## |
3 |
# |
4 |
# Copyright (c) 2003-2019 by the University of Queensland |
5 |
# http://www.uq.edu.au |
6 |
# |
7 |
# Primary Business: Queensland, Australia |
8 |
# Licensed under the Apache License, version 2.0 |
9 |
# http://www.apache.org/licenses/LICENSE-2.0 |
10 |
# |
11 |
# Development until 2012 by Earth Systems Science Computational Center (ESSCC) |
12 |
# Development 2012-2013 by School of Earth Sciences |
13 |
# Development from 2014 by Centre for Geoscience Computing (GeoComp) |
14 |
# Development from 2019 by School of Earth and Environmental Sciences |
15 |
# |
16 |
############################################################################## |
17 |
|
18 |
from __future__ import print_function, division |
19 |
|
20 |
__copyright__="""Copyright (c) 2003-2019 by the University of Queensland |
21 |
http://www.uq.edu.au |
22 |
Primary Business: Queensland, Australia""" |
23 |
__license__="""Licensed under the Apache License, version 2.0 |
24 |
http://www.apache.org/licenses/LICENSE-2.0""" |
25 |
__url__="https://launchpad.net/escript-finley" |
26 |
|
27 |
import os, re, sys |
28 |
from distutils import sysconfig |
29 |
from subprocess import PIPE, Popen |
30 |
from SCons.Script.SConscript import Configure |
31 |
from site_init import findLibWithHeader, detectModule |
32 |
import subprocess |
33 |
|
34 |
REQUIRED_BOOST = (1, 46) |
35 |
|
36 |
def CheckComplexAcos(context): |
37 |
context.Message('Checking for working complex std::acos()... ') |
38 |
result = context.TryRun(""" |
39 |
#include <complex> |
40 |
int main() { std::complex<double> x(0,3.14159265359), y(1.5707963,-1.8622957); |
41 |
return std::abs(std::acos(x)-y) < 1e-6 ? 0:-1;} |
42 |
""", '.cpp') |
43 |
# scons < 2.4 fix: |
44 |
if type(result)==tuple: |
45 |
result = result[0] |
46 |
context.Result(result) |
47 |
return result |
48 |
|
49 |
def checkCompiler(env): |
50 |
conf = Configure(env.Clone(), custom_tests = {'CheckComplexAcos': CheckComplexAcos}) |
51 |
if 'CheckCXX' in dir(conf): # exists since scons 1.1.0 |
52 |
if not conf.CheckCXX(): |
53 |
print("Cannot run C++ compiler '%s' (check config.log)" % (env['CXX'])) |
54 |
env.Exit(1) |
55 |
else: |
56 |
if not conf.CheckFunc('printf', language='c++'): |
57 |
print("Cannot run C++ compiler '%s' (check config.log)" % (env['CXX'])) |
58 |
env.Exit(1) |
59 |
|
60 |
conf.env['buildvars']['cxx']=conf.env['CXX'] |
61 |
|
62 |
if conf.CheckFunc('gethostname', language='c++'): |
63 |
conf.env.Append(CPPDEFINES = ['HAVE_GETHOSTNAME']) |
64 |
|
65 |
if conf.CheckCXXHeader('byteswap.h'): |
66 |
checkhdr="""#include <byteswap.h> |
67 |
#define SCbswap32() {int x=0;bswap_32(x);}""" |
68 |
if conf.CheckFunc('SCbswap32', header=checkhdr, language='c++'): |
69 |
conf.env.Append(CPPDEFINES = ['HAVE_BYTESWAP_H']) |
70 |
if conf.CheckCXXHeader('sys/endian.h'): |
71 |
conf.env.Append(CPPDEFINES = ['HAVE_SYS_ENDIAN_H']) |
72 |
if conf.CheckCXXHeader('libkern/OSByteOrder.h'): |
73 |
conf.env.Append(CPPDEFINES = ['HAVE_OSBYTEORDER_H']) |
74 |
|
75 |
if not conf.CheckComplexAcos(): |
76 |
conf.env.Append(CPPDEFINES = ['ESYS_USE_BOOST_ACOS']) |
77 |
|
78 |
return conf.Finish() |
79 |
|
80 |
def get_external_python_sympy(env,bin): |
81 |
import subprocess |
82 |
cmd='' |
83 |
cmd+='import sympy\n' |
84 |
cmd+='print(sympy.__version__)\n' |
85 |
sp=subprocess.Popen([bin, '-c', cmd], stdin=None, stderr=None, stdout=subprocess.PIPE) |
86 |
#ver=sp.stdout.readline().strip().split('.') |
87 |
|
88 |
import sys |
89 |
if sys.version_info[0] >= 3: |
90 |
ver = str(sp.stdout.readline().strip(), 'utf-8') |
91 |
else: |
92 |
ver = sp.stdout.readline().strip().split('.') |
93 |
|
94 |
tmp1 = ver[0] |
95 |
tmp2 = ver[1] |
96 |
if tmp2 == '.': |
97 |
tmp2 = ver[2] |
98 |
|
99 |
if int(tmp1) == 0 and int(tmp2) < 7: |
100 |
env['sympy'] = False |
101 |
env['warnings'].append("sympy version is too old.") |
102 |
env.Append(CPPDEFINES = ['ESYS_NO_SYMPY']) |
103 |
if (int(tmp1) == 1 and int(tmp2) >= 2) or int(tmp1) >= 2: |
104 |
env['sympy']=False |
105 |
env['warnings'].append("escript does not support sympy version 1.2 and higher. Found version %d.%d" % (int(tmp1),int(tmp2))) |
106 |
env.Append(CPPDEFINES = ['ESYS_NO_SYMPY']) |
107 |
|
108 |
return env |
109 |
|
110 |
def call_python_config(bin=None): |
111 |
import subprocess |
112 |
cmd='' |
113 |
cmd+='import subprocess\n' |
114 |
cmd+='import os\n' |
115 |
cmd+='import sys\n' |
116 |
cmd+='from distutils import sysconfig\n' |
117 |
cmd+='pyversion=sysconfig.get_python_version()\n' |
118 |
cmd+='try:\n' |
119 |
cmd+=' sp=subprocess.Popen(["python"+pyversion+"-config","--ldflags"], stdout=subprocess.PIPE)\n' |
120 |
cmd+='except:\n' |
121 |
cmd+=' pythonroot=sys.exec_prefix+"/bin/"\n' |
122 |
cmd+=' sp=subprocess.Popen([pythonroot+"python"+pyversion+"-config","--ldflags"], stdout=subprocess.PIPE)\n' |
123 |
cmd+='d=sp.stdout.readline().split()\n' |
124 |
cmd+="libdirs=[z[2:] for z in d if z.startswith(b'-L')]\n" |
125 |
cmd+="libs=[z[2:] for z in d if z.startswith(b'-lpython')]\n" |
126 |
cmd+="target=''\n" |
127 |
cmd+="libname=''\n" |
128 |
cmd+="for d in libdirs:\n" |
129 |
cmd+=" for f in libs:\n" |
130 |
cmd+=" s=os.path.join(d,b'lib'+f+b'.so')\n" |
131 |
cmd+=" try:\n" |
132 |
cmd+=" dummy=os.stat(s)\n" |
133 |
cmd+=" if target=='':\n" |
134 |
cmd+=" target=d\n" |
135 |
cmd+=" libname=f\n" |
136 |
cmd+=" except Exception:\n" |
137 |
cmd+=" pass\n" |
138 |
cmd+=" s=os.path.join(d,b'lib'+f+b'.dylib')\n" |
139 |
cmd+=" try:\n" |
140 |
cmd+=" dummy=os.stat(s)\n" |
141 |
cmd+=" if target=='':\n" |
142 |
cmd+=" target=d\n" |
143 |
cmd+=" libname=f\n" |
144 |
cmd+=" except Exception:\n" |
145 |
cmd+=" pass\n" |
146 |
if bin is None: |
147 |
exec(cmd) |
148 |
ver=str(sys.version_info[0])+'.'+str(sys.version_info[1])+'.'+str(sys.version_info[2]) |
149 |
return (target,libname,ver, sysconfig.get_python_inc()) |
150 |
# run an external python to get its library location |
151 |
# yes we are starting another python just to run python?-config |
152 |
cmd+="if 'decode' in dir(target):\n" |
153 |
cmd+=" target=target.decode()\n" |
154 |
cmd+=" libname=libname.decode()\n" |
155 |
cmd+="print(target)\n" |
156 |
cmd+="print(libname)\n" |
157 |
cmd+="import sys\n" |
158 |
cmd+="print(str(sys.version_info[0])+'.'+str(sys.version_info[1])+'.'+str(sys.version_info[2]))\n" |
159 |
cmd+="print(sysconfig.get_python_inc())\n" |
160 |
sp=subprocess.Popen([bin, '-c', cmd], stdin=None, stderr=None, stdout=subprocess.PIPE) |
161 |
target=sp.stdout.readline().strip() |
162 |
libname=sp.stdout.readline().strip() |
163 |
ver=sp.stdout.readline().strip() |
164 |
pinc=sp.stdout.readline().strip() |
165 |
return (target, libname, ver, pinc) |
166 |
|
167 |
def checkPython(env): |
168 |
# First we check to see if the config file has specified |
169 |
# where to find the file. Ideally, this should be automatic |
170 |
# but we need to deal with the case where python is not in its INSTALL |
171 |
# directory. |
172 |
# Use the python scons is running |
173 |
if env['pythoncmd'] == sys.executable: |
174 |
if env['IS_WINDOWS']: |
175 |
python_inc_path=sysconfig.get_python_inc() |
176 |
python_lib_path=os.path.join(sysconfig.get_config_var('prefix'), 'libs') |
177 |
python_libs=['python%s%s'%(sys.version_info[0], sys.version_info[1])] |
178 |
verstring=".".join([str(i) for i in sys.version_info[:3]]) |
179 |
else: |
180 |
(python_lib_path, python_libs,verstring, python_inc_path)=call_python_config(env['pythoncmd']) |
181 |
|
182 |
# if we want to use a python other than the one scons is running |
183 |
# Note: we assume scons is running python 2 in the following. |
184 |
else: |
185 |
if env['IS_WINDOWS']: |
186 |
cmd = "import os, sys\n" |
187 |
cmd += "from distutils import sysconfig\n" |
188 |
cmd += "print(sysconfig.get_python_inc())\n" |
189 |
cmd += "print(os.path.join(sysconfig.get_config_var('prefix'), 'libs'))\n" |
190 |
cmd += "print('python%s%s'%(sys.version_info[0], sys.version_info[1]))\n" |
191 |
cmd += "print('.'.join([str(i) for i in sys.version_info[:3]]))" |
192 |
pout = subprocess.Popen([env['pythoncmd'], '-c', cmd], stdout=subprocess.PIPE).stdout.read() |
193 |
if isinstance(pout, bytes): |
194 |
pout = pout.decode(sys.stdout.encoding) |
195 |
lines = pout.split('\n') |
196 |
python_inc_path = lines[0].strip() |
197 |
python_lib_path = lines[1].strip() |
198 |
python_libs = [lines[2].strip()] |
199 |
verstring = lines[3].strip() |
200 |
else: |
201 |
(python_lib_path, python_libs,verstring, python_inc_path)=call_python_config(env['pythoncmd']) |
202 |
|
203 |
if sys.version_info[0] == 3: |
204 |
if isinstance(verstring, str) is False: |
205 |
verstring = str(verstring, 'utf-8') |
206 |
else: |
207 |
if isinstance(verstring, basestring) is False: |
208 |
verstring = str(verstring, 'utf-8') |
209 |
|
210 |
env['python_version'] = verstring |
211 |
try: |
212 |
ispython3 = (verstring[0] == '3') |
213 |
except: |
214 |
ispython3 = sys.version_info[0] == 3 |
215 |
if ispython3: |
216 |
env.Append(CPPDEFINES=['ESPYTHON3']) |
217 |
env['buildvars']['python_version'] = verstring |
218 |
env['buildvars']['python'] = env['pythoncmd'] |
219 |
# Check for an override from the config file. |
220 |
# Ideally, this should be automatic but we need to deal with the case |
221 |
# where python is not in its INSTALL directory |
222 |
if env['pythonlibpath'] != '': |
223 |
python_lib_path = env['pythonlibpath'] |
224 |
|
225 |
if env['pythonincpath'] != '': |
226 |
python_inc_path = env['pythonincpath'] |
227 |
|
228 |
if env['pythonlibname'] != '': |
229 |
python_libs = env['pythonlibname'] |
230 |
|
231 |
conf = Configure(env.Clone()) |
232 |
|
233 |
if env['sysheaderopt'] == '': |
234 |
conf.env.AppendUnique(CPPPATH = [python_inc_path]) |
235 |
else: |
236 |
conf.env.Append(CCFLAGS = [env['sysheaderopt'], python_inc_path]) |
237 |
|
238 |
conf.env.AppendUnique(LIBPATH = [python_lib_path]) |
239 |
conf.env.AppendUnique(LIBS = python_libs) |
240 |
# The wrapper script needs to find the libs |
241 |
conf.env.PrependENVPath(env['LD_LIBRARY_PATH_KEY'], python_lib_path) |
242 |
|
243 |
if not conf.CheckCXXHeader('Python.h'): |
244 |
print("Cannot find python include files (tried 'Python.h' in directory %s)" % (python_inc_path)) |
245 |
env.Exit(1) |
246 |
if not conf.CheckFunc('Py_Exit', language='c++'): |
247 |
print("Cannot find python library method Py_Exit (tried %s in directory %s)" % (python_libs, python_lib_path)) |
248 |
env.Exit(1) |
249 |
|
250 |
return conf.Finish() |
251 |
|
252 |
def checkCudaVersion(env): |
253 |
# NVCC availability is already checked in the Tool file |
254 |
p = Popen([env['NVCC'], '-V'], stdout=PIPE) |
255 |
out,_ = p.communicate() |
256 |
env['nvcc_version'] = '(unknown version)' |
257 |
for line in out.split('\n'): |
258 |
if 'release' in line: |
259 |
version = line[line.find('release'):].strip() |
260 |
env['nvcc_version'] = version |
261 |
break |
262 |
env['buildvars']['nvcc']=env['NVCC'] |
263 |
return env |
264 |
|
265 |
def checkBoost(env): |
266 |
boost_inc_path,boost_lib_path=findLibWithHeader(env, env['boost_libs'], 'boost/python.hpp', env['boost_prefix'], lang='c++') |
267 |
if env['sysheaderopt'] == '': |
268 |
env.AppendUnique(CPPPATH = [boost_inc_path]) |
269 |
else: |
270 |
# This is required because we can't -isystem /usr/include since it |
271 |
# breaks std includes |
272 |
if os.path.normpath(boost_inc_path) == '/usr/include': |
273 |
env.Append(CCFLAGS=[env['sysheaderopt'], os.path.join(boost_inc_path,'boost')]) |
274 |
else: |
275 |
env.Append(CCFLAGS=[env['sysheaderopt'], boost_inc_path]) |
276 |
|
277 |
env.AppendUnique(LIBPATH = [boost_lib_path]) |
278 |
env.AppendUnique(LIBS = env['boost_libs']) |
279 |
env.PrependENVPath(env['LD_LIBRARY_PATH_KEY'], boost_lib_path) |
280 |
|
281 |
# Try to extract the boost version from version.hpp |
282 |
boosthpp=open(os.path.join(boost_inc_path, 'boost', 'version.hpp')) |
283 |
boostversion='unknown' |
284 |
for line in boosthpp: |
285 |
ver=re.match(r'#define BOOST_VERSION (\d+)',line) |
286 |
if ver: |
287 |
boostversion=ver.group(1) |
288 |
boostversion = int(boostversion) |
289 |
maj = boostversion/100000 |
290 |
minor = (boostversion/100)%1000 |
291 |
sub = boostversion % 100 |
292 |
env['boost_version'] = "%d.%d.%d"%(maj,minor,sub) |
293 |
if maj <= REQUIRED_BOOST[0] and minor < REQUIRED_BOOST[1]: |
294 |
print("The boost version referenced must be at least version %d.%d "%REQUIRED_BOOST + "(have %d.%d.%d)"%(maj,minor,sub)) |
295 |
env.Exit(1) |
296 |
boosthpp.close() |
297 |
env['buildvars']['boost_inc_path']=boost_inc_path |
298 |
env['buildvars']['boost_lib_path']=boost_lib_path |
299 |
env['buildvars']['boostversion']=boostversion |
300 |
|
301 |
# Check for the boost numpy library |
302 |
env['have_boost_numpy']=False |
303 |
if boostversion >= 106300 and env['disable_boost_numpy'] is False: |
304 |
try: |
305 |
boost_numpy_inc_path,boost_numpy_lib_path=findLibWithHeader(env, env['boost_libs'], 'boost/python/numpy.hpp', env['boost_prefix'], lang='c++') |
306 |
|
307 |
# Locate the boost numpy files |
308 |
if env['IS_WINDOWS']: |
309 |
# windows scons template adds boost_numpy to boost_libs |
310 |
env.Append(CPPDEFINES=['ESYS_HAVE_BOOST_NUMPY']) |
311 |
else: |
312 |
p = subprocess.Popen(["ld","--verbose"], stdout=subprocess.PIPE) |
313 |
out,err = p.communicate() |
314 |
spath = [x[13:-3] for x in out.split() if b'SEARCH_DIR' in x] |
315 |
spath.append(boost_lib_path) |
316 |
p2name = '' |
317 |
p3name = '' |
318 |
p2res = '' |
319 |
p3res = '' |
320 |
for name in spath: |
321 |
try: |
322 |
l=os.listdir(name) |
323 |
import sys |
324 |
if sys.version_info[0] == 3: |
325 |
string_type = str |
326 |
else: |
327 |
string_type = basestring |
328 |
for x in l: |
329 |
if isinstance(x,string_type): |
330 |
if x.startswith('libboost_numpy') and x.endswith('.so'): |
331 |
p2res = x |
332 |
if x.startswith('libboost_numpy-py2') and x.endswith('.so'): |
333 |
p2res = x |
334 |
if x.startswith('libboost_numpy3') and x.endswith('.so'): |
335 |
p3res = x |
336 |
if x.startswith('libboost_numpy3-py3') and x.endswith('.so'): |
337 |
p3res = x |
338 |
else: |
339 |
if x.startswith(b'libboost_numpy') and x.endswith(b'.so'): |
340 |
p2res = x |
341 |
if x.startswith(b'libboost_numpy-py2') and x.endswith(b'.so'): |
342 |
p2res = x |
343 |
if x.startswith(b'libboost_numpy3') and x.endswith(b'.so'): |
344 |
p3res = x |
345 |
if x.startswith(b'libboost_numpy3-py3') and x.endswith('.so'): |
346 |
p3res = x |
347 |
except OSError: |
348 |
pass |
349 |
|
350 |
# Pick the right one |
351 |
if int(env['python_version'][0]) == 2: |
352 |
libname = p2res[3:-3] |
353 |
else: |
354 |
libname = p3res[3:-3] |
355 |
|
356 |
# If found, add the necessary information to env |
357 |
if len(libname) > 0: |
358 |
env.AppendUnique(LIBS = libname) |
359 |
tmp=env['boost_libs'] |
360 |
env['boost_libs']=[tmp,libname] |
361 |
env.AppendUnique(CPPPATH = [boost_numpy_inc_path]) |
362 |
env.AppendUnique(LIBPATH = [boost_numpy_lib_path]) |
363 |
env.PrependENVPath(env['LD_LIBRARY_PATH_KEY'], boost_numpy_lib_path) |
364 |
env.Append(CPPDEFINES=['ESYS_HAVE_BOOST_NUMPY']) |
365 |
env['have_boost_numpy']=True |
366 |
|
367 |
print("Found boost/python/numpy.hpp. Building with boost numpy support.") |
368 |
except: |
369 |
print("Warning: Could not find boost/python/numpy.hpp. Building without numpy support.") |
370 |
|
371 |
# Check if the version of boost we are using is missing BOOST_BYTE_ORDER |
372 |
if boostversion >= 107000: |
373 |
env.Append(CPPDEFINES=['ESYS_DEPRECATED_BOOST_ENDIAN']) |
374 |
if boostversion >= 107200: |
375 |
env.Append(CPPDEFINES=['ESYS_MOVED_BOOST_ENDIAN']) |
376 |
|
377 |
return env |
378 |
|
379 |
def checkNumpy(env): |
380 |
if not detectModule(env, 'numpy'): |
381 |
print("Cannot import numpy. If it is installed try setting your PYTHONPATH and probably %s"%env['LD_LIBRARY_PATH_KEY']) |
382 |
env.Exit(1) |
383 |
|
384 |
## check for numpy header (optional) |
385 |
conf = Configure(env.Clone()) |
386 |
numpy_h = False |
387 |
if conf.CheckCXXHeader(['Python.h','numpy/ndarrayobject.h']): |
388 |
numpy_h = True |
389 |
else: |
390 |
conda_prefix = os.environ.get('CONDA_PREFIX') |
391 |
if conda_prefix: |
392 |
# make a copy of CPPPATH so it can be restored if header check fails |
393 |
cpp_path_old = conf.env.get('CPPPATH', []).copy() |
394 |
conf.env.Append(CPPPATH = [conda_prefix+'/Lib/site-packages/numpy/core/include']) |
395 |
if conf.CheckCXXHeader(['Python.h','numpy/ndarrayobject.h']): |
396 |
numpy_h = True |
397 |
else: |
398 |
conf.env['CPPPATH'] = cpp_path_old |
399 |
|
400 |
conf.env['numpy_h'] = numpy_h |
401 |
if numpy_h: |
402 |
conf.env.Append(CPPDEFINES = ['ESYS_HAVE_NUMPY_H']) |
403 |
|
404 |
return conf.Finish() |
405 |
|
406 |
def checkCUDA(env): |
407 |
try: |
408 |
cuda_inc_path,cuda_lib_path=findLibWithHeader(env, 'cudart', 'thrust/version.h', env['cuda_prefix'], lang='c++') |
409 |
env.AppendUnique(CPPPATH = [cuda_inc_path]) |
410 |
env.AppendUnique(LIBPATH = [cuda_lib_path]) |
411 |
env.PrependENVPath(env['LD_LIBRARY_PATH_KEY'], cuda_lib_path) |
412 |
env.Append(CPPDEFINES = ['ESYS_HAVE_CUDA']) |
413 |
env['cuda']=True |
414 |
except: |
415 |
env['cuda']=False |
416 |
return env |
417 |
|
418 |
def checkCppUnit(env): |
419 |
try: |
420 |
cppunit_inc_path,cppunit_lib_path=findLibWithHeader(env, env['cppunit_libs'], 'cppunit/TestFixture.h', env['cppunit_prefix'], lang='c++') |
421 |
env.AppendUnique(CPPPATH = [cppunit_inc_path]) |
422 |
env.AppendUnique(LIBPATH = [cppunit_lib_path]) |
423 |
env.PrependENVPath(env['LD_LIBRARY_PATH_KEY'], cppunit_lib_path) |
424 |
env['cppunit']=True |
425 |
except: |
426 |
env['cppunit']=False |
427 |
return env |
428 |
|
429 |
def checkOptionalModules(env): |
430 |
######## scipy |
431 |
if not detectModule(env, 'scipy'): |
432 |
env['warnings'].append("Cannot import scipy. NetCDF sources will not be available for inversions.") |
433 |
|
434 |
######## pyproj |
435 |
if not detectModule(env, 'pyproj'): |
436 |
env['warnings'].append("Cannot import pyproj. Inversions may not work.") |
437 |
|
438 |
######## gdal |
439 |
if not detectModule(env, 'gdal'): |
440 |
env['warnings'].append("Cannot import gdal. Inversions will not honour WKT coordinate system information.") |
441 |
|
442 |
######## sympy |
443 |
if not detectModule(env, 'sympy'): |
444 |
env['warnings'].append("Cannot import sympy. Symbolic toolbox and nonlinear PDEs will not be available.") |
445 |
env.Append(CPPDEFINES = ['ESYS_NO_SYMPY']) |
446 |
else: |
447 |
if env['pythoncmd'] is not None: |
448 |
env=get_external_python_sympy(env, env['pythoncmd']) |
449 |
else: |
450 |
import sympy as sp |
451 |
import distutils.version as duv |
452 |
spVer=sp.__version__ |
453 |
spl=spVer.split('.') |
454 |
if duv.LooseVersion(sympy.__version__) < duv.LooseVersion('0.7'): |
455 |
env['sympy']=False |
456 |
env['warnings'].append("sympy version too old. Symbolic toolbox and nonlinear PDEs will not be available.") |
457 |
env.Append(CPPDEFINES = ['ESYS_NO_SYMPY']) |
458 |
if duv.LooseVersion(sympy.__version__) > duv.LooseVersion('1.2'): |
459 |
env['sympy']=False |
460 |
env['warnings'].append("escript does not support sympy version 1.2 and higher. Found %d" % duv.LooseVersion(sympy.__version__)) |
461 |
env.Append(CPPDEFINES = ['ESYS_NO_SYMPY']) |
462 |
|
463 |
######## gmshpy |
464 |
env['gmshpy'] = detectModule(env, 'gmshpy') |
465 |
|
466 |
return env |
467 |
|
468 |
def checkForTrilinos(env): |
469 |
trilinos_inc_path='' |
470 |
trilinos_lib_path='' |
471 |
if env['trilinos']: |
472 |
havelibs = (len(env['trilinos_libs']) > 0) |
473 |
trilinos_inc_path,trilinos_lib_path=findLibWithHeader(env, |
474 |
env['trilinos_libs'], 'Amesos2.hpp', |
475 |
env['trilinos_prefix'], lang='c++', try_link=havelibs) |
476 |
env.AppendUnique(CPPPATH = [trilinos_inc_path]) |
477 |
env.AppendUnique(LIBPATH = [trilinos_lib_path]) |
478 |
env.PrependENVPath(env['LD_LIBRARY_PATH_KEY'], trilinos_lib_path) |
479 |
env['buildvars']['trilinos_inc_path']=trilinos_inc_path |
480 |
env['buildvars']['trilinos_lib_path']=trilinos_lib_path |
481 |
conf = Configure(env.Clone()) |
482 |
|
483 |
dependencies=['Amesos2.hpp','Amesos2_Solver_decl.hpp','BelosSolverFactory.hpp','BelosSolverManager.hpp',\ |
484 |
'BelosTFQMRIter.hpp','BelosTFQMRSolMgr.hpp','BelosTpetraAdapter.hpp','BelosTypes.hpp',\ |
485 |
'Ifpack2_Factory.hpp','Kokkos_DefaultNode.hpp',\ |
486 |
'MatrixMarket_Tpetra.hpp','MueLu_CreateTpetraPreconditioner.hpp',\ |
487 |
'Teuchos_DefaultComm.hpp','Teuchos_ParameterList.hpp',\ |
488 |
'Tpetra_CrsGraph.hpp','Tpetra_CrsMatrix.hpp', 'Tpetra_RowMatrix.hpp',\ |
489 |
'Tpetra_Vector.hpp','Trilinos_version.h'] |
490 |
|
491 |
print("Looking for the Trilinos headers...") |
492 |
for check in dependencies: |
493 |
print("Checking for %s... %s" % (check, "yes" if os.path.isfile(os.path.join(trilinos_inc_path,check)) else "no")) |
494 |
if not os.path.isfile(os.path.join(trilinos_inc_path,check)): |
495 |
print("Could not find a Trilinos header file (tried looking in directory %s)" % (trilinos_inc_path)) |
496 |
env.Exit(1) |
497 |
|
498 |
if os.path.isfile(os.path.join(trilinos_inc_path,'Tpetra_DefaultPlatform.hpp')): |
499 |
print("Checking for %s... %s" % ('Tpetra_DefaultPlatform.hpp', "yes" if os.path.isfile(os.path.join(trilinos_inc_path,'Tpetra_DefaultPlatform.hpp')) else "no")) |
500 |
env.Append(CPPDEFINES = ['ESYS_HAVE_TPETRA_DP']) |
501 |
|
502 |
if os.path.isfile(os.path.join(trilinos_inc_path,'Tpetra_BlockCrsMatrix.hpp')): |
503 |
print("Checking for %s... %s" % ('Tpetra_BlockCrsMatrix.hpp', "yes" if os.path.isfile(os.path.join(trilinos_inc_path,'Tpetra_DefaultPlatform.hpp')) else "no")) |
504 |
elif os.path.isfile(os.path.join(trilinos_inc_path,'Tpetra_Experimental_BlockCrsMatrix.hpp')): |
505 |
print("Checking for %s... %s" % ('Tpetra_Experimental_BlockCrsMatrix.hpp', "yes" if os.path.isfile(os.path.join(trilinos_inc_path,'Tpetra_DefaultPlatform.hpp')) else "no")) |
506 |
env.Append(CPPDEFINES = ['ESYS_HAVE_TPETRA_EXPERIMENTAL_BLOCKCRS']) |
507 |
else: |
508 |
raise RuntimeError('Could not locate the Trilinos Block CRS Matrix header') |
509 |
|
510 |
if os.path.isfile(os.path.join(trilinos_inc_path,'Tpetra_BlockCrsMatrix_Helpers.hpp')): |
511 |
print("Checking for %s... %s" % ('Tpetra_BlockCrsMatrix_Helpers.hpp', "yes" if os.path.isfile(os.path.join(trilinos_inc_path,'Tpetra_DefaultPlatform.hpp')) else "no")) |
512 |
elif os.path.isfile(os.path.join(trilinos_inc_path,'Tpetra_Experimental_BlockCrsMatrix_Helpers.hpp')): |
513 |
print("Checking for %s... %s" % ('Tpetra_Experimental_BlockCrsMatrix_Helpers.hpp', "yes" if os.path.isfile(os.path.join(trilinos_inc_path,'Tpetra_DefaultPlatform.hpp')) else "no")) |
514 |
env.Append(CPPDEFINES = ['ESYS_HAVE_TPETRA_EXPERIMENTAL_BLOCKCRSH']) |
515 |
else: |
516 |
raise RuntimeError('Could not locate the Trilinos Block CRS Matrix Helpers header') |
517 |
|
518 |
if os.path.isfile(os.path.join(trilinos_inc_path,'Tpetra_BlockVector.hpp')): |
519 |
print("Checking for %s... %s" % ('Tpetra_BlockVector.hpp', "yes" if os.path.isfile(os.path.join(trilinos_inc_path,'Tpetra_DefaultPlatform.hpp')) else "no")) |
520 |
elif os.path.isfile(os.path.join(trilinos_inc_path,'Tpetra_Experimental_BlockVector.hpp')): |
521 |
print("Checking for %s... %s" % ('Tpetra_Experimental_BlockVector.hpp', "yes" if os.path.isfile(os.path.join(trilinos_inc_path,'Tpetra_DefaultPlatform.hpp')) else "no")) |
522 |
env.Append(CPPDEFINES = ['ESYS_HAVE_TPETRA_EXPERIMENTAL_BLOCKV']) |
523 |
else: |
524 |
raise RuntimeError('Could not locate the Trilinos BlockVector header') |
525 |
|
526 |
# Try to extract the trilinos version from Trilinos_version.h |
527 |
versionh=open(os.path.join(trilinos_inc_path, 'Trilinos_version.h')) |
528 |
trilinos_version='unknown' |
529 |
env['trilinos_version']='unknown' |
530 |
for line in versionh: |
531 |
ver=re.match(r'#define TRILINOS_MAJOR_MINOR_VERSION (\d+)',line) |
532 |
if ver: |
533 |
trilinos_version=ver.group(1) |
534 |
trilinos_version = int(trilinos_version) |
535 |
major=int(str(trilinos_version)[:2]) |
536 |
minor=int(str(trilinos_version)[2:4]) |
537 |
tmp=int(str(trilinos_version)[4:6]) |
538 |
env['trilinos_version'] = str(major)+"."+str(minor)+"."+str(tmp) |
539 |
|
540 |
if not havelibs: |
541 |
packages=['Tpetra','Kokkos','Belos','Amesos2','Ifpack2','MueLu'] |
542 |
libs = [] |
543 |
for pk in packages: |
544 |
# find out what libraries to link with... |
545 |
makefile = os.path.join(trilinos_inc_path, 'Makefile.export.%s'%pk) |
546 |
try: |
547 |
for l in open(makefile, 'r').readlines(): |
548 |
if l.startswith("%s_LIBRARIES"%pk): # or l.startswith("Trilinos_TPL_LIBRARIES"): |
549 |
lst = l.split('=')[1].strip().split() |
550 |
lst = [e.replace('-l','',1) for e in lst] |
551 |
libs += lst |
552 |
elif l.startswith("%s_TPL_INCLUDE_DIRS"%pk): |
553 |
lst = l.split('=')[1].strip().split() |
554 |
lst = [e.replace('-I','',1) for e in lst] |
555 |
env.AppendUnique(CPPPATH = lst) |
556 |
|
557 |
except Exception as e: |
558 |
raise RuntimeError('Error reading Trilinos export Makefile\n%s'%(e)) |
559 |
env['trilinos_libs'] = libs |
560 |
|
561 |
env.Append(CPPDEFINES = ['ESYS_HAVE_TRILINOS']) |
562 |
# env.PrependENVPath(env['LD_LIBRARY_PATH_KEY'], trilinos_lib_path) |
563 |
# env['buildvars']['trilinos_inc_path']=trilinos_inc_path |
564 |
# env['buildvars']['trilinos_lib_path']=trilinos_lib_path |
565 |
env['buildvars']['trilinos']=int(env['trilinos']) |
566 |
return env |
567 |
|
568 |
def checkOptionalLibraries(env): |
569 |
######## netCDF |
570 |
netcdf_inc_path='' |
571 |
netcdf_lib_path='' |
572 |
if env['netcdf']: |
573 |
if env['netcdf']==4: |
574 |
env.Append(CPPDEFINES = ['NETCDF4']) |
575 |
netcdf_inc_path,netcdf_lib_path=findLibWithHeader(env, env['netcdf_libs'], 'ncVar.h', env['netcdf_prefix'], lang='c++') |
576 |
else: |
577 |
netcdf_inc_path,netcdf_lib_path=findLibWithHeader(env, env['netcdf_libs'], 'netcdfcpp.h', env['netcdf_prefix'], lang='c++') |
578 |
env.AppendUnique(CPPPATH = [netcdf_inc_path]) |
579 |
env.AppendUnique(LIBPATH = [netcdf_lib_path]) |
580 |
env.PrependENVPath(env['LD_LIBRARY_PATH_KEY'], netcdf_lib_path) |
581 |
env.Append(CPPDEFINES = ['ESYS_HAVE_NETCDF']) |
582 |
env['buildvars']['netcdf_inc_path']=netcdf_inc_path |
583 |
env['buildvars']['netcdf_lib_path']=netcdf_lib_path |
584 |
env['buildvars']['netcdf']=int(env['netcdf']) |
585 |
|
586 |
######## MKL |
587 |
mkl_inc_path='' |
588 |
mkl_lib_path='' |
589 |
if env['mkl']: |
590 |
mkl_inc_path,mkl_lib_path=findLibWithHeader(env, env['mkl_libs'], 'mkl_pardiso.h', env['mkl_prefix'], lang='c++') |
591 |
env.AppendUnique(CPPPATH = [mkl_inc_path]) |
592 |
env.AppendUnique(LIBPATH = [mkl_lib_path]) |
593 |
env.PrependENVPath(env['LD_LIBRARY_PATH_KEY'], mkl_lib_path) |
594 |
env.Append(CPPDEFINES = ['ESYS_HAVE_MKL']) |
595 |
env['buildvars']['mkl_inc_path']=mkl_inc_path |
596 |
env['buildvars']['mkl_lib_path']=mkl_lib_path |
597 |
env['buildvars']['mkl']=int(env['mkl']) |
598 |
|
599 |
######## UMFPACK |
600 |
umfpack_inc_path='' |
601 |
umfpack_lib_path='' |
602 |
if env['umfpack']: |
603 |
umfpack_inc_path,umfpack_lib_path=findLibWithHeader(env, env['umfpack_libs'], 'umfpack.h', env['umfpack_prefix'], lang='c++') |
604 |
env.AppendUnique(CPPPATH = [umfpack_inc_path]) |
605 |
env.AppendUnique(LIBPATH = [umfpack_lib_path]) |
606 |
env.PrependENVPath(env['LD_LIBRARY_PATH_KEY'], umfpack_lib_path) |
607 |
env.Append(CPPDEFINES = ['ESYS_HAVE_UMFPACK']) |
608 |
env['buildvars']['umfpack_inc_path']=umfpack_inc_path |
609 |
env['buildvars']['umfpack_lib_path']=umfpack_lib_path |
610 |
env['buildvars']['umfpack']=int(env['umfpack']) |
611 |
|
612 |
######## MUMPS |
613 |
mumps_inc_path='' |
614 |
mumps_lib_path='' |
615 |
if env['mumps']: |
616 |
mumps_inc_path,mumps_lib_path=findLibWithHeader(env, env['mumps_libs'], 'mumps_mpi.h', env['mumps_prefix'], lang='c++') |
617 |
env.AppendUnique(CPPPATH = [mumps_inc_path]) |
618 |
env.AppendUnique(LIBPATH = [mumps_lib_path]) |
619 |
env.PrependENVPath(env['LD_LIBRARY_PATH_KEY'], mumps_lib_path) |
620 |
env.Append(CPPDEFINES = ['ESYS_HAVE_MUMPS']) |
621 |
env['buildvars']['mumps_inc_path']=mumps_inc_path |
622 |
env['buildvars']['mumps_lib_path']=mumps_lib_path |
623 |
env['buildvars']['mumps']=int(env['mumps']) |
624 |
|
625 |
######## LAPACK |
626 |
lapack_inc_path='' |
627 |
lapack_lib_path='' |
628 |
flavour = 'none' |
629 |
env['uselapack'] = False |
630 |
if env['lapack'] != 0: |
631 |
# not explicitly disabled so run the checks |
632 |
if env['longindices']: |
633 |
# you want longindices + lapack? sorry. |
634 |
if env['lapack'] == 1: |
635 |
print("LAPACK requires index type = int. Set longindices to False or disable LAPACK.") |
636 |
env.Exit(1) |
637 |
else: |
638 |
if env['mkl']: |
639 |
# we detected MKL so try the MKL header+libs |
640 |
flavour = 'mkl' |
641 |
header = 'mkl_lapack.h' |
642 |
prefix = env['mkl_prefix'] |
643 |
if len(env['lapack_libs']) == 0: |
644 |
libs = env['mkl_libs'] |
645 |
else: |
646 |
libs = env['lapack_libs'] |
647 |
else: |
648 |
# try for clapack |
649 |
flavour = 'clapack' |
650 |
header = 'clapack.h' |
651 |
prefix = env['lapack_prefix'] |
652 |
if len(env['lapack_libs']) == 0: |
653 |
libs = ['lapack_atlas'] |
654 |
else: |
655 |
libs = env['lapack_libs'] |
656 |
|
657 |
try: |
658 |
lapack_inc_path,lapack_lib_path=findLibWithHeader(env, libs, header, prefix, lang='c++') |
659 |
env['lapack_libs'] = libs |
660 |
env['uselapack'] = True |
661 |
env.AppendUnique(CPPPATH = [lapack_inc_path]) |
662 |
env.AppendUnique(LIBPATH = [lapack_lib_path]) |
663 |
env.Append(CPPDEFINES = ['ESYS_HAVE_LAPACK']) |
664 |
if flavour == 'mkl': |
665 |
env.AppendUnique(CPPDEFINES = ['ESYS_MKL_LAPACK']) |
666 |
env['buildvars']['lapack_inc_path']=lapack_inc_path |
667 |
env['buildvars']['lapack_lib_path']=lapack_lib_path |
668 |
except: |
669 |
if env['lapack'] == 1: |
670 |
raise |
671 |
# lapack was set to auto-detect so not a fatal error |
672 |
flavour = 'none' |
673 |
|
674 |
env['lapack'] = flavour |
675 |
env['buildvars']['lapack'] = flavour |
676 |
|
677 |
######## Silo |
678 |
silo_inc_path='' |
679 |
silo_lib_path='' |
680 |
if env['silo']: |
681 |
silo_inc_path,silo_lib_path=findLibWithHeader(env, env['silo_libs'], 'silo.h', env['silo_prefix'], lang='c++') |
682 |
env.AppendUnique(CPPPATH = [silo_inc_path]) |
683 |
env.AppendUnique(LIBPATH = [silo_lib_path]) |
684 |
env.Append(CPPDEFINES = ['ESYS_HAVE_SILO']) |
685 |
env['buildvars']['silo_inc_path']=silo_inc_path |
686 |
env['buildvars']['silo_lib_path']=silo_lib_path |
687 |
env['buildvars']['silo']=int(env['silo']) |
688 |
|
689 |
######## VisIt |
690 |
visit_inc_path='' |
691 |
visit_lib_path='' |
692 |
if env['visit']: |
693 |
visit_inc_path,visit_lib_path=findLibWithHeader(env, env['visit_libs'], 'VisItControlInterface_V2.h', env['visit_prefix'], lang='c++') |
694 |
env.AppendUnique(CPPPATH = [visit_inc_path]) |
695 |
env.AppendUnique(LIBPATH = [visit_lib_path]) |
696 |
env['buildvars']['visit_inc_path']=visit_inc_path |
697 |
env['buildvars']['visit_lib_path']=visit_lib_path |
698 |
env['buildvars']['visit']=int(env['visit']) |
699 |
|
700 |
######## MPI |
701 |
if env['mpi']=='no': |
702 |
env['mpi']='none' |
703 |
|
704 |
env['usempi'] = env['mpi']!='none' |
705 |
mpi_inc_path='' |
706 |
mpi_lib_path='' |
707 |
if env['usempi']: |
708 |
mpi_inc_path,mpi_lib_path=findLibWithHeader(env, env['mpi_libs'], 'mpi.h', env['mpi_prefix'], lang='c++') |
709 |
env.AppendUnique(CPPPATH = [mpi_inc_path]) |
710 |
env.AppendUnique(LIBPATH = [mpi_lib_path]) |
711 |
env.AppendUnique(LIBS = env['mpi_libs']) |
712 |
env.PrependENVPath(env['LD_LIBRARY_PATH_KEY'], mpi_lib_path) |
713 |
env.Append(CPPDEFINES = ['ESYS_MPI', 'MPI_NO_CPPBIND', 'MPICH_IGNORE_CXX_SEEK']) |
714 |
# NetCDF 4.1 defines MPI_Comm et al. if MPI_INCLUDED is not defined! |
715 |
# On the other hand MPT and OpenMPI don't define the latter so we have |
716 |
# to do that here |
717 |
if env['netcdf'] and env['mpi'] in ['MPT','OPENMPI']: |
718 |
env.Append(CPPDEFINES = ['MPI_INCLUDED']) |
719 |
|
720 |
if env['mpi'] == 'OPENMPI': |
721 |
# try to get version for correct launcher arguments |
722 |
try: |
723 |
p = Popen(['orterun', '-V'], stdout=PIPE, stderr=PIPE) |
724 |
o,e = p.communicate() |
725 |
try: |
726 |
e=e.decode() |
727 |
ver = e.split('\n')[0].split()[-1] |
728 |
except IndexError: |
729 |
o=o.decode() |
730 |
ver = o.split('\n')[0].split()[-1] |
731 |
if len(ver) > 0: |
732 |
env['orte_version'] = ver |
733 |
except OSError: |
734 |
pass |
735 |
|
736 |
env['buildvars']['mpi_inc_path']=mpi_inc_path |
737 |
env['buildvars']['mpi_lib_path']=mpi_lib_path |
738 |
env['buildvars']['mpi']=env['mpi'] |
739 |
|
740 |
######## ParMETIS |
741 |
if not env['usempi']: env['parmetis'] = False |
742 |
parmetis_inc_path='' |
743 |
parmetis_lib_path='' |
744 |
if env['parmetis']: |
745 |
parmetis_inc_path,parmetis_lib_path=findLibWithHeader(env, env['parmetis_libs'], 'parmetis.h', env['parmetis_prefix'], lang='c++') |
746 |
env.AppendUnique(CPPPATH = [parmetis_inc_path]) |
747 |
env.AppendUnique(LIBPATH = [parmetis_lib_path]) |
748 |
env.PrependENVPath(env['LD_LIBRARY_PATH_KEY'], parmetis_lib_path) |
749 |
|
750 |
# Try to extract the parmetis version from parmetis.h |
751 |
header=open(os.path.join(parmetis_inc_path, 'parmetis.h')).readlines() |
752 |
major,minor,sub = None,None,None |
753 |
for line in header: |
754 |
ver=re.match(r'#define PARMETIS_MAJOR_VERSION\s*(\d+)',line) |
755 |
if ver: |
756 |
major = int(ver.group(1)) |
757 |
continue |
758 |
ver=re.match(r'#define PARMETIS_MINOR_VERSION\s*(\d+)',line) |
759 |
if ver: |
760 |
minor = int(ver.group(1)) |
761 |
continue |
762 |
ver=re.match(r'#define PARMETIS_SUBMINOR_VERSION\s*(\d+)',line) |
763 |
if ver: |
764 |
sub = int(ver.group(1)) |
765 |
continue |
766 |
if major is not None: |
767 |
env['parmetis_version'] = "%d.%d.%d"%(major,minor,0 if sub is None else sub) |
768 |
if env['longindices']: |
769 |
# ParMETIS version 3.x does not support 64-bit indices |
770 |
if major < 4: |
771 |
print("Sorry, cannot use ParMETIS version < 4.0 with 64-bit index types. Set longindices to False or disable ParMETIS.") |
772 |
env.Exit(1) |
773 |
else: |
774 |
# check if ParMETIS was built with 64-bit indices |
775 |
conf = Configure(env.Clone()) |
776 |
idxsize=conf.CheckTypeSize('idx_t', '#include <parmetis.h>', 'C++') |
777 |
if idxsize != 8: |
778 |
print("Sorry, ParMETIS was not compiled with 64-bit indices. Set longindices to False or disable/rebuild ParMETIS.") |
779 |
env.Exit(1) |
780 |
else: |
781 |
env['parmetis_version'] = "unknown" |
782 |
|
783 |
env.Append(CPPDEFINES = ['ESYS_HAVE_PARMETIS']) |
784 |
env['buildvars']['parmetis_inc_path']=parmetis_inc_path |
785 |
env['buildvars']['parmetis_lib_path']=parmetis_lib_path |
786 |
env['buildvars']['parmetis']=int(env['parmetis']) |
787 |
|
788 |
######## gmsh (for tests) |
789 |
env['gmsh'] = False |
790 |
if env['use_gmsh'] is True: |
791 |
if env['IS_WINDOWS']: |
792 |
try: |
793 |
p=Popen(['gmsh', '-info'], stderr=PIPE) |
794 |
_,e=p.communicate() |
795 |
env.Append(CPPDEFINES=['ESYS_HAVE_GMSH']) |
796 |
if e.split().count("MPI"): |
797 |
env['gmsh']='m' |
798 |
env.Append(CPPDEFINES=['ESYS_GMSH_MPI']) |
799 |
else: |
800 |
env['gmsh']='s' |
801 |
except OSError: |
802 |
pass |
803 |
else: |
804 |
which = Popen(['which', 'gmsh'], stdout=PIPE) |
805 |
path,_ = which.communicate() |
806 |
if which.wait() == 0: |
807 |
cmd = ['ldd', path[:-1]] |
808 |
if env['IS_OSX']: |
809 |
cmd = ['otool','-L', path[:-1]] |
810 |
try: |
811 |
p=Popen(cmd, stdout=PIPE) |
812 |
gmshlibs,_ = p.communicate() |
813 |
gmshlibs.decode() |
814 |
env.Append(CPPDEFINES=['ESYS_HAVE_GMSH']) |
815 |
if p.returncode == 0 and 'libmpi' in gmshlibs.decode('utf-8'): |
816 |
env['gmsh'] = 'm' |
817 |
env.Append(CPPDEFINES=['ESYS_GMSH_MPI']) |
818 |
else: |
819 |
env['gmsh'] = 's' |
820 |
except OSError: |
821 |
pass |
822 |
|
823 |
######## boost::iostreams |
824 |
if env['compressed_files']: |
825 |
try: |
826 |
boost_inc_path, boost_lib_path = findLibWithHeader(env, env['compression_libs'], 'boost/iostreams/filter/gzip.hpp', env['boost_prefix'], lang='c++') |
827 |
env.Append(CPPDEFINES = ['ESYS_HAVE_BOOST_IO']) |
828 |
except RuntimeError as e: |
829 |
env['compressed_files'] = False |
830 |
env['buildvars']['compressed_files']=int(env['compressed_files']) |
831 |
|
832 |
######## Trilinos |
833 |
env = checkForTrilinos(env) |
834 |
return env |
835 |
|
836 |
def checkPDFLatex(env): |
837 |
if 'PDF' in dir(env) and '.tex' in env.PDF.builder.src_suffixes(env): |
838 |
env['pdflatex']=True |
839 |
else: |
840 |
env['pdflatex']=False |
841 |
return env |