/[ascend]/trunk/SConstruct
ViewVC logotype

Annotation of /trunk/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


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

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