/[ascend]/trunk/SConstruct
ViewVC logotype

Annotation of /trunk/SConstruct

Parent Directory Parent Directory | Revision Log Revision Log


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

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