/[ascend]/trunk/SConstruct
ViewVC logotype

Annotation of /trunk/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


Revision 636 - (hide annotations) (download)
Mon May 29 06:22:52 2006 UTC (13 years, 6 months ago) by johnpye
File size: 29377 byte(s)
Fixed up some other small probs with MSVC2005
1 johnpye 393 import os, commands, platform, distutils.sysconfig, os.path
2 johnpye 385
3 johnpye 627 version = "0.9.5.92"
4 johnpye 439
5 johnpye 385 #------------------------------------------------------
6     # OPTIONS
7 johnpye 392 #
8     # Note that if you set the options via the command line, they will be
9     # remembered in the file 'options.cache'. It's a feature ;-)
10 johnpye 385
11     opts = Options(['options.cache', 'config.py'])
12 johnpye 464 #print "PLATFORM = ",platform.system()
13 johnpye 385
14 johnpye 464 if platform.system()=="Windows":
15 johnpye 631 default_tcl_lib = "tcl84"
16     default_tk_lib = "tk84"
17 johnpye 464 default_tktable_lib = "Tktable28"
18 johnpye 499 default_install_assets = "glade/"
19     icon_extension = '.png'
20 johnpye 521 default_tcl = "c:\\Tcl"
21 johnpye 541 default_tcl_libpath = "$TCL\\bin"
22 johnpye 627 default_rel_distdir = '.'
23 johnpye 628 default_absolute_paths = False
24 johnpye 464 else:
25 johnpye 521 default_tcl_lib = "tcl8.3"
26     default_tk_lib = "tk8.3"
27 johnpye 464 default_tktable_lib = "Tktable2.8"
28 johnpye 628 default_install_assets = "$INSTALL_ASCDATA/glade/"
29 johnpye 499 icon_extension = '.svg'
30 johnpye 521 default_tcl = os.path.expanduser("~/activetcl")
31 johnpye 541 default_tcl_libpath = "$TCL/lib"
32 johnpye 627 default_rel_distdir = '../share/ascend'
33 johnpye 628 default_absolute_paths = True
34 johnpye 463
35 johnpye 551 if not os.path.isdir(default_tcl):
36     default_tcl = '/usr'
37    
38 johnpye 562 opts.Add(
39     'CC'
40     ,'C Compiler command'
41     ,None
42     )
43    
44     opts.Add(
45     'CXX'
46     ,'C++ Compiler command'
47     ,None
48     )
49    
50 johnpye 591 opts.Add(BoolOption(
51     'GCOV'
52 johnpye 593 , 'Whether to enable coverage testing in object code'
53     , False
54 johnpye 591 ))
55    
56 johnpye 385 # Package linking option
57 johnpye 386 opts.Add(EnumOption(
58     'PACKAGE_LINKING'
59 johnpye 385 , 'Style of linking for external libraries'
60     , 'DYNAMIC_PACKAGES'
61 johnpye 386 , ['DYNAMIC_PACKAGES', 'STATIC_PACKAGES', 'NO_PACKAGES']
62     ))
63 johnpye 385
64 johnpye 526 opts.Add(BoolOption(
65     'WITH_GCCVISIBILITY'
66     ,"Whether to use GCC Visibility features (only applicable if available)"
67     ,True
68     ))
69    
70 johnpye 392 # You can turn off building of Tcl/Tk interface
71 johnpye 386 opts.Add(BoolOption(
72 johnpye 542 'WITH_TCLTK'
73 johnpye 386 ,"Set to True if you don't want to build the original Tcl/Tk GUI."
74 johnpye 542 , True
75 johnpye 386 ))
76    
77 johnpye 392 # You can turn off the building of the Python interface
78 johnpye 387 opts.Add(BoolOption(
79 johnpye 542 'WITH_PYTHON'
80 johnpye 387 ,"Set to True if you don't want to build Python wrappers."
81 johnpye 542 , True
82 johnpye 387 ))
83    
84 johnpye 392 # Which solvers will we allow?
85     opts.Add(ListOption(
86     'WITH_SOLVERS'
87 johnpye 393 ,"List of the solvers you want to build. The default is the minimum that"
88     +" works."
89 johnpye 392 ,["QRSLV","CMSLV"]
90     ,['QRSLV','MPS','SLV','OPTSQP'
91     ,'NGSLV','CMSLV','LRSLV','MINOS','CONOPT'
92     ,'LSOD','OPTSQP'
93     ]
94     ))
95    
96 johnpye 393 # Where will the local copy of the help files be kept?
97     opts.Add(PackageOption(
98     'WITH_LOCAL_HELP'
99     , "Directory containing the local copy of the help files (optional)"
100     , "no"
101     ))
102    
103     # Will bintoken support be enabled?
104     opts.Add(BoolOption(
105     'WITH_BINTOKEN'
106     ,"Enable bintoken support? This means compiling models as C-code before"
107     +" running them, to increase solving speed for large models."
108     ,False
109     ))
110    
111 johnpye 398 # What should the default ASCENDLIBRARY path be?
112     # Note: users can change it by editing their ~/.ascend.ini
113 johnpye 393 opts.Add(
114     'DEFAULT_ASCENDLIBRARY'
115     ,"Set the default value of the ASCENDLIBRARY -- the location where"
116     +" ASCEND will look for models when running ASCEND"
117 johnpye 628 ,"$INSTALL_ASCDATA/models"
118 johnpye 393 )
119    
120 johnpye 398 # Where is SWIG?
121     opts.Add(
122     'SWIG'
123     ,"SWIG location, probably only required for MinGW and MSVC users."
124     +" Enter the location as a Windows-style path, for example"
125 johnpye 404 +" 'c:\\msys\\1.0\\home\\john\\swigwin-1.3.29\\swig.exe'."
126 johnpye 398 )
127    
128 johnpye 400 # Build the test suite?
129     opts.Add(BoolOption(
130 johnpye 593 'WITH_CUNIT'
131 johnpye 400 ,"Whether to build the CUnit tests. Default is off. If set to on,"
132     +" you must have CUnit installed somewhere that SCons can"
133 johnpye 463 +" find it, or else use the CUNIT_* options to specify."
134 johnpye 400 ,False
135     ))
136 johnpye 393
137 johnpye 400 # Where are the CUnit includes?
138     opts.Add(PackageOption(
139     'CUNIT_CPPPATH'
140     ,"Where are your CUnit include files?"
141 johnpye 459 ,'off'
142 johnpye 400 ))
143 johnpye 392
144 johnpye 404 # Where are the CUnit libraries?
145 johnpye 400 opts.Add(PackageOption(
146     'CUNIT_LIBPATH'
147 johnpye 404 ,"Where are your CUnit libraries?"
148 johnpye 459 ,'off'
149 johnpye 400 ))
150    
151 johnpye 521
152 johnpye 534 opts.Add(
153 johnpye 521 'TCL'
154     ,'Base of Tcl distribution'
155     ,default_tcl
156 johnpye 534 )
157 johnpye 521
158 johnpye 404 # Where are the Tcl includes?
159 johnpye 534 opts.Add(
160 johnpye 404 'TCL_CPPPATH'
161     ,"Where are your Tcl include files?"
162 johnpye 521 ,"$TCL/include"
163 johnpye 534 )
164 johnpye 404
165     # Where are the Tcl libs?
166 johnpye 534 opts.Add(
167 johnpye 404 'TCL_LIBPATH'
168     ,"Where are your Tcl libraries?"
169 johnpye 541 ,default_tcl_libpath
170 johnpye 534 )
171 johnpye 404
172 johnpye 428 # What is the name of the Tcl lib?
173     opts.Add(
174     'TCL_LIB'
175 johnpye 561 ,"Name of Tcl lib (eg 'tcl' or 'tcl83'), for full path to static library (if STATIC_TCLTK is set)"
176 johnpye 464 ,default_tcl_lib
177 johnpye 428 )
178    
179 johnpye 405 # Where are the Tk includes?
180 johnpye 534 opts.Add(
181 johnpye 405 'TK_CPPPATH'
182     ,"Where are your Tk include files?"
183 johnpye 464 ,'$TCL_CPPPATH'
184 johnpye 534 )
185 johnpye 404
186 johnpye 405 # Where are the Tk libs?
187 johnpye 534 opts.Add(
188 johnpye 405 'TK_LIBPATH'
189     ,"Where are your Tk libraries?"
190 johnpye 464 ,'$TCL_LIBPATH'
191 johnpye 534 )
192 johnpye 405
193 johnpye 428 # What is the name of the Tk lib?
194     opts.Add(
195     'TK_LIB'
196 johnpye 521 ,"Name of Tk lib (eg 'tk' or 'tk83'), or full path to static library"
197 johnpye 464 ,default_tk_lib
198 johnpye 435 )
199    
200 johnpye 460 # Static linking to TkTable
201    
202     opts.Add(BoolOption(
203 johnpye 521 'STATIC_TCLTK'
204 johnpye 554 ,'Set true for static linking for Tcl/Tk and TkTable. EXPERIMENTAL'
205 johnpye 460 ,False
206     ))
207    
208 johnpye 464 opts.Add(
209 johnpye 460 'TKTABLE_LIBPATH'
210     ,'Location of TkTable static library'
211 johnpye 464 ,'$TCL_LIBPATH/Tktable2.8'
212     )
213 johnpye 460
214 johnpye 435 opts.Add(
215 johnpye 460 'TKTABLE_LIB'
216 johnpye 521 ,'Stem name of TkTable (eg tktable2.8, no ".so" or "lib") shared library, or full path of static tktable (/usr/lib/...)'
217 johnpye 464 ,default_tktable_lib
218 johnpye 460 )
219    
220     opts.Add(
221 johnpye 521 'TKTABLE_CPPPATH'
222     ,'Location of TkTable header file'
223     ,'$TCL_CPPPATH'
224     )
225    
226     opts.Add(
227     'X11'
228 johnpye 554 ,'Base X11 directory. Only used when STATIC_TCLTK is turned on. EXPERIMENTAL'
229 johnpye 521 ,'/usr/X11R6'
230     )
231    
232     opts.Add(
233     'X11_LIBPATH'
234 johnpye 554 ,'Location of X11 lib. EXPERIMENTAL'
235 johnpye 521 ,'$X11/lib'
236     )
237    
238     opts.Add(
239     'X11_CPPPATH'
240 johnpye 554 ,'Location of X11 includes. EXPERIMENTAL'
241 johnpye 521 ,'$X11/include'
242     )
243    
244     opts.Add(
245     'X11_LIB'
246 johnpye 554 ,'Name of X11 lib. EXPERIMENTAL'
247 johnpye 521 ,'X11'
248     )
249    
250     opts.Add(
251 johnpye 435 'INSTALL_PREFIX'
252     ,'Root location for installed files'
253 johnpye 449 ,'/usr/local'
254 johnpye 428 )
255    
256 johnpye 435 opts.Add(
257     'INSTALL_BIN'
258     ,'Location to put binaries during installation'
259     ,"$INSTALL_PREFIX/bin"
260     )
261    
262     opts.Add(
263 johnpye 463 'INSTALL_LIB'
264     ,'Location to put binaries during installation'
265     ,"$INSTALL_PREFIX/lib"
266     )
267    
268     opts.Add(
269 ben.allan 624 'INSTALL_SHARE'
270 johnpye 628 ,'Common shared-file location on this system'
271     ,"$INSTALL_PREFIX/share"
272 johnpye 435 )
273    
274 johnpye 628
275 johnpye 435 opts.Add(
276 johnpye 628 'INSTALL_ASCDATA'
277     ,"Location of ASCEND shared data (TK, python, models etc)"
278     ,"$INSTALL_SHARE/ascend"
279     )
280    
281     opts.Add(
282 johnpye 435 'INSTALL_INCLUDE'
283     ,'Location to put header files during installation'
284     ,"$INSTALL_PREFIX/include"
285     )
286    
287 johnpye 448 opts.Add(
288 johnpye 455 'PYGTK_ASSETS'
289 johnpye 532 ,'Default location for Glade assets (placed in pygtk/config.py)'
290 johnpye 455 ,default_install_assets
291     )
292    
293 johnpye 508 opts.Add(BoolOption(
294     'DEBUG'
295     ,"Compile source with debugger symbols, eg for use with 'gdb'"
296     ,False
297     ))
298    
299 johnpye 597 opts.Add(BoolOption(
300     'MALLOC_DEBUG'
301     ,"Compile with debugging version of MALLOC. Required for full CUnit testing"
302     ,False
303     ))
304    
305 johnpye 455 opts.Add(
306 johnpye 448 'INSTALL_ROOT'
307     ,'For use by RPM only: location of %{buildroot} during rpmbuild'
308     ,""
309     )
310    
311 johnpye 563 opts.Add(
312     'DISTTAR_NAME'
313     ,"Stem name of the tarball created by 'scons dist'. So for 'ascend-aaa.tar.bz2', set this to 'ascend-aaa'."
314     ,"ascend-"+version
315     )
316    
317 johnpye 605 opts.Add(BoolOption(
318 johnpye 628 'ABSOLUTE_PATHS'
319 johnpye 605 ,"Whether to use absolute or relative paths in the installed Tcl/Tk interface. If you want to build an RPM, set this to false."
320 johnpye 628 ,default_absolute_paths
321 johnpye 605 ))
322    
323 johnpye 578 opts.Add(
324     'WIN_INSTALLER_NAME'
325     ,"Name of the installer .exe to create under Windows (minus the '.exe')"
326     ,"ascend-"+version
327     )
328    
329 johnpye 594 opts.Add(BoolOption(
330     'WITH_XTERM_COLORS'
331     ,"Set to 0 if you don't want xterm colour codes in the console output"
332     ,True
333     ))
334    
335 johnpye 546 if platform.system()!="Windows":
336     opts.Add(BoolOption(
337     'WITH_GCCVISIBILITY'
338     , 'Whether to use GCC Visibility extensions when building with GCC 4.0'
339     , True
340     ))
341    
342 johnpye 392 # TODO: OTHER OPTIONS?
343     # TODO: flags for optimisation
344 johnpye 393 # TODO: turning on/off bintoken functionality
345 johnpye 427 # TODO: Where will the 'Makefile.bt' file be installed?
346 johnpye 393
347 johnpye 498 # Import the outside environment
348    
349 johnpye 569 if os.environ.get('OSTYPE')=='msys':
350 johnpye 552 env = Environment(
351     ENV=os.environ
352 johnpye 578 , tools=['mingw','lex','yacc','fortran','swig','disttar','nsis']
353 johnpye 552 , toolpath=['scons']
354     )
355 johnpye 529 env['IS_MINGW']=True
356 johnpye 498 else:
357 johnpye 552 env = Environment(
358     ENV=os.environ
359 johnpye 578 ,tools=['default','lex','yacc','fortran','swig','disttar','nsis']
360 johnpye 552 , toolpath=['scons']
361     )
362 johnpye 498
363     if platform.system()=='Windows' and env.has_key('MSVS'):
364     print "INCLUDE =",env['ENV']['INCLUDE']
365     print "LIB =",env['ENV']['LIB']
366 johnpye 506 print "PATH =",env['ENV']['PATH']
367 johnpye 498 env.Append(CPPPATH=env['ENV']['INCLUDE'])
368     env.Append(LIBPATH=env['ENV']['LIB'])
369 johnpye 636 env.Append(CCFLAGS=['/D_CRT_SECURE_NO_DEPRECATE'])
370 johnpye 498
371 johnpye 385 opts.Update(env)
372     opts.Save('options.cache',env)
373    
374     Help(opts.GenerateHelpText(env))
375    
376 johnpye 551 with_tcltk = env.get('WITH_TCLTK')
377 johnpye 427 without_tcltk_reason = "disabled by options/config.py"
378 johnpye 386
379 johnpye 551 with_python = env.get('WITH_PYTHON')
380 johnpye 427 without_python_reason = "disabled by options/config.py"
381 johnpye 387
382 johnpye 593 with_cunit = env.get('WITH_CUNIT')
383 johnpye 427 without_cunit_reason = "not requested"
384 johnpye 400
385 johnpye 631 if platform.system()=="Windows":
386     with_installer=1
387     else:
388     with_installer=0
389     without_installer_reason = "only possible under Windows"
390    
391 johnpye 464 #print "SOLVERS:",env['WITH_SOLVERS']
392     #print "WITH_BINTOKEN:",env['WITH_BINTOKEN']
393     #print "DEFAULT_ASCENDLIBRARY:",env['DEFAULT_ASCENDLIBRARY']
394 johnpye 393
395 johnpye 463 can_install = True
396     if platform.system()=='Windows':
397     can_install = False
398    
399     env['CAN_INSTALL']=can_install
400    
401 johnpye 521 print "TCL_CPPPATH =",env['TCL_CPPPATH']
402     print "TCL_LIBPATH =",env['TCL_LIBPATH']
403     print "TCL_LIB =",env['TCL_LIB']
404 johnpye 562 print "CC =",env['CC']
405     print "CXX =",env['CXX']
406 johnpye 393
407 johnpye 628 print "ABSOLUTE PATHS =",env['ABSOLUTE_PATHS']
408 johnpye 385 #------------------------------------------------------
409 johnpye 398 # SPECIAL CONFIGURATION TESTS
410    
411 johnpye 463 need_fortran = False
412    
413 johnpye 400 #----------------
414     # SWIG
415    
416 johnpye 398 import os,re
417    
418 johnpye 413 def get_swig_version(env):
419 johnpye 403 cmd = env['SWIG']+' -version'
420 johnpye 427 (cin,coutcerr) = os.popen4(cmd)
421 johnpye 403 output = coutcerr.read()
422 johnpye 398
423 johnpye 403 restr = "SWIG\\s+Version\\s+(?P<maj>[0-9]+)\\.(?P<min>[0-9]+)\\.(?P<pat>[0-9]+)\\s*$"
424     expr = re.compile(restr,re.M);
425 johnpye 398 m = expr.search(output);
426     if not m:
427 johnpye 413 return None
428 johnpye 398 maj = int(m.group('maj'))
429     min = int(m.group('min'))
430     pat = int(m.group('pat'))
431 johnpye 413
432     return (maj,min,pat)
433 johnpye 398
434 johnpye 413
435     def CheckSwigVersion(context):
436    
437     try:
438     context.Message("Checking version of SWIG... ")
439     maj,min,pat = get_swig_version(context.env)
440     except:
441     context.Result("Failed to detect version, or failed to run SWIG")
442     return 0;
443    
444 johnpye 478 context.env['SWIGVERSION']=tuple([maj,min,pat])
445    
446 johnpye 398 if maj == 1 and (
447 johnpye 400 min > 3
448     or (min == 3 and pat >= 24)
449 johnpye 398 ):
450     context.Result("ok, %d.%d.%d" % (maj,min,pat))
451     return 1;
452 johnpye 401 else:
453     context.Result("too old, %d.%d.%d" % (maj,min,pat))
454     return 0;
455 johnpye 398
456 johnpye 400 #----------------
457     # General purpose library-and-header test
458    
459 johnpye 404 class KeepContext:
460 johnpye 521 def __init__(self,context,varprefix,static=False):
461 johnpye 404 self.keep = {}
462 johnpye 521 for k in ['LIBS','LIBPATH','CPPPATH','LINKFLAGS']:
463 johnpye 404 if context.env.has_key(k):
464     self.keep[k] = context.env[k]
465 johnpye 463 else:
466     self.keep[k] = None
467 johnpye 404
468     if context.env.has_key(varprefix+'_CPPPATH'):
469 johnpye 521 context.env.Append(CPPPATH=[env[varprefix+'_CPPPATH']])
470 johnpye 428 #print "Adding '"+str(cpppath_add)+"' to cpp path"
471    
472 johnpye 521 if static:
473     staticlib=env[varprefix+'_LIB']
474     #print "STATIC LIB = ",staticlib
475     context.env.Append(
476     LINKFLAGS=[staticlib]
477     )
478     else:
479     if context.env.has_key(varprefix+'_LIBPATH'):
480     context.env.Append(LIBPATH=[env[varprefix+'_LIBPATH']])
481     #print "Adding '"+str(libpath_add)+"' to lib path"
482 johnpye 428
483 johnpye 521 if context.env.has_key(varprefix+'_LIB'):
484     context.env.Append(LIBS=[env[varprefix+'_LIB']])
485     #print "Adding '"+str(libs_add)+"' to libs"
486 johnpye 404
487     def restore(self,context):
488 johnpye 464 #print "RESTORING CONTEXT"
489     #print self.keep
490     #print "..."
491 johnpye 404 for k in self.keep:
492 johnpye 463 if self.keep[k]==None:
493 johnpye 521 if context.env.has_key(k):
494     #print "Clearing "+str(k)
495     del context.env[k];
496 johnpye 463 else:
497 johnpye 464 #print "Restoring "+str(k)+" to '"+self.keep[k]+"'"
498 johnpye 463 context.env[k]=self.keep[k];
499 johnpye 404
500 johnpye 521 def CheckExtLib(context,libname,text,ext='.c',varprefix=None,static=False):
501 johnpye 400 """This method will check for variables LIBNAME_LIBPATH
502     and LIBNAME_CPPPATH and try to compile and link the
503     file with the provided text, linking with the
504     library libname."""
505    
506 johnpye 521 if static:
507     context.Message( 'Checking for static '+libname+'... ' )
508     else:
509     context.Message( 'Checking for '+libname+'... ' )
510    
511 johnpye 400 if varprefix==None:
512     varprefix = libname.upper()
513    
514 johnpye 521 keep = KeepContext(context,varprefix,static)
515 johnpye 400
516 johnpye 428 if not context.env.has_key(varprefix+'_LIB'):
517 johnpye 463 # if varprefix_LIB were in env, KeepContext would
518     # have appended it already
519 johnpye 451 context.env.Append(LIBS=libname)
520 johnpye 428
521 johnpye 404 is_ok = context.TryLink(text,ext)
522 johnpye 428
523 johnpye 521 #print "Link success? ",(is_ok != 0)
524 johnpye 400
525 johnpye 405 keep.restore(context)
526 johnpye 400
527 johnpye 428 # print "Restored CPPPATH="+str(context.env['CPPPATH'])
528     # print "Restored LIBS="+libname
529     # print "Restored LIBPATH="+str(context.env['LIBPATH'])
530    
531 johnpye 404 context.Result(is_ok)
532     return is_ok
533    
534     #----------------
535 johnpye 502 # GCC
536    
537     gcc_test_text = """
538     #ifndef __GNUC__
539     # error "Not using GCC"
540     #endif
541    
542     int main(void){
543     return __GNUC__;
544     }
545     """
546    
547     def CheckGcc(context):
548     context.Message("Checking for GCC... ")
549     is_ok = context.TryCompile(gcc_test_text,".c")
550     context.Result(is_ok)
551     return is_ok
552    
553     #----------------
554 johnpye 500 # GCC VISIBILITY feature
555    
556     gccvisibility_test_text = """
557     #if __GNUC__ < 4
558     # error "Require GCC version 4 or newer"
559     #endif
560    
561     __attribute__ ((visibility("default"))) int x;
562    
563     int main(void){
564     extern int x;
565     x = 4;
566     }
567     """
568    
569     def CheckGccVisibility(context):
570     context.Message("Checking for GCC 'visibility' capability... ")
571 johnpye 546 if not context.env.has_key('WITH_GCCVISIBILITY') or not env['WITH_GCCVISIBILITY']:
572     context.Result("disabled")
573     return 0
574 johnpye 500 is_ok = context.TryCompile(gccvisibility_test_text,".c")
575     context.Result(is_ok)
576     return is_ok
577 johnpye 502
578 johnpye 500 #----------------
579 johnpye 502 # YACC
580    
581     yacc_test_text = """
582     %start ROOT
583     %token MSG
584     %%
585    
586     ROOT:
587     MSG { print("HELLO"); }
588     ;
589     """
590    
591     def CheckYacc(context):
592     context.Message("Checking for Yacc... ")
593     is_ok = context.TryCompile(yacc_test_text,".y")
594     context.Result(is_ok)
595     return is_ok
596    
597     #----------------
598 johnpye 404 # CUnit test
599    
600 johnpye 400 cunit_test_text = """
601 johnpye 451 #include <CUnit/CUnit.h>
602 johnpye 400 int maxi(int i1, int i2){
603     return (i1 > i2) ? i1 : i2;
604     }
605    
606     void test_maxi(void){
607     CU_ASSERT(maxi(0,2) == 2);
608     CU_ASSERT(maxi(0,-2) == 0);
609     CU_ASSERT(maxi(2,2) == 2);
610    
611     }
612     int main(void){
613     /* CU_initialize_registry() */
614 johnpye 404 return 0;
615 johnpye 400 }
616     """
617    
618     def CheckCUnit(context):
619 johnpye 451 return CheckExtLib(context,'cunit',cunit_test_text)
620 johnpye 400
621 johnpye 404 #----------------
622 johnpye 405 # Tcl test
623 johnpye 404
624 johnpye 561 # TCL and TK required version 8.1, 8.2, 8.3, or 8.4:
625     tcltk_minor_newest_acceptable = 4
626     tcltk_major_required = 8
627    
628 johnpye 404 tcl_check_text = r"""
629     #include <tcl.h>
630     #include <stdio.h>
631     int main(void){
632     printf("%s",TCL_PATCH_LEVEL);
633     return 0;
634     }
635     """
636    
637     def CheckTcl(context):
638 johnpye 521 return CheckExtLib(context,'tcl',tcl_check_text,static=env['STATIC_TCLTK'])
639 johnpye 405
640     def CheckTclVersion(context):
641 johnpye 521 keep = KeepContext(context,'TCL',static=env['STATIC_TCLTK'])
642 johnpye 405 context.Message("Checking Tcl version... ")
643     (is_ok,output) = context.TryRun(tcl_check_text,'.c')
644 johnpye 404 keep.restore(context)
645     if not is_ok:
646 johnpye 405 context.Result("failed to run check")
647 johnpye 404 return 0
648 johnpye 405
649 wangym 511 major,minor,patch = tuple([int(i) for i in output.split(".")])
650 johnpye 561 if major != tcltk_major_required or minor > tcltk_minor_newest_acceptable:
651 johnpye 428 context.Result(output+" (bad version)")
652 johnpye 405 # bad version
653     return 0
654    
655     # good version
656 johnpye 552 context.Result(output+", good")
657 johnpye 404 return 1
658    
659 johnpye 405 #----------------
660 johnpye 463 # Tk test
661 johnpye 405
662     tk_check_text = r"""
663     #include <tk.h>
664     #include <stdio.h>
665     int main(void){
666     printf("%s",TK_PATCH_LEVEL);
667     return 0;
668     }
669     """
670     def CheckTk(context):
671 johnpye 521 return CheckExtLib(context,'tk',tcl_check_text,static=env['STATIC_TCLTK'])
672 johnpye 405
673 johnpye 428
674 johnpye 405 def CheckTkVersion(context):
675 johnpye 521 keep = KeepContext(context,'TK',static=context.env['STATIC_TCLTK'])
676 johnpye 405 context.Message("Checking Tk version... ")
677 johnpye 521 #print "LINKFLAGS =",context.env['LINKFLAGS']
678 johnpye 405 (is_ok,output) = context.TryRun(tk_check_text,'.c')
679 johnpye 404 keep.restore(context)
680     if not is_ok:
681     context.Result("failed to run check")
682     return 0
683    
684 wangym 511 major,minor,patch = tuple([int(i) for i in output.split(".")])
685 johnpye 561 if major != tcltk_major_required or minor > tcltk_minor_newest_acceptable:
686 johnpye 404 # bad version
687 johnpye 561 context.Result(output+" (bad version)")
688 johnpye 404 return 0
689 johnpye 400
690 johnpye 404 # good version
691 johnpye 561 context.Result(output+" (good)")
692 johnpye 404 return 1
693 johnpye 485
694     #----------------
695 johnpye 521 # Tktable test
696    
697     tktable_check_text = r"""
698     #include <tkTable.h>
699     #include <stdio.h>
700     int main(void){
701     Table mytable;
702     return 0;
703     }
704     """
705    
706     def CheckTkTable(context):
707     return CheckExtLib(context,'tktable',tktable_check_text,static=env['STATIC_TCLTK'])
708    
709     #---------------
710     # X11 test
711    
712     x11_check_text = r"""
713     #include <X11/Xlib.h>
714     #include <X11/IntrinsicP.h>
715     #include <X11/Intrinsic.h>
716     #include <X11/ObjectP.h>
717     #include <X11/Object.h>
718     int main(void){
719     Object mything;
720     return 0;
721     }
722     """
723    
724     def CheckX11(context):
725     return CheckExtLib(context,'X11',x11_check_text)
726    
727     #----------------
728 johnpye 485 # GCC Version sniffing
729    
730     # TODO FIXME
731    
732     gcc_version4 = False
733    
734 johnpye 398 #------------------------------------------------------
735 johnpye 385 # CONFIGURATION
736    
737     conf = Configure(env
738     , custom_tests = {
739 johnpye 398 'CheckSwigVersion' : CheckSwigVersion
740 johnpye 400 , 'CheckCUnit' : CheckCUnit
741 johnpye 404 , 'CheckTcl' : CheckTcl
742     , 'CheckTclVersion' : CheckTclVersion
743 johnpye 405 , 'CheckTk' : CheckTk
744     , 'CheckTkVersion' : CheckTkVersion
745 johnpye 502 , 'CheckGcc' : CheckGcc
746 johnpye 500 , 'CheckGccVisibility' : CheckGccVisibility
747 johnpye 502 , 'CheckYacc' : CheckYacc
748 johnpye 521 , 'CheckTkTable' : CheckTkTable
749     , 'CheckX11' : CheckX11
750 johnpye 400 # , 'CheckIsNan' : CheckIsNan
751     # , 'CheckCppUnitConfig' : CheckCppUnitConfig
752 johnpye 385 }
753 johnpye 459 # , config_h = "config.h"
754 johnpye 385 )
755    
756 johnpye 398
757 johnpye 385 # Math library
758    
759 johnpye 427 #if not conf.CheckFunc('sinh') and not conf.CheckLibWithHeader(['m','c','libc'], 'math.h', 'C'):
760     # print 'Did not find math library, exiting!'
761     # Exit(1)
762    
763 johnpye 385 # Where is 'isnan'?
764    
765     if not conf.CheckFunc('isnan'):
766     print "Didn't find isnan"
767 johnpye 414 # Exit(1)
768 johnpye 385
769 johnpye 500 # GCC visibility
770    
771 johnpye 502 if conf.CheckGcc():
772     conf.env['HAVE_GCC']=True;
773 johnpye 526 if env['WITH_GCCVISIBILITY'] and conf.CheckGccVisibility():
774 johnpye 509 conf.env['HAVE_GCCVISIBILITY']=True;
775     conf.env.Append(CCFLAGS=['-fvisibility=hidden'])
776     conf.env.Append(CPPDEFINES=['HAVE_GCCVISIBILITY'])
777 johnpye 500
778 johnpye 502 # YACC
779    
780 johnpye 506 if not conf.CheckYacc():
781     print "YACC NOT FOUND OR NOT WORKING"
782     else:
783 johnpye 502 conf.env['HAVE_YACC']=True
784    
785     conf.env['HAVE_LEX']=True
786    
787 johnpye 387 # Tcl/Tk
788 johnpye 386
789 johnpye 586 if with_tcltk:
790     if conf.CheckTcl():
791     if conf.CheckTclVersion():
792     if conf.CheckTk():
793     if with_tcltk and conf.CheckTkVersion():
794     if env['STATIC_TCLTK']:
795     if conf.CheckTkTable():
796     pass
797     else:
798     without_tcltk_reason = "TkTable not found"
799     with_tcltk = False
800     else:
801     without_tcltk_reason = "Require Tk version <= 8.4. See 'scons -h'"
802     with_tcltk = False
803 johnpye 521 else:
804 johnpye 586 without_tcltk_reason = "Tk not found."
805 johnpye 551 with_tcltk = False
806 johnpye 428 else:
807 johnpye 586 without_tcltk_reason = "Require Tcl <= 8.4 Tcl."
808 johnpye 551 with_tcltk = False
809 johnpye 586
810 johnpye 428 else:
811 johnpye 586 without_tcltk_reason = "Tcl not found."
812 johnpye 551 with_tcltk = False
813 johnpye 386
814 johnpye 521 if env['STATIC_TCLTK']:
815     conf.CheckX11()
816    
817 johnpye 395 # Python... obviously we're already running python, so we just need to
818     # check that we can link to the python library OK:
819    
820 johnpye 391 if platform.system()=="Windows":
821 johnpye 395 python_lib='python24'
822 johnpye 391 else:
823 johnpye 395 python_lib='python2.4'
824 johnpye 391
825 johnpye 395 # SWIG version
826    
827 johnpye 413 if not conf.CheckSwigVersion():
828     without_python_reason = 'SWIG >= 1.3.24 is required'
829     with_python = False
830    
831 johnpye 400 # CUnit
832    
833 johnpye 593 if with_cunit:
834 johnpye 404 if not conf.CheckCUnit():
835 johnpye 427 without_cunit_reason = 'CUnit not found'
836    
837     # BLAS
838    
839 johnpye 459 need_blas=False
840 johnpye 551 if with_tcltk:
841 johnpye 459 need_blas=True
842     if need_blas:
843     if conf.CheckLib('blas'):
844     with_local_blas = False
845     without_local_blas_reason = "Found BLAS installed on system"
846     else:
847     with_local_blas = True
848     need_fortran = True
849 johnpye 427
850     # FORTRAN
851    
852     if need_fortran:
853 johnpye 629 conf.env.Tool('fortran')
854     detect_fortran = conf.env.Detect(['g77','f77','gfortran'])
855 johnpye 427 if detect_fortran:
856     # For some reason, g77 doesn't get detected properly on MinGW
857     if not env.has_key('F77'):
858     conf.env.Replace(F77=detect_fortran)
859     conf.env.Replace(F77COM='$F77 $F77FLAGS -c -o $TARGET $SOURCE')
860     conf.env.Replace(F77FLAGS='')
861 johnpye 428 #print "F77:",conf.env['F77']
862     #print "F77COM:",conf.env['F77COM']
863     #print "F77FLAGS:",conf.env['F77FLAGS']
864 johnpye 427 fortran_builder = Builder(
865     action='$F77COM'
866     , suffix='.o'
867     , src_suffix='.f'
868     )
869     conf.env.Append(BUILDERS={'Fortran':fortran_builder})
870     else:
871 johnpye 629 with_tcltk=False;
872     without_tcltk_reason="FORTRAN-77 required but not found"
873    
874 johnpye 464 #else:
875     # print "FORTRAN not required"
876 johnpye 400
877 johnpye 385 # TODO: -D_HPUX_SOURCE is needed
878    
879     # TODO: check size of void*
880    
881 johnpye 393 # TODO: detect if dynamic libraries are possible or not
882    
883 johnpye 427 if platform.system()=="Windows" and env.has_key('MSVS'):
884     if not conf.CheckHeader('windows.h') and env['PACKAGE_LINKING']=='DYNAMIC_PACKAGES':
885     print "Reverting to STATIC_PACKAGES since windows.h is not available. Probably you "\
886     +"need to install the Microsoft Windows Server 2003 Platform SDK, or similar."
887     env['PACKAGE_LINKING']='STATIC_PACKAGES'
888    
889 johnpye 534 if with_python and not conf.CheckHeader(['basetsd.h','BaseTsd.h']):
890 johnpye 427 with_python = 0;
891     without_python_reason = "Header file 'basetsd.h' not found. Install the MS Platform SDK."
892    
893     conf.env.Append(CPPDEFINES=env['PACKAGE_LINKING'])
894    
895 johnpye 395 conf.Finish()
896    
897     env.Append(PYTHON_LIBPATH=[distutils.sysconfig.PREFIX+"/libs"])
898     env.Append(PYTHON_LIB=[python_lib])
899     env.Append(PYTHON_CPPPATH=[distutils.sysconfig.get_python_inc()])
900    
901 johnpye 507 #---------------------------------------
902     # SUBSTITUTION DICTIONARY for .in files
903    
904     subst_dict = {
905     '@DEFAULT_ASCENDLIBRARY@':env['DEFAULT_ASCENDLIBRARY']
906     , '@GLADE_FILE@':'ascend.glade'
907     , '@HELP_ROOT@':''
908     , '@ICON_EXTENSION@':icon_extension
909 johnpye 628 , '@INSTALL_ASCDATA@':env['INSTALL_ASCDATA']
910 johnpye 507 , '@INSTALL_BIN@':env['INSTALL_BIN']
911     , '@INSTALL_INCLUDE@':env['INSTALL_INCLUDE']
912     , '@PYGTK_ASSETS@':env['PYGTK_ASSETS']
913     , '@VERSION@':version
914 johnpye 563 , '@DISTTAR_NAME@':env['DISTTAR_NAME']
915 johnpye 507 , '@WEBHELPROOT@':'http://pye.dyndns.org/ascend/manual/'
916 johnpye 508 , '@ASC_SHLIBSUFFIX@':env['SHLIBSUFFIX']
917     , '@ASC_SHLIBPREFIX@':env['SHLIBPREFIX']
918 johnpye 589 , '@ASC_ENV_TK_DEFAULT@' : '$$ASCENDDIST/tcltk'
919 johnpye 627 , '@ASC_DISTDIR_REL_BIN@' : default_rel_distdir
920 johnpye 507 }
921    
922 johnpye 594 if env.get('WITH_LOCAL_HELP'):
923 johnpye 507 print "WITH_LOCAL_HELP:",env['WITH_LOCAL_HELP']
924     subst_dict['@HELP_ROOT@']=env['WITH_LOCAL_HELP']
925    
926 johnpye 597 # bool options...
927 johnpye 605 for k,v in { \
928 johnpye 628 'ABSOLUTE_PATHS' : 'ASC_ABSOLUTE_PATHS', \
929 johnpye 605 'WITH_XTERM_COLORS' : 'ASC_XTERM_COLORS', \
930     'MALLOC_DEBUG' : 'MALLOC_DEBUG' \
931     }.iteritems():
932 johnpye 597 if env.get(k):
933     subst_dict['ifdef '+v]="if 1"
934 johnpye 594
935 johnpye 507 if with_python:
936     subst_dict['@ASCXX_USE_PYTHON@']="1"
937    
938     if env.has_key('HAVE_GCCVISIBILITY'):
939     subst_dict['@HAVE_GCCVISIBILITY@'] = "1"
940    
941     env.Append(SUBST_DICT=subst_dict)
942    
943 johnpye 385 #------------------------------------------------------
944 johnpye 558 # RECIPE: SWIG scanner
945    
946     import SCons.Script
947    
948     SWIGScanner = SCons.Scanner.ClassicCPP(
949     "SWIGScan"
950     , ".i"
951     , "CPPPATH"
952     , '^[ \t]*[%,#][ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")'
953     )
954    
955     env.Append(SCANNERS=[SWIGScanner])
956    
957     #------------------------------------------------------
958 johnpye 393 # RECIPE: 'SubstInFile', used in pygtk SConscript
959    
960     import re
961 johnpye 395 from SCons.Script import * # the usual scons stuff you get in a SConscript
962 johnpye 393
963 johnpye 395 def TOOL_SUBST(env):
964     """Adds SubstInFile builder, which substitutes the keys->values of SUBST_DICT
965     from the source to the target.
966     The values of SUBST_DICT first have any construction variables expanded
967     (its keys are not expanded).
968     If a value of SUBST_DICT is a python callable function, it is called and
969     the result is expanded as the value.
970     If there's more than one source and more than one target, each target gets
971     substituted from the corresponding source.
972 johnpye 393 """
973 johnpye 395 env.Append(TOOLS = 'SUBST')
974     def do_subst_in_file(targetfile, sourcefile, dict):
975     """Replace all instances of the keys of dict with their values.
976     For example, if dict is {'%VERSION%': '1.2345', '%BASE%': 'MyProg'},
977     then all instances of %VERSION% in the file will be replaced with 1.2345 etc.
978     """
979     try:
980     f = open(sourcefile, 'rb')
981     contents = f.read()
982     f.close()
983     except:
984     raise SCons.Errors.UserError, "Can't read source file %s"%sourcefile
985     for (k,v) in dict.items():
986     contents = re.sub(k, v, contents)
987     try:
988     f = open(targetfile, 'wb')
989     f.write(contents)
990     f.close()
991     except:
992     raise SCons.Errors.UserError, "Can't write target file %s"%targetfile
993     return 0 # success
994 johnpye 393
995 johnpye 395 def subst_in_file(target, source, env):
996     if not env.has_key('SUBST_DICT'):
997     raise SCons.Errors.UserError, "SubstInFile requires SUBST_DICT to be set."
998     d = dict(env['SUBST_DICT']) # copy it
999     for (k,v) in d.items():
1000     if callable(v):
1001     d[k] = env.subst(v())
1002     elif SCons.Util.is_String(v):
1003     d[k]=env.subst(v)
1004     else:
1005     raise SCons.Errors.UserError, "SubstInFile: key %s: %s must be a string or callable"%(k, repr(v))
1006     for (t,s) in zip(target, source):
1007     return do_subst_in_file(str(t), str(s), d)
1008 johnpye 393
1009 johnpye 395 def subst_in_file_string(target, source, env):
1010     """This is what gets printed on the console."""
1011     return '\n'.join(['Substituting vars from %s into %s'%(str(s), str(t))
1012     for (t,s) in zip(target, source)])
1013 johnpye 393
1014 johnpye 395 def subst_emitter(target, source, env):
1015     """Add dependency from substituted SUBST_DICT to target.
1016     Returns original target, source tuple unchanged.
1017     """
1018     d = env['SUBST_DICT'].copy() # copy it
1019     for (k,v) in d.items():
1020     if callable(v):
1021     d[k] = env.subst(v())
1022     elif SCons.Util.is_String(v):
1023     d[k]=env.subst(v)
1024     Depends(target, SCons.Node.Python.Value(d))
1025     return target, source
1026 johnpye 393
1027 johnpye 395 subst_action=SCons.Action.Action(subst_in_file, subst_in_file_string)
1028     env['BUILDERS']['SubstInFile'] = Builder(action=subst_action, emitter=subst_emitter)
1029    
1030     TOOL_SUBST(env)
1031    
1032 johnpye 393 #------------------------------------------------------
1033 johnpye 463 # Recipe for 'CHMOD' ACTION
1034 johnpye 439
1035     import SCons
1036     from SCons.Script.SConscript import SConsEnvironment
1037     SConsEnvironment.Chmod = SCons.Action.ActionFactory(os.chmod,
1038     lambda dest, mode: 'Chmod("%s", 0%o)' % (dest, mode))
1039    
1040     def InstallPerm(env, dest, files, perm):
1041     obj = env.Install(dest, files)
1042     for i in obj:
1043     env.AddPostAction(i, env.Chmod(str(i), perm))
1044    
1045     SConsEnvironment.InstallPerm = InstallPerm
1046    
1047     # define wrappers
1048     SConsEnvironment.InstallProgram = lambda env, dest, files: InstallPerm(env, dest, files, 0755)
1049 johnpye 578 SConsEnvironment.InstallHeader = lambda env, dest, files: InstallPerm(env, dest, files, 0644)
1050 johnpye 629 SConsEnvironment.InstallShared = lambda env, dest, files: InstallPerm(env, dest, files, 0644)
1051 johnpye 463
1052 johnpye 439 #------------------------------------------------------
1053 johnpye 463 # BUILD...
1054 johnpye 385
1055 johnpye 463 # so that #include <modulename/headername.h> works across all modules...
1056     env.Append(CPPPATH=['#base/generic'])
1057 johnpye 385
1058 johnpye 485 if gcc_version4:
1059     env.Append(CCFLAGS=['-fvisibility=hidden'])
1060    
1061 johnpye 508 if env['DEBUG']:
1062     env.Append(CCFLAGS=['-g'])
1063    
1064 johnpye 591 if env['GCOV']:
1065     env.Append(
1066     CPPFLAGS=['-g','-fprofile-arcs','-ftest-coverage']
1067     , LIBS=['gcov']
1068     , LINKFLAGS=['-fprofile-arcs','-ftest-coverage']
1069     )
1070    
1071 johnpye 463 #-------------
1072     # TCL/TK GUI
1073 johnpye 385
1074 johnpye 551 if with_tcltk:
1075 johnpye 463 if with_local_blas:
1076     env.SConscript(['blas/SConscript'],'env')
1077     else:
1078     print "Skipping... BLAS won't be build:", without_local_blas_reason
1079 johnpye 385
1080 johnpye 463 env.SConscript(['lsod/SConscript'],'env')
1081 johnpye 385
1082 johnpye 463 env.SConscript(['linpack/SConscript'],'env')
1083 johnpye 569 env.SConscript(['tcltk/generic/interface/SConscript'],'env')
1084 johnpye 391 else:
1085 johnpye 405 print "Skipping... Tcl/Tk GUI isn't being built:",without_tcltk_reason
1086 johnpye 386
1087 johnpye 463 #-------------
1088     # PYTHON INTERFACE
1089    
1090 johnpye 387 if with_python:
1091 johnpye 532 env.SConscript(['pygtk/SConscript'],'env')
1092 johnpye 391 else:
1093 johnpye 413 print "Skipping... Python GUI isn't being built:",without_python_reason
1094 johnpye 400
1095 johnpye 463 #------------
1096     # BASE/GENERIC SUBDIRECTORIES
1097    
1098     dirs = ['general','utilities','compiler','solver','packages']
1099    
1100     srcs = []
1101     for d in dirs:
1102     heresrcs = env.SConscript('base/generic/'+d+'/SConscript','env')
1103     srcs += heresrcs
1104    
1105     #-------------
1106     # LIBASCEND -- all base/generic functionality
1107    
1108     libascend = env.SharedLibrary('ascend',srcs)
1109    
1110     #-------------
1111     # UNIT TESTS
1112    
1113 johnpye 593 if with_cunit:
1114 johnpye 400 testdirs = ['general','solver','utilities']
1115 johnpye 593 testsrcs = []
1116 johnpye 400 for testdir in testdirs:
1117     path = 'base/generic/'+testdir+'/test/'
1118     env.SConscript([path+'SConscript'],'env')
1119 johnpye 593 testsrcs += [i.path for i in env['TESTSRCS_'+testdir.upper()]]
1120    
1121     #print "TESTSRCS =",testsrcs
1122    
1123 johnpye 400 env.SConscript(['test/SConscript'],'env')
1124     env.SConscript(['base/generic/test/SConscript'],'env')
1125 johnpye 593
1126     env.Alias('test',[env.Dir('test'),env.Dir('base/generic/test')])
1127 johnpye 400
1128     else:
1129 johnpye 427 print "Skipping... CUnit tests aren't being built:",without_cunit_reason
1130 johnpye 400
1131 johnpye 463 #------------------------------------------------------
1132     # INSTALLATION
1133 johnpye 427
1134 johnpye 552 if env.get('CAN_INSTALL'):
1135 johnpye 463 # the models directory only needs to be processed for installation, no other processing required.
1136     env.SConscript(['models/SConscript'],'env')
1137 johnpye 427
1138 johnpye 628 dirs = ['INSTALL_BIN','INSTALL_ASCDATA','INSTALL_LIB']
1139 johnpye 463 install_dirs = [env['INSTALL_ROOT']+env[d] for d in dirs]
1140 johnpye 449
1141 johnpye 463 # TODO: add install options
1142     env.Alias('install',install_dirs)
1143 johnpye 400
1144 johnpye 629 env.InstallShared(env['INSTALL_ROOT']+env['INSTALL_LIB'],libascend)
1145 johnpye 435
1146 johnpye 438 #------------------------------------------------------
1147 johnpye 631 # WINDOWS INSTALLER
1148     # For the windows installer, please see pygtk/SConscript
1149    
1150     if with_installer:
1151     pass
1152     else:
1153     print "Skipping... Windows installer isn't being built:",without_installer_reason
1154    
1155     #------------------------------------------------------
1156 johnpye 438 # CREATE the SPEC file for generation of RPM packages
1157    
1158 johnpye 463 if platform.system()=="Linux":
1159     env.SubstInFile('ascend.spec.in')
1160 johnpye 552
1161     #------------------------------------------------------
1162     # DISTRIBUTION TAR FILE
1163    
1164 johnpye 554 env['DISTTAR_FORMAT']='bz2'
1165 johnpye 556 env.Append(
1166 johnpye 566 DISTTAR_EXCLUDEEXTS=['.o','.os','.so','.a','.dll','.cc','.cache','.pyc','.cvsignore','.dblite','.log','.pl']
1167 johnpye 561 , DISTTAR_EXCLUDEDIRS=['CVS','.svn','.sconf_temp', 'dist']
1168 johnpye 556 )
1169 johnpye 554
1170 johnpye 563 tar = env.DistTar("dist/"+env['DISTTAR_NAME']
1171 johnpye 556 , [env.Dir('#')]
1172 johnpye 554 )
1173    
1174     #------------------------------------------------------
1175     # RPM BUILD
1176    
1177     #if platform.system()=="Linux":
1178     # pass
1179    
1180     #------------------------------------------------------
1181     # DEFAULT TARGETS
1182    
1183 johnpye 629 default_targets =[]
1184     if with_tcltk:
1185     default_targets.append('tcltk')
1186     if with_python:
1187     default_targets.append('pygtk')
1188 johnpye 631 if with_installer:
1189     default_targets.append('installer')
1190 johnpye 554
1191 johnpye 629 env.Default(default_targets)
1192    
1193     print "Building targets:"," ".join([str(i) for i in BUILD_TARGETS])
1194    

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22