/[escript]/trunk/SConstruct
ViewVC logotype

Contents of /trunk/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7027 - (show annotations)
Fri Aug 7 05:26:26 2020 UTC (5 days, 16 hours ago) by uqaeller
File size: 34493 byte(s)
Merged in most of Mark's work
1 ##############################################################################
2 #
3 # Copyright (c) 2003-2018 by The University of Queensland
4 # http://www.uq.edu.au
5 #
6 # Primary Business: Queensland, Australia
7 # Licensed under the Apache License, version 2.0
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Development until 2012 by Earth Systems Science Computational Center (ESSCC)
11 # Development 2012-2013 by School of Earth Sciences
12 # Development from 2014 by Centre for Geoscience Computing (GeoComp)
13 #
14 ##############################################################################
15
16 EnsureSConsVersion(0,98,1)
17 EnsurePythonVersion(2,5)
18
19 import atexit, sys, os, platform, re
20 from distutils import sysconfig
21 from dependencies import *
22 from site_init import *
23
24 print(sys.version)
25
26 # Version number to check for in options file. Increment when new features are
27 # added or existing options changed.
28 REQUIRED_OPTS_VERSION=203
29
30 # MS Windows support, many thanks to PH
31 IS_WINDOWS = (os.name == 'nt')
32
33 if IS_WINDOWS:
34 IS_OSX = False
35 else:
36 IS_OSX = (os.uname()[0] == 'Darwin')
37
38 ########################## Determine options file ############################
39 # 1. command line
40 # 2. scons/<hostname>_options.py
41 # 3. name as part of a cluster
42 options_file=ARGUMENTS.get('options_file', None)
43 if not options_file:
44 ext_dir = os.path.join(os.getcwd(), 'scons')
45 hostname = platform.node().split('.')[0]
46 for name in hostname, effectiveName(hostname):
47 mangledhostname = re.sub('[^0-9a-zA-Z]', '_', hostname)
48 options_file = os.path.join(ext_dir, mangledhostname+'_options.py')
49 if os.path.isfile(options_file): break
50
51 if not os.path.isfile(options_file):
52 print("\nWARNING:\nOptions file %s" % options_file)
53 print("not found! Default options will be used which is most likely suboptimal.")
54 print("We recommend that you copy the most relavent options file in the scons/template/")
55 print("subdirectory and customize it to your needs.\n")
56 options_file = None
57
58 ############################### Build options ################################
59
60 default_prefix='/usr'
61 mpi_flavours=('no', 'none', 'MPT', 'MPICH', 'MPICH2', 'OPENMPI', 'INTELMPI')
62 netcdf_flavours = ('no', 'off', 'none', 'False', # Must be last of the false alternatives
63 'yes', 'on', 'True', '3', # Must be last of the version 3 alternatives
64 '4')
65 all_domains = ['dudley','finley','ripley','speckley']
66
67 #Note that scons construction vars the the following purposes:
68 # CPPFLAGS -> to the preprocessor
69 # CCFLAGS -> flags for _both_ C and C++
70 # CXXFLAGS -> flags for c++ _only_
71 # CFLAGS -> flags for c only
72
73 vars = Variables(options_file, ARGUMENTS)
74 vars.AddVariables(
75 PathVariable('options_file', 'Path to options file', options_file, PathVariable.PathIsFile),
76 PathVariable('prefix', 'Installation prefix', Dir('#.').abspath, PathVariable.PathIsDirCreate),
77 PathVariable('build_dir', 'Top-level build directory', Dir('#/build').abspath, PathVariable.PathIsDirCreate),
78 BoolVariable('verbose', 'Output full compile/link lines', False),
79 # Compiler/Linker options
80 ('cxx', 'Path to C++ compiler', 'default'),
81 ('cc_flags', 'Base (C and C++) compiler flags', 'default'),
82 ('cc_optim', 'Additional (C and C++) flags for a non-debug build', 'default'),
83 ('cc_debug', 'Additional (C and C++) flags for a debug build', 'default'),
84 ('cxx_extra', 'Extra C++ compiler flags', ''),
85 ('ld_extra', 'Extra linker flags', ''),
86 BoolVariable('werror','Treat compiler warnings as errors', True),
87 BoolVariable('debug', 'Compile with debug flags', False),
88 BoolVariable('openmp', 'Compile parallel version using OpenMP', False),
89 ('omp_flags', 'OpenMP compiler flags', 'default'),
90 ('omp_ldflags', 'OpenMP linker flags', 'default'),
91 # Mandatory libraries
92 ('boost_prefix', 'Prefix/Paths of boost installation', default_prefix),
93 ('boost_libs', 'Boost libraries to link with', ['boost_python-mt']),
94 # Mandatory for tests
95 ('cppunit_prefix', 'Prefix/Paths of CppUnit installation', default_prefix),
96 ('cppunit_libs', 'CppUnit libraries to link with', ['cppunit']),
97 # Optional libraries and options
98 EnumVariable('mpi', 'Compile parallel version using MPI flavour', 'none', allowed_values=mpi_flavours),
99 ('mpi_prefix', 'Prefix/Paths of MPI installation', default_prefix),
100 ('mpi_libs', 'MPI shared libraries to link with', ['mpi']),
101 BoolVariable('use_gmsh', 'Enable gmsh, if available', True),
102 EnumVariable('netcdf', 'Enable netCDF file support', False, allowed_values=netcdf_flavours),
103 ('netcdf_prefix', 'Prefix/Paths of netCDF installation', default_prefix),
104 ('netcdf_libs', 'netCDF libraries to link with', 'DEFAULT'),
105 BoolVariable('parmetis', 'Enable ParMETIS (requires MPI)', False),
106 ('parmetis_prefix', 'Prefix/Paths of ParMETIS installation', default_prefix),
107 ('parmetis_libs', 'ParMETIS libraries to link with', ['parmetis', 'metis']),
108 BoolVariable('mkl', 'Enable the Math Kernel Library', False),
109 ('mkl_prefix', 'Prefix/Paths to MKL installation', default_prefix),
110 ('mkl_libs', 'MKL libraries to link with', ['mkl_solver','mkl_em64t','guide','pthread']),
111 BoolVariable('umfpack', 'Enable UMFPACK', False),
112 ('umfpack_prefix', 'Prefix/Paths to UMFPACK installation', default_prefix),
113 ('umfpack_libs', 'UMFPACK libraries to link with', ['umfpack']),
114 BoolVariable('mumps', 'Enable MUMPS', False),
115 ('mumps_prefix', 'Prefix/Paths to MUMPS installation', default_prefix),
116 ('mumps_libs', 'MUMPS libraries to link with', ['mumps_common','pord','dmumps','zmumps',
117 'mpiseq','lapack','metis','scotch','esmumps','gfortran']),
118 TristateVariable('lapack', 'Enable LAPACK', 'auto'),
119 ('lapack_prefix', 'Prefix/Paths to LAPACK installation', default_prefix),
120 ('lapack_libs', 'LAPACK libraries to link with', []),
121 BoolVariable('silo', 'Enable the Silo file format in weipa', False),
122 ('silo_prefix', 'Prefix/Paths to Silo installation', default_prefix),
123 ('silo_libs', 'Silo libraries to link with', ['siloh5', 'hdf5']),
124 BoolVariable('trilinos', 'Enable the Trilinos solvers', False),
125 ('trilinos_prefix', 'Prefix/Paths to Trilinos installation', default_prefix),
126 ('trilinos_libs', 'Trilinos libraries to link with', []),
127 BoolVariable('visit', 'Enable the VisIt simulation interface', False),
128 ('visit_prefix', 'Prefix/Paths to VisIt installation', default_prefix),
129 ('visit_libs', 'VisIt libraries to link with', ['simV2']),
130 ListVariable('domains', 'Which domains to build', 'all', all_domains),
131 BoolVariable('paso', 'Build Paso solver library', True),
132 BoolVariable('weipa', 'Build Weipa data export library', True),
133 ('mathjax_path', 'Path to MathJax.js file', 'default'),
134 # Advanced settings
135 ('launcher', 'Launcher command (e.g. mpirun)', 'default'),
136 ('prelaunch', 'Command to execute before launcher (e.g. mpdboot)', 'default'),
137 ('postlaunch', 'Command to execute after launcher (e.g. mpdexit)', 'default'),
138 #dudley_assemble_flags = -funroll-loops to actually do something
139 ('dudley_assemble_flags', 'compiler flags for some dudley optimisations', ''),
140 # To enable passing function pointers through python
141 BoolVariable('iknowwhatimdoing', 'Allow non-standard C', False),
142 # An option for specifying the compiler tools
143 ('tools_names', 'Compiler tools to use', ['default']),
144 ('env_export', 'Environment variables to be passed to tools',[]),
145 TristateVariable('forcelazy', 'For testing use only - set the default value for autolazy', 'auto'),
146 TristateVariable('forcecollres', 'For testing use only - set the default value for force resolving collective ops', 'auto'),
147 BoolVariable('build_shared', '(deprecated option, ignored)', True),
148 ('sys_libs', 'Extra libraries to link with', []),
149 ('escript_opts_version', 'Version of options file (do not specify on command line)'),
150 ('SVN_VERSION', 'Do not use from options file', -2),
151 ('pythoncmd', 'which python to compile with', sys.executable),
152 ('pythonlibname', 'Name of the python library to link. (This is found automatically for python2.X.)', ''),
153 ('pythonlibpath', 'Path to the python library. (You should not need to set this unless your python has moved)',''),
154 ('pythonincpath','Path to python include files. (You should not need to set this unless your python has moved',''),
155 BoolVariable('longindices', 'use long indices (for very large matrices)', False),
156 BoolVariable('compressed_files','Enables reading from compressed binary files', True),
157 ('compression_libs', 'Compression libraries to link with', ['boost_iostreams']),
158 BoolVariable('disable_boost_numpy', 'Do not build using boost_numpy, even if it is available', False),
159 BoolVariable('osx_dependency_fix', 'Fix dependencies for libraries to have absolute paths (OSX)', False),
160 BoolVariable('stdlocationisprefix', 'Set the prefix as escript root in the launcher', False),
161 BoolVariable('mpi_no_host', 'Do not specify --host in run-escript launcher (only OPENMPI)', False),
162 BoolVariable('insane', 'Instructs scons to not run a sanity check after compilation.', False)
163 )
164
165 ##################### Create environment and help text #######################
166
167 # Intel's compiler uses regular expressions improperly and emits a warning
168 # about failing to find the compilers. This warning can be safely ignored.
169
170 # PATH is needed so the compiler, linker and tools are found if they are not
171 # in default locations.
172 env = Environment(tools = ['default'], options = vars,
173 ENV = {'PATH': os.environ['PATH']})
174
175 # set the vars for clang
176 def mkclang(env):
177 env['CXX']='clang++'
178
179 if env['tools_names'] != ['default']:
180 zz=env['tools_names']
181 if 'clang' in zz:
182 zz.remove('clang')
183 zz.insert(0, mkclang)
184 env = Environment(tools = ['default'] + env['tools_names'], options = vars,
185 ENV = {'PATH' : os.environ['PATH']})
186
187 # Covert env['netcdf'] into one of False, 3, 4
188 # Also choose default values for libraries
189 pos1=netcdf_flavours.index('False')
190 pos2=netcdf_flavours.index('3')
191 mypos=netcdf_flavours.index(env['netcdf'])
192 if 0 <= mypos <=pos1:
193 env['netcdf']=0
194 elif pos1 < mypos <= pos2:
195 env['netcdf']=3
196 if env['netcdf_libs']=='DEFAULT':
197 env['netcdf_libs']=['netcdf_c++', 'netcdf']
198 else: # netcdf4
199 env['netcdf']=4
200 if env['netcdf_libs']=='DEFAULT':
201 env['netcdf_libs']=['netcdf_c++4']
202
203 if options_file:
204 opts_valid=False
205 if 'escript_opts_version' in env.Dictionary() and \
206 int(env['escript_opts_version']) >= REQUIRED_OPTS_VERSION:
207 opts_valid=True
208 if opts_valid:
209 print("Using options in %s." % options_file)
210 else:
211 print("\nOptions file %s" % options_file)
212 print("is outdated! Please update the file after reading scons/templates/README_FIRST")
213 print("and setting escript_opts_version to %d.\n"%REQUIRED_OPTS_VERSION)
214 Exit(1)
215
216 # Generate help text (scons -h)
217 Help(vars.GenerateHelpText(env))
218
219 # Check for superfluous options
220 if len(vars.UnknownVariables())>0:
221 for k in vars.UnknownVariables():
222 print("Unknown option '%s'" % k)
223 Exit(1)
224
225 if 'dudley' in env['domains']:
226 env['domains'].append('finley')
227
228 env['domains'] = sorted(set(env['domains']))
229
230 # create dictionary which will be populated with info for buildvars file
231 env['buildvars'] = {}
232 # create list which will be populated with warnings if there are any
233 env['warnings'] = []
234
235 #################### Make sure install directories exist #####################
236
237 env['BUILD_DIR'] = Dir(env['build_dir']).abspath
238 prefix = Dir(env['prefix']).abspath
239 env['buildvars']['prefix'] = prefix
240 env['incinstall'] = os.path.join(prefix, 'include')
241 env['bininstall'] = os.path.join(prefix, 'bin')
242 env['libinstall'] = os.path.join(prefix, 'lib')
243 env['pyinstall'] = os.path.join(prefix, 'esys')
244 if not os.path.isdir(env['bininstall']):
245 os.makedirs(env['bininstall'])
246 if not os.path.isdir(env['libinstall']):
247 os.makedirs(env['libinstall'])
248 if not os.path.isdir(env['pyinstall']):
249 os.makedirs(env['pyinstall'])
250
251 env.Append(CPPPATH = [env['incinstall']])
252 env.Append(LIBPATH = [env['libinstall']])
253
254 ################# Fill in compiler options if not set above ##################
255
256 if env['cxx'] != 'default':
257 env['CXX'] = env['cxx']
258
259 # default compiler/linker options
260 cc_flags = '-std=c++11'
261 cc_optim = ''
262 cc_debug = ''
263 omp_flags = ''
264 omp_ldflags = ''
265 fatalwarning = '' # switch to turn warnings into errors
266 sysheaderopt = '' # how to indicate that a header is a system header
267
268 # env['CC'] might be a full path
269 cc_name=os.path.basename(env['CXX'])
270
271 if cc_name == 'icpc':
272 # Intel compiler
273 # #1478: class "std::auto_ptr<...>" was declared deprecated
274 # #1875: offsetof applied to non-POD types is nonstandard (in boost)
275 # removed -std=c99 because icpc doesn't like it and we aren't using c anymore
276 cc_flags = "-std=c++11 -fPIC -w2 -wd1875 -wd1478 -Wno-unknown-pragmas"
277 cc_optim = "-Ofast -ftz -fno-alias -xCORE-AVX2 -ipo"
278 #cc_optim = "-Ofast -ftz -fno-alias -inline-level=2 -ipo -xCORE-AVX2"
279 #cc_optim = "-O2 -ftz -fno-alias -inline-level=2"
280 #cc_optim = "-O0 -ftz -fno-alias"
281 #cc_optim = "-O3 -ftz -fno-alias -inline-level=2 -ipo -xHost"
282 cc_debug = "-g -O0 -DDOASSERT -DDOPROF -DBOUNDS_CHECK -DSLOWSHARECHECK"
283 omp_flags = "-qopenmp"
284 omp_ldflags = "-qopenmp" # removing -openmp-report (which is deprecated) because the replacement outputs to a file
285 fatalwarning = "-Werror"
286 elif cc_name[:3] == 'g++':
287 # GNU C++ on any system
288 # note that -ffast-math is not used because it breaks isnan(),
289 # see mantis #691
290 cc_flags = "-std=c++11 -pedantic -Wall -fPIC -finline-functions"
291 cc_flags += " -Wno-unknown-pragmas -Wno-sign-compare -Wno-system-headers -Wno-long-long -Wno-strict-aliasing "
292 cc_flags += " -Wno-unused-function"
293 cc_flags += " -Wno-stringop-truncation -Wno-deprecated-declarations --param=max-vartrack-size=100000000"
294 cc_optim = "-O3"
295 #max-vartrack-size: avoid vartrack limit being exceeded with escriptcpp.cpp
296 cc_debug = "-g3 -O0 -DDOASSERT -DDOPROF -DBOUNDS_CHECK -DSLOWSHARECHECK --param=max-vartrack-size=100000000"
297 #Removed because new netcdf doesn't seem to like it
298 #cc_debug += ' -D_GLIBCXX_DEBUG '
299 omp_flags = "-fopenmp"
300 omp_ldflags = "-fopenmp"
301 fatalwarning = "-Werror"
302 sysheaderopt = "-isystem"
303 elif cc_name == 'cl':
304 # Microsoft Visual C on Windows
305 cc_flags = "/EHsc /MD /GR /wd4068 /D_USE_MATH_DEFINES /DDLL_NETCDF"
306 cc_optim = "/O2 /Op /W3"
307 cc_debug = "/Od /RTCcsu /ZI /DBOUNDS_CHECK"
308 fatalwarning = "/WX"
309 elif cc_name == 'icl':
310 # Intel C on Windows
311 cc_flags = '/EHsc /GR /MD'
312 cc_optim = '/fast /Oi /W3 /Qssp /Qinline-factor- /Qinline-min-size=0 /Qunroll'
313 cc_debug = '/Od /RTCcsu /Zi /Y- /debug:all /Qtrapuv'
314 omp_flags = '/Qvec-report0 /Qopenmp /Qopenmp-report0 /Qparallel'
315 omp_ldflags = '/Qvec-report0 /Qopenmp /Qopenmp-report0 /Qparallel'
316 elif cc_name == 'clang++':
317 # Clang++ on any system
318 cc_flags = "-std=c++11 -Wall -fPIC -fdiagnostics-color=always -Wno-uninitialized "
319 cc_flags += "-Wno-unused-private-field -Wno-unknown-pragmas "
320 if env['trilinos'] is True:
321 cc_flags += "-Wno-unused-variable -Wno-exceptions -Wno-deprecated-declarations"
322 cc_optim = "-O3"
323 cc_debug = "-ggdb3 -O0 -fdiagnostics-fixit-info -pedantic "
324 cc_debug += "-DDOASSERT -DDOPROF -DBOUNDS_CHECK -DSLOWSHARECHECK "
325 omp_flags = "-fopenmp"
326 omp_ldflags = "-fopenmp"
327 fatalwarning = "-Werror"
328 sysheaderopt = "-isystem"
329
330 env['sysheaderopt']=sysheaderopt
331
332 # set defaults if not otherwise specified
333 if env['cc_flags'] == 'default': env['cc_flags'] = cc_flags
334 if env['cc_optim'] == 'default': env['cc_optim'] = cc_optim
335 if env['cc_debug'] == 'default': env['cc_debug'] = cc_debug
336 if env['omp_flags'] == 'default': env['omp_flags'] = omp_flags
337 if env['omp_ldflags'] == 'default': env['omp_ldflags'] = omp_ldflags
338 if env['cxx_extra'] != '': env.Append(CXXFLAGS = env['cxx_extra'])
339 if env['ld_extra'] != '': env.Append(LINKFLAGS = env['ld_extra'])
340
341 if env['longindices']:
342 if env['paso']:
343 env.Append(CPPDEFINES = ['ESYS_INDEXTYPE_LONG'])
344 else:
345 env['warnings'].append("The longindices feature requires paso!")
346
347 # set up the autolazy values
348 if env['forcelazy'] == 1:
349 env.Append(CPPDEFINES=['FAUTOLAZYON'])
350 elif env['forcelazy'] == 0:
351 env.Append(CPPDEFINES=['FAUTOLAZYOFF'])
352
353 # set up the collective resolve values
354 if env['forcecollres'] == 1:
355 env.Append(CPPDEFINES=['FRESCOLLECTON'])
356 elif env['forcecollres'] == 0:
357 env.Append(CPPDEFINES=['FRESCOLLECTOFF'])
358
359 # allow non-standard C if requested
360 if env['iknowwhatimdoing']:
361 env.Append(CPPDEFINES=['IKNOWWHATIMDOING'])
362
363 # Disable OpenMP if no flags provided
364 if env['openmp'] and env['omp_flags'] == '':
365 env['warnings'].append("OpenMP requested but no flags provided - disabling OpenMP!")
366 env['openmp'] = False
367
368 if env['openmp']:
369 env.Append(CCFLAGS = env['omp_flags'])
370 if env['omp_ldflags'] != '': env.Append(LINKFLAGS = env['omp_ldflags'])
371 else:
372 env['omp_flags']=''
373 env['omp_ldflags']=''
374
375 env['buildvars']['openmp']=int(env['openmp'])
376
377 # add debug/non-debug compiler flags
378 env['buildvars']['debug']=int(env['debug'])
379 if env['debug']:
380 env.Append(CCFLAGS = env['cc_debug'])
381 else:
382 env.Append(CCFLAGS = env['cc_optim'])
383
384 # always add cc_flags
385 env.Append(CCFLAGS = env['cc_flags'])
386
387 # add system libraries
388 env.AppendUnique(LIBS = env['sys_libs'])
389
390 # determine svn revision
391 global_revision=ARGUMENTS.get('SVN_VERSION', None)
392 if global_revision:
393 global_revision = re.sub(':.*', '', global_revision)
394 global_revision = re.sub('[^0-9]', '', global_revision)
395 if global_revision == '': global_revision='-2'
396 else:
397 # Get the global Subversion revision number for the getVersion() method
398 try:
399 global_revision = os.popen('svnversion -n .').read()
400 global_revision = re.sub(':.*', '', global_revision)
401 global_revision = re.sub('[^0-9]', '', global_revision)
402 if global_revision == '': global_revision='-2'
403 except:
404 global_revision = '-1'
405 env['svn_revision']=global_revision
406 env['buildvars']['svn_revision']=global_revision
407 env.Append(CPPDEFINES=['SVN_VERSION='+global_revision])
408
409 # If that failed, try to get the version number from the file svn_version
410 if global_revision=='-2' or global_revision=='-1':
411 try:
412 global_revision=str(os.popen('cat svn_version 2>/dev/null').read())
413 if global_revision[global_revision.__len__()-1] == '\n':
414 temp=global_revision[0:(global_revision.__len__()-1)]
415 else:
416 temp=global_revision
417 print("Using svn revision information from file. Got revision = %s" % temp)
418 except:
419 global_revision='-2'
420
421 if global_revision=='-2' or global_revision=='-1':
422 env['warnings'].append("Could not detect the svn revision number!")
423
424 env['IS_WINDOWS']=IS_WINDOWS
425 env['IS_OSX']=IS_OSX
426
427 ###################### Copy required environment vars ########################
428
429 # Windows doesn't use LD_LIBRARY_PATH but PATH instead
430 if IS_WINDOWS:
431 LD_LIBRARY_PATH_KEY='PATH'
432 env['ENV']['LD_LIBRARY_PATH']=''
433 else:
434 LD_LIBRARY_PATH_KEY='LD_LIBRARY_PATH'
435
436 env['LD_LIBRARY_PATH_KEY']=LD_LIBRARY_PATH_KEY
437
438 # the following env variables are exported for the unit tests
439
440 for key in 'OMP_NUM_THREADS', 'ESCRIPT_NUM_PROCS', 'ESCRIPT_NUM_NODES':
441 try:
442 env['ENV'][key] = os.environ[key]
443 except KeyError:
444 env['ENV'][key] = '1'
445
446 env_export=env['env_export']
447 env_export.extend(['ESCRIPT_NUM_THREADS','ESCRIPT_HOSTFILE','DISPLAY','XAUTHORITY','PATH','HOME','KMP_MONITOR_STACKSIZE','TMPDIR','TEMP','TMP','LD_PRELOAD'])
448
449 for key in set(env_export):
450 try:
451 env['ENV'][key] = os.environ[key]
452 except KeyError:
453 pass
454
455 for key in os.environ.keys():
456 if key.startswith("SLURM_"):
457 env['ENV'][key] = os.environ[key]
458
459 try:
460 env.PrependENVPath(LD_LIBRARY_PATH_KEY, os.environ[LD_LIBRARY_PATH_KEY])
461 except KeyError:
462 pass
463
464 if IS_OSX:
465 try:
466 env.PrependENVPath('DYLD_LIBRARY_PATH', os.environ['DYLD_LIBRARY_PATH'])
467 except KeyError:
468 pass
469
470 try:
471 env['ENV']['PYTHONPATH'] = os.environ['PYTHONPATH']
472 except KeyError:
473 pass
474
475 ######################## Add some custom builders ############################
476
477 # Takes care of prefix and suffix for Python modules:
478 def build_python_module(env, target, source):
479 sl_suffix = '.pyd' if IS_WINDOWS else '.so'
480 return env.SharedLibrary(target, source, SHLIBPREFIX='', SHLIBSUFFIX=sl_suffix)
481 env.AddMethod(build_python_module, "PythonModule")
482
483 if env['pythoncmd']=='python':
484 py_builder = Builder(action = build_py, suffix = '.pyc', src_suffix = '.py', single_source=True)
485 else:
486 py_builder = Builder(action = env['pythoncmd']+" scripts/py_comp.py $SOURCE $TARGET", suffix = '.pyc', src_suffix = '.py', single_source=True)
487 env.Append(BUILDERS = {'PyCompile' : py_builder});
488
489 runUnitTest_builder = Builder(action = runUnitTest, suffix = '.passed', src_suffix=env['PROGSUFFIX'], single_source=True)
490 env.Append(BUILDERS = {'RunUnitTest' : runUnitTest_builder});
491
492 runPyUnitTest_builder = Builder(action = runPyUnitTest, suffix = '.passed', src_suffic='.py', single_source=True)
493 env.Append(BUILDERS = {'RunPyUnitTest' : runPyUnitTest_builder});
494
495 runPyExample_builder = Builder(action = runPyExample, suffix = '.passed', src_suffic='.py', single_source=True)
496 env.Append(BUILDERS = {'RunPyExample' : runPyExample_builder});
497
498 epstopdfbuilder = Builder(action = eps2pdf, suffix='.pdf', src_suffix='.eps', single_source=True)
499 env.Append(BUILDERS = {'EpsToPDF' : epstopdfbuilder});
500
501 ############################ Dependency checks ###############################
502
503 ######## Compiler
504 env=checkCompiler(env)
505
506 ######## Python headers & library (required)
507 env=checkPython(env)
508
509 ######## boost & boost-python (required)
510 env=checkBoost(env)
511
512 ######## numpy (required) and numpy headers (optional)
513 env=checkNumpy(env)
514
515 ######## CppUnit (required for tests)
516 env=checkCppUnit(env)
517
518 ######## optional python modules (sympy, pyproj)
519 env=checkOptionalModules(env)
520
521 ######## optional dependencies (netCDF, MKL, UMFPACK, MUMPS, Lapack, Silo, ...)
522 env=checkOptionalLibraries(env)
523
524 ######## PDFLaTeX (for documentation)
525 env=checkPDFLatex(env)
526
527 # set defaults for launchers if not otherwise specified
528 if env['prelaunch'] == 'default':
529 if env['mpi'] == 'INTELMPI' and env['openmp']:
530 env['prelaunch'] = "export I_MPI_PIN_DOMAIN=omp"
531 elif env['mpi'] == 'OPENMPI':
532 # transform comma-separated list to '-x a -x b -x c ...'
533 env['prelaunch'] = "EE=$(echo -x %e|sed -e 's/,/ -x /g')"
534 elif env['mpi'] == 'MPT':
535 env['prelaunch'] = "export MPI_NUM_MEMORY_REGIONS=0"
536 elif env['mpi'] == 'MPICH2':
537 env['prelaunch'] = "mpdboot -n %n -r ssh -f %f"
538 else:
539 env['prelaunch'] = ""
540
541 if env['launcher'] == 'default':
542 if env['mpi'] == 'INTELMPI':
543 env['launcher'] = "mpirun -hostfile %f -n %N -ppn %p %b"
544 elif env['mpi'] == 'OPENMPI':
545 if env['mpi_no_host']:
546 hostoptionstr=''
547 else:
548 hostoptionstr='--host %h'
549 # default to OpenMPI version 1.10 or higher
550 env['launcher'] = "mpirun ${AGENTOVERRIDE} --gmca mpi_warn_on_fork 0 ${EE} "+hostoptionstr+" --map-by node:pe=%t -bind-to core -np %N %b"
551 if 'orte_version' in env:
552 major,minor,point = [int(i) for i in env['orte_version'].split('.')]
553 if major == 1 and minor < 10:
554 env['launcher'] = "mpirun ${AGENTOVERRIDE} --gmca mpi_warn_on_fork 0 ${EE} "+hostoptionstr+" --cpus-per-rank %t -np %N %b"
555 elif env['mpi'] == 'MPT':
556 env['launcher'] = "mpirun %h -np %p %b"
557 elif env['mpi'] == 'MPICH':
558 env['launcher'] = "mpirun -machinefile %f -np %N %b"
559 elif env['mpi'] == 'MPICH2':
560 env['launcher'] = "mpiexec -genvlist %e -np %N %b"
561 else:
562 env['launcher'] = "%b"
563
564 if env['postlaunch'] == 'default':
565 if env['mpi'] == 'MPICH2':
566 env['postlaunch'] = "mpdallexit"
567 else:
568 env['postlaunch'] = ""
569
570 # dependency sanity checks
571
572 if len(env['domains']) == 0:
573 env['warnings'].append("No domains have been built, escript will not be very useful!")
574
575 # keep some of our install paths first in the list for the unit tests
576 env.PrependENVPath(LD_LIBRARY_PATH_KEY, env['libinstall'])
577 env.PrependENVPath('PYTHONPATH', prefix)
578 env['ENV']['ESCRIPT_ROOT'] = prefix
579
580 if not env['verbose']:
581 env['CXXCOMSTR'] = "Compiling $TARGET"
582 env['SHCXXCOMSTR'] = "Compiling $TARGET"
583 env['ARCOMSTR'] = "Linking $TARGET"
584 env['LINKCOMSTR'] = "Linking $TARGET"
585 env['SHLINKCOMSTR'] = "Linking $TARGET"
586 env['PDFLATEXCOMSTR'] = "Building $TARGET from LaTeX input $SOURCES"
587 env['BIBTEXCOMSTR'] = "Generating bibliography $TARGET"
588 env['MAKEINDEXCOMSTR'] = "Generating index $TARGET"
589 env['PDFLATEXCOMSTR'] = "Building $TARGET from LaTeX input $SOURCES"
590 #Progress(['Checking -\r', 'Checking \\\r', 'Checking |\r', 'Checking /\r'], interval=17)
591
592 ########################### Configure the targets ############################
593
594 from grouptest import GroupTest
595 TestGroups=[]
596
597 # keep an environment without warnings-as-errors
598 dodgy_env=env.Clone()
599
600 # now add warnings-as-errors flags. This needs to be done after configuration
601 # because the scons test files have warnings in them
602 if ((fatalwarning != '') and (env['werror'])):
603 env.Append(CCFLAGS = fatalwarning)
604
605 Export(
606 ['env',
607 'dodgy_env',
608 'IS_WINDOWS',
609 'TestGroups'
610 ]
611 )
612
613 target_init = env.Command(os.path.join(env['pyinstall'],'__init__.py'), None, Touch('$TARGET'))
614 env.Alias('target_init', [target_init])
615
616 # escript can't be turned off
617 build_all_list = ['build_escript']
618 install_all_list = ['target_init', 'install_escript']
619
620 if env['usempi']:
621 build_all_list += ['build_pythonMPI', 'build_overlord']
622 install_all_list += ['install_pythonMPI', 'install_overlord']
623
624 env['buildvars']['paso'] = int(env['paso'])
625 if env['paso']:
626 env.Append(CPPDEFINES = ['ESYS_HAVE_PASO'])
627 build_all_list += ['build_paso']
628 install_all_list += ['install_paso']
629
630 env['buildvars']['trilinos'] = int(env['trilinos'])
631 if env['trilinos']:
632 build_all_list += ['build_trilinoswrap']
633 install_all_list += ['install_trilinoswrap']
634
635 env['buildvars']['domains'] = ','.join(env['domains'])
636 for domain in env['domains']:
637 env.Append(CPPDEFINES = ['ESYS_HAVE_'+domain.upper()])
638 build_all_list += ['build_%s'%domain]
639 install_all_list += ['install_%s'%domain]
640
641 env['buildvars']['weipa'] = int(env['weipa'])
642 if env['weipa']:
643 env.Append(CPPDEFINES = ['ESYS_HAVE_WEIPA'])
644 build_all_list += ['build_weipa']
645 install_all_list += ['install_weipa']
646 if 'finley' in env['domains'] or 'dudley' in env['domains']:
647 build_all_list += ['build_escriptreader']
648 install_all_list += ['install_escriptreader']
649
650 variant='$BUILD_DIR/$PLATFORM/'
651 env.SConscript('escriptcore/SConscript', variant_dir=variant+'escriptcore', duplicate=0)
652 env.SConscript('escript/py_src/SConscript', variant_dir=variant+'escript', duplicate=0)
653 env.SConscript('pythonMPI/src/SConscript', variant_dir=variant+'pythonMPI', duplicate=0)
654 env.SConscript('tools/overlord/SConscript', variant_dir=variant+'tools/overlord', duplicate=0)
655 env.SConscript('paso/SConscript', variant_dir=variant+'paso', duplicate=0)
656 env.SConscript('trilinoswrap/SConscript', variant_dir=variant+'trilinoswrap', duplicate=0)
657 env.SConscript('cusplibrary/SConscript')
658 env.SConscript('dudley/SConscript', variant_dir=variant+'dudley', duplicate=0)
659 env.SConscript('finley/SConscript', variant_dir=variant+'finley', duplicate=0)
660 env.SConscript('ripley/SConscript', variant_dir=variant+'ripley', duplicate=0)
661 env.SConscript('speckley/SConscript', variant_dir=variant+'speckley', duplicate=0)
662 env.SConscript('weipa/SConscript', variant_dir=variant+'weipa', duplicate=0)
663 env.SConscript(dirs = ['downunder/py_src'], variant_dir=variant+'downunder', duplicate=0)
664 env.SConscript(dirs = ['modellib/py_src'], variant_dir=variant+'modellib', duplicate=0)
665 env.SConscript(dirs = ['pycad/py_src'], variant_dir=variant+'pycad', duplicate=0)
666 env.SConscript('tools/escriptconvert/SConscript', variant_dir=variant+'tools/escriptconvert', duplicate=0)
667 env.SConscript('doc/SConscript', variant_dir=variant+'doc', duplicate=0)
668
669 env.Alias('build', build_all_list)
670
671 install_all_list += ['install_downunder_py']
672 install_all_list += ['install_modellib_py']
673 install_all_list += ['install_pycad_py']
674 install_all_list += [env.Install(Dir('scripts',env['build_dir']), os.path.join('scripts', 'release_sanity.py'))]
675
676 if env['osx_dependency_fix']:
677 print("Require dependency fix")
678 install_all=env.Command('install', install_all_list, 'scripts/moveall.sh')
679 else:
680 install_all=env.Alias('install', install_all_list)
681
682 sanity=env.Alias('sanity', env.Command('dummy','',os.path.join(env['prefix'], 'bin', 'run-escript')+' '+os.path.join(env['build_dir'],'scripts', 'release_sanity.py')))
683 env.Depends('dummy', install_all)
684 if env['usempi']:
685 env.Depends('dummy', ['install_pythonMPI'])
686
687 # if all domains are built:
688 if env['domains'] == all_domains and env['insane'] == False:
689 env.AlwaysBuild('sanity')
690 env.Default('sanity')
691 else:
692 env.Default('install')
693
694 ################## Targets to build and run the test suite ###################
695
696 if not env['cppunit']:
697 test_msg = env.Command('.dummy.', None, '@echo "Cannot run C++ unit tests, CppUnit not found!";exit 1')
698 env.Alias('run_tests', test_msg)
699 env.Alias('build_tests', '')
700 env.Alias('run_tests', ['install'])
701 env.Alias('all_tests', ['install', 'run_tests', 'py_tests'])
702 env.Alias('build_full',['install','build_tests','build_py_tests'])
703 Requires('py_tests', 'install')
704
705 ##################### Targets to build the documentation #####################
706
707 env.Alias('pdfdocs',['user_pdf', 'install_pdf', 'cookbook_pdf', 'inversion_pdf'])
708 env.Alias('basedocs', ['pdfdocs','examples_tarfile', 'examples_zipfile', 'api_doxygen'])
709 env.Alias('docs', ['basedocs', 'sphinxdoc'])
710 env.Alias('release_prep', ['docs', 'install'])
711 env.Alias('release_prep_old', ['basedocs', 'api_epydoc', 'install'])
712
713 # The test scripts are always generated, this target allows us to
714 # generate the testscripts without doing a full build
715 env.Alias('testscripts',[])
716
717 generateTestScripts(env, TestGroups)
718
719 ######################## Populate the buildvars file #########################
720
721 write_buildvars(env)
722 # delete buildvars upon cleanup - target_init is default so use it
723 env.Clean('target_init', File('buildvars', env['libinstall']))
724
725 write_launcher(env)
726
727 # remove obsolete files
728 if not env['usempi']:
729 Execute(Delete(File(['pythonMPI','pythonMPIredirect'], env['libinstall'])))
730 Execute(Delete(File('escript-overlord', env['bininstall'])))
731
732 ######################## Summarize our environment ###########################
733 def print_summary():
734 d_list=[]
735 print("")
736 print("*** Config Summary (see config.log and <prefix>/lib/buildvars for details) ***")
737 print("Escript revision %s"%global_revision)
738 print(" Install prefix: %s"%env['prefix'])
739 print(" Python: %s (Version %s)"%(env['pythoncmd'],env['python_version']))
740 print(" boost: %s (Version %s)"%(env['boost_prefix'],env['boost_version']))
741 if env['have_boost_numpy'] is True:
742 print(" boost numpy: YES")
743 else:
744 print(" boost numpy: NO")
745 if env['trilinos']:
746 print(" trilinos: %s (Version %s)" % (env['trilinos_prefix'],env['trilinos_version']))
747 else:
748 print(" trilinos: NO")
749 if env['numpy_h']:
750 print(" numpy: YES (with headers)")
751 else:
752 print(" numpy: YES (without headers)")
753 if env['usempi']:
754 if 'orte_version' in env:
755 print(" MPI: %s (Version %s)"%(env['mpi'], env['orte_version']))
756 else:
757 print(" MPI: YES (flavour: %s)"%env['mpi'])
758 else:
759 d_list.append('mpi')
760 if env['parmetis']:
761 print(" ParMETIS: %s (Version %s)"%(env['parmetis_prefix'],env['parmetis_version']))
762 else:
763 d_list.append('parmetis')
764 if env['uselapack']:
765 print(" LAPACK: YES (flavour: %s)"%env['lapack'])
766 else:
767 d_list.append('lapack')
768 if env['gmshpy']:
769 gmshpy=" + python module"
770 else:
771 gmshpy=""
772 if env['gmsh']=='m':
773 print(" gmsh: YES, MPI-ENABLED"+gmshpy)
774 elif env['gmsh']=='s':
775 print(" gmsh: YES"+gmshpy)
776 else:
777 if env['gmshpy']:
778 print(" gmsh: python module only")
779 else:
780 d_list.append('gmsh')
781 if env['compressed_files']:
782 print(" gzip: YES")
783 else:
784 d_list.append('gzip')
785
786 solvers = []
787 direct = []
788 if env['paso']:
789 solvers.append('paso')
790 if env['mkl']:
791 direct.append('mkl')
792 if env['umfpack']:
793 direct.append('umfpack')
794 if env['mumps']:
795 direct.append('mumps')
796 else:
797 d_list.append('paso')
798 if env['trilinos']:
799 solvers.append('trilinos')
800 direct.append('trilinos')
801 else:
802 d_list.append('trilinos')
803
804 print(" Solver library: %s"%(", ".join(solvers)))
805 if len(direct) > 0:
806 print(" Direct solver: YES (%s)"%(", ".join(direct)))
807 else:
808 print(" Direct solver: NONE")
809 print(" domains: %s"%(", ".join(env['domains'])))
810 if env['netcdf']==4:
811 print(" netcdf: YES (4 + 3)")
812 elif env['netcdf']==3:
813 print(" netcdf: YES (3)")
814 else:
815 print(" netcdf: NO")
816 e_list=[]
817 for i in ('weipa','debug','openmp','cppunit','gdal','mkl',
818 'mumps','pyproj','scipy','silo','sympy','umfpack','visit'):
819 if env[i]: e_list.append(i)
820 else: d_list.append(i)
821
822 d_list += set(all_domains).difference(env['domains'])
823 for i in e_list:
824 print("%16s: YES"%i)
825 print("\n DISABLED features: %s"%(" ".join(sorted(d_list))))
826
827 if ((fatalwarning != '') and (env['werror'])):
828 print(" Treating warnings as errors")
829 else:
830 print(" NOT treating warnings as errors")
831 print("")
832 for w in env['warnings']:
833 print("WARNING: %s"%w)
834 if len(GetBuildFailures()):
835 print("\nERROR: build stopped due to errors\n")
836 else:
837 print("\nSUCCESS: build complete\n")
838
839 atexit.register(print_summary)

  ViewVC Help
Powered by ViewVC 1.1.26