/[escript]/branches/pre3.3/SConstruct
ViewVC logotype

Contents of /branches/pre3.3/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3933 - (show annotations)
Wed Jul 11 06:07:34 2012 UTC (5 years, 10 months ago) by jfenwick
File size: 39491 byte(s)
Added option to options file to allow override of the python library
and include locations

1 ########################################################
2 #
3 # Copyright (c) 2003-2012 by University of Queensland
4 # Earth Systems Science Computational Center (ESSCC)
5 # http://www.uq.edu.au/esscc
6 #
7 # Primary Business: Queensland, Australia
8 # Licensed under the Open Software License version 3.0
9 # http://www.opensource.org/licenses/osl-3.0.php
10 #
11 ########################################################
12
13 EnsureSConsVersion(0,98,1)
14 EnsurePythonVersion(2,5)
15
16 import sys, os, platform, re
17 from distutils import sysconfig
18 from site_init import *
19 import subprocess
20 from subprocess import PIPE, Popen
21
22 # Version number to check for in options file. Increment when new features are
23 # added or existing options changed.
24 REQUIRED_OPTS_VERSION=201
25
26 # MS Windows support, many thanks to PH
27 IS_WINDOWS = (os.name == 'nt')
28
29 ########################## Determine options file ############################
30 # 1. command line
31 # 2. scons/<hostname>_options.py
32 # 3. name as part of a cluster
33 options_file=ARGUMENTS.get('options_file', None)
34 if not options_file:
35 ext_dir = os.path.join(os.getcwd(), 'scons')
36 hostname = platform.node().split('.')[0]
37 for name in hostname, effectiveName(hostname):
38 mangledhostname = re.sub('[^0-9a-zA-Z]', '_', hostname)
39 options_file = os.path.join(ext_dir, mangledhostname+'_options.py')
40 if os.path.isfile(options_file): break
41
42 if not os.path.isfile(options_file):
43 print("\nWARNING:\nOptions file %s" % options_file)
44 print("not found! Default options will be used which is most likely suboptimal.")
45 print("It is recommended that you copy one of the TEMPLATE files in the scons/")
46 print("subdirectory and customize it to your needs.\n")
47 options_file = None
48
49 ############################### Build options ################################
50
51 default_prefix='/usr'
52 mpi_flavours=('no', 'none', 'MPT', 'MPICH', 'MPICH2', 'OPENMPI', 'INTELMPI')
53 lapack_flavours=('none', 'clapack', 'mkl')
54
55 vars = Variables(options_file, ARGUMENTS)
56 vars.AddVariables(
57 PathVariable('options_file', 'Path to options file', options_file, PathVariable.PathIsFile),
58 PathVariable('prefix', 'Installation prefix', Dir('#.').abspath, PathVariable.PathIsDirCreate),
59 PathVariable('build_dir', 'Top-level build directory', Dir('#/build').abspath, PathVariable.PathIsDirCreate),
60 BoolVariable('verbose', 'Output full compile/link lines', False),
61 # Compiler/Linker options
62 ('cc', 'Path to C compiler', 'default'),
63 ('cxx', 'Path to C++ compiler', 'default'),
64 ('cc_flags', 'Base C/C++ compiler flags', 'default'),
65 ('cc_optim', 'Additional C/C++ flags for a non-debug build', 'default'),
66 ('cc_debug', 'Additional C/C++ flags for a debug build', 'default'),
67 ('cc_extra', 'Extra C compiler flags', ''),
68 ('cxx_extra', 'Extra C++ compiler flags', ''),
69 ('ld_extra', 'Extra linker flags', ''),
70 BoolVariable('werror','Treat compiler warnings as errors', True),
71 BoolVariable('debug', 'Compile with debug flags', False),
72 BoolVariable('openmp', 'Compile parallel version using OpenMP', False),
73 ('omp_flags', 'OpenMP compiler flags', 'default'),
74 ('omp_ldflags', 'OpenMP linker flags', 'default'),
75 # Mandatory libraries
76 ('boost_prefix', 'Prefix/Paths of boost installation', default_prefix),
77 ('boost_libs', 'Boost libraries to link with', ['boost_python-mt']),
78 # Mandatory for tests
79 ('cppunit_prefix', 'Prefix/Paths of CppUnit installation', default_prefix),
80 ('cppunit_libs', 'CppUnit libraries to link with', ['cppunit']),
81 # Optional libraries and options
82 EnumVariable('mpi', 'Compile parallel version using MPI flavour', 'none', allowed_values=mpi_flavours),
83 ('mpi_prefix', 'Prefix/Paths of MPI installation', default_prefix),
84 ('mpi_libs', 'MPI shared libraries to link with', ['mpi']),
85 BoolVariable('netcdf', 'Enable netCDF file support', False),
86 ('netcdf_prefix', 'Prefix/Paths of netCDF installation', default_prefix),
87 ('netcdf_libs', 'netCDF libraries to link with', ['netcdf_c++', 'netcdf']),
88 BoolVariable('parmetis', 'Enable ParMETIS (requires MPI)', False),
89 ('parmetis_prefix', 'Prefix/Paths of ParMETIS installation', default_prefix),
90 ('parmetis_libs', 'ParMETIS libraries to link with', ['parmetis', 'metis']),
91 BoolVariable('papi', 'Enable PAPI', False),
92 ('papi_prefix', 'Prefix/Paths to PAPI installation', default_prefix),
93 ('papi_libs', 'PAPI libraries to link with', ['papi']),
94 BoolVariable('papi_instrument_solver', 'Use PAPI to instrument each iteration of the solver', False),
95 BoolVariable('mkl', 'Enable the Math Kernel Library', False),
96 ('mkl_prefix', 'Prefix/Paths to MKL installation', default_prefix),
97 ('mkl_libs', 'MKL libraries to link with', ['mkl_solver','mkl_em64t','guide','pthread']),
98 BoolVariable('umfpack', 'Enable UMFPACK', False),
99 ('umfpack_prefix', 'Prefix/Paths to UMFPACK installation', default_prefix),
100 ('umfpack_libs', 'UMFPACK libraries to link with', ['umfpack']),
101 BoolVariable('boomeramg', 'Enable BoomerAMG', False),
102 ('boomeramg_prefix', 'Prefix/Paths to BoomerAMG installation', default_prefix),
103 ('boomeramg_libs', 'BoomerAMG libraries to link with', ['boomeramg']),
104 EnumVariable('lapack', 'Set LAPACK flavour', 'none', allowed_values=lapack_flavours),
105 ('lapack_prefix', 'Prefix/Paths to LAPACK installation', default_prefix),
106 ('lapack_libs', 'LAPACK libraries to link with', []),
107 BoolVariable('silo', 'Enable the Silo file format in weipa', False),
108 ('silo_prefix', 'Prefix/Paths to Silo installation', default_prefix),
109 ('silo_libs', 'Silo libraries to link with', ['siloh5', 'hdf5']),
110 BoolVariable('visit', 'Enable the VisIt simulation interface', False),
111 ('visit_prefix', 'Prefix/Paths to VisIt installation', default_prefix),
112 ('visit_libs', 'VisIt libraries to link with', ['simV2']),
113 BoolVariable('vsl_random', 'Use VSL from intel for random data', False),
114 # Advanced settings
115 #dudley_assemble_flags = -funroll-loops to actually do something
116 ('dudley_assemble_flags', 'compiler flags for some dudley optimisations', ''),
117 # To enable passing function pointers through python
118 BoolVariable('iknowwhatimdoing', 'Allow non-standard C', False),
119 # An option for specifying the compiler tools (see windows branch)
120 ('tools_names', 'Compiler tools to use', ['default']),
121 ('env_export', 'Environment variables to be passed to tools',[]),
122 EnumVariable('forcelazy', 'For testing use only - set the default value for autolazy', 'leave_alone', allowed_values=('leave_alone', 'on', 'off')),
123 EnumVariable('forcecollres', 'For testing use only - set the default value for force resolving collective ops', 'leave_alone', allowed_values=('leave_alone', 'on', 'off')),
124 # finer control over library building, intel aggressive global optimisation
125 # works with dynamic libraries on windows.
126 ('build_shared', 'Build dynamic libraries only', False),
127 ('sys_libs', 'Extra libraries to link with', []),
128 ('escript_opts_version', 'Version of options file (do not specify on command line)'),
129 ('SVN_VERSION', 'Do not use from options file', -2),
130 ('pythoncmd', 'which python to compile with','python'),
131 ('usepython3', 'Is this a python3 build? (experimental)', False),
132 ('pythonlibname', 'Name of the python library to link. (This is found automatically for python2.X.)', ''),
133 ('pythonlibpath', 'Path to the python library. (You should not need to set this unless your python has moved)',''),
134 ('pythonincpath','Path to python include files. (You should not need to set this unless your python has moved',''),
135 )
136
137 ##################### Create environment and help text #######################
138
139 # Intel's compiler uses regular expressions improperly and emits a warning
140 # about failing to find the compilers. This warning can be safely ignored.
141
142 # PATH is needed so the compiler, linker and tools are found if they are not
143 # in default locations.
144 env = Environment(tools = ['default'], options = vars,
145 ENV = {'PATH': os.environ['PATH']})
146 if env['tools_names'] != 'default':
147 env = Environment(tools = ['default'] + env['tools_names'], options = vars,
148 ENV = {'PATH' : os.environ['PATH']})
149
150 if options_file:
151 opts_valid=False
152 if 'escript_opts_version' in env.Dictionary() and \
153 int(env['escript_opts_version']) >= REQUIRED_OPTS_VERSION:
154 opts_valid=True
155 if opts_valid:
156 print("Using options in %s." % options_file)
157 else:
158 print("\nOptions file %s" % options_file)
159 print("is outdated! Please update the file by examining one of the TEMPLATE")
160 print("files in the scons/ subdirectory and setting escript_opts_version to %d.\n"%REQUIRED_OPTS_VERSION)
161 Exit(1)
162
163 # Generate help text (scons -h)
164 Help(vars.GenerateHelpText(env))
165
166 # Check for superfluous options
167 if len(vars.UnknownVariables())>0:
168 for k in vars.UnknownVariables():
169 print("Unknown option '%s'" % k)
170 Exit(1)
171
172 #################### Make sure install directories exist #####################
173
174 env['BUILD_DIR']=env['build_dir']
175 prefix=Dir(env['prefix']).abspath
176 env['incinstall'] = os.path.join(prefix, 'include')
177 env['bininstall'] = os.path.join(prefix, 'bin')
178 env['libinstall'] = os.path.join(prefix, 'lib')
179 env['pyinstall'] = os.path.join(prefix, 'esys')
180 if not os.path.isdir(env['bininstall']):
181 os.makedirs(env['bininstall'])
182 if not os.path.isdir(env['libinstall']):
183 os.makedirs(env['libinstall'])
184 if not os.path.isdir(env['pyinstall']):
185 os.makedirs(env['pyinstall'])
186
187 env.Append(CPPPATH = [env['incinstall']])
188 env.Append(LIBPATH = [env['libinstall']])
189
190 ################# Fill in compiler options if not set above ##################
191
192 if env['cc'] != 'default': env['CC']=env['cc']
193 if env['cxx'] != 'default': env['CXX']=env['cxx']
194
195 # version >=9 of intel C++ compiler requires use of icpc to link in C++
196 # runtimes (icc does not)
197 if not IS_WINDOWS and os.uname()[4]=='ia64' and env['CXX']=='icpc':
198 env['LINK'] = env['CXX']
199
200 # default compiler/linker options
201 cc_flags = ''
202 cc_optim = ''
203 cc_debug = ''
204 omp_flags = ''
205 omp_ldflags = ''
206 fatalwarning = '' # switch to turn warnings into errors
207 sysheaderopt = '' # how to indicate that a header is a system header
208
209 # env['CC'] might be a full path
210 cc_name=os.path.basename(env['CC'])
211
212 if cc_name == 'icc':
213 # Intel compiler
214 cc_flags = "-std=c99 -fPIC -wd161 -w1 -vec-report0 -DBLOCKTIMER -DCORE_ID1"
215 cc_optim = "-O3 -ftz -IPF_ftlacc- -IPF_fma -fno-alias -ip"
216 cc_debug = "-g -O0 -DDOASSERT -DDOPROF -DBOUNDS_CHECK"
217 omp_flags = "-openmp -openmp_report0"
218 omp_ldflags = "-openmp -openmp_report0 -lpthread"
219 fatalwarning = "-Werror"
220 elif cc_name[:3] == 'gcc':
221 # GNU C on any system
222 cc_flags = "-pedantic -Wall -fPIC -ffast-math -Wno-unknown-pragmas -DBLOCKTIMER -Wno-sign-compare -Wno-system-headers -Wno-long-long -Wno-strict-aliasing -finline-functions"
223 cc_optim = "-O3"
224 cc_debug = "-g -O0 -DDOASSERT -DDOPROF -DBOUNDS_CHECK"
225 omp_flags = "-fopenmp"
226 omp_ldflags = "-fopenmp"
227 fatalwarning = "-Werror"
228 sysheaderopt = "-isystem"
229 elif cc_name == 'cl':
230 # Microsoft Visual C on Windows
231 cc_flags = "/EHsc /MD /GR /wd4068 /D_USE_MATH_DEFINES /DDLL_NETCDF"
232 cc_optim = "/O2 /Op /W3"
233 cc_debug = "/Od /RTCcsu /ZI /DBOUNDS_CHECK"
234 fatalwarning = "/WX"
235 elif cc_name == 'icl':
236 # Intel C on Windows
237 cc_flags = '/EHsc /GR /MD'
238 cc_optim = '/fast /Oi /W3 /Qssp /Qinline-factor- /Qinline-min-size=0 /Qunroll'
239 cc_debug = '/Od /RTCcsu /Zi /Y- /debug:all /Qtrapuv'
240 omp_flags = '/Qvec-report0 /Qopenmp /Qopenmp-report0 /Qparallel'
241 omp_ldflags = '/Qvec-report0 /Qopenmp /Qopenmp-report0 /Qparallel'
242
243 # set defaults if not otherwise specified
244 if env['cc_flags'] == 'default': env['cc_flags'] = cc_flags
245 if env['cc_optim'] == 'default': env['cc_optim'] = cc_optim
246 if env['cc_debug'] == 'default': env['cc_debug'] = cc_debug
247 if env['omp_flags'] == 'default': env['omp_flags'] = omp_flags
248 if env['omp_ldflags'] == 'default': env['omp_ldflags'] = omp_ldflags
249 if env['cc_extra'] != '': env.Append(CFLAGS = env['cc_extra'])
250 if env['cxx_extra'] != '': env.Append(CXXFLAGS = env['cxx_extra'])
251 if env['ld_extra'] != '': env.Append(LINKFLAGS = env['ld_extra'])
252
253 if env['usepython3']:
254 env.Append(CPPDEFINES=['ESPYTHON3'])
255
256 # set up the autolazy values
257 if env['forcelazy'] == 'on':
258 env.Append(CPPDEFINES=['FAUTOLAZYON'])
259 elif env['forcelazy'] == 'off':
260 env.Append(CPPDEFINES=['FAUTOLAZYOFF'])
261
262 # set up the collective resolve values
263 if env['forcecollres'] == 'on':
264 env.Append(CPPDEFINES=['FRESCOLLECTON'])
265 elif env['forcecollres'] == 'off':
266 env.Append(CPPDEFINES=['FRESCOLLECTOFF'])
267
268 # allow non-standard C if requested
269 if env['iknowwhatimdoing']:
270 env.Append(CPPDEFINES=['IKNOWWHATIMDOING'])
271
272 # Disable OpenMP if no flags provided
273 if env['openmp'] and env['omp_flags'] == '':
274 print("OpenMP requested but no flags provided - disabling OpenMP!")
275 env['openmp'] = False
276
277 if env['openmp']:
278 env.Append(CCFLAGS = env['omp_flags'])
279 if env['omp_ldflags'] != '': env.Append(LINKFLAGS = env['omp_ldflags'])
280 else:
281 env['omp_flags']=''
282 env['omp_ldflags']=''
283
284 # add debug/non-debug compiler flags
285 if env['debug']:
286 env.Append(CCFLAGS = env['cc_debug'])
287 else:
288 env.Append(CCFLAGS = env['cc_optim'])
289
290 # always add cc_flags
291 env.Append(CCFLAGS = env['cc_flags'])
292
293 # add system libraries
294 env.AppendUnique(LIBS = env['sys_libs'])
295
296
297 global_revision=ARGUMENTS.get('SVN_VERSION', None)
298 if global_revision:
299 global_revision = re.sub(':.*', '', global_revision)
300 global_revision = re.sub('[^0-9]', '', global_revision)
301 if global_revision == '': global_revision='-2'
302 else:
303 # Get the global Subversion revision number for the getVersion() method
304 try:
305 global_revision = os.popen('svnversion -n .').read()
306 global_revision = re.sub(':.*', '', global_revision)
307 global_revision = re.sub('[^0-9]', '', global_revision)
308 if global_revision == '': global_revision='-2'
309 except:
310 global_revision = '-1'
311 env['svn_revision']=global_revision
312 env.Append(CPPDEFINES=['SVN_VERSION='+global_revision])
313
314 if IS_WINDOWS:
315 if not env['build_shared']:
316 env.Append(CPPDEFINES = ['ESYSUTILS_STATIC_LIB'])
317 env.Append(CPPDEFINES = ['PASO_STATIC_LIB'])
318
319 ###################### Copy required environment vars ########################
320
321 # Windows doesn't use LD_LIBRARY_PATH but PATH instead
322 if IS_WINDOWS:
323 LD_LIBRARY_PATH_KEY='PATH'
324 env['ENV']['LD_LIBRARY_PATH']=''
325 else:
326 LD_LIBRARY_PATH_KEY='LD_LIBRARY_PATH'
327
328 # the following env variables are exported for the unit tests
329
330 for key in 'OMP_NUM_THREADS', 'ESCRIPT_NUM_PROCS', 'ESCRIPT_NUM_NODES':
331 try:
332 env['ENV'][key] = os.environ[key]
333 except KeyError:
334 env['ENV'][key] = 1
335
336 env_export=env['env_export']
337 env_export.extend(['ESCRIPT_NUM_THREADS','ESCRIPT_HOSTFILE','DISPLAY','XAUTHORITY','PATH','HOME','TMPDIR','TEMP','TMP'])
338
339 for key in set(env_export):
340 try:
341 env['ENV'][key] = os.environ[key]
342 except KeyError:
343 pass
344
345 try:
346 env.PrependENVPath(LD_LIBRARY_PATH_KEY, os.environ[LD_LIBRARY_PATH_KEY])
347 except KeyError:
348 pass
349
350 # these shouldn't be needed
351 #for key in 'C_INCLUDE_PATH','CPLUS_INCLUDE_PATH','LIBRARY_PATH':
352 # try:
353 # env['ENV'][key] = os.environ[key]
354 # except KeyError:
355 # pass
356
357 try:
358 env['ENV']['PYTHONPATH'] = os.environ['PYTHONPATH']
359 except KeyError:
360 pass
361
362 ######################## Add some custom builders ############################
363
364 if env['pythoncmd']=='python':
365 py_builder = Builder(action = build_py, suffix = '.pyc', src_suffix = '.py', single_source=True)
366 else:
367 py_builder = Builder(action = env['pythoncmd']+" scripts/py_comp.py $SOURCE $TARGET", suffix = '.pyc', src_suffix = '.py', single_source=True)
368 env.Append(BUILDERS = {'PyCompile' : py_builder});
369
370 runUnitTest_builder = Builder(action = runUnitTest, suffix = '.passed', src_suffix=env['PROGSUFFIX'], single_source=True)
371 env.Append(BUILDERS = {'RunUnitTest' : runUnitTest_builder});
372
373 runPyUnitTest_builder = Builder(action = runPyUnitTest, suffix = '.passed', src_suffic='.py', single_source=True)
374 env.Append(BUILDERS = {'RunPyUnitTest' : runPyUnitTest_builder});
375
376 epstopdfbuilder = Builder(action = eps2pdf, suffix='.pdf', src_suffix='.eps', single_source=True)
377 env.Append(BUILDERS = {'EpsToPDF' : epstopdfbuilder});
378
379 ############################ Dependency checks ###############################
380
381 # Create a Configure() environment to check for compilers and python
382 conf = Configure(env.Clone())
383
384 ######## Test that the compilers work
385
386 if 'CheckCC' in dir(conf): # exists since scons 1.1.0
387 if not conf.CheckCC():
388 print("Cannot run C compiler '%s' (check config.log)" % (env['CC']))
389 Exit(1)
390 if not conf.CheckCXX():
391 print("Cannot run C++ compiler '%s' (check config.log)" % (env['CXX']))
392 Exit(1)
393 else:
394 if not conf.CheckFunc('printf', language='c'):
395 print("Cannot run C compiler '%s' (check config.log)" % (env['CC']))
396 Exit(1)
397 if not conf.CheckFunc('printf', language='c++'):
398 print("Cannot run C++ compiler '%s' (check config.log)" % (env['CXX']))
399 Exit(1)
400
401 if conf.CheckFunc('gethostname'):
402 conf.env.Append(CPPDEFINES = ['HAVE_GETHOSTNAME'])
403
404 ######## Python headers & library (required)
405
406 #First we check to see if the config file has specified
407 ##Where to find the filae. Ideally, this should be automatic
408 #But we need to deal with the case where python is not in its INSTALL
409 #Directory
410 # Use the python scons is running
411 if env['pythoncmd']=='python':
412 python_inc_path=sysconfig.get_python_inc()
413 if IS_WINDOWS:
414 python_lib_path=os.path.join(sysconfig.get_config_var('prefix'), 'libs')
415 elif env['PLATFORM']=='darwin':
416 python_lib_path=sysconfig.get_config_var('LIBPL')
417 else:
418 python_lib_path=sysconfig.get_config_var('LIBDIR')
419
420 #python_libs=[sysconfig.get_config_var('LDLIBRARY')] # only on linux
421 if IS_WINDOWS:
422 python_libs=['python%s%s'%(sys.version_info[0], sys.version_info[1])]
423 else:
424 python_libs=['python'+sysconfig.get_python_version()]
425
426 #if we want to use a python other than the one scons is running
427 else:
428 initstring='from __future__ import print_function;from distutils import sysconfig;'
429 if env['pythonlibname']!='':
430 python_libs=env['pythonlibname']
431 else: # work it out by calling python
432 if IS_WINDOWS:
433 cmd='print("python%s%s"%(sys.version_info[0], sys.version_info[1]))'
434 else:
435 cmd='print("python"+sysconfig.get_python_version())'
436 p=Popen([env['pythoncmd'], '-c', initstring+cmd], stdout=PIPE)
437 python_libs=p.stdout.readline()
438 if env['usepython3']: # This is to convert unicode str into py2 string
439 python_libs=python_libs.encode() # If scons runs on py3 then this must be rethought
440 p.wait()
441 python_libs=python_libs.strip()
442
443
444 # Now we know whether we are using python3 or not
445 p=Popen([env['pythoncmd'], '-c', initstring+'print(sysconfig.get_python_inc())'], stdout=PIPE)
446 python_inc_path=p.stdout.readline()
447 if env['usepython3']:
448 python_inc_path=python_inc_path.encode()
449 p.wait()
450 python_inc_path=python_inc_path.strip()
451 if IS_WINDOWS:
452 cmd="os.path.join(sysconfig.get_config_var('prefix'), 'libs')"
453 elif env['PLATFORM']=='darwin':
454 cmd="sysconfig.get_config_var(\"LIBPL\")"
455 else:
456 cmd="sysconfig.get_config_var(\"LIBDIR\")"
457
458 p=Popen([env['pythoncmd'], '-c', initstring+'print('+cmd+')'], stdout=PIPE)
459 python_lib_path=p.stdout.readline()
460 if env['usepython3']:
461 python_lib_path=python_lib_path.decode()
462 p.wait()
463 python_lib_path=python_lib_path.strip()
464
465 #Check for an override from the config file.
466 #Ideally, this should be automatic
467 #But we need to deal with the case where python is not in its INSTALL
468 #Directory
469 if env['pythonlibpath']!='':
470 python_lib_path=env['pythonlibpath']
471
472 if env['pythonincpath']!='':
473 python_inc_path=env['pythonincpath']
474
475
476 if sysheaderopt == '':
477 conf.env.AppendUnique(CPPPATH = [python_inc_path])
478 else:
479 conf.env.Append(CCFLAGS = [sysheaderopt, python_inc_path])
480
481 conf.env.AppendUnique(LIBPATH = [python_lib_path])
482 conf.env.AppendUnique(LIBS = python_libs)
483 # The wrapper script needs to find the libs
484 conf.env.PrependENVPath(LD_LIBRARY_PATH_KEY, python_lib_path)
485
486 if not conf.CheckCHeader('Python.h'):
487 print("Cannot find python include files (tried 'Python.h' in directory %s)" % (python_inc_path))
488 Exit(1)
489 if not conf.CheckFunc('Py_Exit'):
490 print("Cannot find python library method Py_Main (tried %s in directory %s)" % (python_libs, python_lib_path))
491 Exit(1)
492
493 ## reuse conf to check for numpy header (optional)
494 if env['usepython3']:
495 # FIXME: This is until we can work out how to make the checks in python 3
496 conf.env['numpy_h']=False
497 else:
498 if conf.CheckCXXHeader(['Python.h','numpy/ndarrayobject.h']):
499 conf.env.Append(CPPDEFINES = ['HAVE_NUMPY_H'])
500 conf.env['numpy_h']=True
501 else:
502 conf.env['numpy_h']=False
503
504 # Commit changes to environment
505 env = conf.Finish()
506
507 ######## boost (required)
508
509 boost_inc_path,boost_lib_path=findLibWithHeader(env, env['boost_libs'], 'boost/python.hpp', env['boost_prefix'], lang='c++')
510 if sysheaderopt == '':
511 env.AppendUnique(CPPPATH = [boost_inc_path])
512 else:
513 # This is required because we can't -isystem /usr/include since it breaks
514 # std includes
515 if os.path.normpath(boost_inc_path) == '/usr/include':
516 conf.env.Append(CCFLAGS=[sysheaderopt, os.path.join(boost_inc_path,'boost')])
517 else:
518 env.Append(CCFLAGS=[sysheaderopt, boost_inc_path])
519
520 env.AppendUnique(LIBPATH = [boost_lib_path])
521 env.AppendUnique(LIBS = env['boost_libs'])
522 env.PrependENVPath(LD_LIBRARY_PATH_KEY, boost_lib_path)
523
524 ######## numpy (required)
525
526 if env['pythoncmd']=='python':
527 try:
528 from numpy import identity
529 except ImportError:
530 print("Cannot import numpy, you need to set your PYTHONPATH and probably %s"%LD_LIBRARY_PATH_KEY)
531 Exit(1)
532 else:
533 p=subprocess.call([env['pythoncmd'],'-c','import numpy'])
534 if p!=0:
535 print("Cannot import numpy, you need to set your PYTHONPATH and probably %s"%LD_LIBRARY_PATH_KEY)
536 Exit(1)
537
538 ######## CppUnit (required for tests)
539
540 try:
541 cppunit_inc_path,cppunit_lib_path=findLibWithHeader(env, env['cppunit_libs'], 'cppunit/TestFixture.h', env['cppunit_prefix'], lang='c++')
542 env.AppendUnique(CPPPATH = [cppunit_inc_path])
543 env.AppendUnique(LIBPATH = [cppunit_lib_path])
544 env.PrependENVPath(LD_LIBRARY_PATH_KEY, cppunit_lib_path)
545 env['cppunit']=True
546 except:
547 env['cppunit']=False
548
549 ######## netCDF (optional)
550
551 netcdf_inc_path=''
552 netcdf_lib_path=''
553 if env['netcdf']:
554 netcdf_inc_path,netcdf_lib_path=findLibWithHeader(env, env['netcdf_libs'], 'netcdf.h', env['netcdf_prefix'], lang='c++')
555 env.AppendUnique(CPPPATH = [netcdf_inc_path])
556 env.AppendUnique(LIBPATH = [netcdf_lib_path])
557 env.AppendUnique(LIBS = env['netcdf_libs'])
558 env.PrependENVPath(LD_LIBRARY_PATH_KEY, netcdf_lib_path)
559 env.Append(CPPDEFINES = ['USE_NETCDF'])
560
561 ######## PAPI (optional)
562
563 papi_inc_path=''
564 papi_lib_path=''
565 if env['papi']:
566 papi_inc_path,papi_lib_path=findLibWithHeader(env, env['papi_libs'], 'papi.h', env['papi_prefix'], lang='c')
567 env.AppendUnique(CPPPATH = [papi_inc_path])
568 env.AppendUnique(LIBPATH = [papi_lib_path])
569 env.AppendUnique(LIBS = env['papi_libs'])
570 env.PrependENVPath(LD_LIBRARY_PATH_KEY, papi_lib_path)
571 env.Append(CPPDEFINES = ['BLOCKPAPI'])
572
573 ######## MKL (optional)
574
575 mkl_inc_path=''
576 mkl_lib_path=''
577 if env['mkl']:
578 mkl_inc_path,mkl_lib_path=findLibWithHeader(env, env['mkl_libs'], 'mkl_solver.h', env['mkl_prefix'], lang='c')
579 env.AppendUnique(CPPPATH = [mkl_inc_path])
580 env.AppendUnique(LIBPATH = [mkl_lib_path])
581 env.AppendUnique(LIBS = env['mkl_libs'])
582 env.PrependENVPath(LD_LIBRARY_PATH_KEY, mkl_lib_path)
583 env.Append(CPPDEFINES = ['MKL'])
584
585 ######## UMFPACK (optional)
586
587 umfpack_inc_path=''
588 umfpack_lib_path=''
589 if env['umfpack']:
590 umfpack_inc_path,umfpack_lib_path=findLibWithHeader(env, env['umfpack_libs'], 'umfpack.h', env['umfpack_prefix'], lang='c')
591 env.AppendUnique(CPPPATH = [umfpack_inc_path])
592 env.AppendUnique(LIBPATH = [umfpack_lib_path])
593 env.AppendUnique(LIBS = env['umfpack_libs'])
594 env.PrependENVPath(LD_LIBRARY_PATH_KEY, umfpack_lib_path)
595 env.Append(CPPDEFINES = ['UMFPACK'])
596
597 ######## LAPACK (optional)
598
599 if env['lapack']=='mkl' and not env['mkl']:
600 print("mkl_lapack requires MKL!")
601 Exit(1)
602
603 env['uselapack'] = env['lapack']!='none'
604 lapack_inc_path=''
605 lapack_lib_path=''
606 if env['uselapack']:
607 header='clapack.h'
608 if env['lapack']=='mkl':
609 env.AppendUnique(CPPDEFINES = ['MKL_LAPACK'])
610 header='mkl_lapack.h'
611 lapack_inc_path,lapack_lib_path=findLibWithHeader(env, env['lapack_libs'], header, env['lapack_prefix'], lang='c')
612 env.AppendUnique(CPPPATH = [lapack_inc_path])
613 env.AppendUnique(LIBPATH = [lapack_lib_path])
614 env.AppendUnique(LIBS = env['lapack_libs'])
615 env.Append(CPPDEFINES = ['USE_LAPACK'])
616
617 ######## Silo (optional)
618
619 silo_inc_path=''
620 silo_lib_path=''
621 if env['silo']:
622 silo_inc_path,silo_lib_path=findLibWithHeader(env, env['silo_libs'], 'silo.h', env['silo_prefix'], lang='c')
623 env.AppendUnique(CPPPATH = [silo_inc_path])
624 env.AppendUnique(LIBPATH = [silo_lib_path])
625 # Note that we do not add the libs since they are only needed for the
626 # weipa library and tools.
627 #env.AppendUnique(LIBS = [env['silo_libs']])
628
629 ######## VSL random numbers (optional)
630 if env['vsl_random']:
631 env.Append(CPPDEFINES = ['MKLRANDOM'])
632
633 ######## VisIt (optional)
634
635 visit_inc_path=''
636 visit_lib_path=''
637 if env['visit']:
638 visit_inc_path,visit_lib_path=findLibWithHeader(env, env['visit_libs'], 'VisItControlInterface_V2.h', env['visit_prefix'], lang='c')
639 env.AppendUnique(CPPPATH = [visit_inc_path])
640 env.AppendUnique(LIBPATH = [visit_lib_path])
641
642 ######## MPI (optional)
643
644 if env['mpi']=='no':
645 env['mpi']='none'
646
647 env['usempi'] = env['mpi']!='none'
648 mpi_inc_path=''
649 mpi_lib_path=''
650 if env['usempi']:
651 mpi_inc_path,mpi_lib_path=findLibWithHeader(env, env['mpi_libs'], 'mpi.h', env['mpi_prefix'], lang='c')
652 env.AppendUnique(CPPPATH = [mpi_inc_path])
653 env.AppendUnique(LIBPATH = [mpi_lib_path])
654 env.AppendUnique(LIBS = env['mpi_libs'])
655 env.PrependENVPath(LD_LIBRARY_PATH_KEY, mpi_lib_path)
656 env.Append(CPPDEFINES = ['ESYS_MPI', 'MPI_NO_CPPBIND', 'MPICH_IGNORE_CXX_SEEK'])
657 # NetCDF 4.1 defines MPI_Comm et al. if MPI_INCLUDED is not defined!
658 # On the other hand MPT and OpenMPI don't define the latter so we have to
659 # do that here
660 if env['netcdf'] and env['mpi'] in ['MPT','OPENMPI']:
661 env.Append(CPPDEFINES = ['MPI_INCLUDED'])
662
663 ######## BOOMERAMG (optional)
664
665 if env['mpi'] == 'none': env['boomeramg'] = False
666
667 boomeramg_inc_path=''
668 boomeramg_lib_path=''
669 if env['boomeramg']:
670 boomeramg_inc_path,boomeramg_lib_path=findLibWithHeader(env, env['boomeramg_libs'], 'HYPRE.h', env['boomeramg_prefix'], lang='c')
671 env.AppendUnique(CPPPATH = [boomeramg_inc_path])
672 env.AppendUnique(LIBPATH = [boomeramg_lib_path])
673 env.AppendUnique(LIBS = env['boomeramg_libs'])
674 env.PrependENVPath(LD_LIBRARY_PATH_KEY, boomeramg_lib_path)
675 env.Append(CPPDEFINES = ['BOOMERAMG'])
676
677 ######## ParMETIS (optional)
678
679 if not env['usempi']: env['parmetis'] = False
680
681 parmetis_inc_path=''
682 parmetis_lib_path=''
683 if env['parmetis']:
684 parmetis_inc_path,parmetis_lib_path=findLibWithHeader(env, env['parmetis_libs'], 'parmetis.h', env['parmetis_prefix'], lang='c')
685 env.AppendUnique(CPPPATH = [parmetis_inc_path])
686 env.AppendUnique(LIBPATH = [parmetis_lib_path])
687 env.AppendUnique(LIBS = env['parmetis_libs'])
688 env.PrependENVPath(LD_LIBRARY_PATH_KEY, parmetis_lib_path)
689 env.Append(CPPDEFINES = ['USE_PARMETIS'])
690
691 ######## gmsh (optional, for tests)
692
693 try:
694 import subprocess
695 p=subprocess.Popen(['gmsh', '-info'], stderr=subprocess.PIPE)
696 _,e=p.communicate()
697 if e.split().count("MPI"):
698 env['gmsh']='m'
699 else:
700 env['gmsh']='s'
701 except OSError:
702 env['gmsh']=False
703
704 ######## PDFLaTeX (for documentation)
705 if 'PDF' in dir(env) and '.tex' in env.PDF.builder.src_suffixes(env):
706 env['pdflatex']=True
707 else:
708 env['pdflatex']=False
709
710 ######################## Summarize our environment ###########################
711
712 # keep some of our install paths first in the list for the unit tests
713 env.PrependENVPath(LD_LIBRARY_PATH_KEY, env['libinstall'])
714 env.PrependENVPath('PYTHONPATH', prefix)
715 env['ENV']['ESCRIPT_ROOT'] = prefix
716
717 if not env['verbose']:
718 env['CCCOMSTR'] = "Compiling $TARGET"
719 env['CXXCOMSTR'] = "Compiling $TARGET"
720 env['SHCCCOMSTR'] = "Compiling $TARGET"
721 env['SHCXXCOMSTR'] = "Compiling $TARGET"
722 env['ARCOMSTR'] = "Linking $TARGET"
723 env['LINKCOMSTR'] = "Linking $TARGET"
724 env['SHLINKCOMSTR'] = "Linking $TARGET"
725 env['PDFLATEXCOMSTR'] = "Building $TARGET from LaTeX input $SOURCES"
726 env['BIBTEXCOMSTR'] = "Generating bibliography $TARGET"
727 env['MAKEINDEXCOMSTR'] = "Generating index $TARGET"
728 env['PDFLATEXCOMSTR'] = "Building $TARGET from LaTeX input $SOURCES"
729 #Progress(['Checking -\r', 'Checking \\\r', 'Checking |\r', 'Checking /\r'], interval=17)
730
731 print("")
732 print("*** Config Summary (see config.log and lib/buildvars for details) ***")
733 print("Escript/Finley revision %s"%global_revision)
734 print(" Install prefix: %s"%env['prefix'])
735 print(" Python: %s"%sysconfig.PREFIX)
736 print(" boost: %s"%env['boost_prefix'])
737 print(" numpy: YES")
738 if env['usempi']:
739 print(" MPI: YES (flavour: %s)"%env['mpi'])
740 else:
741 print(" MPI: DISABLED")
742 if env['uselapack']:
743 print(" LAPACK: YES (flavour: %s)"%env['lapack'])
744 else:
745 print(" LAPACK: DISABLED")
746 d_list=[]
747 e_list=[]
748 for i in 'debug','openmp','netcdf','parmetis','papi','mkl','umfpack','boomeramg','silo','visit','vsl_random':
749 if env[i]: e_list.append(i)
750 else: d_list.append(i)
751 for i in e_list:
752 print("%16s: YES"%i)
753 for i in d_list:
754 print("%16s: DISABLED"%i)
755 if env['cppunit']:
756 print(" CppUnit: FOUND")
757 else:
758 print(" CppUnit: NOT FOUND")
759 if env['gmsh']=='m':
760 print(" gmsh: FOUND, MPI-ENABLED")
761 elif env['gmsh']=='s':
762 print(" gmsh: FOUND")
763 else:
764 print(" gmsh: NOT FOUND")
765 if env['numpy_h']:
766 print(" numpy headers: FOUND")
767 else:
768 print(" numpy headers: NOT FOUND")
769 print(" vsl_random: %s"%env['vsl_random'])
770
771 if ((fatalwarning != '') and (env['werror'])):
772 print(" Treating warnings as errors")
773 else:
774 print(" NOT treating warnings as errors")
775 print("")
776
777 ####################### Configure the subdirectories #########################
778
779 from grouptest import *
780
781 TestGroups=[]
782
783 # keep an environment without warnings-as-errors
784 dodgy_env=env.Clone()
785
786 # now add warnings-as-errors flags. This needs to be done after configuration
787 # because the scons test files have warnings in them
788 if ((fatalwarning != '') and (env['werror'])):
789 env.Append(CCFLAGS = fatalwarning)
790
791 Export(
792 ['env',
793 'dodgy_env',
794 'IS_WINDOWS',
795 'TestGroups'
796 ]
797 )
798
799 env.SConscript(dirs = ['tools/escriptconvert'], variant_dir='$BUILD_DIR/$PLATFORM/tools/escriptconvert', duplicate=0)
800 env.SConscript(dirs = ['paso/src'], variant_dir='$BUILD_DIR/$PLATFORM/paso', duplicate=0)
801 env.SConscript(dirs = ['weipa/src'], variant_dir='$BUILD_DIR/$PLATFORM/weipa', duplicate=0)
802 env.SConscript(dirs = ['escript/src'], variant_dir='$BUILD_DIR/$PLATFORM/escript', duplicate=0)
803 env.SConscript(dirs = ['esysUtils/src'], variant_dir='$BUILD_DIR/$PLATFORM/esysUtils', duplicate=0)
804 env.SConscript(dirs = ['pasowrap/src'], variant_dir='$BUILD_DIR/$PLATFORM/pasowrap', duplicate=0)
805 env.SConscript(dirs = ['dudley/src'], variant_dir='$BUILD_DIR/$PLATFORM/dudley', duplicate=0)
806 env.SConscript(dirs = ['finley/src'], variant_dir='$BUILD_DIR/$PLATFORM/finley', duplicate=0)
807 env.SConscript(dirs = ['modellib/py_src'], variant_dir='$BUILD_DIR/$PLATFORM/modellib', duplicate=0)
808 env.SConscript(dirs = ['doc'], variant_dir='$BUILD_DIR/$PLATFORM/doc', duplicate=0)
809 env.SConscript(dirs = ['pycad/py_src'], variant_dir='$BUILD_DIR/$PLATFORM/pycad', duplicate=0)
810 env.SConscript(dirs = ['pythonMPI/src'], variant_dir='$BUILD_DIR/$PLATFORM/pythonMPI', duplicate=0)
811 env.SConscript(dirs = ['paso/profiling'], variant_dir='$BUILD_DIR/$PLATFORM/paso/profiling', duplicate=0)
812
813
814 ######################## Populate the buildvars file #########################
815
816 # remove obsolete file
817 if not env['usempi']:
818 Execute(Delete(os.path.join(env['libinstall'], 'pythonMPI')))
819 Execute(Delete(os.path.join(env['libinstall'], 'pythonMPIredirect')))
820
821 # Try to extract the boost version from version.hpp
822 boosthpp=open(os.path.join(boost_inc_path, 'boost', 'version.hpp'))
823 boostversion='unknown'
824 try:
825 for line in boosthpp:
826 ver=re.match(r'#define BOOST_VERSION (\d+)',line)
827 if ver:
828 boostversion=ver.group(1)
829 except StopIteration:
830 pass
831 boosthpp.close()
832
833
834 buildvars=open(os.path.join(env['libinstall'], 'buildvars'), 'w')
835 buildvars.write("svn_revision="+str(global_revision)+"\n")
836 buildvars.write("prefix="+prefix+"\n")
837 buildvars.write("cc="+env['CC']+"\n")
838 buildvars.write("cxx="+env['CXX']+"\n")
839 if env['pythoncmd']=='python':
840 buildvars.write("python="+sys.executable+"\n")
841 buildvars.write("python_version="+str(sys.version_info[0])+"."+str(sys.version_info[1])+"."+str(sys.version_info[2])+"\n")
842 else:
843 buildvars.write("python="+env['pythoncmd']+"\n")
844 p=Popen([env['pythoncmd'], '-c', 'from __future__ import print_function;import sys;print(str(sys.version_info[0])+"."+str(sys.version_info[1])+"."+str(sys.version_info[2]))'], stdout=PIPE)
845 verstring=p.stdout.readline().strip()
846 p.wait()
847 buildvars.write("python_version="+verstring+"\n")
848 buildvars.write("boost_inc_path="+boost_inc_path+"\n")
849 buildvars.write("boost_lib_path="+boost_lib_path+"\n")
850 buildvars.write("boost_version="+boostversion+"\n")
851 buildvars.write("debug=%d\n"%int(env['debug']))
852 buildvars.write("openmp=%d\n"%int(env['openmp']))
853 buildvars.write("mpi=%s\n"%env['mpi'])
854 buildvars.write("mpi_inc_path=%s\n"%mpi_inc_path)
855 buildvars.write("mpi_lib_path=%s\n"%mpi_lib_path)
856 buildvars.write("lapack=%s\n"%env['lapack'])
857 buildvars.write("vsl_random=%d\n"%int(env['vsl_random']))
858 for i in 'netcdf','parmetis','papi','mkl','umfpack','boomeramg','silo','visit':
859 buildvars.write("%s=%d\n"%(i, int(env[i])))
860 if env[i]:
861 buildvars.write("%s_inc_path=%s\n"%(i, eval(i+'_inc_path')))
862 buildvars.write("%s_lib_path=%s\n"%(i, eval(i+'_lib_path')))
863 buildvars.close()
864
865 ################### Targets to build and install libraries ###################
866
867 target_init = env.Command(os.path.join(env['pyinstall'],'__init__.py'), None, Touch('$TARGET'))
868 env.Alias('target_init', [target_init])
869 # delete buildvars upon cleanup
870 env.Clean('target_init', os.path.join(env['libinstall'], 'buildvars'))
871
872 # The headers have to be installed prior to build in order to satisfy
873 # #include <paso/Common.h>
874 env.Alias('build_esysUtils', ['install_esysUtils_headers', 'build_esysUtils_lib'])
875 env.Alias('install_esysUtils', ['build_esysUtils', 'install_esysUtils_lib'])
876
877 env.Alias('build_paso', ['install_paso_headers', 'build_paso_lib'])
878 env.Alias('install_paso', ['build_paso', 'install_paso_lib'])
879
880 env.Alias('build_escript', ['install_escript_headers', 'build_escript_lib', 'build_escriptcpp_lib'])
881 env.Alias('install_escript', ['build_escript', 'install_escript_lib', 'install_escriptcpp_lib', 'install_escript_py'])
882
883 env.Alias('build_pasowrap', ['install_pasowrap_headers', 'build_pasowrap_lib', 'build_pasowrapcpp_lib'])
884 env.Alias('install_pasowrap', ['build_pasowrap', 'install_pasowrap_lib', 'install_pasowrapcpp_lib', 'install_pasowrap_py'])
885
886 env.Alias('build_dudley', ['install_dudley_headers', 'build_dudley_lib', 'build_dudleycpp_lib'])
887 env.Alias('install_dudley', ['build_dudley', 'install_dudley_lib', 'install_dudleycpp_lib', 'install_dudley_py'])
888
889 env.Alias('build_finley', ['install_finley_headers', 'build_finley_lib', 'build_finleycpp_lib'])
890 env.Alias('install_finley', ['build_finley', 'install_finley_lib', 'install_finleycpp_lib', 'install_finley_py'])
891
892
893 env.Alias('build_weipa', ['install_weipa_headers', 'build_weipa_lib', 'build_weipacpp_lib'])
894 env.Alias('install_weipa', ['build_weipa', 'install_weipa_lib', 'install_weipacpp_lib', 'install_weipa_py'])
895
896 env.Alias('build_escriptreader', ['install_weipa_headers', 'build_escriptreader_lib'])
897 env.Alias('install_escriptreader', ['build_escriptreader', 'install_escriptreader_lib'])
898
899 # Now gather all the above into some easy targets: build_all and install_all
900 build_all_list = []
901 build_all_list += ['build_esysUtils']
902 build_all_list += ['build_paso']
903 build_all_list += ['build_escript']
904 build_all_list += ['build_pasowrap']
905 build_all_list += ['build_dudley']
906 build_all_list += ['build_finley']
907 build_all_list += ['build_weipa']
908 if not IS_WINDOWS: build_all_list += ['build_escriptreader']
909 if env['usempi']: build_all_list += ['build_pythonMPI']
910 build_all_list += ['build_escriptconvert']
911 env.Alias('build_all', build_all_list)
912
913 install_all_list = []
914 install_all_list += ['target_init']
915 install_all_list += ['install_esysUtils']
916 install_all_list += ['install_paso']
917 install_all_list += ['install_escript']
918 install_all_list += ['install_pasowrap']
919 install_all_list += ['install_dudley']
920 install_all_list += ['install_finley']
921 install_all_list += ['install_weipa']
922 if not IS_WINDOWS: install_all_list += ['install_escriptreader']
923 install_all_list += ['install_modellib_py']
924 install_all_list += ['install_pycad_py']
925 if env['usempi']: install_all_list += ['install_pythonMPI']
926 install_all_list += ['install_escriptconvert']
927 env.Alias('install_all', install_all_list)
928
929 # Default target is install
930 env.Default('install_all')
931
932 ################## Targets to build and run the test suite ###################
933
934 if not env['cppunit']:
935 test_msg = env.Command('.dummy.', None, '@echo "Cannot run C/C++ unit tests, CppUnit not found!";exit 1')
936 env.Alias('run_tests', test_msg)
937 env.Alias('run_tests', ['install_all'])
938 env.Alias('all_tests', ['install_all', 'run_tests', 'py_tests'])
939 env.Alias('build_full',['install_all','build_tests','build_py_tests'])
940 env.Alias('build_PasoTests','$BUILD_DIR/$PLATFORM/paso/profiling/PasoTests')
941
942 ##################### Targets to build the documentation #####################
943
944 env.Alias('api_epydoc','install_all')
945 env.Alias('docs', ['examples_tarfile', 'examples_zipfile', 'api_epydoc', 'api_doxygen', 'user_pdf', 'install_pdf', 'cookbook_pdf'])
946 env.Alias('release_prep', ['docs', 'install_all'])
947
948 if not IS_WINDOWS:
949 try:
950 utest=open('utest.sh','w')
951 utest.write(GroupTest.makeHeader(env['PLATFORM'], prefix))
952 for tests in TestGroups:
953 utest.write(tests.makeString())
954 utest.close()
955 Execute(Chmod('utest.sh', 0o755))
956 print("Generated utest.sh.")
957 except IOError:
958 print("Error attempting to write unittests file.")
959 Exit(1)
960
961 # delete utest.sh upon cleanup
962 env.Clean('target_init', 'utest.sh')
963
964 # Make sure that the escript wrapper is in place
965 if not os.path.isfile(os.path.join(env['bininstall'], 'run-escript')):
966 print("Copying escript wrapper.")
967 Execute(Copy(os.path.join(env['bininstall'],'run-escript'), 'bin/run-escript'))
968

  ViewVC Help
Powered by ViewVC 1.1.26