LOOS  v2.3.2
scons_support.py
1 #!/usr/bin/env python
2 # This file is part of LOOS.
3 #
4 # LOOS (Lightweight Object-Oriented Structure library)
5 # Copyright (c) 2013, Tod D. Romo
6 # Department of Biochemistry and Biophysics
7 # School of Medicine & Dentistry, University of Rochester
8 #
9 # This package (LOOS) is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation under version 3 of the License.
12 #
13 # This package is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21 
22 # This file contains support code for SCons for building LOOS
23 
24 import sys
25 import os
26 import glob
27 import platform
28 import re
29 from subprocess import *
30 from time import strftime
31 import shutil
32 import distutils.sysconfig
33 import distutils.spawn
34 import string
35 from distutils.version import LooseVersion
36 
37 import SCons
38 
39 import loos_build_config
40 
41 
42 default_lib_path = 'crap'
43 
44 # Attempt to canonicalize system name, type and other related info...
45 # Note: this exports to globals rather than being contained within the check framework.
46 def CheckSystemType(conf):
47  conf.Message('Determining platform ...')
48  loos_build_config.host_type = platform.system()
49 
50 # Detect CYGWIN & canonicalize linux type, setting defaults...
51  if (re.search("(?i)cygwin", loos_build_config.host_type)):
52  loos_build_config.host_type = 'Cygwin'
53  loos_build_config.suffix = 'dll.a'
54  elif (loos_build_config.host_type == 'Linux'):
55  # Determine linux variant...
56  linux_type = platform.platform()
57 
58  if (re.search("(?i)ubuntu", linux_type)):
59  linux_type = 'ubuntu'
60  elif (re.search("(?i)suse", linux_type)):
61  linux_type = 'suse'
62  elif (re.search("(?i)debian", linux_type)):
63  linux_type = 'debian'
64  elif (re.search("(?i)centos", linux_type)):
65  linux_type = 'centos'
66  elif (re.search("(?i)fedora", linux_type)):
67  linux_type = 'fedora'
68 
69  loos_build_config.linux_type = linux_type
70 
71  # MacOS is special (of course...)
72  elif (loos_build_config.host_type == 'Darwin'):
73  loos_build_config.suffix = 'dylib'
74 
75  typemsg = loos_build_config.host_type
76  if (typemsg == 'Linux'):
77  typemsg = typemsg + ' [' + loos_build_config.linux_type + ']'
78 
79  conf.Result(typemsg)
80 
81 
82 
83 
84 ### Create a revision file for linking against.
85 def setupRevision(env):
86 
87  # Divine the current revision...
88  revision = loos_build_config.loos_version + " " + strftime("%y%m%d")
89 
90  # Now, write this out to a cpp file that can be linked in...this avoids having
91  # to recompile everything when building on a new date. We also rely on SCons
92  # using the MD5 checksum to detect changes in the file (even though it's always
93  # rewritten)
94  revfile = open('src/revision.cpp', 'w')
95  revfile.write('#include <string>\n')
96  revfile.write('std::string revision_label = "')
97  revfile.write(revision)
98  revfile.write('";\n')
99  revfile.close()
100 
101 
102 ### Let environment variables override or modify some build paramaters...
103 def environOverride(conf):
104  # Allow overrides from environment...
105  if 'CXX' in os.environ:
106  conf.env.Replace(CXX = os.environ['CXX'])
107  print '*** Using compiler ' + os.environ['CXX']
108 
109  if 'CCFLAGS' in os.environ:
110  conf.env.Append(CCFLAGS = os.environ['CCFLAGS'])
111  print '*** Appending custom build flags: ' + os.environ['CCFLAGS']
112 
113  if 'LDFLAGS' in os.environ:
114  conf.env.Append(LINKFLAGS = os.environ['LDFLAGS'])
115  print '*** Appending custom link flag: ' + os.environ['LDFLAGS']
116 
117 
118 
119 ### Builder for setup scripts
120 
121 def expand_scons_paths(path, topdir):
122  newpath = []
123  for item in path:
124  item = string.replace(item, '#', topdir + '/')
125  newpath.append(item)
126  return(newpath)
127 
128 # This copies the environment setup script while changing the directory
129 # that's used for setting up PATH and [DY]LD_LIBRARY_PATH. If LOOS
130 # is being built in a directory, the env script will be setup to use
131 # the built-in-place distribution. If LOOS is being installed, then
132 # it will use the installation directory instead.
133 
134 def script_builder_python(target, source, env):
135 
136  libpaths = env['LIBPATH']
137  libpaths.pop(0)
138 
139  cpppaths = env['CPPPATH']
140  cpppaths.pop(0)
141 
142  ldlibrary = loos_build_config.user_libdirs.values()
143 
144  if not 'install' in SCons.Script.COMMAND_LINE_TARGETS:
145  toolpath = '$LOOS/Tools:' + ':'.join(['$LOOS/Packages/' + s for s in [loos_build_config.package_list[i] for i in loos_build_config.package_list]])
146  loos_dir = env.Dir('.').abspath
147  libpaths.insert(0, loos_dir)
148  cpppaths.insert(0, loos_dir)
149  ldlibrary.insert(0, loos_dir)
150 
151  libpaths = expand_scons_paths(libpaths, loos_dir)
152  cpppaths = expand_scons_paths(cpppaths, loos_dir)
153  ldlibrary = expand_scons_paths(ldlibrary, loos_dir)
154 
155  loos_pythonpath = loos_dir
156 
157  else:
158  loos_dir = env['PREFIX']
159  toolpath = loos_dir + '/bin'
160  libpaths.insert(0, loos_dir + '/lib')
161  cpppaths.insert(0, loos_dir + '/include')
162  ldlibrary.insert(0, loos_dir + '/lib')
163  loos_pythonpath = loos_dir + '/lib'
164 
165 
166  file = open(str(source[0]), 'r')
167  script = file.read()
168  script_template = string.Template(script)
169  script = script_template.substitute(loos_path = loos_dir,
170  tool_path = toolpath,
171  libpath = ':'.join(libpaths),
172  cpppath = ':'.join(cpppaths),
173  linkflags = env['LINKFLAGS'],
174  libs = ':'.join(env['LIBS']),
175  ccflags = env['CCFLAGS'],
176  loos_cxx = env['CXX'],
177  loos_pythonpath = loos_pythonpath,
178  ldlibrary = ':'.join(ldlibrary))
179 
180  outfile = open(str(target[0]), 'w')
181  outfile.write(script)
182 
183  return None
184 
185 
186 
187 # Verify that we have swig and it's v2.0+
188 # Returns the path to swig
189 def CheckForSwig(conf, min_version):
190  conf.Message('Checking for Swig...')
191  # Need to use has_key() for older distros...
192  if conf.env.has_key('SWIGVERSION'):
193  if LooseVersion(conf.env['SWIGVERSION']) >= LooseVersion(min_version):
194  conf.Result('yes [%s]' % (conf.env['SWIGVERSION']))
195  return(1)
196  else:
197  conf.Result('too old [%s, requires at least %s; pyloos disabled]' % (conf.env['SWIGVERSION'], min_version))
198  return(0)
199 
200  conf.Result('no [pyloos disabled]')
201  return(0)
202 
203 
204 # See if a library requires another to link...
205 def CheckAtlasRequires(conf, name, lib, required):
206 
207  conf.Message('Checking if %s requires %s ... ' % (name, required))
208  lastLIBS = list(conf.env['LIBS'])
209  conf.env.Append(LIBS=lib)
210 
211 # test_code = """
212 #extern "C"{void dgesvd_(char*, char*, int*, int*, double*, int*, double*, double*, int*, double*, int*#, double*, int*, int*);}
213 #int main(int argc, char *argv[]) { char C[1]; double D[1];int I[1];dgesvd_(C, C, I, I, D, I, D, D, I, #D, I, D, I, I); }
214 #"""
215  test_code="int main(){return(0);}"
216 
217  result = conf.TryLink(test_code, '.cpp')
218  if not result:
219  conf.env.Append(LIBS=required)
220  result = conf.TryLink(test_code, '.cpp')
221  conf.env.Replace(LIBS=lastLIBS)
222  if not result:
223  conf.Result('fail')
224  return()
225  conf.Result('yes')
226  return(lib, required)
227 
228  conf.env.Replace(LIBS=lastLIBS)
229  conf.Result('no')
230  return(lib)
231 
232 
233 # Check for IEC-559 compliance
234 def CheckForIEC559(conf):
235 
236  conf.Message('Checking for IEC-559/IEE-754 support... ')
237 
238  test_code = """
239 #include <iostream>
240 #include <limits>
241 
242 int main(int argc, char *argv[]) {
243  if (std::numeric_limits<double>::is_iec559 && std::numeric_limits<float>::is_iec559)
244  std::cout << "yes";
245  else
246  std::cout << "no";
247 }
248 """
249 
250  result = conf.TryRun(test_code, '.cpp')
251  if not result[0]:
252  conf.Result('unable to check')
253  return(0)
254 
255  if (result[1] != 'yes'):
256  conf.Result('no')
257  return(0)
258 
259  conf.Result('yes')
260 
261  return(1)
262 
263 
264 
265 # Check for existince of boost library with various naming variants
266 # Will return a tuple containing the correct name and a flag indicating
267 # whether this is the threaded or non-threaded version.
268 # This will only search specified paths, not the built-in paths for g++,
269 # so some libraries may be missed...
270 def CheckForBoostLibrary(conf, name, path, suffix):
271  conf.Message('Checking for Boost library %s...' % name)
272  name = 'boost_' + name
273 
274  def sortByLength(w1,w2):
275  return len(w1)-len(w2)
276 
277  # Now check for names lib libboost_regex-gcc43-mt.so ...
278  files = glob.glob(os.path.join(path, 'lib%s*-mt.%s' % (name, suffix)))
279  files.sort(cmp=sortByLength)
280  if files:
281  conf.Result(name + '-mt')
282  name = os.path.basename(files[0])[3:-(len(suffix)+1)]
283  return(name, 1)
284 
285  files = glob.glob(os.path.join(path, 'lib%s*.%s' % (name, suffix)))
286  files.sort(cmp=sortByLength)
287  if files:
288  conf.Result(name)
289  name = os.path.basename(files[0])[3:-(len(suffix)+1)]
290  return(name, 0)
291 
292 
293  conf.Result('missing')
294  return('', -1)
295 
296 
297 # Check for Boost include files...
298 def CheckBoostHeaders(conf):
299  test_code = """
300 #include <boost/version.hpp>
301 int main(int argc, char *argv[]) { return(0); }
302 """
303 
304  conf.Message('Checking for Boost... ')
305  result = conf.TryLink(test_code, '.cpp')
306  if not result:
307  conf.Result('no')
308  return(0)
309 
310  conf.Result('yes')
311  return(1)
312 
313 
314 # Check for version of Boost includes
315 def CheckBoostHeaderVersion(conf, min_boost_version):
316  source_code = """
317 #include <iostream>
318 #include <boost/version.hpp>
319 int main(int argc, char *argv[]) { std::cout << BOOST_LIB_VERSION; return(0); }
320 """
321 
322  conf.Message('Checking Boost version... ')
323  result = conf.TryRun(source_code, '.cpp')
324  if not result[0]:
325  conf.Result('boost missing or incomplete?')
326  return(0)
327  version = result[1]
328 
329  if LooseVersion(version) < LooseVersion(min_boost_version):
330  conf.Result('%s [too old, LOOS requires at least %s]' % (version, min_boost_version))
331  return(0)
332 
333  conf.Result('%s [ok]' % version)
334  return(1)
335 
336 # Check for presence of a directory
337 def CheckDirectory(conf, dirname):
338 
339  conf.Message('Checking for directory %s... ' % dirname)
340  if os.path.isdir(dirname):
341  conf.Result('yes')
342  return(1)
343  conf.Result('no')
344  return(0)
345 
346 
347 
348 def CheckNumpy(conf, pythonpath):
349  global default_lib_path
350  conf.Message('Checking for numpy... ')
351 
352  ok = checkForPythonHeader(conf, 'numpy/arrayobject.h')
353  if ok:
354  conf.Result('yes')
355  return(1)
356  newpaths = []
357  if 'PYTHON_PATH' in conf.env:
358  envpath = conf.env['PYTHON_PATH']
359  if len(envpath) > 1: # Catches cases where PYTHON_PATH is present but null...
360  newpaths.extend(envpath.split(':'))
361 
362 
363  # Assume the python running scons is what we will be using for LOOS...
364  vinfo = sys.version_info
365  python_tag = '/python%d.%d' % (vinfo[0], vinfo[1])
366 
367  newpaths.append(default_lib_path + python_tag)
368  pythonpaths = [s + '/site-packages/numpy/core/include' for s in newpaths]
369  if pythonpaths:
370  ok = checkForPythonHeaderInPath(conf, 'numpy/arrayobject.h', pythonpaths)
371  if ok:
372  conf.Result('yes')
373  return(1)
374 
375 
376  # Special handling for MacOS
377  if loos_build_config.host_type == 'Darwin':
378  ok = checkForPythonHeaderInPath(conf, 'numpy/arrayobject.h', ['/System/Library/Frameworks/Python.framework/Versions/Current/Extras/lib/python/numpy/core/include'])
379  if ok:
380  conf.Result('yes')
381  return(1)
382 
383  conf.Result('no')
384  return(0)
385 
386 
387 def SetupBoostPaths(env):
388 
389  BOOST=env['BOOST']
390  BOOST_INCLUDE=env['BOOST_INCLUDE']
391  BOOST_LIBPATH=env['BOOST_LIBPATH']
392  BOOST_LIBS = env['BOOST_LIBS']
393 
394  boost_libpath = ''
395  boost_include = ''
396 
397  if BOOST:
398  boost = BOOST
399  boost_include = boost + '/include'
400  boost_libpath = boost + '/lib'
401  loos_build_config.user_libdirs['BOOST'] = boost_libpath
402  loos_build_config.user_boost_flag = 1
403 
404  if BOOST_INCLUDE:
405  boost_include = BOOST_INCLUDE
406  if BOOST_LIBPATH:
407  boost_libpath= BOOST_LIBPATH
408  loos_build_config.user_libdirs['BOOST'] = boost_libpath
409  loos_build_config.user_boost_flag = 1
410 
411  if boost_libpath:
412  env.Prepend(LIBPATH=[boost_libpath])
413  env['BOOST_LIBPATH'] = boost_libpath
414  if boost_include:
415  env.Prepend(CPPPATH=[boost_include] )
416 
417 
418 
419 
420 def SetupNetCDFPaths(env):
421  NETCDF=env['NETCDF']
422  NETCDF_INCLUDE=env['NETCDF_INCLUDE']
423  NETCDF_LIBPATH=env['NETCDF_LIBPATH']
424  NETCDF_LIBS = env['NETCDF_LIBS']
425 
426  netcdf_libpath = ''
427  netcdf_include = ''
428 
429  if NETCDF:
430  netcdf = NETCDF
431  netcdf_include = netcdf + '/include'
432  netcdf_libpath = netcdf + '/lib'
433  loos_build_config.user_libdirs['NETCDF'] = netcdf_libpath
434 
435  if NETCDF_INCLUDE:
436  netcdf_include = NETCDF_INCLUDE
437  if NETCDF_LIBPATH:
438  netcdf_libpath= NETCDF_LIBPATH
439  loos_build_config.user_libdirs['NETCDF'] = netcdf_libpath
440 
441  if netcdf_libpath:
442  env.Prepend(LIBPATH=[netcdf_libpath])
443  if netcdf_include:
444  env.Prepend(CPPPATH=[netcdf_include])
445 
446 
447 
448 def AutoConfigSystemBoost(conf):
449  boost_libs = []
450  first = 1
451  thread_suffix = 0
452 
453  for libname in loos_build_config.required_boost_libraries:
454  if first:
455  first = 0
456  full_libname = 'boost_' + libname + '-mt'
457  result = conf.CheckLib(full_libname, autoadd = 0)
458  if result:
459  boost_libs.append(full_libname)
460  thread_suffix = 1
461  else:
462  full_libname = 'boost_' + libname
463  result = conf.CheckLib(full_libname, autoadd = 0)
464  if result:
465  boost_libs.append(full_libname)
466  else:
467  full_libname = 'boost_' + libname
468  if thread_suffix:
469  full_libname += '-mt'
470  result = conf.CheckLib(full_libname, autoadd = 0)
471  if result:
472  boost_libs.append(full_libname)
473  else:
474  print 'Error- missing Boost library %s' % libname
475  conf.env.Exit(1)
476 
477 
478  return boost_libs
479 
480 
481 
482 def AutoConfigUserBoost(conf):
483  boost_libs = []
484  first = 1
485  thread_suffix = 0
486 
487  for libname in loos_build_config.required_boost_libraries:
488  result = conf.CheckForBoostLibrary(libname, conf.env['BOOST_LIBPATH'], loos_build_config.suffix)
489  if not result[0]:
490  print 'Error- missing Boost library %s' % libname
491  conf.env.Exit(1)
492  if first:
493  thread_suffix = result[1]
494  else:
495  if thread_suffix and not result[1]:
496  print 'Error- expected %s-mt but found %s' % (libname, libname)
497  conf.env.Exit(1)
498  elif not thread_suffix and result[1]:
499  print 'Error- expected %s but found %s-mt' % (libname, libname)
500  conf.env.Exit(1)
501  boost_libs.append(result[0])
502 
503  return boost_libs
504 
505 
506 
507 # Check to see if a function exists with current libs
508 # If gfortran is present and function is not found, then
509 # try appending gfortran to lib list...
510 
511 def checkForFunction(context, funcname, libs, has_gfortran):
512  old_libs = list(context.env['LIBS'])
513  context.env.Append(LIBS=libs)
514  requires_gf = 0
515 
516  ok = context.CheckFunc(funcname)
517  if not ok and has_gfortran:
518  print 'Trying again with gfortran...'
519  context.env.Append(LIBS=['gfortran'])
520  ok = context.CheckFunc(funcname)
521  if ok:
522  requires_gf = 1
523 
524  context.env['LIBS'] = old_libs
525  return (ok, requires_gf)
526 
527 
528 
529 
530 # Tries adding each library from list to the build lib list
531 # and sees if funcname is present. Any lib in the excludelist
532 # is ignored. No special handling for gfortran...
533 
534 def checkLibsForFunction(context, funcname, liblist, excludelist):
535  for lib in liblist:
536  if lib in excludelist:
537  continue
538  old_libs = list(context.env['LIBS'])
539  context.env.Append(LIBS=lib)
540  print "> Checking in %s ..." % lib
541  ok = context.CheckFunc(funcname)
542  context.env['LIBS'] = old_libs
543  if ok:
544  return(lib)
545  return('')
546 
547 
548 def checkForPythonHeader(context, header):
549  test_code = """
550 #include <Python.h>
551 #include <%s>
552 """ % header
553 
554  oldcpp = None
555  if 'CPPFLAGS' in context.env:
556  oldcpp = context.env['CPPFLAGS']
557  if 'CPPPATH' in context.env:
558  for dir in context.env['CPPPATH']:
559  context.env.Append(CPPFLAGS="-I%s " % dir)
560  ok = context.TryCompile(test_code, '.cpp')
561 
562  if oldcpp:
563  context.env['CPPFLAGS'] = oldcpp
564 
565  return(ok)
566 
567 
568 def checkForPythonHeaderInPath(context, header, pathlist):
569 
570  for path in pathlist:
571  oldcpp = None
572  if 'CPPPATH' in context.env:
573  oldcpp = context.env['CPPPATH']
574  context.env.Append(CPPPATH=[path])
575  ok = checkForPythonHeader(context, header)
576  if (ok):
577  return(True)
578  if oldcpp:
579  context.env['CPPPATH'] = oldcpp
580  return(False)
581 
582 
583 
584 def AutoConfiguration(env):
585  global default_lib_path
586 
587  conf = env.Configure(custom_tests = { 'CheckForSwig' : CheckForSwig,
588  'CheckBoostHeaders' : CheckBoostHeaders,
589  'CheckForBoostLibrary' : CheckForBoostLibrary,
590  'CheckBoostHeaderVersion' : CheckBoostHeaderVersion,
591  'CheckDirectory' : CheckDirectory,
592  'CheckAtlasRequires' : CheckAtlasRequires,
593  'CheckForIEC559' : CheckForIEC559,
594  'CheckSystemType' : CheckSystemType,
595  'CheckNumpy' : CheckNumpy
596  })
597 
598  use_threads = int(env['threads'])
599 
600  # Get system information
601  conf.CheckSystemType()
602 
603  conf.env['host_type'] = loos_build_config.host_type
604  conf.env['linux_type'] = loos_build_config.linux_type
605 
606 
607  if env.GetOption('clean') or env.GetOption('help'):
608  env['HAS_NETCDF'] = 1
609  else:
610  has_netcdf = 0
611 
612 
613  # Some distros use /usr/lib, others have /usr/lib64.
614  # Check to see what's here and prefer lib64 to lib
615  default_lib_path = '/usr/lib'
616  if not conf.CheckDirectory('/usr/lib64'):
617  if not conf.CheckDirectory('/usr/lib'):
618  print 'Fatal error- cannot find your system library directory'
619  conf.env.Exit(1)
620  else:
621  # /usr/lib64 is found, so make sure we link against this (and not against any 32-bit libs)
622  default_lib_path = '/usr/lib64'
623  conf.env.Append(LIBPATH = default_lib_path)
624  # Only setup ATLAS if we're not on a Mac...
625  if loos_build_config.host_type != 'Darwin':
626  atlas_libpath = ''
627  ATLAS_LIBPATH = env['ATLAS_LIBPATH']
628  ATLAS_LIBS = env['ATLAS_LIBS']
629  if not ATLAS_LIBPATH:
630  # Some distros may have atlas in /atlas-base, so must check for that...
631  if conf.CheckDirectory(default_lib_path + '/atlas-base'):
632  atlas_libpath = default_lib_path + '/atlas-base'
633  elif conf.CheckDirectory(default_lib_path + '/atlas'):
634  atlas_libpath = default_lib_path + '/atlas'
635  else:
636  print 'Warning: Could not find an atlas directory! Winging it...'
637  else:
638  atlas_libpath = ATLAS_LIBPATH
639  loos_build_config.user_libdirs['ATLAS'] = atlas_libpath
640 
641  if atlas_libpath:
642  conf.env.Prepend(LIBPATH = [atlas_libpath])
643 
644  # Now that we know the default library path, setup Boost, NetCDF, and ATLAS
645  # based on the environment or custom.py file
646  SetupBoostPaths(conf.env)
647  SetupNetCDFPaths(conf.env)
648 
649 
650 
651  # Check for standard typedefs...
652  if not conf.CheckType('ulong','#include <sys/types.h>\n'):
653  conf.env.Append(CCFLAGS = '-DREQUIRES_ULONG')
654  if not conf.CheckType('uint','#include <sys/types.h>\n'):
655  conf.env.Append(CCFLAGS = '-DREQUIRES_UINT')
656 
657 
658  # Check for floating point format...
659  if not conf.CheckForIEC559():
660  print 'Error- your system must use the IEC559/IEEE754 floating point'
661  print ' format for Gromacs support in LOOS. Check your compiler'
662  print ' options or contact the LOOS developers at'
663  print ' loos.maintainer@gmail.com'
664  conf.env.Exit(1)
665 
666  # --- NetCDF Autoconf
667  has_netcdf = 0
668  if conf.env['NETCDF_LIBS']:
669  netcdf_libs = env['NETCDF_LIBS']
670  conf.env.Append(CCFLAGS=['-DHAS_NETCDF'])
671  has_netcdf = 1
672  else:
673  if conf.CheckLibWithHeader('netcdf', 'netcdf.h', 'c'): # Should we check C or C++?
674  netcdf_libs = 'netcdf'
675  conf.env.Append(CCFLAGS=['-DHAS_NETCDF'])
676  has_netcdf = 1
677 
678  conf.env['HAS_NETCDF'] = has_netcdf
679 
680 
681  # --- Swig Autoconf (unless user requested NO PyLOOS)
682  if int(env['pyloos']):
683  if conf.CheckForSwig(loos_build_config.min_swig_version):
684  conf.env['pyloos'] = 1
685  pythonpath = distutils.sysconfig.get_python_inc()
686  conf.env.Append(CPPPATH=[pythonpath])
687  if not conf.CheckNumpy(pythonpath):
688  print 'ERROR- PyLOOS build requires NumPy'
689  conf.env.Exit(1)
690  else:
691  conf.env['pyloos'] = 0
692 
693  # --- Boost Autoconf
694  if not conf.CheckBoostHeaders():
695  conf.env.Exit(1)
696 
697  if not conf.CheckBoostHeaderVersion(loos_build_config.min_boost_version):
698  conf.env.Exit(1)
699 
700  if conf.env['BOOST_LIBS']:
701  boost_libs = env.Split(env['BOOST_LIBS'])
702  else:
703  if not loos_build_config.user_boost_flag:
704  boost_libs = AutoConfigSystemBoost(conf)
705  else:
706  boost_libs = AutoConfigUserBoost(conf)
707 
708  env.Append(LIBS = boost_libs)
709 
710 
711  # --- Check for ATLAS/LAPACK and how to build
712 
713  # MacOS will use accelerate framework, so skip all of this...
714  if loos_build_config.host_type != 'Darwin':
715  atlas_libs = '' # List of numerics libs required for LOOS
716 
717  if env['ATLAS_LIBS']:
718  atlas_libs = env.Split(env['ATLAS_LIBS'])
719  else:
720 
721  numerics = { 'satlas' : 0,
722  'atlas' : 0,
723  'lapack' : 0,
724  'f77blas' : 0,
725  'cblas' : 0,
726  'blas' : 0 }
727 
728 
729 
730  if use_threads:
731  numerics['tatlas'] = 0
732  numerics['ptcblas'] = 0
733  numerics['ptf77blas'] = 0
734 
735  for libname in numerics:
736  if conf.CheckLib(libname, autoadd = 0):
737  numerics[libname] = 1
738 
739  atlas_libs = []
740  atlas_name = ''
741 
742  has_gfortran = 0
743  if conf.CheckLib('gfortran', autoadd = 0):
744  has_gfortran = 1
745 
746  if use_threads and numerics['tatlas']:
747  atlas_libs.append('tatlas')
748  atlas_name = 'tatlas'
749  elif numerics['satlas']:
750  atlas_libs.append('satlas')
751  atlas_name = 'satlas'
752  else:
753 
754  if (numerics['lapack']):
755  atlas_libs.append('lapack')
756 
757  if (use_threads and (numerics['ptf77blas'] and numerics['ptcblas'])):
758  atlas_libs.extend(['ptf77blas', 'ptcblas'])
759  elif (numerics['f77blas'] and numerics['cblas']):
760  atlas_libs.extend(['f77blas', 'cblas'])
761  elif (numerics['blas']):
762  atlas_libs.append('blas')
763  else:
764  print 'Error- you must have some kind of blas installed'
765  conf.env.Exit(1)
766 
767  if (numerics['atlas']):
768  atlas_libs.append('atlas')
769  atlas_name = 'atlas'
770 
771  # Try to figure out how to build with ATLAS...
772  # We need these functions, so find a combination of libs and
773  # libpaths will work...
774  for funcname in ('dgesvd_', 'dgemm_', 'dtrmm_', 'dsyev_'):
775  (ok, requires_gfortran) = checkForFunction(conf, funcname, atlas_libs, has_gfortran)
776  if requires_gfortran:
777  print 'Build Requires gfortran'
778  atlas_libs.append('gfortran')
779 
780  if not ok:
781  lib = checkLibsForFunction(conf, funcname, numerics.keys(), atlas_libs)
782  if lib:
783  atlas_libs.insert(0, lib)
784  else:
785  # Try putting scanning default_lib_path first...SUSE requires
786  # the lapack in /usr/lib first...
787  print 'Searching %s first for libraries...' % default_lib_path
788  # Remove the default_lib_path from the list and prepend...
789  libpaths = list(conf.env['LIBPATH'])
790  libpaths.remove(default_lib_path)
791  libpaths.insert(0, default_lib_path)
792  conf.env['LIBPATH'] = libpaths
793  (ok, requires_gfortran) = checkForFunction(conf, funcname, atlas_libs, has_gfortran)
794  if requires_gfortran:
795  print 'Build requires gfortran'
796  atlas_libs.append('gfortran')
797 
798  if not ok:
799  lib = checkLibsForFunction(conf, funcname, numerics.keys(), atlas_libs)
800  if lib:
801  atlas_libs.insert(0, lib)
802  else:
803  print 'Error- could not figure out where ', funcname, ' is located.'
804  print 'Try manually specifying ATLAS_LIBS and ATLAS_LIBPATH'
805  conf.env.Exit(1)
806 
807 
808 
809 
810  # Hack to extend list rather than append a list into a list
811  for lib in atlas_libs:
812  conf.env.Append(LIBS=lib)
813 
814 
815  # Suppress those annoying maybe used unitialized warnings that -Wall gives us...
816  ccflags = conf.env['CCFLAGS']
817  conf.env.Append(CCFLAGS=['-Wno-maybe-uninitialized', '-Werror']) # Try suppressing, make bad flags an error
818  ok = conf.TryCompile('', '.c')
819  conf.env['CCFLAGS'] = ccflags
820  if ok:
821  conf.env.Append(CCFLAGS=['-Wno-maybe-uninitialized'])
822 
823  environOverride(conf)
824  if 'LIBS' in conf.env:
825  print 'Autoconfigure will use these libraries to build LOOS:\n\t', conf.env['LIBS']
826  if 'LIBPATH' in conf.env:
827  print 'Autoconfigure will add the following directories to find libs:\n\t', conf.env['LIBPATH']
828  env = conf.Finish()
829 
830 #########################################################################################3
831 
832 def addDeprecatedOptions(opt):
833  from SCons.Variables import PathVariable
834 
835  opt.Add(PathVariable('LAPACK', 'Path to LAPACK', '', PathVariable.PathAccept))
836  opt.Add(PathVariable('ATLAS', 'Path to ATLAS', '', PathVariable.PathAccept))
837  opt.Add(PathVariable('ATLASINC', 'Path to ATLAS includes', '', PathVariable.PathAccept))
838  opt.Add(PathVariable('BOOSTLIB', 'Path to BOOST libraries', '', PathVariable.PathAccept))
839  opt.Add(PathVariable('BOOSTINC', 'Path to BOOST includes', '', PathVariable.PathAccept))
840  opt.Add('BOOSTREGEX', 'Boost regex library name', '')
841  opt.Add('BOOSTPO', 'Boost program options library name', '')
842  opt.Add(PathVariable('LIBXTRA', 'Path to additional libraries', '', PathVariable.PathAccept))
843  opt.Add(PathVariable('NETCDFINC', 'Path to netcdf include files', '', PathVariable.PathAccept))
844  opt.Add(PathVariable('NETCDFLIB', 'Path to netcdf library files', '', PathVariable.PathAccept))
845  opt.Add(PathVariable('ALTPATH', 'Additional path to commands', '', PathVariable.PathAccept))
846  opt.Add(PathVariable('LIBS_OVERRIDE', 'Override linked libs', '', PathVariable.PathAccept))
847  opt.Add(PathVariable('LIBS_PATHS_OVERRIDE', 'Override paths to libs', '', PathVariable.PathAccept))
848 
849 def makeDeprecatedVariableWarning():
850  state = { 'warned' : 0 }
851 
852  def warning(what, mapto):
853  if not state['warned']:
854  state['warned'] = 1
855  print """
856 ***WARNING***
857 You are using old-style (deprecated) variables either
858 on the command line or in your custom.py file. These
859 will be ignored. The following deprecated variables
860 are set,
861 """
862  print '\t%s: %s' % (what, mapto)
863  return warning
864 
865 
866 def checkForDeprecatedOptions(env):
867  mapping = {
868  'LAPACK' : 'use ATLAS_LIBPATH',
869  'ATLAS' : 'use ATLAS_LIBPATH',
870  'ATLASINC' : 'no replacement',
871  'BOOSTLIB' : 'use BOOST_LIBPATH or BOOST',
872  'BOOSTINC' : 'use BOOST_INCLUDE or BOOST',
873  'BOOSTREGEX' : 'use BOOST_LIBS',
874  'BOOSTPO' : 'use BOOST_LIBS',
875  'LIBXTRA' : 'use ATLAS_LIBS, BOOST_LIBS, or NETCDF_LIBS',
876  'NETCDFINC' : 'use NETCDF_INCLUDE or NETCDF',
877  'NETCDFLIB' : 'use NETCDF_LIBPATH or NETCDF',
878  'ALTPATH' : 'Set your shell PATH instead',
879  'LIBS_OVERRIDE' : 'use ATLAS_LIBS, BOOST_LIBS, or NETCDF_LIBS',
880  'LIBS_PATHS_OVERRIDE' : 'use ATLAS_LIBPATH, BOOST_LIBPATH, or NETCDF_LIBPATH'
881  }
882 
883  warner = makeDeprecatedVariableWarning()
884  for name in mapping:
885  if env.has_key(name):
886  if env[name]:
887  warner(name, mapping[name])