/[ascend]/trunk/SConstruct
ViewVC logotype

Contents of /trunk/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


Revision 435 - (show annotations) (download)
Tue Apr 4 10:09:09 2006 UTC (13 years, 8 months ago) by johnpye
File size: 17919 byte(s)
Starting work on linux-based install process
1 import os, commands, platform, distutils.sysconfig, os.path
2
3 #------------------------------------------------------
4 # OPTIONS
5 #
6 # Note that if you set the options via the command line, they will be
7 # remembered in the file 'options.cache'. It's a feature ;-)
8
9 opts = Options(['options.cache', 'config.py'])
10 print "PLATFORM = ",platform.system()
11
12 # Import the outside environment
13 env = Environment(ENV=os.environ)
14
15 if platform.system()=='Windows' and env.has_key('MSVS'):
16 print "INCLUDE =",env['ENV']['INCLUDE']
17 print "LIB =",env['ENV']['LIB']
18 print "LINK =",env['LINK']
19 print "LINKCOM =",env['LINKCOM']
20 print "AR =",env['AR']
21 print "ARCOM =",env['ARCOM']
22 #env['AR']='link /lib'
23 env.Append(CPPPATH=env['ENV']['INCLUDE'])
24 env.Append(LIBPATH=env['ENV']['LIB'])
25 env.Append(CPPDEFINES=['_CRT_SECURE_NO_DEPRECATED','_CRT_SECURE_NO_DEPRECATE'])
26
27 # Package linking option
28 opts.Add(EnumOption(
29 'PACKAGE_LINKING'
30 , 'Style of linking for external libraries'
31 , 'DYNAMIC_PACKAGES'
32 , ['DYNAMIC_PACKAGES', 'STATIC_PACKAGES', 'NO_PACKAGES']
33 ))
34
35 # You can turn off building of Tcl/Tk interface
36 opts.Add(BoolOption(
37 'WITHOUT_TCLTK_GUI'
38 ,"Set to True if you don't want to build the original Tcl/Tk GUI."
39 , False
40 ))
41
42 # You can turn off the building of the Python interface
43 opts.Add(BoolOption(
44 'WITHOUT_PYTHON'
45 ,"Set to True if you don't want to build Python wrappers."
46 , False
47 ))
48
49 # Which solvers will we allow?
50 opts.Add(ListOption(
51 'WITH_SOLVERS'
52 ,"List of the solvers you want to build. The default is the minimum that"
53 +" works."
54 ,["QRSLV","CMSLV"]
55 ,['QRSLV','MPS','SLV','OPTSQP'
56 ,'NGSLV','CMSLV','LRSLV','MINOS','CONOPT'
57 ,'LSOD','OPTSQP'
58 ]
59 ))
60
61 # Where will the local copy of the help files be kept?
62 opts.Add(PackageOption(
63 'WITH_LOCAL_HELP'
64 , "Directory containing the local copy of the help files (optional)"
65 , "no"
66 ))
67
68 # Will bintoken support be enabled?
69 opts.Add(BoolOption(
70 'WITH_BINTOKEN'
71 ,"Enable bintoken support? This means compiling models as C-code before"
72 +" running them, to increase solving speed for large models."
73 ,False
74 ))
75
76 # What should the default ASCENDLIBRARY path be?
77 # Note: users can change it by editing their ~/.ascend.ini
78 opts.Add(
79 'DEFAULT_ASCENDLIBRARY'
80 ,"Set the default value of the ASCENDLIBRARY -- the location where"
81 +" ASCEND will look for models when running ASCEND"
82 ,os.path.expanduser("~/src/ascend/trunk/models")
83 )
84
85 # Where is SWIG?
86 opts.Add(
87 'SWIG'
88 ,"SWIG location, probably only required for MinGW and MSVC users."
89 +" Enter the location as a Windows-style path, for example"
90 +" 'c:\\msys\\1.0\\home\\john\\swigwin-1.3.29\\swig.exe'."
91 )
92
93 # Build the test suite?
94 opts.Add(BoolOption(
95 'WITH_CUNIT_TESTS'
96 ,"Whether to build the CUnit tests. Default is off. If set to on,"
97 +" you must have CUnit installed somewhere that SCons can"
98 +" find it."
99 ,False
100 ))
101
102 # Where are the CUnit includes?
103 opts.Add(PackageOption(
104 'CUNIT_CPPPATH'
105 ,"Where are your CUnit include files?"
106 ,"off"
107 ))
108
109 # Where are the CUnit libraries?
110 opts.Add(PackageOption(
111 'CUNIT_LIBPATH'
112 ,"Where are your CUnit libraries?"
113 ,"off"
114 ))
115
116 # Where are the Tcl includes?
117 opts.Add(PackageOption(
118 'TCL_CPPPATH'
119 ,"Where are your Tcl include files?"
120 ,None
121 ))
122
123 # Where are the Tcl libs?
124 opts.Add(PackageOption(
125 'TCL_LIBPATH'
126 ,"Where are your Tcl libraries?"
127 ,None
128 ))
129
130 # What is the name of the Tcl lib?
131 opts.Add(
132 'TCL_LIB'
133 ,"Name of Tcl lib (eg 'tcl' or 'tcl83')"
134 ,'tcl'
135 )
136
137 # Where are the Tk includes?
138 opts.Add(PackageOption(
139 'TK_CPPPATH'
140 ,"Where are your Tk include files?"
141 ,None
142 ))
143
144 # Where are the Tk libs?
145 opts.Add(PackageOption(
146 'TK_LIBPATH'
147 ,"Where are your Tk libraries?"
148 ,None
149 ))
150
151 # What is the name of the Tk lib?
152 opts.Add(
153 'TK_LIB'
154 ,"Name of Tk lib (eg 'tk' or 'tk83')"
155 ,'tk'
156 )
157
158 opts.Add(
159 'INSTALL_PREFIX'
160 ,'Root location for installed files'
161 ,'/usr'
162 )
163
164 opts.Add(
165 'INSTALL_BIN'
166 ,'Location to put binaries during installation'
167 ,"$INSTALL_PREFIX/bin"
168 )
169
170 opts.Add(
171 'INSTALL_DATA'
172 ,'Location to put data files during installation'
173 ,"$INSTALL_PREFIX/share"
174 )
175
176 opts.Add(
177 'INSTALL_INCLUDE'
178 ,'Location to put header files during installation'
179 ,"$INSTALL_PREFIX/include"
180 )
181
182 # TODO: OTHER OPTIONS?
183 # TODO: flags for optimisation
184 # TODO: turning on/off bintoken functionality
185 # TODO: Where will the 'Makefile.bt' file be installed?
186
187 opts.Update(env)
188 opts.Save('options.cache',env)
189
190 Help(opts.GenerateHelpText(env))
191
192 with_tcltk_gui = (env['WITHOUT_TCLTK_GUI']==False)
193 without_tcltk_reason = "disabled by options/config.py"
194
195 with_python = (env['WITHOUT_PYTHON']==False)
196 without_python_reason = "disabled by options/config.py"
197
198 with_cunit_tests = env['WITH_CUNIT_TESTS']
199 without_cunit_reason = "not requested"
200
201 print "SOLVERS:",env['WITH_SOLVERS']
202 print "WITH_LOCAL_HELP:",env['WITH_LOCAL_HELP']
203 print "WITH_BINTOKEN:",env['WITH_BINTOKEN']
204 print "DEFAULT_ASCENDLIBRARY:",env['DEFAULT_ASCENDLIBRARY']
205
206 subst_dict = {
207 '@WEBHELPROOT@':'http://pye.dyndns.org/ascend/manual/'
208 , '@GLADE_FILE@':'glade/ascend.glade'
209 , '@DEFAULT_ASCENDLIBRARY@':env['DEFAULT_ASCENDLIBRARY']
210 , '@ASCEND_ICON@':'glade/ascend.png'
211 , '@HELP_ROOT@':''
212 }
213
214 if env['WITH_LOCAL_HELP']:
215 subst_dict['@HELP_ROOT@']=env['WITH_LOCAL_HELP']
216
217 env.Append(SUBST_DICT=subst_dict)
218
219 #------------------------------------------------------
220 # SPECIAL CONFIGURATION TESTS
221
222 #----------------
223 # SWIG
224
225 import os,re
226
227 need_fortran = False
228
229 def get_swig_version(env):
230 cmd = env['SWIG']+' -version'
231 (cin,coutcerr) = os.popen4(cmd)
232 output = coutcerr.read()
233
234 restr = "SWIG\\s+Version\\s+(?P<maj>[0-9]+)\\.(?P<min>[0-9]+)\\.(?P<pat>[0-9]+)\\s*$"
235 expr = re.compile(restr,re.M);
236 m = expr.search(output);
237 if not m:
238 return None
239 maj = int(m.group('maj'))
240 min = int(m.group('min'))
241 pat = int(m.group('pat'))
242
243 return (maj,min,pat)
244
245
246 def CheckSwigVersion(context):
247
248 try:
249 context.Message("Checking version of SWIG... ")
250 maj,min,pat = get_swig_version(context.env)
251 except:
252 context.Result("Failed to detect version, or failed to run SWIG")
253 return 0;
254
255 if maj == 1 and (
256 min > 3
257 or (min == 3 and pat >= 24)
258 ):
259 context.Result("ok, %d.%d.%d" % (maj,min,pat))
260 return 1;
261 else:
262 context.Result("too old, %d.%d.%d" % (maj,min,pat))
263 return 0;
264
265 #----------------
266 # General purpose library-and-header test
267
268 class KeepContext:
269 def __init__(self,context,varprefix):
270 self.keep = {}
271 for k in ['LIBS','LIBPATH','CPPPATH']:
272 if context.env.has_key(k):
273 self.keep[k] = context.env[k]
274
275 libpath_add = []
276 if context.env.has_key(varprefix+'_LIBPATH'):
277 libpath_add = [env[varprefix+'_LIBPATH']]
278 #print "Adding '"+str(libpath_add)+"' to lib path"
279
280 cpppath_add = []
281 if context.env.has_key(varprefix+'_CPPPATH'):
282 cpppath_add = [env[varprefix+'_CPPPATH']]
283 #print "Adding '"+str(cpppath_add)+"' to cpp path"
284
285 libs_add = []
286 if context.env.has_key(varprefix+'_LIB'):
287 libs_add = [env[varprefix+'_LIB']]
288 #print "Adding '"+str(libs_add)+"' to libs"
289
290 context.env.Append(
291 LIBPATH = libpath_add
292 , CPPPATH = cpppath_add
293 , LIBS = libs_add
294 )
295
296 def restore(self,context):
297 for k in self.keep:
298 context.env[k]=self.keep[k];
299
300 def CheckExtLib(context,libname,text,ext='.c',varprefix=None):
301 """This method will check for variables LIBNAME_LIBPATH
302 and LIBNAME_CPPPATH and try to compile and link the
303 file with the provided text, linking with the
304 library libname."""
305
306 context.Message( 'Checking for '+libname+'... ' )
307
308 if varprefix==None:
309 varprefix = libname.upper()
310
311 keep = KeepContext(context,varprefix)
312
313 # print "TryLink with CPPPATH="+str(context.env['CPPPATH'])
314 # print "TryLink with LIBS="+str(context.env['LIBS'])
315 # print "TryLink with LIBPATH="+str(context.env['LIBPATH'])
316
317 if not context.env.has_key(varprefix+'_LIB'):
318 context.env.AppendUnique(LIBS=libname)
319
320 is_ok = context.TryLink(text,ext)
321
322 # print "Link success? ",(is_ok != 0)
323
324 keep.restore(context)
325
326 # print "Restored CPPPATH="+str(context.env['CPPPATH'])
327 # print "Restored LIBS="+libname
328 # print "Restored LIBPATH="+str(context.env['LIBPATH'])
329
330 context.Result(is_ok)
331 return is_ok
332
333 #----------------
334 # CUnit test
335
336 cunit_test_text = """
337 #include <CUnit/Cunit.h>
338 int maxi(int i1, int i2){
339 return (i1 > i2) ? i1 : i2;
340 }
341
342 void test_maxi(void){
343 CU_ASSERT(maxi(0,2) == 2);
344 CU_ASSERT(maxi(0,-2) == 0);
345 CU_ASSERT(maxi(2,2) == 2);
346
347 }
348 int main(void){
349 /* CU_initialize_registry() */
350 return 0;
351 }
352 """
353
354 def CheckCUnit(context):
355 return context.CheckExtLib(context
356 ,'cunit'
357 ,cunit_test_text
358 )
359
360 #----------------
361 # Tcl test
362
363 tcl_check_text = r"""
364 #include <tcl.h>
365 #include <stdio.h>
366 int main(void){
367 printf("%s",TCL_PATCH_LEVEL);
368 return 0;
369 }
370 """
371
372 def CheckTcl(context):
373 return CheckExtLib(context,'tcl',tcl_check_text)
374
375 def CheckTclVersion(context):
376 keep = KeepContext(context,'TCL')
377 context.Message("Checking Tcl version... ")
378 (is_ok,output) = context.TryRun(tcl_check_text,'.c')
379 keep.restore(context)
380 if not is_ok:
381 context.Result("failed to run check")
382 return 0
383
384 major,minor,patch = tuple(int(i) for i in output.split("."))
385 if major != 8 or minor > 3:
386 context.Result(output+" (bad version)")
387 # bad version
388 return 0
389
390 # good version
391 context.Result(output+" (good)")
392 return 1
393
394 #----------------
395 # Tcl test
396
397 tk_check_text = r"""
398 #include <tk.h>
399 #include <stdio.h>
400 int main(void){
401 printf("%s",TK_PATCH_LEVEL);
402 return 0;
403 }
404 """
405 def CheckTk(context):
406 return CheckExtLib(context,'tk',tcl_check_text)
407
408
409 def CheckTkVersion(context):
410 keep = KeepContext(context,'TK')
411 context.Message("Checking Tk version... ")
412 (is_ok,output) = context.TryRun(tk_check_text,'.c')
413 keep.restore(context)
414 if not is_ok:
415 context.Result("failed to run check")
416 return 0
417 context.Result(output)
418
419 major,minor,patch = tuple(int(i) for i in output.split("."))
420 if major != 8 or minor > 3:
421 # bad version
422 return 0
423
424 # good version
425 return 1
426
427 #------------------------------------------------------
428 # CONFIGURATION
429
430 conf = Configure(env
431 , custom_tests = {
432 'CheckSwigVersion' : CheckSwigVersion
433 , 'CheckCUnit' : CheckCUnit
434 , 'CheckTcl' : CheckTcl
435 , 'CheckTclVersion' : CheckTclVersion
436 , 'CheckTk' : CheckTk
437 , 'CheckTkVersion' : CheckTkVersion
438 # , 'CheckIsNan' : CheckIsNan
439 # , 'CheckCppUnitConfig' : CheckCppUnitConfig
440 }
441 , config_h = "config.h"
442 )
443
444
445 # Math library
446
447 #if not conf.CheckFunc('sinh') and not conf.CheckLibWithHeader(['m','c','libc'], 'math.h', 'C'):
448 # print 'Did not find math library, exiting!'
449 # Exit(1)
450
451 # Where is 'isnan'?
452
453 if not conf.CheckFunc('isnan'):
454 print "Didn't find isnan"
455 # Exit(1)
456
457 # Tcl/Tk
458
459 if conf.CheckTcl():
460 if with_tcltk_gui and conf.CheckTclVersion():
461 if conf.CheckTk():
462 if with_tcltk_gui and not conf.CheckTkVersion():
463 without_tcltk_reason = "Require Tk version <= 8.3. See 'scons -h'"
464 with_tcltk_gui = False
465 else:
466 without_tcltk_reason = "Tk not found."
467 with_tcltk_gui = False
468 else:
469 without_tcltk_reason = "Require Tcl <= 8.3 Tcl."
470 with_tcltk_gui = False
471
472 else:
473 without_tcltk_reason = "Tcl not found."
474 with_tcltk_gui = False
475
476 # Python... obviously we're already running python, so we just need to
477 # check that we can link to the python library OK:
478
479 if platform.system()=="Windows":
480 python_lib='python24'
481 else:
482 python_lib='python2.4'
483
484 # SWIG version
485
486 if platform.system()=="Windows":
487 env['ENV']['SWIGFEATURES']='-O'
488 else:
489 env['ENV']['SWIGFEATURES']='-O'
490
491
492 if not conf.CheckSwigVersion():
493 without_python_reason = 'SWIG >= 1.3.24 is required'
494 with_python = False
495
496 # CUnit
497
498 if with_cunit_tests:
499 if not conf.CheckCUnit():
500 without_cunit_reason = 'CUnit not found'
501
502 # BLAS
503
504 if conf.CheckLib('blas'):
505 print "FOUND BLAS"
506 with_local_blas = False
507 without_local_blas_reason = "Found BLAS installed on system"
508 else:
509 print "DIDN'T FIND BLAS"
510 with_local_blas = True
511 need_fortran = True
512
513 # FORTRAN
514
515 if need_fortran:
516 conf.env.Tool('f77')
517 detect_fortran = conf.env.Detect(['g77','f77'])
518 if detect_fortran:
519 # For some reason, g77 doesn't get detected properly on MinGW
520 if not env.has_key('F77'):
521 conf.env.Replace(F77=detect_fortran)
522 conf.env.Replace(F77COM='$F77 $F77FLAGS -c -o $TARGET $SOURCE')
523 conf.env.Replace(F77FLAGS='')
524 #print "F77:",conf.env['F77']
525 #print "F77COM:",conf.env['F77COM']
526 #print "F77FLAGS:",conf.env['F77FLAGS']
527 fortran_builder = Builder(
528 action='$F77COM'
529 , suffix='.o'
530 , src_suffix='.f'
531 )
532 conf.env.Append(BUILDERS={'Fortran':fortran_builder})
533 else:
534 print "FORTRAN-77 required but not found"
535 Exit(1)
536 else:
537 print "FORTRAN not required"
538
539 # TODO: -D_HPUX_SOURCE is needed
540
541 # TODO: check size of void*
542
543 # TODO: detect if dynamic libraries are possible or not
544
545 if platform.system()=="Windows" and env.has_key('MSVS'):
546 if not conf.CheckHeader('windows.h') and env['PACKAGE_LINKING']=='DYNAMIC_PACKAGES':
547 print "Reverting to STATIC_PACKAGES since windows.h is not available. Probably you "\
548 +"need to install the Microsoft Windows Server 2003 Platform SDK, or similar."
549 env['PACKAGE_LINKING']='STATIC_PACKAGES'
550
551 if with_python and not conf.CheckHeader('basetsd.h'):
552 with_python = 0;
553 without_python_reason = "Header file 'basetsd.h' not found. Install the MS Platform SDK."
554
555 conf.env.Append(CPPDEFINES=env['PACKAGE_LINKING'])
556
557 conf.Finish()
558
559 env.Append(PYTHON_LIBPATH=[distutils.sysconfig.PREFIX+"/libs"])
560 env.Append(PYTHON_LIB=[python_lib])
561 env.Append(PYTHON_CPPPATH=[distutils.sysconfig.get_python_inc()])
562
563 #------------------------------------------------------
564 # RECIPE: 'SubstInFile', used in pygtk SConscript
565
566 import re
567 from SCons.Script import * # the usual scons stuff you get in a SConscript
568
569 def TOOL_SUBST(env):
570 """Adds SubstInFile builder, which substitutes the keys->values of SUBST_DICT
571 from the source to the target.
572 The values of SUBST_DICT first have any construction variables expanded
573 (its keys are not expanded).
574 If a value of SUBST_DICT is a python callable function, it is called and
575 the result is expanded as the value.
576 If there's more than one source and more than one target, each target gets
577 substituted from the corresponding source.
578 """
579 env.Append(TOOLS = 'SUBST')
580 def do_subst_in_file(targetfile, sourcefile, dict):
581 """Replace all instances of the keys of dict with their values.
582 For example, if dict is {'%VERSION%': '1.2345', '%BASE%': 'MyProg'},
583 then all instances of %VERSION% in the file will be replaced with 1.2345 etc.
584 """
585 try:
586 f = open(sourcefile, 'rb')
587 contents = f.read()
588 f.close()
589 except:
590 raise SCons.Errors.UserError, "Can't read source file %s"%sourcefile
591 for (k,v) in dict.items():
592 contents = re.sub(k, v, contents)
593 try:
594 f = open(targetfile, 'wb')
595 f.write(contents)
596 f.close()
597 except:
598 raise SCons.Errors.UserError, "Can't write target file %s"%targetfile
599 return 0 # success
600
601 def subst_in_file(target, source, env):
602 if not env.has_key('SUBST_DICT'):
603 raise SCons.Errors.UserError, "SubstInFile requires SUBST_DICT to be set."
604 d = dict(env['SUBST_DICT']) # copy it
605 for (k,v) in d.items():
606 if callable(v):
607 d[k] = env.subst(v())
608 elif SCons.Util.is_String(v):
609 d[k]=env.subst(v)
610 else:
611 raise SCons.Errors.UserError, "SubstInFile: key %s: %s must be a string or callable"%(k, repr(v))
612 for (t,s) in zip(target, source):
613 return do_subst_in_file(str(t), str(s), d)
614
615 def subst_in_file_string(target, source, env):
616 """This is what gets printed on the console."""
617 return '\n'.join(['Substituting vars from %s into %s'%(str(s), str(t))
618 for (t,s) in zip(target, source)])
619
620 def subst_emitter(target, source, env):
621 """Add dependency from substituted SUBST_DICT to target.
622 Returns original target, source tuple unchanged.
623 """
624 d = env['SUBST_DICT'].copy() # copy it
625 for (k,v) in d.items():
626 if callable(v):
627 d[k] = env.subst(v())
628 elif SCons.Util.is_String(v):
629 d[k]=env.subst(v)
630 Depends(target, SCons.Node.Python.Value(d))
631 return target, source
632
633 subst_action=SCons.Action.Action(subst_in_file, subst_in_file_string)
634 env['BUILDERS']['SubstInFile'] = Builder(action=subst_action, emitter=subst_emitter)
635
636 TOOL_SUBST(env)
637
638 #------------------------------------------------------
639 # SUBDIRECTORIES....
640
641
642 env.Append(CPPPATH=['..'])
643
644 env.SConscript(['base/generic/general/SConscript'],'env')
645
646 env.SConscript(['base/generic/utilities/SConscript'],'env')
647
648 env.SConscript(['base/generic/compiler/SConscript'],'env')
649
650 env.SConscript(['base/generic/solver/SConscript'],'env')
651
652 env.SConscript(['base/generic/packages/SConscript'],'env')
653
654 if with_tcltk_gui:
655 env.SConscript(['tcltk98/generic/interface/SConscript'],'env')
656 else:
657 print "Skipping... Tcl/Tk GUI isn't being built:",without_tcltk_reason
658
659 if with_python:
660 env.SConscript(['pygtk/interface/SConscript'],'env')
661 else:
662 print "Skipping... Python GUI isn't being built:",without_python_reason
663
664 if with_cunit_tests:
665 testdirs = ['general','solver','utilities']
666 for testdir in testdirs:
667 path = 'base/generic/'+testdir+'/test/'
668 env.SConscript([path+'SConscript'],'env')
669 env.SConscript(['test/SConscript'],'env')
670 env.SConscript(['base/generic/test/SConscript'],'env')
671
672
673 else:
674 print "Skipping... CUnit tests aren't being built:",without_cunit_reason
675
676 #if with_tcltk_gui:
677 if with_local_blas:
678 env.SConscript(['blas/SConscript'],'env')
679 else:
680 print "Skipping... BLAS won't be build:", without_local_blas_reason
681
682 env.SConscript(['lsod/SConscript'],'env')
683
684 env.SConscript(['linpack/SConscript'],'env')
685
686 #------------------------------------------------------
687 # INSTALLATION
688
689 install_dirs = [env['INSTALL_BIN']]+[env['INSTALL_DATA']]
690
691 # TODO: add install options
692 env.Alias('install',install_dirs)
693

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