/[escript]/trunk/SConstruct
ViewVC logotype

Annotation of /trunk/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2358 - (hide annotations)
Wed Apr 1 22:25:24 2009 UTC (9 years, 3 months ago) by gross
File size: 34034 byte(s)
mpi is not really ready yet.
1 ksteube 1811
2     ########################################################
3 jgs 214 #
4 ksteube 1811 # Copyright (c) 2003-2008 by University of Queensland
5     # Earth Systems Science Computational Center (ESSCC)
6     # http://www.uq.edu.au/esscc
7     #
8     # Primary Business: Queensland, Australia
9     # Licensed under the Open Software License version 3.0
10     # http://www.opensource.org/licenses/osl-3.0.php
11     #
12     ########################################################
13 jgs 455
14 ksteube 1811
15 robwdcock 682 EnsureSConsVersion(0,96,91)
16     EnsurePythonVersion(2,3)
17 jgs 214
18 jfenwick 2299 import sys, os, re, socket, platform, stat
19 ksteube 1705
20 robwdcock 682 # Add our extensions
21 ksteube 1705 if os.path.isdir('scons'): sys.path.append('scons')
22 robwdcock 682 import scons_extensions
23 jgs 192
24 ksteube 1705 # Use /usr/lib64 if available, else /usr/lib
25     usr_lib = '/usr/lib'
26     if os.path.isfile('/usr/lib64/libc.so'): usr_lib = '/usr/lib64'
27 gross 1374
28 ksteube 1705 # The string python2.4 or python2.5
29     python_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1])
30 gross 806
31 ksteube 1705 # MS Windows support, many thanks to PH
32     IS_WINDOWS_PLATFORM = (os.name== "nt")
33 gross 806
34 ksteube 1705 prefix = ARGUMENTS.get('prefix', Dir('#.').abspath)
35 ksteube 1217
36 ksteube 1705 # Read configuration options from file scons/<hostname>_options.py
37     hostname = re.sub("[^0-9a-zA-Z]", "_", socket.gethostname().split('.')[0])
38     tmp = os.path.join("scons",hostname+"_options.py")
39     options_file = ARGUMENTS.get('options_file', tmp)
40 ksteube 1866 if not os.path.isfile(options_file):
41     options_file = False
42 ksteube 1887 print "Options file not found (expected '%s')" % tmp
43 ksteube 1866 else:
44     print "Options file is", options_file
45 ksteube 1217
46 ksteube 1705 # Load options file and command-line arguments
47 gross 1133 opts = Options(options_file, ARGUMENTS)
48 gross 1149
49 ksteube 1705 ############ Load build options ################################
50 ksteube 1312
51 robwdcock 682 opts.AddOptions(
52     # Where to install esys stuff
53 ksteube 1705 ('prefix', 'where everything will be installed', Dir('#.').abspath),
54     ('incinstall', 'where the esys headers will be installed', os.path.join(Dir('#.').abspath,'include')),
55 ksteube 1756 ('bininstall', 'where the esys binaries will be installed', os.path.join(prefix,'bin')),
56 ksteube 1705 ('libinstall', 'where the esys libraries will be installed', os.path.join(prefix,'lib')),
57     ('pyinstall', 'where the esys python modules will be installed', os.path.join(prefix,'esys')),
58 robwdcock 682 # Compilation options
59 ksteube 1705 BoolOption('dodebug', 'For backwards compatibility', 'no'),
60     BoolOption('usedebug', 'Do you want a debug build?', 'no'),
61     BoolOption('usevtk', 'Do you want to use VTK?', 'yes'),
62     ('options_file', 'File of paths/options. Default: scons/<hostname>_options.py', options_file),
63 phornby 1930 ('win_cc_name', 'windows C compiler name if needed', 'msvc'),
64 ksteube 1705 # The strings -DDEFAULT_ get replaced by scons/<hostname>_options.py or by defaults below
65     ('cc_flags', 'C compiler flags to use', '-DEFAULT_1'),
66     ('cc_optim', 'C compiler optimization flags to use', '-DEFAULT_2'),
67     ('cc_debug', 'C compiler debug flags to use', '-DEFAULT_3'),
68     ('omp_optim', 'OpenMP compiler flags to use (Release build)', '-DEFAULT_4'),
69     ('omp_debug', 'OpenMP compiler flags to use (Debug build)', '-DEFAULT_5'),
70     ('omp_libs', 'OpenMP compiler libraries to link with', '-DEFAULT_6'),
71     ('cc_extra', 'Extra C/C++ flags', ''),
72 ksteube 1771 ('ld_extra', 'Extra linker flags', ''),
73 ksteube 1705 ('sys_libs', 'System libraries to link with', []),
74     ('ar_flags', 'Static library archiver flags to use', ''),
75 jfenwick 2292 BoolOption('useopenmp', 'Compile parallel version using OpenMP', 'no'),
76 jfenwick 2026 BoolOption('usepedantic', 'Compile with -pedantic if using gcc', 'no'),
77     BoolOption('usewarnings','Compile with warnings as errors if using gcc','yes'),
78 jfenwick 2273 ('forcelazy','for testing use only - set the default value for autolazy','leave_alone'),
79 robwdcock 682 # Python
80 ksteube 1705 ('python_path', 'Path to Python includes', '/usr/include/'+python_version),
81     ('python_lib_path', 'Path to Python libs', usr_lib),
82     ('python_libs', 'Python libraries to link with', [python_version]),
83 phornby 1243 ('python_cmd', 'Python command', 'python'),
84 robwdcock 682 # Boost
85 ksteube 1705 ('boost_path', 'Path to Boost includes', '/usr/include'),
86     ('boost_lib_path', 'Path to Boost libs', usr_lib),
87     ('boost_libs', 'Boost libraries to link with', ['boost_python']),
88     # NetCDF
89     BoolOption('usenetcdf', 'switch on/off the usage of netCDF', 'yes'),
90     ('netCDF_path', 'Path to netCDF includes', '/usr/include'),
91     ('netCDF_lib_path', 'Path to netCDF libs', usr_lib),
92     ('netCDF_libs', 'netCDF C++ libraries to link with', ['netcdf_c++', 'netcdf']),
93 bcumming 759 # MPI
94 ksteube 1705 BoolOption('useMPI', 'For backwards compatibility', 'no'),
95     BoolOption('usempi', 'Compile parallel version using MPI', 'no'),
96 ksteube 1312 ('MPICH_IGNORE_CXX_SEEK', 'name of macro to ignore MPI settings of C++ SEEK macro (for MPICH)' , 'MPICH_IGNORE_CXX_SEEK'),
97 ksteube 1705 ('mpi_path', 'Path to MPI includes', '/usr/include'),
98     ('mpi_run', 'mpirun name' , 'mpiexec -np 1'),
99     ('mpi_lib_path', 'Path to MPI libs (needs to be added to the LD_LIBRARY_PATH)', usr_lib),
100     ('mpi_libs', 'MPI libraries to link with (needs to be shared!)', ['mpich' , 'pthread', 'rt']),
101 jfenwick 2338 ('mpi_flavour','Type of MPI execution environment','none'),
102 ksteube 1705 # ParMETIS
103     BoolOption('useparmetis', 'Compile parallel version using ParMETIS', 'yes'),
104     ('parmetis_path', 'Path to ParMETIS includes', '/usr/include'),
105     ('parmetis_lib_path', 'Path to ParMETIS library', usr_lib),
106     ('parmetis_libs', 'ParMETIS library to link with', ['parmetis', 'metis']),
107     # PAPI
108     BoolOption('usepapi', 'switch on/off the usage of PAPI', 'no'),
109     ('papi_path', 'Path to PAPI includes', '/usr/include'),
110     ('papi_lib_path', 'Path to PAPI libs', usr_lib),
111     ('papi_libs', 'PAPI libraries to link with', ['papi']),
112     BoolOption('papi_instrument_solver', 'use PAPI in Solver.c to instrument each iteration of the solver', False),
113     # MKL
114     BoolOption('usemkl', 'switch on/off the usage of MKL', 'no'),
115     ('mkl_path', 'Path to MKL includes', '/sw/sdev/cmkl/10.0.2.18/include'),
116     ('mkl_lib_path', 'Path to MKL libs', '/sw/sdev/cmkl/10.0.2.18/lib/em64t'),
117     ('mkl_libs', 'MKL libraries to link with', ['mkl_solver', 'mkl_em64t', 'guide', 'pthread']),
118     # UMFPACK
119 ksteube 1708 BoolOption('useumfpack', 'switch on/off the usage of UMFPACK', 'no'),
120 ksteube 1705 ('ufc_path', 'Path to UFconfig includes', '/usr/include/suitesparse'),
121     ('umf_path', 'Path to UMFPACK includes', '/usr/include/suitesparse'),
122     ('umf_lib_path', 'Path to UMFPACK libs', usr_lib),
123     ('umf_libs', 'UMFPACK libraries to link with', ['umfpack']),
124 caltinay 2184 # Silo
125     BoolOption('usesilo', 'switch on/off the usage of Silo', 'yes'),
126     ('silo_path', 'Path to Silo includes', '/usr/include'),
127     ('silo_lib_path', 'Path to Silo libs', usr_lib),
128     ('silo_libs', 'Silo libraries to link with', ['siloh5', 'hdf5']),
129 ksteube 1705 # AMD (used by UMFPACK)
130     ('amd_path', 'Path to AMD includes', '/usr/include/suitesparse'),
131     ('amd_lib_path', 'Path to AMD libs', usr_lib),
132     ('amd_libs', 'AMD libraries to link with', ['amd']),
133     # BLAS (used by UMFPACK)
134     ('blas_path', 'Path to BLAS includes', '/usr/include/suitesparse'),
135     ('blas_lib_path', 'Path to BLAS libs', usr_lib),
136 phornby 2012 ('blas_libs', 'BLAS libraries to link with', ['blas']),
137     # An option for specifying the compiler tools set (see windows branch).
138 phornby 2054 ('tools_names', 'allow control over the tools in the env setup', ['intelc']),
139     # finer control over library building, intel aggressive global optimisation
140     # works with dynamic libraries on windows.
141     ('share_esysUtils', 'control static or dynamic esysUtils lib', False),
142     ('share_paso', 'control static or dynamic paso lib', False)
143 robwdcock 682 )
144 phornby 1232
145 ksteube 1705 ############ Specify which compilers to use ####################
146    
147     # intelc uses regular expressions improperly and emits a warning about
148     # failing to find the compilers. This warning can be safely ignored.
149    
150 gross 1133 if IS_WINDOWS_PLATFORM:
151 phornby 2012 env = Environment(options = opts)
152     env = Environment(tools = ['default'] + env['tools_names'],
153     options = opts)
154 robwdcock 682 else:
155 ksteube 1559 if socket.gethostname().split('.')[0] == 'service0':
156 gross 1133 env = Environment(tools = ['default', 'intelc'], options = opts)
157 ksteube 1559 elif os.uname()[4]=='ia64':
158     env = Environment(tools = ['default', 'intelc'], options = opts)
159 gross 1133 if env['CXX'] == 'icpc':
160 ksteube 1705 env['LINK'] = env['CXX'] # version >=9 of intel c++ compiler requires use of icpc to link in C++ runtimes (icc does not)
161 gross 1133 else:
162     env = Environment(tools = ['default'], options = opts)
163     Help(opts.GenerateHelpText(env))
164 phornby 1232
165 ksteube 1705 ############ Fill in compiler options if not set above #########
166 ksteube 1312
167 ksteube 1705 # Backwards compatibility: allow dodebug=yes and useMPI=yes
168     if env['dodebug']: env['usedebug'] = 1
169     if env['useMPI']: env['usempi'] = 1
170 gross 1024
171 ksteube 1705 # Default compiler options (override allowed in hostname_options.py, but should not be necessary)
172     # For both C and C++ you get: cc_flags and either the optim flags or debug flags
173 phornby 1243
174 jfenwick 2130 sysheaderopt = "" # how do we indicate that a header is a system header. Use "" for no action.
175    
176 ksteube 1705 if env["CC"] == "icc":
177     # Intel compilers
178     cc_flags = "-fPIC -ansi -wd161 -w1 -vec-report0 -DBLOCKTIMER -DCORE_ID1"
179     cc_optim = "-O3 -ftz -IPF_ftlacc- -IPF_fma -fno-alias"
180 jfenwick 1796 cc_debug = "-g -O0 -DDOASSERT -DDOPROF -DBOUNDS_CHECK"
181 ksteube 1705 omp_optim = "-openmp -openmp_report0"
182     omp_debug = "-openmp -openmp_report0"
183     omp_libs = ['guide', 'pthread']
184     pedantic = ""
185 jfenwick 2026 fatalwarning = "" # Switch to turn warnings into errors
186 jfenwick 2130 sysheaderopt = ""
187 ksteube 1705 elif env["CC"] == "gcc":
188     # GNU C on any system
189 gross 2208 cc_flags = "-pedantic -Wall -fPIC -ansi -ffast-math -Wno-unknown-pragmas -DBLOCKTIMER -Wno-sign-compare -Wno-system-headers -Wno-long-long -Wno-strict-aliasing"
190 jfenwick 2063 #the long long warning occurs on the Mac
191 ksteube 1705 cc_optim = "-O3"
192 jfenwick 1796 cc_debug = "-g -O0 -DDOASSERT -DDOPROF -DBOUNDS_CHECK"
193 gross 2300 omp_optim = "-fopenmp"
194     omp_debug = "-fopenmp"
195     omp_libs = ['gomp']
196 ksteube 1705 pedantic = "-pedantic-errors -Wno-long-long"
197 jfenwick 2026 fatalwarning = "-Werror"
198 jfenwick 2130 sysheaderopt = "-isystem "
199 ksteube 1705 elif env["CC"] == "cl":
200     # Microsoft Visual C on Windows
201     cc_flags = "/FD /EHsc /GR /wd4068 -D_USE_MATH_DEFINES -DDLL_NETCDF"
202     cc_optim = "/O2 /Op /MT /W3"
203     cc_debug = "/Od /RTC1 /MTd /ZI -DBOUNDS_CHECK"
204     omp_optim = ""
205     omp_debug = ""
206     omp_libs = []
207     pedantic = ""
208 jfenwick 2026 fatalwarning = ""
209 jfenwick 2130 sysheaderopt = ""
210 phornby 1930 elif env["CC"] == "icl":
211 phornby 2027 # intel C on Windows, see windows_intelc_options.py for a start
212 phornby 1930 pedantic = ""
213 jfenwick 2026 fatalwarning = ""
214 jfenwick 2130 sysheaderopt = ""
215 phornby 1243
216 jfenwick 2130
217 ksteube 1705 # If not specified in hostname_options.py then set them here
218     if env["cc_flags"] == "-DEFAULT_1": env['cc_flags'] = cc_flags
219     if env["cc_optim"] == "-DEFAULT_2": env['cc_optim'] = cc_optim
220     if env["cc_debug"] == "-DEFAULT_3": env['cc_debug'] = cc_debug
221     if env["omp_optim"] == "-DEFAULT_4": env['omp_optim'] = omp_optim
222     if env["omp_debug"] == "-DEFAULT_5": env['omp_debug'] = omp_debug
223     if env["omp_libs"] == "-DEFAULT_6": env['omp_libs'] = omp_libs
224 ksteube 1312
225 jfenwick 2273 #set up the autolazy values
226     if env['forcelazy'] != "leave_alone":
227     if env['forcelazy'] == 'on':
228     env.Append(CPPDEFINES='FAUTOLAZYON')
229     else:
230     if env['forcelazy'] == 'off':
231     env.Append(CPPDEFINES='FAUTOLAZYOFF')
232    
233 ksteube 1705 # OpenMP is disabled if useopenmp=no or both variables omp_optim and omp_debug are empty
234     if not env["useopenmp"]:
235     env['omp_optim'] = ""
236     env['omp_debug'] = ""
237     env['omp_libs'] = []
238 gross 1160
239 ksteube 1705 if env['omp_optim'] == "" and env['omp_debug'] == "": env["useopenmp"] = 0
240 ksteube 1312
241 ksteube 1705 ############ Copy environment variables into scons env #########
242 gross 1163
243 ksteube 1705 try: env['ENV']['OMP_NUM_THREADS'] = os.environ['OMP_NUM_THREADS']
244     except KeyError: env['ENV']['OMP_NUM_THREADS'] = 1
245 phornby 1243
246 ksteube 1705 try: env['ENV']['PATH'] = os.environ['PATH']
247     except KeyError: pass
248 robwdcock 682
249 ksteube 1705 try: env['ENV']['PYTHONPATH'] = os.environ['PYTHONPATH']
250     except KeyError: pass
251 phornby 1244
252 ksteube 1705 try: env['ENV']['C_INCLUDE_PATH'] = os.environ['C_INCLUDE_PATH']
253     except KeyError: pass
254 robwdcock 682
255 ksteube 1705 try: env['ENV']['CPLUS_INCLUDE_PATH'] = os.environ['CPLUS_INCLUDE_PATH']
256     except KeyError: pass
257 robwdcock 682
258 ksteube 1705 try: env['ENV']['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
259     except KeyError: pass
260 ksteube 1312
261 ksteube 1705 try: env['ENV']['LIBRARY_PATH'] = os.environ['LIBRARY_PATH']
262     except KeyError: pass
263 ksteube 1312
264 ksteube 1705 try: env['ENV']['DISPLAY'] = os.environ['DISPLAY']
265     except KeyError: pass
266 ksteube 1312
267 ksteube 1705 try: env['ENV']['XAUTHORITY'] = os.environ['XAUTHORITY']
268     except KeyError: pass
269 ksteube 1312
270 ksteube 1705 try: env['ENV']['HOME'] = os.environ['HOME']
271     except KeyError: pass
272 ksteube 1312
273 ksteube 1705 # Configure for test suite
274     env.PrependENVPath('PYTHONPATH', prefix)
275     env.PrependENVPath('LD_LIBRARY_PATH', env['libinstall'])
276 ksteube 1312
277 ksteube 1756 env['ENV']['ESCRIPT_ROOT'] = prefix
278    
279 ksteube 1705 ############ Set up paths for Configure() ######################
280 ksteube 817
281 ksteube 1705 # Make a copy of an environment
282     # Use env.Clone if available, but fall back on env.Copy for older version of scons
283     def clone_env(env):
284     if 'Clone' in dir(env): return env.Clone() # scons-0.98
285     else: return env.Copy() # scons-0.96
286 phornby 1246
287 ksteube 1705 # Add cc option -I<Escript>/trunk/include
288     env.Append(CPPPATH = [Dir('include')])
289 phornby 1634
290 ksteube 1705 # Add cc option -L<Escript>/trunk/lib
291 ksteube 1729 env.Append(LIBPATH = [Dir(env['libinstall'])])
292 ksteube 1705
293     if env['cc_extra'] != '': env.Append(CCFLAGS = env['cc_extra'])
294 ksteube 1771 if env['ld_extra'] != '': env.Append(LINKFLAGS = env['ld_extra'])
295 ksteube 1705
296     if env['usepedantic']: env.Append(CCFLAGS = pedantic)
297    
298     # MS Windows
299     if IS_WINDOWS_PLATFORM:
300 jfenwick 2334 env.AppendENVPath('PATH', [env['boost_lib_path']])
301     env.AppendENVPath('PATH', [env['libinstall']])
302 phornby 2054 if not env['share_esysUtils'] :
303     env.Append(CPPDEFINES = ['ESYSUTILS_STATIC_LIB'])
304     if not env['share_paso'] :
305     env.Append(CPPDEFINES = ['PASO_STATIC_LIB'])
306 phornby 2040
307 ksteube 1705 if env['usenetcdf']:
308 jfenwick 2334 env.AppendENVPath('PATH', [env['netCDF_lib_path']])
309 ksteube 1705
310     env.Append(ARFLAGS = env['ar_flags'])
311    
312     # Get the global Subversion revision number for getVersion() method
313 robwdcock 682 try:
314 ksteube 1705 global_revision = os.popen("svnversion -n .").read()
315     global_revision = re.sub(":.*", "", global_revision)
316     global_revision = re.sub("[^0-9]", "", global_revision)
317 ksteube 1312 except:
318 ksteube 1705 global_revision="-1"
319     if global_revision == "": global_revision="-2"
320     env.Append(CPPDEFINES = ["SVN_VERSION="+global_revision])
321 phornby 1634
322 ksteube 1705 ############ numarray (required) ###############################
323 robwdcock 682
324 ksteube 1705 try:
325     from numarray import identity
326     except ImportError:
327     print "Cannot import numarray, you need to set your PYTHONPATH"
328     sys.exit(1)
329 ksteube 1348
330 ksteube 1705 ############ C compiler (required) #############################
331 gross 700
332 ksteube 1705 # Create a Configure() environment for checking existence of required libraries and headers
333     conf = Configure(clone_env(env))
334 gross 700
335 ksteube 1705 # Test that the compiler is working
336     if not conf.CheckFunc('printf'):
337 gross 2284 print "Cannot run C compiler '%s' (or libc is missing)" % (env['CC'])
338     sys.exit(1)
339 gross 806
340 phornby 1789 if conf.CheckFunc('gethostname'):
341     conf.env.Append(CPPDEFINES = ['HAVE_GETHOSTNAME'])
342 gross 806
343 ksteube 1705 ############ python libraries (required) #######################
344 gross 806
345 jfenwick 2130
346     if not sysheaderopt =="":
347     conf.env.Append(CCFLAGS=sysheaderopt+env['python_path'])
348     else:
349     conf.env.AppendUnique(CPPPATH = [env['python_path']])
350    
351 ksteube 1705 conf.env.AppendUnique(LIBPATH = [env['python_lib_path']])
352     conf.env.AppendUnique(LIBS = [env['python_libs']])
353 gross 805
354 ksteube 1785 conf.env.PrependENVPath('LD_LIBRARY_PATH', env['python_lib_path']) # The wrapper script needs to find these libs
355 jfenwick 2296 conf.env.PrependENVPath('PYTHONPATH', prefix)
356     conf.env.PrependENVPath('LD_LIBRARY_PATH', env['libinstall'])
357 ksteube 1785
358 ksteube 1705 if not conf.CheckCHeader('Python.h'):
359     print "Cannot find python include files (tried 'Python.h' in directory %s)" % (env['python_path'])
360     sys.exit(1)
361 gross 2284 if not conf.CheckFunc('Py_Exit'):
362 ksteube 1705 print "Cannot find python library method Py_Main (tried lib %s in directory %s)" % (env['python_libs'], env['python_lib_path'])
363     sys.exit(1)
364 gross 805
365 ksteube 1705 ############ boost (required) ##################################
366 gross 805
367 jfenwick 2130 if not sysheaderopt =="":
368 jfenwick 2295 # This is required because we can't -isystem /usr/system because it breaks std includes
369     if os.path.normpath(env['boost_path']) =="/usr/include":
370     conf.env.Append(CCFLAGS=sysheaderopt+os.path.join(env['boost_path'],'boost'))
371     else:
372     conf.env.Append(CCFLAGS=sysheaderopt+env['boost_path'])
373 jfenwick 2130 else:
374     conf.env.AppendUnique(CPPPATH = [env['boost_path']])
375    
376 ksteube 1705 conf.env.AppendUnique(LIBPATH = [env['boost_lib_path']])
377     conf.env.AppendUnique(LIBS = [env['boost_libs']])
378 ksteube 1312
379 ksteube 1785 conf.env.PrependENVPath('LD_LIBRARY_PATH', env['boost_lib_path']) # The wrapper script needs to find these libs
380 jfenwick 2296 #ensure that our path entries remain at the front
381     conf.env.PrependENVPath('PYTHONPATH', prefix)
382     conf.env.PrependENVPath('LD_LIBRARY_PATH', env['libinstall'])
383 ksteube 1785
384 ksteube 1705 if not conf.CheckCXXHeader('boost/python.hpp'):
385     print "Cannot find boost include files (tried boost/python.hpp in directory %s)" % (env['boost_path'])
386     sys.exit(1)
387 gross 2284
388 ksteube 1705 if not conf.CheckFunc('PyObject_SetAttr'):
389     print "Cannot find boost library method PyObject_SetAttr (tried method PyObject_SetAttr in library %s in directory %s)" % (env['boost_libs'], env['boost_lib_path'])
390     sys.exit(1)
391 ksteube 1312
392 ksteube 1705 # Commit changes to environment
393     env = conf.Finish()
394 ksteube 1312
395 ksteube 1705 ############ VTK (optional) ####################################
396 ksteube 1312
397 ksteube 1705 if env['usevtk']:
398     try:
399     import vtk
400     env['usevtk'] = 1
401     except ImportError:
402     env['usevtk'] = 0
403 gross 806
404 ksteube 1705 # Add VTK to environment env if it was found
405     if env['usevtk']:
406     env.Append(CPPDEFINES = ['USE_VTK'])
407 gross 805
408 ksteube 1705 ############ NetCDF (optional) #################################
409 gross 805
410 ksteube 1705 conf = Configure(clone_env(env))
411 gross 806
412 ksteube 1705 if env['usenetcdf']:
413     conf.env.AppendUnique(CPPPATH = [env['netCDF_path']])
414     conf.env.AppendUnique(LIBPATH = [env['netCDF_lib_path']])
415     conf.env.AppendUnique(LIBS = [env['netCDF_libs']])
416 ksteube 1785 conf.env.PrependENVPath('LD_LIBRARY_PATH', env['netCDF_lib_path']) # The wrapper script needs to find these libs
417 jfenwick 2296 #ensure that our path entries remain at the front
418     conf.env.PrependENVPath('PYTHONPATH', prefix)
419     conf.env.PrependENVPath('LD_LIBRARY_PATH', env['libinstall'])
420 gross 806
421 ksteube 1705 if env['usenetcdf'] and not conf.CheckCHeader('netcdf.h'): env['usenetcdf'] = 0
422     if env['usenetcdf'] and not conf.CheckFunc('nc_open'): env['usenetcdf'] = 0
423 ksteube 1312
424 ksteube 1705 # Add NetCDF to environment env if it was found
425     if env['usenetcdf']:
426     env = conf.Finish()
427     env.Append(CPPDEFINES = ['USE_NETCDF'])
428     else:
429     conf.Finish()
430 ksteube 1312
431 ksteube 1705 ############ PAPI (optional) ###################################
432    
433     # Start a new configure environment that reflects what we've already found
434     conf = Configure(clone_env(env))
435    
436     if env['usepapi']:
437     conf.env.AppendUnique(CPPPATH = [env['papi_path']])
438     conf.env.AppendUnique(LIBPATH = [env['papi_lib_path']])
439     conf.env.AppendUnique(LIBS = [env['papi_libs']])
440 ksteube 1785 conf.env.PrependENVPath('LD_LIBRARY_PATH', env['papi_lib_path']) # The wrapper script needs to find these libs
441 jfenwick 2296 #ensure that our path entries remain at the front
442     conf.env.PrependENVPath('PYTHONPATH', prefix)
443     conf.env.PrependENVPath('LD_LIBRARY_PATH', env['libinstall'])
444 ksteube 1705
445     if env['usepapi'] and not conf.CheckCHeader('papi.h'): env['usepapi'] = 0
446     if env['usepapi'] and not conf.CheckFunc('PAPI_start_counters'): env['usepapi'] = 0
447    
448     # Add PAPI to environment env if it was found
449     if env['usepapi']:
450     env = conf.Finish()
451     env.Append(CPPDEFINES = ['BLOCKPAPI'])
452 ksteube 1312 else:
453 ksteube 1705 conf.Finish()
454 ksteube 1312
455 ksteube 1705 ############ MKL (optional) ####################################
456 gross 806
457 ksteube 1705 # Start a new configure environment that reflects what we've already found
458     conf = Configure(clone_env(env))
459 gross 806
460 ksteube 1705 if env['usemkl']:
461     conf.env.AppendUnique(CPPPATH = [env['mkl_path']])
462     conf.env.AppendUnique(LIBPATH = [env['mkl_lib_path']])
463     conf.env.AppendUnique(LIBS = [env['mkl_libs']])
464 ksteube 1785 conf.env.PrependENVPath('LD_LIBRARY_PATH', env['mkl_lib_path']) # The wrapper script needs to find these libs
465 jfenwick 2296 #ensure that our path entries remain at the front
466     conf.env.PrependENVPath('PYTHONPATH', prefix)
467     conf.env.PrependENVPath('LD_LIBRARY_PATH', env['libinstall'])
468 gross 805
469 ksteube 1705 if env['usemkl'] and not conf.CheckCHeader('mkl_solver.h'): env['usemkl'] = 0
470 gross 2358 if env['usemkl'] and not conf.CheckFunc('pardiso'): env['usemkl'] = 0
471 phornby 1246
472 ksteube 1705 # Add MKL to environment env if it was found
473     if env['usemkl']:
474     env = conf.Finish()
475     env.Append(CPPDEFINES = ['MKL'])
476     else:
477     conf.Finish()
478 gross 950
479 ksteube 1705 ############ UMFPACK (optional) ################################
480    
481     # Start a new configure environment that reflects what we've already found
482     conf = Configure(clone_env(env))
483    
484     if env['useumfpack']:
485     conf.env.AppendUnique(CPPPATH = [env['ufc_path']])
486     conf.env.AppendUnique(CPPPATH = [env['umf_path']])
487     conf.env.AppendUnique(LIBPATH = [env['umf_lib_path']])
488     conf.env.AppendUnique(LIBS = [env['umf_libs']])
489     conf.env.AppendUnique(CPPPATH = [env['amd_path']])
490     conf.env.AppendUnique(LIBPATH = [env['amd_lib_path']])
491     conf.env.AppendUnique(LIBS = [env['amd_libs']])
492     conf.env.AppendUnique(CPPPATH = [env['blas_path']])
493     conf.env.AppendUnique(LIBPATH = [env['blas_lib_path']])
494     conf.env.AppendUnique(LIBS = [env['blas_libs']])
495 ksteube 1785 conf.env.PrependENVPath('LD_LIBRARY_PATH', env['umf_lib_path']) # The wrapper script needs to find these libs
496     conf.env.PrependENVPath('LD_LIBRARY_PATH', env['amd_lib_path']) # The wrapper script needs to find these libs
497     conf.env.PrependENVPath('LD_LIBRARY_PATH', env['blas_lib_path']) # The wrapper script needs to find these libs
498 jfenwick 2296 #ensure that our path entries remain at the front
499     conf.env.PrependENVPath('PYTHONPATH', prefix)
500     conf.env.PrependENVPath('LD_LIBRARY_PATH', env['libinstall'])
501 ksteube 1705
502 gross 2284 if env['useumfpack'] and not conf.CheckFunc('umfpack_di_symbolic'): env['useumfpack'] = 0
503 gross 2101 if env['useumfpack'] and not conf.CheckCHeader('umfpack.h'): env['useumfpack'] = 0
504 gross 2284 # if env['useumfpack'] and not conf.CheckFunc('daxpy'): env['useumfpack'] = 0 # this does not work on shake73?
505 ksteube 1705
506     # Add UMFPACK to environment env if it was found
507     if env['useumfpack']:
508     env = conf.Finish()
509     env.Append(CPPDEFINES = ['UMFPACK'])
510 gross 1023 else:
511 ksteube 1705 conf.Finish()
512 gross 1023
513 caltinay 2184 ############ Silo (optional) ###################################
514    
515     if env['usesilo']:
516     conf = Configure(clone_env(env))
517     conf.env.AppendUnique(CPPPATH = [env['silo_path']])
518     conf.env.AppendUnique(LIBPATH = [env['silo_lib_path']])
519     conf.env.AppendUnique(LIBS = [env['silo_libs']])
520     if not conf.CheckCHeader('silo.h'): env['usesilo'] = 0
521     if not conf.CheckFunc('DBMkDir'): env['usesilo'] = 0
522     conf.Finish()
523    
524     # Add the path to Silo to environment env if it was found.
525     # Note that we do not add the libs since they are only needed for the
526     # escriptreader library and tools.
527     if env['usesilo']:
528     env.AppendUnique(CPPPATH = [env['silo_path']])
529     env.AppendUnique(LIBPATH = [env['silo_lib_path']])
530     env.Append(CPPDEFINES = ['HAVE_SILO'])
531    
532 ksteube 1705 ############ Add the compiler flags ############################
533 ksteube 1459
534 ksteube 1705 # Enable debug by choosing either cc_debug or cc_optim
535     if env['usedebug']:
536     env.Append(CCFLAGS = env['cc_debug'])
537     env.Append(CCFLAGS = env['omp_debug'])
538     else:
539     env.Append(CCFLAGS = env['cc_optim'])
540     env.Append(CCFLAGS = env['omp_optim'])
541 robwdcock 682
542 ksteube 1705 # Always use cc_flags
543     env.Append(CCFLAGS = env['cc_flags'])
544     env.Append(LIBS = [env['omp_libs']])
545 gross 707
546 jfenwick 2232 ############ Add some custom builders ##########################
547    
548     py_builder = Builder(action = scons_extensions.build_py, suffix = '.pyc', src_suffix = '.py', single_source=True)
549     env.Append(BUILDERS = {'PyCompile' : py_builder});
550    
551     runUnitTest_builder = Builder(action = scons_extensions.runUnitTest, suffix = '.passed', src_suffix=env['PROGSUFFIX'], single_source=True)
552     env.Append(BUILDERS = {'RunUnitTest' : runUnitTest_builder});
553    
554     runPyUnitTest_builder = Builder(action = scons_extensions.runPyUnitTest, suffix = '.passed', src_suffic='.py', single_source=True)
555     env.Append(BUILDERS = {'RunPyUnitTest' : runPyUnitTest_builder});
556    
557 ksteube 1705 ############ MPI (optional) ####################################
558    
559     # Create a modified environment for MPI programs (identical to env if usempi=no)
560     env_mpi = clone_env(env)
561    
562     # Start a new configure environment that reflects what we've already found
563     conf = Configure(clone_env(env_mpi))
564    
565     if env_mpi['usempi']:
566 gross 2356 VALID_MPIs=[ "MPT", "OPENMPI", "MPICH", "OPENMPI", "INTELMPI" ]
567     if not env_mpi['mpi_flavour'] in VALID_MPIs:
568 gross 2358 raise ValueError,"MPI is enabled but mpi_flavour = %s is not a valid key from %s."%( env_mpi['mpi_flavour'],VALID_MPIs)
569 ksteube 1705 conf.env.AppendUnique(CPPPATH = [env_mpi['mpi_path']])
570     conf.env.AppendUnique(LIBPATH = [env_mpi['mpi_lib_path']])
571     conf.env.AppendUnique(LIBS = [env_mpi['mpi_libs']])
572 ksteube 1785 conf.env.PrependENVPath('LD_LIBRARY_PATH', env['mpi_lib_path']) # The wrapper script needs to find these libs
573 jfenwick 2296 #ensure that our path entries remain at the front
574     conf.env.PrependENVPath('PYTHONPATH', prefix)
575     conf.env.PrependENVPath('LD_LIBRARY_PATH', env['libinstall'])
576 ksteube 1705
577     if env_mpi['usempi'] and not conf.CheckCHeader('mpi.h'): env_mpi['usempi'] = 0
578 gross 2308 # if env_mpi['usempi'] and not conf.CheckFunc('MPI_Init'): env_mpi['usempi'] = 0
579 ksteube 1705
580     # Add MPI to environment env_mpi if it was found
581     if env_mpi['usempi']:
582     env_mpi = conf.Finish()
583     env_mpi.Append(CPPDEFINES = ['PASO_MPI', 'MPI_NO_CPPBIND', env_mpi['MPICH_IGNORE_CXX_SEEK']])
584 ksteube 1312 else:
585 ksteube 1705 conf.Finish()
586 ksteube 1312
587 ksteube 1705 env['usempi'] = env_mpi['usempi']
588 ksteube 1312
589 ksteube 1705 ############ ParMETIS (optional) ###############################
590 gross 700
591 ksteube 1705 # Start a new configure environment that reflects what we've already found
592     conf = Configure(clone_env(env_mpi))
593 gross 700
594 ksteube 1705 if not env_mpi['usempi']: env_mpi['useparmetis'] = 0
595 gross 700
596 ksteube 1705 if env_mpi['useparmetis']:
597     conf.env.AppendUnique(CPPPATH = [env_mpi['parmetis_path']])
598     conf.env.AppendUnique(LIBPATH = [env_mpi['parmetis_lib_path']])
599     conf.env.AppendUnique(LIBS = [env_mpi['parmetis_libs']])
600 ksteube 1785 conf.env.PrependENVPath('LD_LIBRARY_PATH', env['parmetis_lib_path']) # The wrapper script needs to find these libs
601 jfenwick 2296 #ensure that our path entries remain at the front
602     conf.env.PrependENVPath('PYTHONPATH', prefix)
603     conf.env.PrependENVPath('LD_LIBRARY_PATH', env['libinstall'])
604 gross 707
605 ksteube 1705 if env_mpi['useparmetis'] and not conf.CheckCHeader('parmetis.h'): env_mpi['useparmetis'] = 0
606     if env_mpi['useparmetis'] and not conf.CheckFunc('ParMETIS_V3_PartGeomKway'): env_mpi['useparmetis'] = 0
607 elspeth 712
608 ksteube 1705 # Add ParMETIS to environment env_mpi if it was found
609     if env_mpi['useparmetis']:
610     env_mpi = conf.Finish()
611     env_mpi.Append(CPPDEFINES = ['USE_PARMETIS'])
612     else:
613     conf.Finish()
614 ksteube 1215
615 ksteube 1705 env['useparmetis'] = env_mpi['useparmetis']
616 ksteube 1247
617 jfenwick 2026 ############ Now we switch on Warnings as errors ###############
618    
619     #this needs to be done after configuration because the scons test files have warnings in them
620    
621     if ((fatalwarning != "") and (env['usewarnings'])):
622     env.Append(CCFLAGS = fatalwarning)
623     env_mpi.Append(CCFLAGS = fatalwarning)
624    
625 ksteube 1705 ############ Summarize our environment #########################
626 phornby 1243
627 ksteube 1705 print ""
628     print "Summary of configuration (see ./config.log for information)"
629     print " Using python libraries"
630     print " Using numarray"
631     print " Using boost"
632     if env['usenetcdf']: print " Using NetCDF"
633     else: print " Not using NetCDF"
634     if env['usevtk']: print " Using VTK"
635     else: print " Not using VTK"
636     if env['usemkl']: print " Using MKL"
637     else: print " Not using MKL"
638     if env['useumfpack']: print " Using UMFPACK"
639     else: print " Not using UMFPACK"
640 caltinay 2184 if env['usesilo']: print " Using Silo"
641     else: print " Not using Silo"
642 ksteube 1705 if env['useopenmp']: print " Using OpenMP"
643     else: print " Not using OpenMP"
644 gross 2356 if env['usempi']: print " Using MPI (flavour = %s)"%env['mpi_flavour']
645 ksteube 1705 else: print " Not using MPI"
646     if env['useparmetis']: print " Using ParMETIS"
647     else: print " Not using ParMETIS (requires MPI)"
648     if env['usepapi']: print " Using PAPI"
649     else: print " Not using PAPI"
650     if env['usedebug']: print " Compiling for debug"
651     else: print " Not compiling for debug"
652     print " Installing in", prefix
653 jfenwick 2026 if ((fatalwarning != "") and (env['usewarnings'])): print " Treating warnings as errors"
654     else: print " Not treating warnings as errors"
655 ksteube 1705 print ""
656 phornby 1243
657 ksteube 1756 ############ Delete option-dependent files #####################
658    
659 jfenwick 2324 Execute(Delete(os.path.join(env['libinstall'],"Compiled.with.debug")))
660     Execute(Delete(os.path.join(env['libinstall'],"Compiled.with.mpi")))
661     Execute(Delete(os.path.join(env['libinstall'],"Compiled.with.openmp")))
662     Execute(Delete(os.path.join(env['libinstall'],"pyversion")))
663     Execute(Delete(os.path.join(env['libinstall'],"buildvars")))
664     if not env['usempi']: Execute(Delete(os.path.join(env['libinstall'],"pythonMPI")))
665 ksteube 1756
666 phornby 1243
667 ksteube 1756 ############ Build the subdirectories ##########################
668 robwdcock 682
669 jfenwick 2235 from grouptest import *
670    
671     TestGroups=[]
672    
673 phornby 2027 Export(
674     ["env",
675     "env_mpi",
676     "clone_env",
677 jfenwick 2235 "IS_WINDOWS_PLATFORM",
678     "TestGroups"
679 phornby 2027 ]
680     )
681 ksteube 1705
682 robwdcock 682 env.SConscript(dirs = ['tools/CppUnitTest/src'], build_dir='build/$PLATFORM/tools/CppUnitTest', duplicate=0)
683 caltinay 2184 env.SConscript(dirs = ['tools/libescriptreader/src'], build_dir='build/$PLATFORM/tools/libescriptreader', duplicate=0)
684 ksteube 1705 env.SConscript(dirs = ['paso/src'], build_dir='build/$PLATFORM/paso', duplicate=0)
685     env.SConscript(dirs = ['escript/src'], build_dir='build/$PLATFORM/escript', duplicate=0)
686 phornby 1628 env.SConscript(dirs = ['esysUtils/src'], build_dir='build/$PLATFORM/esysUtils', duplicate=0)
687 robwdcock 682 env.SConscript(dirs = ['finley/src'], build_dir='build/$PLATFORM/finley', duplicate=0)
688     env.SConscript(dirs = ['modellib/py_src'], build_dir='build/$PLATFORM/modellib', duplicate=0)
689 gross 707 env.SConscript(dirs = ['doc'], build_dir='build/$PLATFORM/doc', duplicate=0)
690 matt 863 env.SConscript(dirs = ['pyvisi/py_src'], build_dir='build/$PLATFORM/pyvisi', duplicate=0)
691 gross 898 env.SConscript(dirs = ['pycad/py_src'], build_dir='build/$PLATFORM/pycad', duplicate=0)
692 matt 863 env.SConscript(dirs = ['pythonMPI/src'], build_dir='build/$PLATFORM/pythonMPI', duplicate=0)
693 ksteube 1756 env.SConscript(dirs = ['scripts'], build_dir='build/$PLATFORM/scripts', duplicate=0)
694 artak 2161 env.SConscript(dirs = ['paso/profiling'], build_dir='build/$PLATFORM/paso/profiling', duplicate=0)
695 phornby 1243
696 jfenwick 2235
697 ksteube 1705 ############ Remember what optimizations we used ###############
698 phornby 1243
699 ksteube 1705 remember_list = []
700 phornby 1243
701 ksteube 1705 if env['usedebug']:
702 jfenwick 2324 remember_list += env.Command(os.path.join(env['libinstall'],"Compiled.with.debug"), None, Touch('$TARGET'))
703 ksteube 1705
704     if env['usempi']:
705 jfenwick 2324 remember_list += env.Command(os.path.join(env['libinstall'],"Compiled.with.mpi"), None, Touch('$TARGET'))
706 ksteube 1705
707 jfenwick 2302 if env['useopenmp']:
708 jfenwick 2324 remember_list += env.Command(os.path.join(env['libinstall'],"Compiled.with.openmp"), None, Touch('$TARGET'))
709 ksteube 1705
710     env.Alias('remember_options', remember_list)
711    
712 jfenwick 2297
713     ############### Record python interpreter version ##############
714    
715     if not IS_WINDOWS_PLATFORM:
716     versionstring="Python "+str(sys.version_info[0])+"."+str(sys.version_info[1])+"."+str(sys.version_info[2])
717 jfenwick 2302 os.system("echo "+versionstring+" > "+os.path.join(env['libinstall'],"pyversion"))
718 jfenwick 2297
719 jfenwick 2302 ############## Populate the buildvars file #####################
720    
721     buildvars=open(os.path.join(env['libinstall'],'buildvars'),'w')
722     buildvars.write('python='+str(sys.version_info[0])+"."+str(sys.version_info[1])+"."+str(sys.version_info[2])+'\n')
723    
724     # Find the boost version by extracting it from version.hpp
725     boosthpp=open(os.path.join(env['boost_path'],'boost','version.hpp'))
726     boostversion='unknown'
727     try:
728     for line in boosthpp:
729     ver=re.match(r'#define BOOST_VERSION (\d+)',line)
730     if ver:
731     boostversion=ver.group(1)
732     except StopIteration:
733     pass
734     buildvars.write("boost="+boostversion+"\n")
735     buildvars.write("svn_revision="+str(global_revision)+"\n")
736     out="usedebug="
737     if env['usedebug']:
738     out+="y"
739     else:
740     out+="n"
741     out+="\nusempi="
742     if env['usempi']:
743     out+="y"
744     else:
745     out+="n"
746     out+="\nuseopenmp="
747     if env['useopenmp']:
748     out+="y"
749     else:
750     out+="n"
751     buildvars.write(out+"\n")
752 jfenwick 2338 buildvars.write("mpi_flavour="+env['mpi_flavour']+'\n')
753 jfenwick 2302
754     buildvars.close()
755    
756    
757 ksteube 1705 ############ Targets to build and install libraries ############
758    
759     target_init = env.Command(env['pyinstall']+'/__init__.py', None, Touch('$TARGET'))
760     env.Alias('target_init', [target_init])
761    
762     # The headers have to be installed prior to build in order to satisfy #include <paso/Common.h>
763     env.Alias('build_esysUtils', ['target_install_esysUtils_headers', 'target_esysUtils_a'])
764     env.Alias('install_esysUtils', ['build_esysUtils', 'target_install_esysUtils_a'])
765    
766     env.Alias('build_paso', ['target_install_paso_headers', 'target_paso_a'])
767     env.Alias('install_paso', ['build_paso', 'target_install_paso_a'])
768    
769     env.Alias('build_escript', ['target_install_escript_headers', 'target_escript_so', 'target_escriptcpp_so'])
770     env.Alias('install_escript', ['build_escript', 'target_install_escript_so', 'target_install_escriptcpp_so', 'target_install_escript_py'])
771    
772     env.Alias('build_finley', ['target_install_finley_headers', 'target_finley_so', 'target_finleycpp_so'])
773     env.Alias('install_finley', ['build_finley', 'target_install_finley_so', 'target_install_finleycpp_so', 'target_install_finley_py'])
774    
775     # Now gather all the above into a couple easy targets: build_all and install_all
776     build_all_list = []
777     build_all_list += ['build_esysUtils']
778     build_all_list += ['build_paso']
779     build_all_list += ['build_escript']
780     build_all_list += ['build_finley']
781 ksteube 1756 if env['usempi']: build_all_list += ['target_pythonMPI_exe']
782 jfenwick 2294 if not IS_WINDOWS_PLATFORM: build_all_list += ['target_escript_wrapper']
783 caltinay 2184 if env['usesilo']: build_all_list += ['target_escript2silo']
784 ksteube 1705 env.Alias('build_all', build_all_list)
785    
786     install_all_list = []
787     install_all_list += ['target_init']
788     install_all_list += ['install_esysUtils']
789     install_all_list += ['install_paso']
790     install_all_list += ['install_escript']
791     install_all_list += ['install_finley']
792     install_all_list += ['target_install_pyvisi_py']
793     install_all_list += ['target_install_modellib_py']
794     install_all_list += ['target_install_pycad_py']
795 ksteube 1756 if env['usempi']: install_all_list += ['target_install_pythonMPI_exe']
796 jfenwick 2294 if not IS_WINDOWS_PLATFORM: install_all_list += ['target_install_escript_wrapper']
797 caltinay 2184 if env['usesilo']: install_all_list += ['target_install_escript2silo']
798 ksteube 1705 install_all_list += ['remember_options']
799     env.Alias('install_all', install_all_list)
800    
801     # Default target is install
802     env.Default('install_all')
803    
804     ############ Targets to build and run the test suite ###########
805    
806     env.Alias('build_cppunittest', ['target_install_cppunittest_headers', 'target_cppunittest_a'])
807     env.Alias('install_cppunittest', ['build_cppunittest', 'target_install_cppunittest_a'])
808     env.Alias('run_tests', ['install_all', 'target_install_cppunittest_a'])
809     env.Alias('all_tests', ['install_all', 'target_install_cppunittest_a', 'run_tests', 'py_tests'])
810 jfenwick 2286 env.Alias('build_full',['install_all','build_tests','build_py_tests'])
811 ksteube 1705
812     ############ Targets to build the documentation ################
813    
814 jfenwick 2334 env.Alias('docs', ['examples_tarfile', 'examples_zipfile', 'api_epydoc', 'api_doxygen', 'guide_pdf', 'guide_html','install_pdf'])
815 ksteube 1705
816 jfenwick 2235 if not IS_WINDOWS_PLATFORM:
817     try:
818     utest=open("utest.sh","w")
819 jfenwick 2276 build_platform=os.name #Sometimes Mac python says it is posix
820     if (build_platform=='posix') and platform.system()=="Darwin":
821     build_platform='darwin'
822     utest.write(GroupTest.makeHeader(build_platform))
823 jfenwick 2235 for tests in TestGroups:
824     utest.write(tests.makeString())
825     utest.close()
826 jfenwick 2299 os.chmod("utest.sh",stat.S_IRWXU|stat.S_IRGRP|stat.S_IXGRP|stat.S_IROTH|stat.S_IXOTH)
827 jfenwick 2235 print "utest.sh written"
828     except IOError:
829     print "Error attempting to write unittests file."
830     sys.exit(1)
831    

  ViewVC Help
Powered by ViewVC 1.1.26