/[ascend]/trunk/SConstruct
ViewVC logotype

Contents of /trunk/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


Revision 500 - (show annotations) (download)
Tue Apr 18 11:55:12 2006 UTC (15 years, 7 months ago) by johnpye
File size: 27572 byte(s)
Reduced some runtime debug messages from Python and C++ and base/generic/compiler/type_descio.c.
Fixed up support for GCC Visibility and add SCons 'sniffer' for this.
Fixed a bug with 'fileopenpath' in PyGTK interface (File->Open location is remembered from last time).
Fixed a bug with missing includes in C++.
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 if with_python:
295 subst_dict['@ASCXX_USE_PYTHON@']="1"
296
297 can_install = True
298 if platform.system()=='Windows':
299 can_install = False
300
301 env['CAN_INSTALL']=can_install
302
303 env.Append(SUBST_DICT=subst_dict)
304
305 #------------------------------------------------------
306 # SPECIAL CONFIGURATION TESTS
307
308 need_fortran = False
309
310 #----------------
311 # SWIG
312
313 import os,re
314
315 def get_swig_version(env):
316 cmd = env['SWIG']+' -version'
317 (cin,coutcerr) = os.popen4(cmd)
318 output = coutcerr.read()
319
320 restr = "SWIG\\s+Version\\s+(?P<maj>[0-9]+)\\.(?P<min>[0-9]+)\\.(?P<pat>[0-9]+)\\s*$"
321 expr = re.compile(restr,re.M);
322 m = expr.search(output);
323 if not m:
324 return None
325 maj = int(m.group('maj'))
326 min = int(m.group('min'))
327 pat = int(m.group('pat'))
328
329 return (maj,min,pat)
330
331
332 def CheckSwigVersion(context):
333
334 try:
335 context.Message("Checking version of SWIG... ")
336 maj,min,pat = get_swig_version(context.env)
337 except:
338 context.Result("Failed to detect version, or failed to run SWIG")
339 return 0;
340
341 context.env['SWIGVERSION']=tuple([maj,min,pat])
342
343 if maj == 1 and (
344 min > 3
345 or (min == 3 and pat >= 24)
346 ):
347 context.Result("ok, %d.%d.%d" % (maj,min,pat))
348 return 1;
349 else:
350 context.Result("too old, %d.%d.%d" % (maj,min,pat))
351 return 0;
352
353 #----------------
354 # General purpose library-and-header test
355
356 class KeepContext:
357 def __init__(self,context,varprefix):
358 self.keep = {}
359 for k in ['LIBS','LIBPATH','CPPPATH']:
360 if context.env.has_key(k):
361 self.keep[k] = context.env[k]
362 else:
363 self.keep[k] = None
364
365 libpath_add = []
366 if context.env.has_key(varprefix+'_LIBPATH'):
367 libpath_add = [env[varprefix+'_LIBPATH']]
368 #print "Adding '"+str(libpath_add)+"' to lib path"
369
370 cpppath_add = []
371 if context.env.has_key(varprefix+'_CPPPATH'):
372 cpppath_add = [env[varprefix+'_CPPPATH']]
373 #print "Adding '"+str(cpppath_add)+"' to cpp path"
374
375 libs_add = []
376 if context.env.has_key(varprefix+'_LIB'):
377 libs_add = [env[varprefix+'_LIB']]
378 #print "Adding '"+str(libs_add)+"' to libs"
379
380 context.env.Append(
381 LIBPATH = libpath_add
382 , CPPPATH = cpppath_add
383 , LIBS = libs_add
384 )
385
386 def restore(self,context):
387 #print "RESTORING CONTEXT"
388 #print self.keep
389 #print "..."
390 for k in self.keep:
391 if self.keep[k]==None:
392 #print "Clearing "+str(k)
393 del context.env[k];
394 else:
395 #print "Restoring "+str(k)+" to '"+self.keep[k]+"'"
396 context.env[k]=self.keep[k];
397
398 def CheckExtLib(context,libname,text,ext='.c',varprefix=None):
399 """This method will check for variables LIBNAME_LIBPATH
400 and LIBNAME_CPPPATH and try to compile and link the
401 file with the provided text, linking with the
402 library libname."""
403
404 context.Message( 'Checking for '+libname+'... ' )
405
406 if varprefix==None:
407 varprefix = libname.upper()
408
409 keep = KeepContext(context,varprefix)
410
411 if not context.env.has_key(varprefix+'_LIB'):
412 # if varprefix_LIB were in env, KeepContext would
413 # have appended it already
414 context.env.Append(LIBS=libname)
415
416 is_ok = context.TryLink(text,ext)
417
418 # print "Link success? ",(is_ok != 0)
419
420 keep.restore(context)
421
422 # print "Restored CPPPATH="+str(context.env['CPPPATH'])
423 # print "Restored LIBS="+libname
424 # print "Restored LIBPATH="+str(context.env['LIBPATH'])
425
426 context.Result(is_ok)
427 return is_ok
428
429 #----------------
430 # GCC VISIBILITY feature
431
432 gccvisibility_test_text = """
433 #if __GNUC__ < 4
434 # error "Require GCC version 4 or newer"
435 #endif
436
437 __attribute__ ((visibility("default"))) int x;
438
439 int main(void){
440 extern int x;
441 x = 4;
442 }
443 """
444
445 def CheckGccVisibility(context):
446 context.Message("Checking for GCC 'visibility' capability... ")
447 is_ok = context.TryCompile(gccvisibility_test_text,".c")
448 context.Result(is_ok)
449 return is_ok
450
451 #----------------
452 # CUnit test
453
454 cunit_test_text = """
455 #include <CUnit/CUnit.h>
456 int maxi(int i1, int i2){
457 return (i1 > i2) ? i1 : i2;
458 }
459
460 void test_maxi(void){
461 CU_ASSERT(maxi(0,2) == 2);
462 CU_ASSERT(maxi(0,-2) == 0);
463 CU_ASSERT(maxi(2,2) == 2);
464
465 }
466 int main(void){
467 /* CU_initialize_registry() */
468 return 0;
469 }
470 """
471
472 def CheckCUnit(context):
473 return CheckExtLib(context,'cunit',cunit_test_text)
474
475 #----------------
476 # Tcl test
477
478 tcl_check_text = r"""
479 #include <tcl.h>
480 #include <stdio.h>
481 int main(void){
482 printf("%s",TCL_PATCH_LEVEL);
483 return 0;
484 }
485 """
486
487 def CheckTcl(context):
488 return CheckExtLib(context,'tcl',tcl_check_text)
489
490 def CheckTclVersion(context):
491 keep = KeepContext(context,'TCL')
492 context.Message("Checking Tcl version... ")
493 (is_ok,output) = context.TryRun(tcl_check_text,'.c')
494 keep.restore(context)
495 if not is_ok:
496 context.Result("failed to run check")
497 return 0
498
499 major,minor,patch = tuple(int(i) for i in output.split("."))
500 if major != 8 or minor > 3:
501 context.Result(output+" (bad version)")
502 # bad version
503 return 0
504
505 # good version
506 context.Result(output+" (good)")
507 return 1
508
509 #----------------
510 # Tk test
511
512 tk_check_text = r"""
513 #include <tk.h>
514 #include <stdio.h>
515 int main(void){
516 printf("%s",TK_PATCH_LEVEL);
517 return 0;
518 }
519 """
520 def CheckTk(context):
521 return CheckExtLib(context,'tk',tcl_check_text)
522
523
524 def CheckTkVersion(context):
525 keep = KeepContext(context,'TK')
526 context.Message("Checking Tk version... ")
527 (is_ok,output) = context.TryRun(tk_check_text,'.c')
528 keep.restore(context)
529 if not is_ok:
530 context.Result("failed to run check")
531 return 0
532 context.Result(output)
533
534 major,minor,patch = tuple(int(i) for i in output.split("."))
535 if major != 8 or minor > 3:
536 # bad version
537 return 0
538
539 # good version
540 return 1
541
542 #----------------
543 # GCC Version sniffing
544
545 # TODO FIXME
546
547 gcc_version4 = False
548
549 #------------------------------------------------------
550 # CONFIGURATION
551
552 conf = Configure(env
553 , custom_tests = {
554 'CheckSwigVersion' : CheckSwigVersion
555 , 'CheckCUnit' : CheckCUnit
556 , 'CheckTcl' : CheckTcl
557 , 'CheckTclVersion' : CheckTclVersion
558 , 'CheckTk' : CheckTk
559 , 'CheckTkVersion' : CheckTkVersion
560 , 'CheckGccVisibility' : CheckGccVisibility
561 # , 'CheckIsNan' : CheckIsNan
562 # , 'CheckCppUnitConfig' : CheckCppUnitConfig
563 }
564 # , config_h = "config.h"
565 )
566
567
568 # Math library
569
570 #if not conf.CheckFunc('sinh') and not conf.CheckLibWithHeader(['m','c','libc'], 'math.h', 'C'):
571 # print 'Did not find math library, exiting!'
572 # Exit(1)
573
574 # Where is 'isnan'?
575
576 if not conf.CheckFunc('isnan'):
577 print "Didn't find isnan"
578 # Exit(1)
579
580 # GCC visibility
581
582 if conf.CheckGccVisibility():
583 conf.env['HAVE_GCCVISIBILITY']=True;
584
585 # Tcl/Tk
586
587 if conf.CheckTcl():
588 if with_tcltk_gui and conf.CheckTclVersion():
589 if conf.CheckTk():
590 if with_tcltk_gui and not conf.CheckTkVersion():
591 without_tcltk_reason = "Require Tk version <= 8.3. See 'scons -h'"
592 with_tcltk_gui = False
593 else:
594 without_tcltk_reason = "Tk not found."
595 with_tcltk_gui = False
596 else:
597 without_tcltk_reason = "Require Tcl <= 8.3 Tcl."
598 with_tcltk_gui = False
599
600 else:
601 without_tcltk_reason = "Tcl not found."
602 with_tcltk_gui = False
603
604 # Python... obviously we're already running python, so we just need to
605 # check that we can link to the python library OK:
606
607 if platform.system()=="Windows":
608 python_lib='python24'
609 else:
610 python_lib='python2.4'
611
612 # SWIG version
613
614 if not conf.CheckSwigVersion():
615 without_python_reason = 'SWIG >= 1.3.24 is required'
616 with_python = False
617
618 # CUnit
619
620 if with_cunit_tests:
621 if not conf.CheckCUnit():
622 without_cunit_reason = 'CUnit not found'
623
624 # BLAS
625
626 need_blas=False
627 if with_tcltk_gui:
628 need_blas=True
629 if need_blas:
630 if conf.CheckLib('blas'):
631 print "FOUND BLAS"
632 with_local_blas = False
633 without_local_blas_reason = "Found BLAS installed on system"
634 else:
635 print "DIDN'T FIND BLAS"
636 with_local_blas = True
637 need_fortran = True
638
639 # FORTRAN
640
641 if need_fortran:
642 conf.env.Tool('f77')
643 detect_fortran = conf.env.Detect(['g77','f77'])
644 if detect_fortran:
645 # For some reason, g77 doesn't get detected properly on MinGW
646 if not env.has_key('F77'):
647 conf.env.Replace(F77=detect_fortran)
648 conf.env.Replace(F77COM='$F77 $F77FLAGS -c -o $TARGET $SOURCE')
649 conf.env.Replace(F77FLAGS='')
650 #print "F77:",conf.env['F77']
651 #print "F77COM:",conf.env['F77COM']
652 #print "F77FLAGS:",conf.env['F77FLAGS']
653 fortran_builder = Builder(
654 action='$F77COM'
655 , suffix='.o'
656 , src_suffix='.f'
657 )
658 conf.env.Append(BUILDERS={'Fortran':fortran_builder})
659 else:
660 print "FORTRAN-77 required but not found"
661 Exit(1)
662 #else:
663 # print "FORTRAN not required"
664
665 # TODO: -D_HPUX_SOURCE is needed
666
667 # TODO: check size of void*
668
669 # TODO: detect if dynamic libraries are possible or not
670
671 if platform.system()=="Windows" and env.has_key('MSVS'):
672 if not conf.CheckHeader('windows.h') and env['PACKAGE_LINKING']=='DYNAMIC_PACKAGES':
673 print "Reverting to STATIC_PACKAGES since windows.h is not available. Probably you "\
674 +"need to install the Microsoft Windows Server 2003 Platform SDK, or similar."
675 env['PACKAGE_LINKING']='STATIC_PACKAGES'
676
677 if with_python and not conf.CheckHeader('basetsd.h'):
678 with_python = 0;
679 without_python_reason = "Header file 'basetsd.h' not found. Install the MS Platform SDK."
680
681 conf.env.Append(CPPDEFINES=env['PACKAGE_LINKING'])
682
683 conf.Finish()
684
685 env.Append(PYTHON_LIBPATH=[distutils.sysconfig.PREFIX+"/libs"])
686 env.Append(PYTHON_LIB=[python_lib])
687 env.Append(PYTHON_CPPPATH=[distutils.sysconfig.get_python_inc()])
688
689 #------------------------------------------------------
690 # RECIPE: 'SubstInFile', used in pygtk SConscript
691
692 import re
693 from SCons.Script import * # the usual scons stuff you get in a SConscript
694
695 def TOOL_SUBST(env):
696 """Adds SubstInFile builder, which substitutes the keys->values of SUBST_DICT
697 from the source to the target.
698 The values of SUBST_DICT first have any construction variables expanded
699 (its keys are not expanded).
700 If a value of SUBST_DICT is a python callable function, it is called and
701 the result is expanded as the value.
702 If there's more than one source and more than one target, each target gets
703 substituted from the corresponding source.
704 """
705 env.Append(TOOLS = 'SUBST')
706 def do_subst_in_file(targetfile, sourcefile, dict):
707 """Replace all instances of the keys of dict with their values.
708 For example, if dict is {'%VERSION%': '1.2345', '%BASE%': 'MyProg'},
709 then all instances of %VERSION% in the file will be replaced with 1.2345 etc.
710 """
711 try:
712 f = open(sourcefile, 'rb')
713 contents = f.read()
714 f.close()
715 except:
716 raise SCons.Errors.UserError, "Can't read source file %s"%sourcefile
717 for (k,v) in dict.items():
718 contents = re.sub(k, v, contents)
719 try:
720 f = open(targetfile, 'wb')
721 f.write(contents)
722 f.close()
723 except:
724 raise SCons.Errors.UserError, "Can't write target file %s"%targetfile
725 return 0 # success
726
727 def subst_in_file(target, source, env):
728 if not env.has_key('SUBST_DICT'):
729 raise SCons.Errors.UserError, "SubstInFile requires SUBST_DICT to be set."
730 d = dict(env['SUBST_DICT']) # copy it
731 for (k,v) in d.items():
732 if callable(v):
733 d[k] = env.subst(v())
734 elif SCons.Util.is_String(v):
735 d[k]=env.subst(v)
736 else:
737 raise SCons.Errors.UserError, "SubstInFile: key %s: %s must be a string or callable"%(k, repr(v))
738 for (t,s) in zip(target, source):
739 return do_subst_in_file(str(t), str(s), d)
740
741 def subst_in_file_string(target, source, env):
742 """This is what gets printed on the console."""
743 return '\n'.join(['Substituting vars from %s into %s'%(str(s), str(t))
744 for (t,s) in zip(target, source)])
745
746 def subst_emitter(target, source, env):
747 """Add dependency from substituted SUBST_DICT to target.
748 Returns original target, source tuple unchanged.
749 """
750 d = env['SUBST_DICT'].copy() # copy it
751 for (k,v) in d.items():
752 if callable(v):
753 d[k] = env.subst(v())
754 elif SCons.Util.is_String(v):
755 d[k]=env.subst(v)
756 Depends(target, SCons.Node.Python.Value(d))
757 return target, source
758
759 subst_action=SCons.Action.Action(subst_in_file, subst_in_file_string)
760 env['BUILDERS']['SubstInFile'] = Builder(action=subst_action, emitter=subst_emitter)
761
762 TOOL_SUBST(env)
763
764 #------------------------------------------------------
765 # Recipe for 'CHMOD' ACTION
766
767 import SCons
768 from SCons.Script.SConscript import SConsEnvironment
769 SConsEnvironment.Chmod = SCons.Action.ActionFactory(os.chmod,
770 lambda dest, mode: 'Chmod("%s", 0%o)' % (dest, mode))
771
772 def InstallPerm(env, dest, files, perm):
773 obj = env.Install(dest, files)
774 for i in obj:
775 env.AddPostAction(i, env.Chmod(str(i), perm))
776
777 SConsEnvironment.InstallPerm = InstallPerm
778
779 # define wrappers
780 SConsEnvironment.InstallProgram = lambda env, dest, files: InstallPerm(env, dest, files, 0755)
781 SConsEnvironment.InstallHeader = lambda env, dest, files: InstallPerm(env, dest, files, 0644)
782
783 #------------------------------------------------------
784 # NSIS Support for SCons
785
786 # Adapted version by John Pye, April 2006.
787 # from http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/NsisSconsTool
788 # Written by Mike Elkins, January 2004.
789
790 #This tool provides SCons support for the Nullsoft Scriptable Install System
791 #a windows installer builder available at http://nsis.sourceforge.net/home
792
793 #In addition, if you set NSISDEFINES to a dictionary, those variables will be passed
794 #to NSIS.
795
796 import SCons.Builder
797 import SCons.Util
798 import SCons.Scanner
799 import SCons.Sig
800 import os.path
801 import glob
802
803 def nsis_parse( sources, keyword, multiple ):
804 """
805 A function that knows how to read a .nsi file and figure
806 out what files are referenced, or find the 'OutFile' line.
807
808
809 sources is a list of nsi files.
810 keyword is the command ('File' or 'OutFile') to look for
811 multiple is true if you want all the args as a list, false if you
812 just want the first one.
813 """
814 stuff = []
815 for s in sources:
816 c = s.get_contents()
817 for l in c.split('\n'):
818 semi = l.find(';')
819 if (semi != -1):
820 l = l[:semi]
821 hash = l.find('#')
822 if (hash != -1):
823 l = l[:hash]
824 # Look for the keyword
825 l = l.strip()
826 spl = l.split(None,1)
827 if len(spl) > 1:
828 if spl[0].capitalize() == keyword.capitalize():
829 arg = spl[1]
830 if arg.startswith('"') and arg.endswith('"'):
831 arg = arg[1:-1]
832 if multiple:
833 stuff += [ arg ]
834 else:
835 return arg
836 return stuff
837
838
839 def nsis_path( filename, nsisdefines, rootdir ):
840 """
841 Do environment replacement, and prepend with the SCons root dir if
842 necessary
843 """
844 # We can't do variables defined by NSIS itself (like $INSTDIR),
845 # only user supplied ones (like ${FOO})
846 varPos = filename.find('${')
847 while varPos != -1:
848 endpos = filename.find('}',varPos)
849 assert endpos != -1
850 if not nsisdefines.has_key(filename[varPos+2:endpos]):
851 raise KeyError ("Could not find %s in NSISDEFINES" % filename[varPos+2:endpos])
852 val = nsisdefines[filename[varPos+2:endpos]]
853 if type(val) == list:
854 if varPos != 0 or endpos+1 != len(filename):
855 raise Exception("Can't use lists on variables that aren't complete filenames")
856 return val
857 filename = filename[0:varPos] + val + filename[endpos+1:]
858 varPos = filename.find('${')
859 return filename
860
861
862 def nsis_scanner( node, env, path ):
863 """
864 The scanner that looks through the source .nsi files and finds all lines
865 that are the 'File' command, fixes the directories etc, and returns them.
866 """
867 nodes = node.rfile()
868 if not node.exists():
869 return []
870 nodes = []
871 source_dir = node.get_dir()
872 for include in nsis_parse([node],'file',1):
873 exp = nsis_path(include,env['NSISDEFINES'],source_dir)
874 if type(exp) != list:
875 exp = [exp]
876 for p in exp:
877 for filename in glob.glob( os.path.abspath(
878 os.path.join(str(source_dir),p))):
879 # Why absolute path? Cause it breaks mysteriously without it :(
880 nodes.append(filename)
881 return nodes
882
883
884 def nsis_emitter( source, target, env ):
885 """
886 The emitter changes the target name to match what the command actually will
887 output, which is the argument to the OutFile command.
888 """
889 nsp = nsis_parse(source,'outfile',0)
890 if not nsp:
891 return (target,source)
892 x = (
893 nsis_path(nsp,env['NSISDEFINES'],''),
894 source)
895 return x
896
897 def quoteIfSpaced(text):
898 if ' ' in text:
899 return '"'+text+'"'
900 else:
901 return text
902
903 def toString(item,env):
904 if type(item) == list:
905 ret = ''
906 for i in item:
907 if ret:
908 ret += ' '
909 val = toString(i,env)
910 if ' ' in val:
911 val = "'"+val+"'"
912 ret += val
913 return ret
914 else:
915 # For convienence, handle #s here
916 if str(item).startswith('#'):
917 item = env.File(item).get_abspath()
918 return str(item)
919
920 def runNSIS(source,target,env,for_signature):
921 ret = env['NSIS']+" "
922 if env.has_key('NSISFLAGS'):
923 for flag in env['NSISFLAGS']:
924 ret += flag
925 ret += ' '
926 if env.has_key('NSISDEFINES'):
927 for d in env['NSISDEFINES']:
928 ret += '/D'+d
929 if env['NSISDEFINES'][d]:
930 ret +='='+quoteIfSpaced(toString(env['NSISDEFINES'][d],env))
931 ret += ' '
932 for s in source:
933 ret += quoteIfSpaced(str(s))
934 return ret
935
936 def find_nsis(env):
937 """
938 Try and figure out if NSIS is installed on this machine, and if so,
939 where.
940 """
941 if SCons.Util.can_read_reg:
942 # If we can read the registry, get the NSIS command from it
943 try:
944 k = SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
945 'SOFTWARE\\NSIS')
946 val, tok = SCons.Util.RegQueryValueEx(k,None)
947 ret = val + os.path.sep + 'makensis.exe'
948 if os.path.exists(ret):
949 return '"' + ret + '"'
950 else:
951 return None
952 except:
953 pass # Couldn't find the key, just act like we can't read the registry
954 # Hope it's on the path
955 return env.WhereIs('makensis.exe')
956
957 def nsis_exists(env):
958 """
959 Is NSIS findable on this machine?
960 """
961 if find_nsis(env) != None:
962 return 1
963 return 0
964
965 env['BUILDERS']['Nsis'] = SCons.Builder.Builder(generator=runNSIS,
966 src_suffix='.nsi',
967 emitter=nsis_emitter)
968
969 env.Append(SCANNERS = SCons.Scanner.Scanner( function = nsis_scanner,
970 skeys = ['.nsi']))
971
972 if not env.has_key('NSISDEFINES'):
973 env['NSISDEFINES'] = {}
974 env['NSIS'] = find_nsis(env)
975
976 #------------------------------------------------------
977 # BUILD...
978
979 # so that #include <modulename/headername.h> works across all modules...
980 env.Append(CPPPATH=['#base/generic'])
981
982 if gcc_version4:
983 env.Append(CCFLAGS=['-fvisibility=hidden'])
984
985 #-------------
986 # TCL/TK GUI
987
988 if with_tcltk_gui:
989 if with_local_blas:
990 env.SConscript(['blas/SConscript'],'env')
991 else:
992 print "Skipping... BLAS won't be build:", without_local_blas_reason
993
994 env.SConscript(['lsod/SConscript'],'env')
995
996 env.SConscript(['linpack/SConscript'],'env')
997 env.SConscript(['tcltk98/generic/interface/SConscript'],'env')
998 else:
999 print "Skipping... Tcl/Tk GUI isn't being built:",without_tcltk_reason
1000
1001 #-------------
1002 # PYTHON INTERFACE
1003
1004 if with_python:
1005 env.SConscript(['pygtk/interface/SConscript'],'env')
1006 else:
1007 print "Skipping... Python GUI isn't being built:",without_python_reason
1008
1009 #------------
1010 # BASE/GENERIC SUBDIRECTORIES
1011
1012 dirs = ['general','utilities','compiler','solver','packages']
1013
1014 srcs = []
1015 for d in dirs:
1016 heresrcs = env.SConscript('base/generic/'+d+'/SConscript','env')
1017 srcs += heresrcs
1018
1019 #-------------
1020 # LIBASCEND -- all base/generic functionality
1021
1022 libascend = env.SharedLibrary('ascend',srcs)
1023
1024 #-------------
1025 # UNIT TESTS
1026
1027 if with_cunit_tests:
1028 testdirs = ['general','solver','utilities']
1029 for testdir in testdirs:
1030 path = 'base/generic/'+testdir+'/test/'
1031 env.SConscript([path+'SConscript'],'env')
1032 env.SConscript(['test/SConscript'],'env')
1033 env.SConscript(['base/generic/test/SConscript'],'env')
1034
1035
1036 else:
1037 print "Skipping... CUnit tests aren't being built:",without_cunit_reason
1038
1039
1040 #------------------------------------------------------
1041 # INSTALLATION
1042
1043 if env.has_key('CAN_INSTALL') and env['CAN_INSTALL']:
1044 # the models directory only needs to be processed for installation, no other processing required.
1045 env.SConscript(['models/SConscript'],'env')
1046
1047 dirs = ['INSTALL_BIN','INSTALL_DATA','INSTALL_LIB']
1048 install_dirs = [env['INSTALL_ROOT']+env[d] for d in dirs]
1049
1050 # TODO: add install options
1051 env.Alias('install',install_dirs)
1052
1053 env.Install(env['INSTALL_ROOT']+env['INSTALL_LIB'],libascend)
1054
1055 #------------------------------------------------------
1056 # CREATE the SPEC file for generation of RPM packages
1057
1058 if platform.system()=="Linux":
1059 env.SubstInFile('ascend.spec.in')

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