/[ascend]/trunk/SConstruct
ViewVC logotype

Contents of /trunk/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


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

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