/[ascend]/trunk/SConstruct
ViewVC logotype

Contents of /trunk/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


Revision 502 - (show annotations) (download)
Tue Apr 18 12:57:30 2006 UTC (13 years, 11 months ago) by johnpye
File size: 28335 byte(s)
Added check to see that YACC runs OK.
Fixing build with MSVC++ 2005.
All builds now except for some problems in the SWIG-generated code.
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
626 # YACC
627
628
629 if conf.CheckYacc():
630 conf.env['HAVE_YACC']=True
631
632 conf.env['HAVE_LEX']=True
633
634 # Tcl/Tk
635
636 if conf.CheckTcl():
637 if with_tcltk_gui and conf.CheckTclVersion():
638 if conf.CheckTk():
639 if with_tcltk_gui and not conf.CheckTkVersion():
640 without_tcltk_reason = "Require Tk version <= 8.3. See 'scons -h'"
641 with_tcltk_gui = False
642 else:
643 without_tcltk_reason = "Tk not found."
644 with_tcltk_gui = False
645 else:
646 without_tcltk_reason = "Require Tcl <= 8.3 Tcl."
647 with_tcltk_gui = False
648
649 else:
650 without_tcltk_reason = "Tcl not found."
651 with_tcltk_gui = False
652
653 # Python... obviously we're already running python, so we just need to
654 # check that we can link to the python library OK:
655
656 if platform.system()=="Windows":
657 python_lib='python24'
658 else:
659 python_lib='python2.4'
660
661 # SWIG version
662
663 if not conf.CheckSwigVersion():
664 without_python_reason = 'SWIG >= 1.3.24 is required'
665 with_python = False
666
667 # CUnit
668
669 if with_cunit_tests:
670 if not conf.CheckCUnit():
671 without_cunit_reason = 'CUnit not found'
672
673 # BLAS
674
675 need_blas=False
676 if with_tcltk_gui:
677 need_blas=True
678 if need_blas:
679 if conf.CheckLib('blas'):
680 print "FOUND BLAS"
681 with_local_blas = False
682 without_local_blas_reason = "Found BLAS installed on system"
683 else:
684 print "DIDN'T FIND BLAS"
685 with_local_blas = True
686 need_fortran = True
687
688 # FORTRAN
689
690 if need_fortran:
691 conf.env.Tool('f77')
692 detect_fortran = conf.env.Detect(['g77','f77'])
693 if detect_fortran:
694 # For some reason, g77 doesn't get detected properly on MinGW
695 if not env.has_key('F77'):
696 conf.env.Replace(F77=detect_fortran)
697 conf.env.Replace(F77COM='$F77 $F77FLAGS -c -o $TARGET $SOURCE')
698 conf.env.Replace(F77FLAGS='')
699 #print "F77:",conf.env['F77']
700 #print "F77COM:",conf.env['F77COM']
701 #print "F77FLAGS:",conf.env['F77FLAGS']
702 fortran_builder = Builder(
703 action='$F77COM'
704 , suffix='.o'
705 , src_suffix='.f'
706 )
707 conf.env.Append(BUILDERS={'Fortran':fortran_builder})
708 else:
709 print "FORTRAN-77 required but not found"
710 Exit(1)
711 #else:
712 # print "FORTRAN not required"
713
714 # TODO: -D_HPUX_SOURCE is needed
715
716 # TODO: check size of void*
717
718 # TODO: detect if dynamic libraries are possible or not
719
720 if platform.system()=="Windows" and env.has_key('MSVS'):
721 if not conf.CheckHeader('windows.h') and env['PACKAGE_LINKING']=='DYNAMIC_PACKAGES':
722 print "Reverting to STATIC_PACKAGES since windows.h is not available. Probably you "\
723 +"need to install the Microsoft Windows Server 2003 Platform SDK, or similar."
724 env['PACKAGE_LINKING']='STATIC_PACKAGES'
725
726 if with_python and not conf.CheckHeader('basetsd.h'):
727 with_python = 0;
728 without_python_reason = "Header file 'basetsd.h' not found. Install the MS Platform SDK."
729
730 conf.env.Append(CPPDEFINES=env['PACKAGE_LINKING'])
731
732 conf.Finish()
733
734 env.Append(PYTHON_LIBPATH=[distutils.sysconfig.PREFIX+"/libs"])
735 env.Append(PYTHON_LIB=[python_lib])
736 env.Append(PYTHON_CPPPATH=[distutils.sysconfig.get_python_inc()])
737
738 #------------------------------------------------------
739 # RECIPE: 'SubstInFile', used in pygtk SConscript
740
741 import re
742 from SCons.Script import * # the usual scons stuff you get in a SConscript
743
744 def TOOL_SUBST(env):
745 """Adds SubstInFile builder, which substitutes the keys->values of SUBST_DICT
746 from the source to the target.
747 The values of SUBST_DICT first have any construction variables expanded
748 (its keys are not expanded).
749 If a value of SUBST_DICT is a python callable function, it is called and
750 the result is expanded as the value.
751 If there's more than one source and more than one target, each target gets
752 substituted from the corresponding source.
753 """
754 env.Append(TOOLS = 'SUBST')
755 def do_subst_in_file(targetfile, sourcefile, dict):
756 """Replace all instances of the keys of dict with their values.
757 For example, if dict is {'%VERSION%': '1.2345', '%BASE%': 'MyProg'},
758 then all instances of %VERSION% in the file will be replaced with 1.2345 etc.
759 """
760 try:
761 f = open(sourcefile, 'rb')
762 contents = f.read()
763 f.close()
764 except:
765 raise SCons.Errors.UserError, "Can't read source file %s"%sourcefile
766 for (k,v) in dict.items():
767 contents = re.sub(k, v, contents)
768 try:
769 f = open(targetfile, 'wb')
770 f.write(contents)
771 f.close()
772 except:
773 raise SCons.Errors.UserError, "Can't write target file %s"%targetfile
774 return 0 # success
775
776 def subst_in_file(target, source, env):
777 if not env.has_key('SUBST_DICT'):
778 raise SCons.Errors.UserError, "SubstInFile requires SUBST_DICT to be set."
779 d = dict(env['SUBST_DICT']) # copy it
780 for (k,v) in d.items():
781 if callable(v):
782 d[k] = env.subst(v())
783 elif SCons.Util.is_String(v):
784 d[k]=env.subst(v)
785 else:
786 raise SCons.Errors.UserError, "SubstInFile: key %s: %s must be a string or callable"%(k, repr(v))
787 for (t,s) in zip(target, source):
788 return do_subst_in_file(str(t), str(s), d)
789
790 def subst_in_file_string(target, source, env):
791 """This is what gets printed on the console."""
792 return '\n'.join(['Substituting vars from %s into %s'%(str(s), str(t))
793 for (t,s) in zip(target, source)])
794
795 def subst_emitter(target, source, env):
796 """Add dependency from substituted SUBST_DICT to target.
797 Returns original target, source tuple unchanged.
798 """
799 d = env['SUBST_DICT'].copy() # copy it
800 for (k,v) in d.items():
801 if callable(v):
802 d[k] = env.subst(v())
803 elif SCons.Util.is_String(v):
804 d[k]=env.subst(v)
805 Depends(target, SCons.Node.Python.Value(d))
806 return target, source
807
808 subst_action=SCons.Action.Action(subst_in_file, subst_in_file_string)
809 env['BUILDERS']['SubstInFile'] = Builder(action=subst_action, emitter=subst_emitter)
810
811 TOOL_SUBST(env)
812
813 #------------------------------------------------------
814 # Recipe for 'CHMOD' ACTION
815
816 import SCons
817 from SCons.Script.SConscript import SConsEnvironment
818 SConsEnvironment.Chmod = SCons.Action.ActionFactory(os.chmod,
819 lambda dest, mode: 'Chmod("%s", 0%o)' % (dest, mode))
820
821 def InstallPerm(env, dest, files, perm):
822 obj = env.Install(dest, files)
823 for i in obj:
824 env.AddPostAction(i, env.Chmod(str(i), perm))
825
826 SConsEnvironment.InstallPerm = InstallPerm
827
828 # define wrappers
829 SConsEnvironment.InstallProgram = lambda env, dest, files: InstallPerm(env, dest, files, 0755)
830 SConsEnvironment.InstallHeader = lambda env, dest, files: InstallPerm(env, dest, files, 0644)
831
832 #------------------------------------------------------
833 # NSIS Support for SCons
834
835 # Adapted version by John Pye, April 2006.
836 # from http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/NsisSconsTool
837 # Written by Mike Elkins, January 2004.
838
839 #This tool provides SCons support for the Nullsoft Scriptable Install System
840 #a windows installer builder available at http://nsis.sourceforge.net/home
841
842 #In addition, if you set NSISDEFINES to a dictionary, those variables will be passed
843 #to NSIS.
844
845 import SCons.Builder
846 import SCons.Util
847 import SCons.Scanner
848 import SCons.Sig
849 import os.path
850 import glob
851
852 def nsis_parse( sources, keyword, multiple ):
853 """
854 A function that knows how to read a .nsi file and figure
855 out what files are referenced, or find the 'OutFile' line.
856
857
858 sources is a list of nsi files.
859 keyword is the command ('File' or 'OutFile') to look for
860 multiple is true if you want all the args as a list, false if you
861 just want the first one.
862 """
863 stuff = []
864 for s in sources:
865 c = s.get_contents()
866 for l in c.split('\n'):
867 semi = l.find(';')
868 if (semi != -1):
869 l = l[:semi]
870 hash = l.find('#')
871 if (hash != -1):
872 l = l[:hash]
873 # Look for the keyword
874 l = l.strip()
875 spl = l.split(None,1)
876 if len(spl) > 1:
877 if spl[0].capitalize() == keyword.capitalize():
878 arg = spl[1]
879 if arg.startswith('"') and arg.endswith('"'):
880 arg = arg[1:-1]
881 if multiple:
882 stuff += [ arg ]
883 else:
884 return arg
885 return stuff
886
887
888 def nsis_path( filename, nsisdefines, rootdir ):
889 """
890 Do environment replacement, and prepend with the SCons root dir if
891 necessary
892 """
893 # We can't do variables defined by NSIS itself (like $INSTDIR),
894 # only user supplied ones (like ${FOO})
895 varPos = filename.find('${')
896 while varPos != -1:
897 endpos = filename.find('}',varPos)
898 assert endpos != -1
899 if not nsisdefines.has_key(filename[varPos+2:endpos]):
900 raise KeyError ("Could not find %s in NSISDEFINES" % filename[varPos+2:endpos])
901 val = nsisdefines[filename[varPos+2:endpos]]
902 if type(val) == list:
903 if varPos != 0 or endpos+1 != len(filename):
904 raise Exception("Can't use lists on variables that aren't complete filenames")
905 return val
906 filename = filename[0:varPos] + val + filename[endpos+1:]
907 varPos = filename.find('${')
908 return filename
909
910
911 def nsis_scanner( node, env, path ):
912 """
913 The scanner that looks through the source .nsi files and finds all lines
914 that are the 'File' command, fixes the directories etc, and returns them.
915 """
916 nodes = node.rfile()
917 if not node.exists():
918 return []
919 nodes = []
920 source_dir = node.get_dir()
921 for include in nsis_parse([node],'file',1):
922 exp = nsis_path(include,env['NSISDEFINES'],source_dir)
923 if type(exp) != list:
924 exp = [exp]
925 for p in exp:
926 for filename in glob.glob( os.path.abspath(
927 os.path.join(str(source_dir),p))):
928 # Why absolute path? Cause it breaks mysteriously without it :(
929 nodes.append(filename)
930 return nodes
931
932
933 def nsis_emitter( source, target, env ):
934 """
935 The emitter changes the target name to match what the command actually will
936 output, which is the argument to the OutFile command.
937 """
938 nsp = nsis_parse(source,'outfile',0)
939 if not nsp:
940 return (target,source)
941 x = (
942 nsis_path(nsp,env['NSISDEFINES'],''),
943 source)
944 return x
945
946 def quoteIfSpaced(text):
947 if ' ' in text:
948 return '"'+text+'"'
949 else:
950 return text
951
952 def toString(item,env):
953 if type(item) == list:
954 ret = ''
955 for i in item:
956 if ret:
957 ret += ' '
958 val = toString(i,env)
959 if ' ' in val:
960 val = "'"+val+"'"
961 ret += val
962 return ret
963 else:
964 # For convienence, handle #s here
965 if str(item).startswith('#'):
966 item = env.File(item).get_abspath()
967 return str(item)
968
969 def runNSIS(source,target,env,for_signature):
970 ret = env['NSIS']+" "
971 if env.has_key('NSISFLAGS'):
972 for flag in env['NSISFLAGS']:
973 ret += flag
974 ret += ' '
975 if env.has_key('NSISDEFINES'):
976 for d in env['NSISDEFINES']:
977 ret += '/D'+d
978 if env['NSISDEFINES'][d]:
979 ret +='='+quoteIfSpaced(toString(env['NSISDEFINES'][d],env))
980 ret += ' '
981 for s in source:
982 ret += quoteIfSpaced(str(s))
983 return ret
984
985 def find_nsis(env):
986 """
987 Try and figure out if NSIS is installed on this machine, and if so,
988 where.
989 """
990 if SCons.Util.can_read_reg:
991 # If we can read the registry, get the NSIS command from it
992 try:
993 k = SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
994 'SOFTWARE\\NSIS')
995 val, tok = SCons.Util.RegQueryValueEx(k,None)
996 ret = val + os.path.sep + 'makensis.exe'
997 if os.path.exists(ret):
998 return '"' + ret + '"'
999 else:
1000 return None
1001 except:
1002 pass # Couldn't find the key, just act like we can't read the registry
1003 # Hope it's on the path
1004 return env.WhereIs('makensis.exe')
1005
1006 def nsis_exists(env):
1007 """
1008 Is NSIS findable on this machine?
1009 """
1010 if find_nsis(env) != None:
1011 return 1
1012 return 0
1013
1014 env['BUILDERS']['Nsis'] = SCons.Builder.Builder(generator=runNSIS,
1015 src_suffix='.nsi',
1016 emitter=nsis_emitter)
1017
1018 env.Append(SCANNERS = SCons.Scanner.Scanner( function = nsis_scanner,
1019 skeys = ['.nsi']))
1020
1021 if not env.has_key('NSISDEFINES'):
1022 env['NSISDEFINES'] = {}
1023 env['NSIS'] = find_nsis(env)
1024
1025 #------------------------------------------------------
1026 # BUILD...
1027
1028 # so that #include <modulename/headername.h> works across all modules...
1029 env.Append(CPPPATH=['#base/generic'])
1030
1031 if gcc_version4:
1032 env.Append(CCFLAGS=['-fvisibility=hidden'])
1033
1034 #-------------
1035 # TCL/TK GUI
1036
1037 if with_tcltk_gui:
1038 if with_local_blas:
1039 env.SConscript(['blas/SConscript'],'env')
1040 else:
1041 print "Skipping... BLAS won't be build:", without_local_blas_reason
1042
1043 env.SConscript(['lsod/SConscript'],'env')
1044
1045 env.SConscript(['linpack/SConscript'],'env')
1046 env.SConscript(['tcltk98/generic/interface/SConscript'],'env')
1047 else:
1048 print "Skipping... Tcl/Tk GUI isn't being built:",without_tcltk_reason
1049
1050 #-------------
1051 # PYTHON INTERFACE
1052
1053 if with_python:
1054 env.SConscript(['pygtk/interface/SConscript'],'env')
1055 else:
1056 print "Skipping... Python GUI isn't being built:",without_python_reason
1057
1058 #------------
1059 # BASE/GENERIC SUBDIRECTORIES
1060
1061 dirs = ['general','utilities','compiler','solver','packages']
1062
1063 srcs = []
1064 for d in dirs:
1065 heresrcs = env.SConscript('base/generic/'+d+'/SConscript','env')
1066 srcs += heresrcs
1067
1068 #-------------
1069 # LIBASCEND -- all base/generic functionality
1070
1071 libascend = env.SharedLibrary('ascend',srcs)
1072
1073 #-------------
1074 # UNIT TESTS
1075
1076 if with_cunit_tests:
1077 testdirs = ['general','solver','utilities']
1078 for testdir in testdirs:
1079 path = 'base/generic/'+testdir+'/test/'
1080 env.SConscript([path+'SConscript'],'env')
1081 env.SConscript(['test/SConscript'],'env')
1082 env.SConscript(['base/generic/test/SConscript'],'env')
1083
1084
1085 else:
1086 print "Skipping... CUnit tests aren't being built:",without_cunit_reason
1087
1088
1089 #------------------------------------------------------
1090 # INSTALLATION
1091
1092 if env.has_key('CAN_INSTALL') and env['CAN_INSTALL']:
1093 # the models directory only needs to be processed for installation, no other processing required.
1094 env.SConscript(['models/SConscript'],'env')
1095
1096 dirs = ['INSTALL_BIN','INSTALL_DATA','INSTALL_LIB']
1097 install_dirs = [env['INSTALL_ROOT']+env[d] for d in dirs]
1098
1099 # TODO: add install options
1100 env.Alias('install',install_dirs)
1101
1102 env.Install(env['INSTALL_ROOT']+env['INSTALL_LIB'],libascend)
1103
1104 #------------------------------------------------------
1105 # CREATE the SPEC file for generation of RPM packages
1106
1107 if platform.system()=="Linux":
1108 env.SubstInFile('ascend.spec.in')

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