/[ascend]/trunk/SConstruct
ViewVC logotype

Contents of /trunk/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


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

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