/[ascend]/trunk/SConstruct
ViewVC logotype

Annotation of /trunk/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


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

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