/[ascend]/trunk/SConstruct
ViewVC logotype

Contents of /trunk/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


Revision 478 - (show annotations) (download)
Mon Apr 17 08:10:48 2006 UTC (13 years, 7 months ago) by johnpye
File size: 26696 byte(s)
Fixing build for SWIG 1.3.24 (no -O flag)
Adding more debug info to loading output in PyGTK interface/config.py.in
Adding SWIGVERSION flag to SCons env.
Commenting in ascDynaLoad.c and ascParse.y
Adding VERSION to config.py
1 import os, commands, platform, distutils.sysconfig, os.path
2
3 version = "0.9.6rc0"
4
5 #------------------------------------------------------
6 # OPTIONS
7 #
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
11 opts = Options(['options.cache', 'config.py'])
12 #print "PLATFORM = ",platform.system()
13
14 # Import the outside environment
15 env = Environment(ENV=os.environ)
16
17 if platform.system()=='Windows' and env.has_key('MSVS'):
18 print "INCLUDE =",env['ENV']['INCLUDE']
19 print "LIB =",env['ENV']['LIB']
20 print "LINK =",env['LINK']
21 print "LINKCOM =",env['LINKCOM']
22 print "AR =",env['AR']
23 print "ARCOM =",env['ARCOM']
24 #env['AR']='link /lib'
25 env.Append(CPPPATH=env['ENV']['INCLUDE'])
26 env.Append(LIBPATH=env['ENV']['LIB'])
27 env.Append(CPPDEFINES=['_CRT_SECURE_NO_DEPRECATED','_CRT_SECURE_NO_DEPRECATE'])
28
29 if platform.system()=="Windows":
30 default_tcl_lib = "tcl83"
31 default_tk_lib = "tk83"
32 default_tktable_lib = "Tktable28"
33 else:
34 default_tcl_lib = "tcl"
35 default_tk_lib = "tk"
36 default_tktable_lib = "Tktable2.8"
37
38
39 # Package linking option
40 opts.Add(EnumOption(
41 'PACKAGE_LINKING'
42 , 'Style of linking for external libraries'
43 , 'DYNAMIC_PACKAGES'
44 , ['DYNAMIC_PACKAGES', 'STATIC_PACKAGES', 'NO_PACKAGES']
45 ))
46
47 # You can turn off building of Tcl/Tk interface
48 opts.Add(BoolOption(
49 'WITHOUT_TCLTK'
50 ,"Set to True if you don't want to build the original Tcl/Tk GUI."
51 , False
52 ))
53
54 # You can turn off the building of the Python interface
55 opts.Add(BoolOption(
56 'WITHOUT_PYTHON'
57 ,"Set to True if you don't want to build Python wrappers."
58 , False
59 ))
60
61 # Which solvers will we allow?
62 opts.Add(ListOption(
63 'WITH_SOLVERS'
64 ,"List of the solvers you want to build. The default is the minimum that"
65 +" works."
66 ,["QRSLV","CMSLV"]
67 ,['QRSLV','MPS','SLV','OPTSQP'
68 ,'NGSLV','CMSLV','LRSLV','MINOS','CONOPT'
69 ,'LSOD','OPTSQP'
70 ]
71 ))
72
73 # Where will the local copy of the help files be kept?
74 opts.Add(PackageOption(
75 'WITH_LOCAL_HELP'
76 , "Directory containing the local copy of the help files (optional)"
77 , "no"
78 ))
79
80 # Will bintoken support be enabled?
81 opts.Add(BoolOption(
82 'WITH_BINTOKEN'
83 ,"Enable bintoken support? This means compiling models as C-code before"
84 +" running them, to increase solving speed for large models."
85 ,False
86 ))
87
88 # What should the default ASCENDLIBRARY path be?
89 # Note: users can change it by editing their ~/.ascend.ini
90 opts.Add(
91 'DEFAULT_ASCENDLIBRARY'
92 ,"Set the default value of the ASCENDLIBRARY -- the location where"
93 +" ASCEND will look for models when running ASCEND"
94 ,"$INSTALL_DATA/models"
95 )
96
97 # Where is SWIG?
98 opts.Add(
99 'SWIG'
100 ,"SWIG location, probably only required for MinGW and MSVC users."
101 +" Enter the location as a Windows-style path, for example"
102 +" 'c:\\msys\\1.0\\home\\john\\swigwin-1.3.29\\swig.exe'."
103 )
104
105 # Build the test suite?
106 opts.Add(BoolOption(
107 'WITH_CUNIT_TESTS'
108 ,"Whether to build the CUnit tests. Default is off. If set to on,"
109 +" you must have CUnit installed somewhere that SCons can"
110 +" find it, or else use the CUNIT_* options to specify."
111 ,False
112 ))
113
114 # Where are the CUnit includes?
115 opts.Add(PackageOption(
116 'CUNIT_CPPPATH'
117 ,"Where are your CUnit include files?"
118 ,'off'
119 ))
120
121 # Where are the CUnit libraries?
122 opts.Add(PackageOption(
123 'CUNIT_LIBPATH'
124 ,"Where are your CUnit libraries?"
125 ,'off'
126 ))
127
128 # Where are the Tcl includes?
129 opts.Add(PackageOption(
130 'TCL_CPPPATH'
131 ,"Where are your Tcl include files?"
132 ,"disable"
133 ))
134
135 # Where are the Tcl libs?
136 opts.Add(PackageOption(
137 'TCL_LIBPATH'
138 ,"Where are your Tcl libraries?"
139 ,'off'
140 ))
141
142 # What is the name of the Tcl lib?
143 opts.Add(
144 'TCL_LIB'
145 ,"Name of Tcl lib (eg 'tcl' or 'tcl83')"
146 ,default_tcl_lib
147 )
148
149 # Where are the Tk includes?
150 opts.Add(PackageOption(
151 'TK_CPPPATH'
152 ,"Where are your Tk include files?"
153 ,'$TCL_CPPPATH'
154 ))
155
156 # Where are the Tk libs?
157 opts.Add(PackageOption(
158 'TK_LIBPATH'
159 ,"Where are your Tk libraries?"
160 ,'$TCL_LIBPATH'
161 ))
162
163 # What is the name of the Tk lib?
164 opts.Add(
165 'TK_LIB'
166 ,"Name of Tk lib (eg 'tk' or 'tk83')"
167 ,default_tk_lib
168 )
169
170 # Static linking to TkTable
171
172 opts.Add(BoolOption(
173 'STATIC_TKTABLE'
174 ,'Use static linking to TkTable or not'
175 ,False
176 ))
177
178 opts.Add(
179 'TKTABLE_LIBPATH'
180 ,'Location of TkTable static library'
181 ,'$TCL_LIBPATH/Tktable2.8'
182 )
183
184 opts.Add(
185 'TKTABLE_LIB'
186 ,'Name of TkTable static library (excluding suffix/prefix, eg libtktable2.8.so -> tktable2.8)'
187 ,default_tktable_lib
188 )
189
190 opts.Add(
191 'INSTALL_PREFIX'
192 ,'Root location for installed files'
193 ,'/usr/local'
194 )
195
196 opts.Add(
197 'INSTALL_BIN'
198 ,'Location to put binaries during installation'
199 ,"$INSTALL_PREFIX/bin"
200 )
201
202 opts.Add(
203 'INSTALL_LIB'
204 ,'Location to put binaries during installation'
205 ,"$INSTALL_PREFIX/lib"
206 )
207
208 opts.Add(
209 'INSTALL_DATA'
210 ,'Location to put data files during installation'
211 ,"$INSTALL_PREFIX/share"
212 )
213
214 opts.Add(
215 'INSTALL_INCLUDE'
216 ,'Location to put header files during installation'
217 ,"$INSTALL_PREFIX/include"
218 )
219
220 if platform.system()=="Windows":
221 default_install_assets = "glade/"
222 icon_extension = '.png'
223 else:
224 default_install_assets = "$INSTALL_DATA/ascend/glade/"
225 icon_extension = '.svg'
226
227 opts.Add(
228 'PYGTK_ASSETS'
229 ,'Default location for Glade assets (placed in pygtk/interface/config.py)'
230 ,default_install_assets
231 )
232
233 opts.Add(
234 'INSTALL_ROOT'
235 ,'For use by RPM only: location of %{buildroot} during rpmbuild'
236 ,""
237 )
238
239 if platform.system()=="Windows":
240 opts.Add(BoolOption(
241 'WITH_INSTALLER'
242 ,'Build the Windows Installer (setup program) using NSIS'
243 ,False
244 ))
245
246 # TODO: OTHER OPTIONS?
247 # TODO: flags for optimisation
248 # TODO: turning on/off bintoken functionality
249 # TODO: Where will the 'Makefile.bt' file be installed?
250
251 opts.Update(env)
252 opts.Save('options.cache',env)
253
254 Help(opts.GenerateHelpText(env))
255
256 with_tcltk_gui = (env['WITHOUT_TCLTK']==False)
257 without_tcltk_reason = "disabled by options/config.py"
258
259 with_python = (env['WITHOUT_PYTHON']==False)
260 without_python_reason = "disabled by options/config.py"
261
262 with_cunit_tests = env['WITH_CUNIT_TESTS']
263 without_cunit_reason = "not requested"
264
265 #print "SOLVERS:",env['WITH_SOLVERS']
266 #print "WITH_BINTOKEN:",env['WITH_BINTOKEN']
267 #print "DEFAULT_ASCENDLIBRARY:",env['DEFAULT_ASCENDLIBRARY']
268
269 subst_dict = {
270 '@WEBHELPROOT@':'http://pye.dyndns.org/ascend/manual/'
271 , '@GLADE_FILE@':'ascend.glade'
272 , '@DEFAULT_ASCENDLIBRARY@':env['DEFAULT_ASCENDLIBRARY']
273 , '@ICON_EXTENSION@':icon_extension
274 , '@HELP_ROOT@':''
275 , '@INSTALL_DATA@':env['INSTALL_DATA']
276 , '@INSTALL_BIN@':env['INSTALL_BIN']
277 , '@INSTALL_INCLUDE@':env['INSTALL_INCLUDE']
278 , '@PYGTK_ASSETS@':env['PYGTK_ASSETS']
279 , '@VERSION@':version
280 }
281
282 if env['WITH_LOCAL_HELP']:
283 print "WITH_LOCAL_HELP:",env['WITH_LOCAL_HELP']
284 subst_dict['@HELP_ROOT@']=env['WITH_LOCAL_HELP']
285
286 can_install = True
287 if platform.system()=='Windows':
288 can_install = False
289
290 env['CAN_INSTALL']=can_install
291
292 env.Append(SUBST_DICT=subst_dict)
293
294 #------------------------------------------------------
295 # SPECIAL CONFIGURATION TESTS
296
297 need_fortran = False
298
299 #----------------
300 # SWIG
301
302 import os,re
303
304 def get_swig_version(env):
305 cmd = env['SWIG']+' -version'
306 (cin,coutcerr) = os.popen4(cmd)
307 output = coutcerr.read()
308
309 restr = "SWIG\\s+Version\\s+(?P<maj>[0-9]+)\\.(?P<min>[0-9]+)\\.(?P<pat>[0-9]+)\\s*$"
310 expr = re.compile(restr,re.M);
311 m = expr.search(output);
312 if not m:
313 return None
314 maj = int(m.group('maj'))
315 min = int(m.group('min'))
316 pat = int(m.group('pat'))
317
318 return (maj,min,pat)
319
320
321 def CheckSwigVersion(context):
322
323 try:
324 context.Message("Checking version of SWIG... ")
325 maj,min,pat = get_swig_version(context.env)
326 except:
327 context.Result("Failed to detect version, or failed to run SWIG")
328 return 0;
329
330 context.env['SWIGVERSION']=tuple([maj,min,pat])
331
332 if maj == 1 and (
333 min > 3
334 or (min == 3 and pat >= 24)
335 ):
336 context.Result("ok, %d.%d.%d" % (maj,min,pat))
337 return 1;
338 else:
339 context.Result("too old, %d.%d.%d" % (maj,min,pat))
340 return 0;
341
342 #----------------
343 # General purpose library-and-header test
344
345 class KeepContext:
346 def __init__(self,context,varprefix):
347 self.keep = {}
348 for k in ['LIBS','LIBPATH','CPPPATH']:
349 if context.env.has_key(k):
350 self.keep[k] = context.env[k]
351 else:
352 self.keep[k] = None
353
354 libpath_add = []
355 if context.env.has_key(varprefix+'_LIBPATH'):
356 libpath_add = [env[varprefix+'_LIBPATH']]
357 #print "Adding '"+str(libpath_add)+"' to lib path"
358
359 cpppath_add = []
360 if context.env.has_key(varprefix+'_CPPPATH'):
361 cpppath_add = [env[varprefix+'_CPPPATH']]
362 #print "Adding '"+str(cpppath_add)+"' to cpp path"
363
364 libs_add = []
365 if context.env.has_key(varprefix+'_LIB'):
366 libs_add = [env[varprefix+'_LIB']]
367 #print "Adding '"+str(libs_add)+"' to libs"
368
369 context.env.Append(
370 LIBPATH = libpath_add
371 , CPPPATH = cpppath_add
372 , LIBS = libs_add
373 )
374
375 def restore(self,context):
376 #print "RESTORING CONTEXT"
377 #print self.keep
378 #print "..."
379 for k in self.keep:
380 if self.keep[k]==None:
381 #print "Clearing "+str(k)
382 del context.env[k];
383 else:
384 #print "Restoring "+str(k)+" to '"+self.keep[k]+"'"
385 context.env[k]=self.keep[k];
386
387 def CheckExtLib(context,libname,text,ext='.c',varprefix=None):
388 """This method will check for variables LIBNAME_LIBPATH
389 and LIBNAME_CPPPATH and try to compile and link the
390 file with the provided text, linking with the
391 library libname."""
392
393 context.Message( 'Checking for '+libname+'... ' )
394
395 if varprefix==None:
396 varprefix = libname.upper()
397
398 keep = KeepContext(context,varprefix)
399
400 if not context.env.has_key(varprefix+'_LIB'):
401 # if varprefix_LIB were in env, KeepContext would
402 # have appended it already
403 context.env.Append(LIBS=libname)
404
405 is_ok = context.TryLink(text,ext)
406
407 # print "Link success? ",(is_ok != 0)
408
409 keep.restore(context)
410
411 # print "Restored CPPPATH="+str(context.env['CPPPATH'])
412 # print "Restored LIBS="+libname
413 # print "Restored LIBPATH="+str(context.env['LIBPATH'])
414
415 context.Result(is_ok)
416 return is_ok
417
418 #----------------
419 # CUnit test
420
421 cunit_test_text = """
422 #include <CUnit/CUnit.h>
423 int maxi(int i1, int i2){
424 return (i1 > i2) ? i1 : i2;
425 }
426
427 void test_maxi(void){
428 CU_ASSERT(maxi(0,2) == 2);
429 CU_ASSERT(maxi(0,-2) == 0);
430 CU_ASSERT(maxi(2,2) == 2);
431
432 }
433 int main(void){
434 /* CU_initialize_registry() */
435 return 0;
436 }
437 """
438
439 def CheckCUnit(context):
440 return CheckExtLib(context,'cunit',cunit_test_text)
441
442 #----------------
443 # Tcl test
444
445 tcl_check_text = r"""
446 #include <tcl.h>
447 #include <stdio.h>
448 int main(void){
449 printf("%s",TCL_PATCH_LEVEL);
450 return 0;
451 }
452 """
453
454 def CheckTcl(context):
455 return CheckExtLib(context,'tcl',tcl_check_text)
456
457 def CheckTclVersion(context):
458 keep = KeepContext(context,'TCL')
459 context.Message("Checking Tcl version... ")
460 (is_ok,output) = context.TryRun(tcl_check_text,'.c')
461 keep.restore(context)
462 if not is_ok:
463 context.Result("failed to run check")
464 return 0
465
466 major,minor,patch = tuple(int(i) for i in output.split("."))
467 if major != 8 or minor > 3:
468 context.Result(output+" (bad version)")
469 # bad version
470 return 0
471
472 # good version
473 context.Result(output+" (good)")
474 return 1
475
476 #----------------
477 # Tk test
478
479 tk_check_text = r"""
480 #include <tk.h>
481 #include <stdio.h>
482 int main(void){
483 printf("%s",TK_PATCH_LEVEL);
484 return 0;
485 }
486 """
487 def CheckTk(context):
488 return CheckExtLib(context,'tk',tcl_check_text)
489
490
491 def CheckTkVersion(context):
492 keep = KeepContext(context,'TK')
493 context.Message("Checking Tk version... ")
494 (is_ok,output) = context.TryRun(tk_check_text,'.c')
495 keep.restore(context)
496 if not is_ok:
497 context.Result("failed to run check")
498 return 0
499 context.Result(output)
500
501 major,minor,patch = tuple(int(i) for i in output.split("."))
502 if major != 8 or minor > 3:
503 # bad version
504 return 0
505
506 # good version
507 return 1
508
509 #------------------------------------------------------
510 # CONFIGURATION
511
512 conf = Configure(env
513 , custom_tests = {
514 'CheckSwigVersion' : CheckSwigVersion
515 , 'CheckCUnit' : CheckCUnit
516 , 'CheckTcl' : CheckTcl
517 , 'CheckTclVersion' : CheckTclVersion
518 , 'CheckTk' : CheckTk
519 , 'CheckTkVersion' : CheckTkVersion
520 # , 'CheckIsNan' : CheckIsNan
521 # , 'CheckCppUnitConfig' : CheckCppUnitConfig
522 }
523 # , config_h = "config.h"
524 )
525
526
527 # Math library
528
529 #if not conf.CheckFunc('sinh') and not conf.CheckLibWithHeader(['m','c','libc'], 'math.h', 'C'):
530 # print 'Did not find math library, exiting!'
531 # Exit(1)
532
533 # Where is 'isnan'?
534
535 if not conf.CheckFunc('isnan'):
536 print "Didn't find isnan"
537 # Exit(1)
538
539 # Tcl/Tk
540
541 if conf.CheckTcl():
542 if with_tcltk_gui and conf.CheckTclVersion():
543 if conf.CheckTk():
544 if with_tcltk_gui and not conf.CheckTkVersion():
545 without_tcltk_reason = "Require Tk version <= 8.3. See 'scons -h'"
546 with_tcltk_gui = False
547 else:
548 without_tcltk_reason = "Tk not found."
549 with_tcltk_gui = False
550 else:
551 without_tcltk_reason = "Require Tcl <= 8.3 Tcl."
552 with_tcltk_gui = False
553
554 else:
555 without_tcltk_reason = "Tcl not found."
556 with_tcltk_gui = False
557
558 # Python... obviously we're already running python, so we just need to
559 # check that we can link to the python library OK:
560
561 if platform.system()=="Windows":
562 python_lib='python24'
563 else:
564 python_lib='python2.4'
565
566 # SWIG version
567
568 if platform.system()=="Windows":
569 env['ENV']['SWIGFEATURES']='-O'
570 else:
571 env['ENV']['SWIGFEATURES']='-O'
572
573
574 if not conf.CheckSwigVersion():
575 without_python_reason = 'SWIG >= 1.3.24 is required'
576 with_python = False
577
578 # CUnit
579
580 if with_cunit_tests:
581 if not conf.CheckCUnit():
582 without_cunit_reason = 'CUnit not found'
583
584 # BLAS
585
586 need_blas=False
587 if with_tcltk_gui:
588 need_blas=True
589 if need_blas:
590 if conf.CheckLib('blas'):
591 print "FOUND BLAS"
592 with_local_blas = False
593 without_local_blas_reason = "Found BLAS installed on system"
594 else:
595 print "DIDN'T FIND BLAS"
596 with_local_blas = True
597 need_fortran = True
598
599 # FORTRAN
600
601 if need_fortran:
602 conf.env.Tool('f77')
603 detect_fortran = conf.env.Detect(['g77','f77'])
604 if detect_fortran:
605 # For some reason, g77 doesn't get detected properly on MinGW
606 if not env.has_key('F77'):
607 conf.env.Replace(F77=detect_fortran)
608 conf.env.Replace(F77COM='$F77 $F77FLAGS -c -o $TARGET $SOURCE')
609 conf.env.Replace(F77FLAGS='')
610 #print "F77:",conf.env['F77']
611 #print "F77COM:",conf.env['F77COM']
612 #print "F77FLAGS:",conf.env['F77FLAGS']
613 fortran_builder = Builder(
614 action='$F77COM'
615 , suffix='.o'
616 , src_suffix='.f'
617 )
618 conf.env.Append(BUILDERS={'Fortran':fortran_builder})
619 else:
620 print "FORTRAN-77 required but not found"
621 Exit(1)
622 #else:
623 # print "FORTRAN not required"
624
625 # TODO: -D_HPUX_SOURCE is needed
626
627 # TODO: check size of void*
628
629 # TODO: detect if dynamic libraries are possible or not
630
631 if platform.system()=="Windows" and env.has_key('MSVS'):
632 if not conf.CheckHeader('windows.h') and env['PACKAGE_LINKING']=='DYNAMIC_PACKAGES':
633 print "Reverting to STATIC_PACKAGES since windows.h is not available. Probably you "\
634 +"need to install the Microsoft Windows Server 2003 Platform SDK, or similar."
635 env['PACKAGE_LINKING']='STATIC_PACKAGES'
636
637 if with_python and not conf.CheckHeader('basetsd.h'):
638 with_python = 0;
639 without_python_reason = "Header file 'basetsd.h' not found. Install the MS Platform SDK."
640
641 conf.env.Append(CPPDEFINES=env['PACKAGE_LINKING'])
642
643 conf.Finish()
644
645 env.Append(PYTHON_LIBPATH=[distutils.sysconfig.PREFIX+"/libs"])
646 env.Append(PYTHON_LIB=[python_lib])
647 env.Append(PYTHON_CPPPATH=[distutils.sysconfig.get_python_inc()])
648
649 #------------------------------------------------------
650 # RECIPE: 'SubstInFile', used in pygtk SConscript
651
652 import re
653 from SCons.Script import * # the usual scons stuff you get in a SConscript
654
655 def TOOL_SUBST(env):
656 """Adds SubstInFile builder, which substitutes the keys->values of SUBST_DICT
657 from the source to the target.
658 The values of SUBST_DICT first have any construction variables expanded
659 (its keys are not expanded).
660 If a value of SUBST_DICT is a python callable function, it is called and
661 the result is expanded as the value.
662 If there's more than one source and more than one target, each target gets
663 substituted from the corresponding source.
664 """
665 env.Append(TOOLS = 'SUBST')
666 def do_subst_in_file(targetfile, sourcefile, dict):
667 """Replace all instances of the keys of dict with their values.
668 For example, if dict is {'%VERSION%': '1.2345', '%BASE%': 'MyProg'},
669 then all instances of %VERSION% in the file will be replaced with 1.2345 etc.
670 """
671 try:
672 f = open(sourcefile, 'rb')
673 contents = f.read()
674 f.close()
675 except:
676 raise SCons.Errors.UserError, "Can't read source file %s"%sourcefile
677 for (k,v) in dict.items():
678 contents = re.sub(k, v, contents)
679 try:
680 f = open(targetfile, 'wb')
681 f.write(contents)
682 f.close()
683 except:
684 raise SCons.Errors.UserError, "Can't write target file %s"%targetfile
685 return 0 # success
686
687 def subst_in_file(target, source, env):
688 if not env.has_key('SUBST_DICT'):
689 raise SCons.Errors.UserError, "SubstInFile requires SUBST_DICT to be set."
690 d = dict(env['SUBST_DICT']) # copy it
691 for (k,v) in d.items():
692 if callable(v):
693 d[k] = env.subst(v())
694 elif SCons.Util.is_String(v):
695 d[k]=env.subst(v)
696 else:
697 raise SCons.Errors.UserError, "SubstInFile: key %s: %s must be a string or callable"%(k, repr(v))
698 for (t,s) in zip(target, source):
699 return do_subst_in_file(str(t), str(s), d)
700
701 def subst_in_file_string(target, source, env):
702 """This is what gets printed on the console."""
703 return '\n'.join(['Substituting vars from %s into %s'%(str(s), str(t))
704 for (t,s) in zip(target, source)])
705
706 def subst_emitter(target, source, env):
707 """Add dependency from substituted SUBST_DICT to target.
708 Returns original target, source tuple unchanged.
709 """
710 d = env['SUBST_DICT'].copy() # copy it
711 for (k,v) in d.items():
712 if callable(v):
713 d[k] = env.subst(v())
714 elif SCons.Util.is_String(v):
715 d[k]=env.subst(v)
716 Depends(target, SCons.Node.Python.Value(d))
717 return target, source
718
719 subst_action=SCons.Action.Action(subst_in_file, subst_in_file_string)
720 env['BUILDERS']['SubstInFile'] = Builder(action=subst_action, emitter=subst_emitter)
721
722 TOOL_SUBST(env)
723
724 #------------------------------------------------------
725 # Recipe for 'CHMOD' ACTION
726
727 import SCons
728 from SCons.Script.SConscript import SConsEnvironment
729 SConsEnvironment.Chmod = SCons.Action.ActionFactory(os.chmod,
730 lambda dest, mode: 'Chmod("%s", 0%o)' % (dest, mode))
731
732 def InstallPerm(env, dest, files, perm):
733 obj = env.Install(dest, files)
734 for i in obj:
735 env.AddPostAction(i, env.Chmod(str(i), perm))
736
737 SConsEnvironment.InstallPerm = InstallPerm
738
739 # define wrappers
740 SConsEnvironment.InstallProgram = lambda env, dest, files: InstallPerm(env, dest, files, 0755)
741 SConsEnvironment.InstallHeader = lambda env, dest, files: InstallPerm(env, dest, files, 0644)
742
743 #------------------------------------------------------
744 # NSIS Support for SCons
745
746 # Adapted version by John Pye, April 2006.
747 # from http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/NsisSconsTool
748 # Written by Mike Elkins, January 2004.
749
750 #This tool provides SCons support for the Nullsoft Scriptable Install System
751 #a windows installer builder available at http://nsis.sourceforge.net/home
752
753 #In addition, if you set NSISDEFINES to a dictionary, those variables will be passed
754 #to NSIS.
755
756 import SCons.Builder
757 import SCons.Util
758 import SCons.Scanner
759 import SCons.Sig
760 import os.path
761 import glob
762
763 def nsis_parse( sources, keyword, multiple ):
764 """
765 A function that knows how to read a .nsi file and figure
766 out what files are referenced, or find the 'OutFile' line.
767
768
769 sources is a list of nsi files.
770 keyword is the command ('File' or 'OutFile') to look for
771 multiple is true if you want all the args as a list, false if you
772 just want the first one.
773 """
774 stuff = []
775 for s in sources:
776 c = s.get_contents()
777 for l in c.split('\n'):
778 semi = l.find(';')
779 if (semi != -1):
780 l = l[:semi]
781 hash = l.find('#')
782 if (hash != -1):
783 l = l[:hash]
784 # Look for the keyword
785 l = l.strip()
786 spl = l.split(None,1)
787 if len(spl) > 1:
788 if spl[0].capitalize() == keyword.capitalize():
789 arg = spl[1]
790 if arg.startswith('"') and arg.endswith('"'):
791 arg = arg[1:-1]
792 if multiple:
793 stuff += [ arg ]
794 else:
795 return arg
796 return stuff
797
798
799 def nsis_path( filename, nsisdefines, rootdir ):
800 """
801 Do environment replacement, and prepend with the SCons root dir if
802 necessary
803 """
804 # We can't do variables defined by NSIS itself (like $INSTDIR),
805 # only user supplied ones (like ${FOO})
806 varPos = filename.find('${')
807 while varPos != -1:
808 endpos = filename.find('}',varPos)
809 assert endpos != -1
810 if not nsisdefines.has_key(filename[varPos+2:endpos]):
811 raise KeyError ("Could not find %s in NSISDEFINES" % filename[varPos+2:endpos])
812 val = nsisdefines[filename[varPos+2:endpos]]
813 if type(val) == list:
814 if varPos != 0 or endpos+1 != len(filename):
815 raise Exception("Can't use lists on variables that aren't complete filenames")
816 return val
817 filename = filename[0:varPos] + val + filename[endpos+1:]
818 varPos = filename.find('${')
819 return filename
820
821
822 def nsis_scanner( node, env, path ):
823 """
824 The scanner that looks through the source .nsi files and finds all lines
825 that are the 'File' command, fixes the directories etc, and returns them.
826 """
827 nodes = node.rfile()
828 if not node.exists():
829 return []
830 nodes = []
831 source_dir = node.get_dir()
832 for include in nsis_parse([node],'file',1):
833 exp = nsis_path(include,env['NSISDEFINES'],source_dir)
834 if type(exp) != list:
835 exp = [exp]
836 for p in exp:
837 for filename in glob.glob( os.path.abspath(
838 os.path.join(str(source_dir),p))):
839 # Why absolute path? Cause it breaks mysteriously without it :(
840 nodes.append(filename)
841 return nodes
842
843
844 def nsis_emitter( source, target, env ):
845 """
846 The emitter changes the target name to match what the command actually will
847 output, which is the argument to the OutFile command.
848 """
849 nsp = nsis_parse(source,'outfile',0)
850 if not nsp:
851 return (target,source)
852 x = (
853 nsis_path(nsp,env['NSISDEFINES'],''),
854 source)
855 return x
856
857 def quoteIfSpaced(text):
858 if ' ' in text:
859 return '"'+text+'"'
860 else:
861 return text
862
863 def toString(item,env):
864 if type(item) == list:
865 ret = ''
866 for i in item:
867 if ret:
868 ret += ' '
869 val = toString(i,env)
870 if ' ' in val:
871 val = "'"+val+"'"
872 ret += val
873 return ret
874 else:
875 # For convienence, handle #s here
876 if str(item).startswith('#'):
877 item = env.File(item).get_abspath()
878 return str(item)
879
880 def runNSIS(source,target,env,for_signature):
881 ret = env['NSIS']+" "
882 if env.has_key('NSISFLAGS'):
883 for flag in env['NSISFLAGS']:
884 ret += flag
885 ret += ' '
886 if env.has_key('NSISDEFINES'):
887 for d in env['NSISDEFINES']:
888 ret += '/D'+d
889 if env['NSISDEFINES'][d]:
890 ret +='='+quoteIfSpaced(toString(env['NSISDEFINES'][d],env))
891 ret += ' '
892 for s in source:
893 ret += quoteIfSpaced(str(s))
894 return ret
895
896 def find_nsis(env):
897 """
898 Try and figure out if NSIS is installed on this machine, and if so,
899 where.
900 """
901 if SCons.Util.can_read_reg:
902 # If we can read the registry, get the NSIS command from it
903 try:
904 k = SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
905 'SOFTWARE\\NSIS')
906 val, tok = SCons.Util.RegQueryValueEx(k,None)
907 ret = val + os.path.sep + 'makensis.exe'
908 if os.path.exists(ret):
909 return '"' + ret + '"'
910 else:
911 return None
912 except:
913 pass # Couldn't find the key, just act like we can't read the registry
914 # Hope it's on the path
915 return env.WhereIs('makensis.exe')
916
917 def nsis_exists(env):
918 """
919 Is NSIS findable on this machine?
920 """
921 if find_nsis(env) != None:
922 return 1
923 return 0
924
925 env['BUILDERS']['Nsis'] = SCons.Builder.Builder(generator=runNSIS,
926 src_suffix='.nsi',
927 emitter=nsis_emitter)
928
929 env.Append(SCANNERS = SCons.Scanner.Scanner( function = nsis_scanner,
930 skeys = ['.nsi']))
931
932 if not env.has_key('NSISDEFINES'):
933 env['NSISDEFINES'] = {}
934 env['NSIS'] = find_nsis(env)
935
936 #------------------------------------------------------
937 # BUILD...
938
939 # so that #include <modulename/headername.h> works across all modules...
940 env.Append(CPPPATH=['#base/generic'])
941
942 #-------------
943 # TCL/TK GUI
944
945 if with_tcltk_gui:
946 if with_local_blas:
947 env.SConscript(['blas/SConscript'],'env')
948 else:
949 print "Skipping... BLAS won't be build:", without_local_blas_reason
950
951 env.SConscript(['lsod/SConscript'],'env')
952
953 env.SConscript(['linpack/SConscript'],'env')
954 env.SConscript(['tcltk98/generic/interface/SConscript'],'env')
955 else:
956 print "Skipping... Tcl/Tk GUI isn't being built:",without_tcltk_reason
957
958 #-------------
959 # PYTHON INTERFACE
960
961 if with_python:
962 env.SConscript(['pygtk/interface/SConscript'],'env')
963 else:
964 print "Skipping... Python GUI isn't being built:",without_python_reason
965
966 #------------
967 # BASE/GENERIC SUBDIRECTORIES
968
969 dirs = ['general','utilities','compiler','solver','packages']
970
971 srcs = []
972 for d in dirs:
973 heresrcs = env.SConscript('base/generic/'+d+'/SConscript','env')
974 srcs += heresrcs
975
976 #-------------
977 # LIBASCEND -- all base/generic functionality
978
979 libascend = env.SharedLibrary('ascend',srcs)
980
981 #-------------
982 # UNIT TESTS
983
984 if with_cunit_tests:
985 testdirs = ['general','solver','utilities']
986 for testdir in testdirs:
987 path = 'base/generic/'+testdir+'/test/'
988 env.SConscript([path+'SConscript'],'env')
989 env.SConscript(['test/SConscript'],'env')
990 env.SConscript(['base/generic/test/SConscript'],'env')
991
992
993 else:
994 print "Skipping... CUnit tests aren't being built:",without_cunit_reason
995
996
997 #------------------------------------------------------
998 # INSTALLATION
999
1000 if env.has_key('CAN_INSTALL') and env['CAN_INSTALL']:
1001 # the models directory only needs to be processed for installation, no other processing required.
1002 env.SConscript(['models/SConscript'],'env')
1003
1004 dirs = ['INSTALL_BIN','INSTALL_DATA','INSTALL_LIB']
1005 install_dirs = [env['INSTALL_ROOT']+env[d] for d in dirs]
1006
1007 # TODO: add install options
1008 env.Alias('install',install_dirs)
1009
1010 env.Install(env['INSTALL_ROOT']+env['INSTALL_LIB'],libascend)
1011
1012 #------------------------------------------------------
1013 # CREATE the SPEC file for generation of RPM packages
1014
1015 if platform.system()=="Linux":
1016 env.SubstInFile('ascend.spec.in')

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