/[ascend]/trunk/SConstruct
ViewVC logotype

Contents of /trunk/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


Revision 508 - (show annotations) (download)
Wed Apr 19 04:48:32 2006 UTC (14 years, 2 months ago) by johnpye
File size: 28742 byte(s)
More fixes for compiling and running on ubuntu 5.10 with GCC:
gcc version 4.0.2 20050808 (prerelease) (Ubuntu 4.0.1-4ubuntu9)

Added ASC_SHLIBSUFFIX and ASC_SHLIBPREFIX which are used in packages.c in preference to platform-specific #ifdefs.

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

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