/[ascend]/trunk/SConstruct
ViewVC logotype

Contents of /trunk/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


Revision 561 - (show annotations) (download)
Thu May 4 07:35:43 2006 UTC (13 years, 8 months ago) by johnpye
File size: 32261 byte(s)
Changes to detection of TkTable. TkTable detection was not possible
on FC5 due to the provided tktable package not coming with header
files, and no tktable-devel being offered. Hence static linkage
to Tktable is not possible. Maybe it's not a great idea anyway.
Also modified and updated the DistTar builder for SCons.
Modified SConstruct to allow Tcl/Tk 8.4 to be used.
Modified ascend.spec.in to use system-standard version of Tcl/Tk 8.4.
1 import os, commands, platform, distutils.sysconfig, os.path
2
3 version = "0.9.5.90"
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 (if STATIC_TCLTK is set)"
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. EXPERIMENTAL'
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. Only used when STATIC_TCLTK is turned on. EXPERIMENTAL'
207 ,'/usr/X11R6'
208 )
209
210 opts.Add(
211 'X11_LIBPATH'
212 ,'Location of X11 lib. EXPERIMENTAL'
213 ,'$X11/lib'
214 )
215
216 opts.Add(
217 'X11_CPPPATH'
218 ,'Location of X11 includes. EXPERIMENTAL'
219 ,'$X11/include'
220 )
221
222 opts.Add(
223 'X11_LIB'
224 ,'Name of X11 lib. EXPERIMENTAL'
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 and TK required version 8.1, 8.2, 8.3, or 8.4:
563 tcltk_minor_newest_acceptable = 4
564 tcltk_major_required = 8
565
566 tcl_check_text = r"""
567 #include <tcl.h>
568 #include <stdio.h>
569 int main(void){
570 printf("%s",TCL_PATCH_LEVEL);
571 return 0;
572 }
573 """
574
575 def CheckTcl(context):
576 return CheckExtLib(context,'tcl',tcl_check_text,static=env['STATIC_TCLTK'])
577
578 def CheckTclVersion(context):
579 keep = KeepContext(context,'TCL',static=env['STATIC_TCLTK'])
580 context.Message("Checking Tcl version... ")
581 (is_ok,output) = context.TryRun(tcl_check_text,'.c')
582 keep.restore(context)
583 if not is_ok:
584 context.Result("failed to run check")
585 return 0
586
587 major,minor,patch = tuple([int(i) for i in output.split(".")])
588 if major != tcltk_major_required or minor > tcltk_minor_newest_acceptable:
589 context.Result(output+" (bad version)")
590 # bad version
591 return 0
592
593 # good version
594 context.Result(output+", good")
595 return 1
596
597 #----------------
598 # Tk test
599
600 tk_check_text = r"""
601 #include <tk.h>
602 #include <stdio.h>
603 int main(void){
604 printf("%s",TK_PATCH_LEVEL);
605 return 0;
606 }
607 """
608 def CheckTk(context):
609 return CheckExtLib(context,'tk',tcl_check_text,static=env['STATIC_TCLTK'])
610
611
612 def CheckTkVersion(context):
613 keep = KeepContext(context,'TK',static=context.env['STATIC_TCLTK'])
614 context.Message("Checking Tk version... ")
615 #print "LINKFLAGS =",context.env['LINKFLAGS']
616 (is_ok,output) = context.TryRun(tk_check_text,'.c')
617 keep.restore(context)
618 if not is_ok:
619 context.Result("failed to run check")
620 return 0
621
622 major,minor,patch = tuple([int(i) for i in output.split(".")])
623 if major != tcltk_major_required or minor > tcltk_minor_newest_acceptable:
624 # bad version
625 context.Result(output+" (bad version)")
626 return 0
627
628 # good version
629 context.Result(output+" (good)")
630 return 1
631
632 #----------------
633 # Tktable test
634
635 tktable_check_text = r"""
636 #include <tkTable.h>
637 #include <stdio.h>
638 int main(void){
639 Table mytable;
640 return 0;
641 }
642 """
643
644 def CheckTkTable(context):
645 return CheckExtLib(context,'tktable',tktable_check_text,static=env['STATIC_TCLTK'])
646
647 #---------------
648 # X11 test
649
650 x11_check_text = r"""
651 #include <X11/Xlib.h>
652 #include <X11/IntrinsicP.h>
653 #include <X11/Intrinsic.h>
654 #include <X11/ObjectP.h>
655 #include <X11/Object.h>
656 int main(void){
657 Object mything;
658 return 0;
659 }
660 """
661
662 def CheckX11(context):
663 return CheckExtLib(context,'X11',x11_check_text)
664
665 #----------------
666 # GCC Version sniffing
667
668 # TODO FIXME
669
670 gcc_version4 = False
671
672 #------------------------------------------------------
673 # CONFIGURATION
674
675 conf = Configure(env
676 , custom_tests = {
677 'CheckSwigVersion' : CheckSwigVersion
678 , 'CheckCUnit' : CheckCUnit
679 , 'CheckTcl' : CheckTcl
680 , 'CheckTclVersion' : CheckTclVersion
681 , 'CheckTk' : CheckTk
682 , 'CheckTkVersion' : CheckTkVersion
683 , 'CheckGcc' : CheckGcc
684 , 'CheckGccVisibility' : CheckGccVisibility
685 , 'CheckYacc' : CheckYacc
686 , 'CheckTkTable' : CheckTkTable
687 , 'CheckX11' : CheckX11
688 # , 'CheckIsNan' : CheckIsNan
689 # , 'CheckCppUnitConfig' : CheckCppUnitConfig
690 }
691 # , config_h = "config.h"
692 )
693
694
695 # Math library
696
697 #if not conf.CheckFunc('sinh') and not conf.CheckLibWithHeader(['m','c','libc'], 'math.h', 'C'):
698 # print 'Did not find math library, exiting!'
699 # Exit(1)
700
701 # Where is 'isnan'?
702
703 if not conf.CheckFunc('isnan'):
704 print "Didn't find isnan"
705 # Exit(1)
706
707 # GCC visibility
708
709 if conf.CheckGcc():
710 conf.env['HAVE_GCC']=True;
711 if env['WITH_GCCVISIBILITY'] and conf.CheckGccVisibility():
712 conf.env['HAVE_GCCVISIBILITY']=True;
713 conf.env.Append(CCFLAGS=['-fvisibility=hidden'])
714 conf.env.Append(CPPDEFINES=['HAVE_GCCVISIBILITY'])
715
716 # YACC
717
718 if not conf.CheckYacc():
719 print "YACC NOT FOUND OR NOT WORKING"
720 else:
721 conf.env['HAVE_YACC']=True
722
723 conf.env['HAVE_LEX']=True
724
725 # Tcl/Tk
726
727 if conf.CheckTcl():
728 if with_tcltk and conf.CheckTclVersion():
729 if conf.CheckTk():
730 if with_tcltk and conf.CheckTkVersion():
731 if env['STATIC_TCLTK']:
732 if conf.CheckTkTable():
733 pass
734 else:
735 without_tcltk_reason = "TkTable not found"
736 with_tcltk = False
737 else:
738 without_tcltk_reason = "Require Tk version <= 8.4. See 'scons -h'"
739 with_tcltk = False
740 else:
741 without_tcltk_reason = "Tk not found."
742 with_tcltk = False
743 else:
744 without_tcltk_reason = "Require Tcl <= 8.4 Tcl."
745 with_tcltk = False
746
747 else:
748 without_tcltk_reason = "Tcl not found."
749 with_tcltk = False
750
751 if env['STATIC_TCLTK']:
752 conf.CheckX11()
753
754 # Python... obviously we're already running python, so we just need to
755 # check that we can link to the python library OK:
756
757 if platform.system()=="Windows":
758 python_lib='python24'
759 else:
760 python_lib='python2.4'
761
762 # SWIG version
763
764 if not conf.CheckSwigVersion():
765 without_python_reason = 'SWIG >= 1.3.24 is required'
766 with_python = False
767
768 # CUnit
769
770 if with_cunit_tests:
771 if not conf.CheckCUnit():
772 without_cunit_reason = 'CUnit not found'
773
774 # BLAS
775
776 need_blas=False
777 if with_tcltk:
778 need_blas=True
779 if need_blas:
780 if conf.CheckLib('blas'):
781 with_local_blas = False
782 without_local_blas_reason = "Found BLAS installed on system"
783 else:
784 with_local_blas = True
785 need_fortran = True
786
787 # FORTRAN
788
789 if need_fortran:
790 conf.env.Tool('f77')
791 detect_fortran = conf.env.Detect(['g77','f77'])
792 if detect_fortran:
793 # For some reason, g77 doesn't get detected properly on MinGW
794 if not env.has_key('F77'):
795 conf.env.Replace(F77=detect_fortran)
796 conf.env.Replace(F77COM='$F77 $F77FLAGS -c -o $TARGET $SOURCE')
797 conf.env.Replace(F77FLAGS='')
798 #print "F77:",conf.env['F77']
799 #print "F77COM:",conf.env['F77COM']
800 #print "F77FLAGS:",conf.env['F77FLAGS']
801 fortran_builder = Builder(
802 action='$F77COM'
803 , suffix='.o'
804 , src_suffix='.f'
805 )
806 conf.env.Append(BUILDERS={'Fortran':fortran_builder})
807 else:
808 print "FORTRAN-77 required but not found"
809 Exit(1)
810 #else:
811 # print "FORTRAN not required"
812
813 # TODO: -D_HPUX_SOURCE is needed
814
815 # TODO: check size of void*
816
817 # TODO: detect if dynamic libraries are possible or not
818
819 if platform.system()=="Windows" and env.has_key('MSVS'):
820 if not conf.CheckHeader('windows.h') and env['PACKAGE_LINKING']=='DYNAMIC_PACKAGES':
821 print "Reverting to STATIC_PACKAGES since windows.h is not available. Probably you "\
822 +"need to install the Microsoft Windows Server 2003 Platform SDK, or similar."
823 env['PACKAGE_LINKING']='STATIC_PACKAGES'
824
825 if with_python and not conf.CheckHeader(['basetsd.h','BaseTsd.h']):
826 with_python = 0;
827 without_python_reason = "Header file 'basetsd.h' not found. Install the MS Platform SDK."
828
829 conf.env.Append(CPPDEFINES=env['PACKAGE_LINKING'])
830
831 conf.Finish()
832
833 env.Append(PYTHON_LIBPATH=[distutils.sysconfig.PREFIX+"/libs"])
834 env.Append(PYTHON_LIB=[python_lib])
835 env.Append(PYTHON_CPPPATH=[distutils.sysconfig.get_python_inc()])
836
837 #---------------------------------------
838 # SUBSTITUTION DICTIONARY for .in files
839
840 subst_dict = {
841 '@DEFAULT_ASCENDLIBRARY@':env['DEFAULT_ASCENDLIBRARY']
842 , '@GLADE_FILE@':'ascend.glade'
843 , '@HELP_ROOT@':''
844 , '@ICON_EXTENSION@':icon_extension
845 , '@INSTALL_DATA@':env['INSTALL_DATA']
846 , '@INSTALL_BIN@':env['INSTALL_BIN']
847 , '@INSTALL_INCLUDE@':env['INSTALL_INCLUDE']
848 , '@PYGTK_ASSETS@':env['PYGTK_ASSETS']
849 , '@VERSION@':version
850 , '@WEBHELPROOT@':'http://pye.dyndns.org/ascend/manual/'
851 , '@ASC_SHLIBSUFFIX@':env['SHLIBSUFFIX']
852 , '@ASC_SHLIBPREFIX@':env['SHLIBPREFIX']
853 }
854
855 if env['WITH_LOCAL_HELP']:
856 print "WITH_LOCAL_HELP:",env['WITH_LOCAL_HELP']
857 subst_dict['@HELP_ROOT@']=env['WITH_LOCAL_HELP']
858
859 if with_python:
860 subst_dict['@ASCXX_USE_PYTHON@']="1"
861
862 if env.has_key('HAVE_GCCVISIBILITY'):
863 subst_dict['@HAVE_GCCVISIBILITY@'] = "1"
864
865 env.Append(SUBST_DICT=subst_dict)
866
867 #------------------------------------------------------
868 # RECIPE: SWIG scanner
869
870 import SCons.Script
871
872 SWIGScanner = SCons.Scanner.ClassicCPP(
873 "SWIGScan"
874 , ".i"
875 , "CPPPATH"
876 , '^[ \t]*[%,#][ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")'
877 )
878
879 env.Append(SCANNERS=[SWIGScanner])
880
881 #------------------------------------------------------
882 # RECIPE: 'SubstInFile', used in pygtk SConscript
883
884 import re
885 from SCons.Script import * # the usual scons stuff you get in a SConscript
886
887 def TOOL_SUBST(env):
888 """Adds SubstInFile builder, which substitutes the keys->values of SUBST_DICT
889 from the source to the target.
890 The values of SUBST_DICT first have any construction variables expanded
891 (its keys are not expanded).
892 If a value of SUBST_DICT is a python callable function, it is called and
893 the result is expanded as the value.
894 If there's more than one source and more than one target, each target gets
895 substituted from the corresponding source.
896 """
897 env.Append(TOOLS = 'SUBST')
898 def do_subst_in_file(targetfile, sourcefile, dict):
899 """Replace all instances of the keys of dict with their values.
900 For example, if dict is {'%VERSION%': '1.2345', '%BASE%': 'MyProg'},
901 then all instances of %VERSION% in the file will be replaced with 1.2345 etc.
902 """
903 try:
904 f = open(sourcefile, 'rb')
905 contents = f.read()
906 f.close()
907 except:
908 raise SCons.Errors.UserError, "Can't read source file %s"%sourcefile
909 for (k,v) in dict.items():
910 contents = re.sub(k, v, contents)
911 try:
912 f = open(targetfile, 'wb')
913 f.write(contents)
914 f.close()
915 except:
916 raise SCons.Errors.UserError, "Can't write target file %s"%targetfile
917 return 0 # success
918
919 def subst_in_file(target, source, env):
920 if not env.has_key('SUBST_DICT'):
921 raise SCons.Errors.UserError, "SubstInFile requires SUBST_DICT to be set."
922 d = dict(env['SUBST_DICT']) # 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 else:
929 raise SCons.Errors.UserError, "SubstInFile: key %s: %s must be a string or callable"%(k, repr(v))
930 for (t,s) in zip(target, source):
931 return do_subst_in_file(str(t), str(s), d)
932
933 def subst_in_file_string(target, source, env):
934 """This is what gets printed on the console."""
935 return '\n'.join(['Substituting vars from %s into %s'%(str(s), str(t))
936 for (t,s) in zip(target, source)])
937
938 def subst_emitter(target, source, env):
939 """Add dependency from substituted SUBST_DICT to target.
940 Returns original target, source tuple unchanged.
941 """
942 d = env['SUBST_DICT'].copy() # copy it
943 for (k,v) in d.items():
944 if callable(v):
945 d[k] = env.subst(v())
946 elif SCons.Util.is_String(v):
947 d[k]=env.subst(v)
948 Depends(target, SCons.Node.Python.Value(d))
949 return target, source
950
951 subst_action=SCons.Action.Action(subst_in_file, subst_in_file_string)
952 env['BUILDERS']['SubstInFile'] = Builder(action=subst_action, emitter=subst_emitter)
953
954 TOOL_SUBST(env)
955
956 #------------------------------------------------------
957 # Recipe for 'CHMOD' ACTION
958
959 import SCons
960 from SCons.Script.SConscript import SConsEnvironment
961 SConsEnvironment.Chmod = SCons.Action.ActionFactory(os.chmod,
962 lambda dest, mode: 'Chmod("%s", 0%o)' % (dest, mode))
963
964 def InstallPerm(env, dest, files, perm):
965 obj = env.Install(dest, files)
966 for i in obj:
967 env.AddPostAction(i, env.Chmod(str(i), perm))
968
969 SConsEnvironment.InstallPerm = InstallPerm
970
971 # define wrappers
972 SConsEnvironment.InstallProgram = lambda env, dest, files: InstallPerm(env, dest, files, 0755)
973 SConsEnvironment.InstallHeader = lambda env, dest, files: InstallPerm(env, dest, files, 0644)
974
975 #------------------------------------------------------
976 # NSIS Support for SCons
977
978 # Adapted version by John Pye, April 2006.
979 # from http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/NsisSconsTool
980 # Written by Mike Elkins, January 2004.
981
982 #This tool provides SCons support for the Nullsoft Scriptable Install System
983 #a windows installer builder available at http://nsis.sourceforge.net/home
984
985 #In addition, if you set NSISDEFINES to a dictionary, those variables will be passed
986 #to NSIS.
987
988 import SCons.Builder
989 import SCons.Util
990 import SCons.Scanner
991 import SCons.Sig
992 import os.path
993 import glob
994
995 def nsis_parse( sources, keyword, multiple ):
996 """
997 A function that knows how to read a .nsi file and figure
998 out what files are referenced, or find the 'OutFile' line.
999
1000
1001 sources is a list of nsi files.
1002 keyword is the command ('File' or 'OutFile') to look for
1003 multiple is true if you want all the args as a list, false if you
1004 just want the first one.
1005 """
1006 stuff = []
1007 for s in sources:
1008 c = s.get_contents()
1009 for l in c.split('\n'):
1010 semi = l.find(';')
1011 if (semi != -1):
1012 l = l[:semi]
1013 hash = l.find('#')
1014 if (hash != -1):
1015 l = l[:hash]
1016 # Look for the keyword
1017 l = l.strip()
1018 spl = l.split(None,1)
1019 if len(spl) > 1:
1020 if spl[0].capitalize() == keyword.capitalize():
1021 arg = spl[1]
1022 if arg.startswith('"') and arg.endswith('"'):
1023 arg = arg[1:-1]
1024 if multiple:
1025 stuff += [ arg ]
1026 else:
1027 return arg
1028 return stuff
1029
1030
1031 def nsis_path( filename, nsisdefines, rootdir ):
1032 """
1033 Do environment replacement, and prepend with the SCons root dir if
1034 necessary
1035 """
1036 # We can't do variables defined by NSIS itself (like $INSTDIR),
1037 # only user supplied ones (like ${FOO})
1038 varPos = filename.find('${')
1039 while varPos != -1:
1040 endpos = filename.find('}',varPos)
1041 assert endpos != -1
1042 if not nsisdefines.has_key(filename[varPos+2:endpos]):
1043 raise KeyError ("Could not find %s in NSISDEFINES" % filename[varPos+2:endpos])
1044 val = nsisdefines[filename[varPos+2:endpos]]
1045 if type(val) == list:
1046 if varPos != 0 or endpos+1 != len(filename):
1047 raise Exception("Can't use lists on variables that aren't complete filenames")
1048 return val
1049 filename = filename[0:varPos] + val + filename[endpos+1:]
1050 varPos = filename.find('${')
1051 return filename
1052
1053
1054 def nsis_scanner( node, env, path ):
1055 """
1056 The scanner that looks through the source .nsi files and finds all lines
1057 that are the 'File' command, fixes the directories etc, and returns them.
1058 """
1059 nodes = node.rfile()
1060 if not node.exists():
1061 return []
1062 nodes = []
1063 source_dir = node.get_dir()
1064 for include in nsis_parse([node],'file',1):
1065 exp = nsis_path(include,env['NSISDEFINES'],source_dir)
1066 if type(exp) != list:
1067 exp = [exp]
1068 for p in exp:
1069 for filename in glob.glob( os.path.abspath(
1070 os.path.join(str(source_dir),p))):
1071 # Why absolute path? Cause it breaks mysteriously without it :(
1072 nodes.append(filename)
1073 return nodes
1074
1075
1076 def nsis_emitter( source, target, env ):
1077 """
1078 The emitter changes the target name to match what the command actually will
1079 output, which is the argument to the OutFile command.
1080 """
1081 nsp = nsis_parse(source,'outfile',0)
1082 if not nsp:
1083 return (target,source)
1084 x = (
1085 nsis_path(nsp,env['NSISDEFINES'],''),
1086 source)
1087 return x
1088
1089 def quoteIfSpaced(text):
1090 if ' ' in text:
1091 return '"'+text+'"'
1092 else:
1093 return text
1094
1095 def toString(item,env):
1096 if type(item) == list:
1097 ret = ''
1098 for i in item:
1099 if ret:
1100 ret += ' '
1101 val = toString(i,env)
1102 if ' ' in val:
1103 val = "'"+val+"'"
1104 ret += val
1105 return ret
1106 else:
1107 # For convienence, handle #s here
1108 if str(item).startswith('#'):
1109 item = env.File(item).get_abspath()
1110 return str(item)
1111
1112 def runNSIS(source,target,env,for_signature):
1113 ret = env['NSIS']+" "
1114 if env.has_key('NSISFLAGS'):
1115 for flag in env['NSISFLAGS']:
1116 ret += flag
1117 ret += ' '
1118 if env.has_key('NSISDEFINES'):
1119 for d in env['NSISDEFINES']:
1120 ret += '/D'+d
1121 if env['NSISDEFINES'][d]:
1122 ret +='='+quoteIfSpaced(toString(env['NSISDEFINES'][d],env))
1123 ret += ' '
1124 for s in source:
1125 ret += quoteIfSpaced(str(s))
1126 return ret
1127
1128 def find_nsis(env):
1129 """
1130 Try and figure out if NSIS is installed on this machine, and if so,
1131 where.
1132 """
1133 if SCons.Util.can_read_reg:
1134 # If we can read the registry, get the NSIS command from it
1135 try:
1136 k = SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
1137 'SOFTWARE\\NSIS')
1138 val, tok = SCons.Util.RegQueryValueEx(k,None)
1139 ret = val + os.path.sep + 'makensis.exe'
1140 if os.path.exists(ret):
1141 return '"' + ret + '"'
1142 else:
1143 return None
1144 except:
1145 pass # Couldn't find the key, just act like we can't read the registry
1146 # Hope it's on the path
1147 return env.WhereIs('makensis.exe')
1148
1149 def nsis_exists(env):
1150 """
1151 Is NSIS findable on this machine?
1152 """
1153 if find_nsis(env) != None:
1154 return 1
1155 return 0
1156
1157 env['BUILDERS']['Nsis'] = SCons.Builder.Builder(generator=runNSIS,
1158 src_suffix='.nsi',
1159 emitter=nsis_emitter)
1160
1161 env.Append(SCANNERS = SCons.Scanner.Scanner( function = nsis_scanner,
1162 skeys = ['.nsi']))
1163
1164 if not env.has_key('NSISDEFINES'):
1165 env['NSISDEFINES'] = {}
1166 env['NSIS'] = find_nsis(env)
1167
1168 #------------------------------------------------------
1169 # BUILD...
1170
1171 # so that #include <modulename/headername.h> works across all modules...
1172 env.Append(CPPPATH=['#base/generic'])
1173
1174 if gcc_version4:
1175 env.Append(CCFLAGS=['-fvisibility=hidden'])
1176
1177 if env['DEBUG']:
1178 env.Append(CCFLAGS=['-g'])
1179
1180 #-------------
1181 # TCL/TK GUI
1182
1183 if with_tcltk:
1184 if with_local_blas:
1185 env.SConscript(['blas/SConscript'],'env')
1186 else:
1187 print "Skipping... BLAS won't be build:", without_local_blas_reason
1188
1189 env.SConscript(['lsod/SConscript'],'env')
1190
1191 env.SConscript(['linpack/SConscript'],'env')
1192 env.SConscript(['tcltk98/generic/interface/SConscript'],'env')
1193 else:
1194 print "Skipping... Tcl/Tk GUI isn't being built:",without_tcltk_reason
1195
1196 #-------------
1197 # PYTHON INTERFACE
1198
1199 if with_python:
1200 env.SConscript(['pygtk/SConscript'],'env')
1201 else:
1202 print "Skipping... Python GUI isn't being built:",without_python_reason
1203
1204 #------------
1205 # BASE/GENERIC SUBDIRECTORIES
1206
1207 dirs = ['general','utilities','compiler','solver','packages']
1208
1209 srcs = []
1210 for d in dirs:
1211 heresrcs = env.SConscript('base/generic/'+d+'/SConscript','env')
1212 srcs += heresrcs
1213
1214 #-------------
1215 # LIBASCEND -- all base/generic functionality
1216
1217 libascend = env.SharedLibrary('ascend',srcs)
1218
1219 #-------------
1220 # UNIT TESTS
1221
1222 if with_cunit_tests:
1223 testdirs = ['general','solver','utilities']
1224 for testdir in testdirs:
1225 path = 'base/generic/'+testdir+'/test/'
1226 env.SConscript([path+'SConscript'],'env')
1227 env.SConscript(['test/SConscript'],'env')
1228 env.SConscript(['base/generic/test/SConscript'],'env')
1229
1230
1231 else:
1232 print "Skipping... CUnit tests aren't being built:",without_cunit_reason
1233
1234
1235 #------------------------------------------------------
1236 # INSTALLATION
1237
1238 if env.get('CAN_INSTALL'):
1239 # the models directory only needs to be processed for installation, no other processing required.
1240 env.SConscript(['models/SConscript'],'env')
1241
1242 dirs = ['INSTALL_BIN','INSTALL_DATA','INSTALL_LIB']
1243 install_dirs = [env['INSTALL_ROOT']+env[d] for d in dirs]
1244
1245 # TODO: add install options
1246 env.Alias('install',install_dirs)
1247
1248 env.Install(env['INSTALL_ROOT']+env['INSTALL_LIB'],libascend)
1249
1250 #------------------------------------------------------
1251 # CREATE the SPEC file for generation of RPM packages
1252
1253 if platform.system()=="Linux":
1254 env.SubstInFile('ascend.spec.in')
1255
1256 #------------------------------------------------------
1257 # DISTRIBUTION TAR FILE
1258
1259 env['DISTTAR_FORMAT']='bz2'
1260 env.Append(
1261 DISTTAR_EXCLUDEEXTS=['.o','.os','.so','.a','.dll','.cc','.cache','.pyc','.cvsignore','.dblite','.log']
1262 , DISTTAR_EXCLUDEDIRS=['CVS','.svn','.sconf_temp', 'dist']
1263 )
1264
1265 tar = env.DistTar("dist/ascend-"+version
1266 , [env.Dir('#')]
1267 )
1268
1269 #------------------------------------------------------
1270 # RPM BUILD
1271
1272 #if platform.system()=="Linux":
1273 # pass
1274
1275 #------------------------------------------------------
1276 # DEFAULT TARGETS
1277
1278 env.Default(['pygtk','tcltk98'])
1279

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