/[ascend]/trunk/SConstruct
ViewVC logotype

Contents of /trunk/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


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

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