/[ascend]/trunk/SConstruct
ViewVC logotype

Contents of /trunk/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


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

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