/[ascend]/trunk/SConstruct
ViewVC logotype

Contents of /trunk/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


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

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