/[ascend]/trunk/SConstruct
ViewVC logotype

Contents of /trunk/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


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

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