/[ascend]/trunk/SConstruct
ViewVC logotype

Contents of /trunk/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


Revision 542 - (show annotations) (download)
Wed Apr 26 15:15:40 2006 UTC (19 years ago) by johnpye
File size: 30695 byte(s)
This is a patch to allow statements like "IMPORT johnpye/extfn/extfntest".
It modifies the methods in packages.c. Plan is to reuse the same code for "REQUIRE xxxxxx" statements as well.

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

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