/[ascend]/trunk/SConstruct
ViewVC logotype

Contents of /trunk/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


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

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