/[ascend]/trunk/SConstruct
ViewVC logotype

Contents of /trunk/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


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

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