Advertisement
Guest User

SConstruct

a guest
Jul 16th, 2014
293
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.95 KB | None | 0 0
  1. # preCICE/SConstruct
  2.  
  3. # Main buildfile for Linux based systems.
  4.  
  5. import os
  6.  
  7. ##################################################################### FUNCTIONS
  8.  
  9. def uniqueCheckLib(conf, lib):
  10.     """ Checks for a library and appends it to env if not already appended. """
  11.     if conf.CheckLib(lib, autoadd=0):
  12.         conf.env.AppendUnique(LIBS = [lib])
  13.         return True
  14.     else:
  15.         return False
  16.        
  17. def errorMissingLib(lib, usage):
  18.     print "ERROR: Library '" + lib + "' (needed for " + usage + ") not found!"
  19.     Exit(1)
  20.    
  21. def errorMissingHeader(header, usage):
  22.     print "ERROR: Header '" + header + "' (needed for " + usage + ") not found or does not compile!"
  23.     Exit(1)
  24.    
  25. def print_options(vars):
  26.     """ Print all build option and if they have been modified from their default value. """    
  27.     for opt in vars.options:
  28.         try:
  29.             is_default = vars.args[opt.key] == opt.default
  30.         except KeyError:
  31.             is_default = True
  32.         vprint(opt.key, env[opt.key], is_default, opt.help)
  33.  
  34. def vprint(name, value, default=True, description = None):
  35.     """ Pretty prints an environment variabe with value and modified or not. """
  36.     mod = "(default)" if default else "(modified)"
  37.     desc = "   " + description if description else ""
  38.     print "{:10} {:25} = {!s:6}{}".format(mod, name, value, desc)
  39.  
  40. def checkset_var(varname, default):
  41.     """ Checks if environment variable is set, use default otherwise and print the value. """    
  42.     var = os.getenv(varname)
  43.     if not var:
  44.         var = default
  45.         vprint(varname, var)
  46.     else:
  47.         vprint(varname, var, False)
  48.     return var
  49.  
  50. def compiler_validator(key, value, environment):
  51.     """ Validator function for the compiler option. Checks if the given compiler is either (g++ or icc or clang++) or an MPI compiler. """
  52.     if value in ["g++", "icc", "clang++"] or value.startswith("mpic"):
  53.         return True
  54.     else:
  55.         return False
  56.        
  57.  
  58. ########################################################################## MAIN
  59.    
  60. vars = Variables(None, ARGUMENTS)
  61.  
  62. vars.Add(PathVariable("builddir", "Directory holding build files.", "build", PathVariable.PathAccept))
  63. vars.Add(EnumVariable('build', 'Build type, either release or debug', "debug", allowed_values=('release', 'debug')))
  64. vars.Add("compiler", "Compiler must be either g++ or icc or clang++ or starting with mpic when using MPI.", "g++", validator=compiler_validator)
  65. vars.Add(BoolVariable("mpi", "Enables MPI-based communication and running coupling tests.", True))
  66. vars.Add(BoolVariable("sockets", "Enables Socket-based communication.", True))
  67. vars.Add(BoolVariable("boost_inst", "Enable if Boost is available compiled and installed.", False))
  68. vars.Add(BoolVariable("spirit2", "Used for parsing VRML file geometries and checkpointing.", True))
  69. vars.Add(BoolVariable("python", "Used for Python scripted solver actions.", True))
  70. vars.Add(BoolVariable("gprof", "Used in detailed performance analysis.", False))
  71.  
  72.  
  73. env = Environment(variables = vars)   # For configuring build variables
  74. conf = Configure(env) # For checking libraries, headers, ...
  75.  
  76.  
  77. Help(vars.GenerateHelpText(env))
  78. env.Append(CPPPATH = ['#src'])
  79. # env.Append(CPPDEFINES = ['tarch=tarchp2']) # Was (!) needed for linking to Peano 1
  80.  
  81. # Produce position independent code for dynamic linking. makes a difference on the m68k, PowerPC and SPARC.
  82. env.Append(CCFLAGS = ['-fPIC'])
  83.  
  84.  
  85. #---------------------------------------------------------- Check build options
  86.  
  87. print
  88. print "Build options ..."
  89. print_options(vars)
  90.  
  91. buildpath = os.path.join(env["builddir"], "") # Ensures to have a trailing slash
  92.  
  93. if not env["mpi"] and env["compiler"].startswith('mpic'):
  94.     print "ERROR: Option 'compiler' must be set to an MPI compiler wrapper only when using MPI!"
  95.     Exit(1)
  96.      
  97. print '... done'
  98.  
  99.  
  100. #-------------------------------------------------- Fetch environment variables
  101.  
  102. print
  103. print 'Environment variables used for this build ...'
  104. print '(have to be defined by the user to configure build)'
  105.  
  106. boostRootPath = checkset_var('PRECICE_BOOST_ROOT', "./src")
  107.  
  108. if env["boost_inst"]:
  109.     if env["sockets"]:
  110.         boostLibPath = checkset_var('PRECICE_BOOST_LIB_PATH', "/usr/lib/")
  111.         boostSystemLib = checkset_var('PRECICE_BOOST_SYSTEM_LIB', "boost_system")
  112.         boostThreadLib = checkset_var('PRECICE_BOOST_THREAD_LIB', "boost_thread")
  113.  
  114.      
  115.    #boostIncPath = os.getenv('PRECICE_BOOST_INC_PATH')
  116.    #if ((boostIncPath == None) or (boostIncPath == "")):
  117.    #   boostIncPath = '/usr/include/'
  118.    #   print 'PRECICE_BOOST_INC_PATH = ' + boostIncPath + ' (default)'  
  119.    #else:
  120.    #   print 'PRECICE_BOOST_INC_PATH =', boostIncPath
  121.  
  122. if env["mpi"]:
  123.     mpiLibPath = checkset_var('PRECICE_MPI_LIB_PATH', "/usr/lib/")
  124.    
  125.     # Determine MPI library name
  126.     mpiLib = checkset_var('PRECICE_MPI_LIB', "mpich")
  127.     mpiIncPath = checkset_var('PRECICE_MPI_INC_PATH', '/usr/include/mpich2')
  128.    
  129.  
  130. if env["sockets"]:
  131.     socketLibPath = checkset_var('PRECICE_SOCKET_LIB_PATH', "/usr/lib")
  132.     socketLib = checkset_var('PRECICE_SOCKET_LIB', "pthread")
  133.     socketIncPath =  checkset_var('PRECICE_SOCKET_INC_PATH', '/usr/include')
  134.  
  135.  
  136. #useSAGA = ARGUMENTS.get('saga', 'off')
  137. #if useSAGA == 'off':
  138. #    cppdefines.append('PRECICE_NO_SAGA')
  139. #elif useSAGA == 'on':
  140. #    libs.append('saga_package_advert')
  141. #    libs.append('xyz')
  142. #    libpath.append('/opt/saga-1.5.4/lib/')
  143.  
  144.  
  145. if env["python"]:
  146.     pythonLibPath = checkset_var('PRECICE_PYTHON_LIB_PATH', '/usr/lib/')
  147.     pythonLib = checkset_var('PRECICE_PYTHON_LIB', "python2.7")
  148.     pythonIncPath = checkset_var('PRECICE_PYTHON_INC_PATH', '/usr/include/python2.7/')
  149.     numpyIncPath = checkset_var('PRECICE_NUMPY_INC_PATH',  '/usr/include/python2.7/numpy/')
  150.  
  151. print '... done'
  152.  
  153.  
  154.  
  155. #---------------------------- Modify environment according to fetched variables
  156.  
  157. print
  158. print 'Configuring build variables ...'
  159.  
  160. env.Replace(ENV = os.environ)
  161.  
  162. env.Append(LIBPATH = [('#' + buildpath)])
  163.  
  164. if env["compiler"] == 'icc':
  165.     env.AppendUnique(LIBPATH = ['/usr/lib/'])
  166.     env.Append(LIBS = ['stdc++'])
  167.     if env["build"] == 'debug':
  168.         env.Append(CCFLAGS = ['-align'])
  169.     elif env["build"] == 'release':
  170.         env.Append(CCFLAGS = ['-w', '-fast', '-align', '-ansi-alias'])
  171. elif env["compiler"] == 'g++':
  172.     pass
  173. elif env["compiler"] == "clang++":
  174.     env.Append(CCFLAGS = ["-stdlib=libc++"])
  175.    
  176. env.Replace(CXX = env["compiler"])
  177.  
  178.  
  179. if env["build"] == 'debug':
  180.     env.Append(CPPDEFINES = ['Debug', 'Asserts'])
  181.     env.Append(CCFLAGS = ['-g3', '-O0'])
  182.     buildpath += "debug"
  183. elif env["build"] == 'release':
  184.     env.Append(CCFLAGS = ['-O3'])
  185.     buildpath += "release"    
  186.  
  187.  
  188.  
  189. if env["boost_inst"]:
  190.     #env.AppendUnique(CPPPATH = [boostIncPath])
  191.     # The socket implementation is based on Boost libs
  192.     if env["sockets"]:
  193.         env.AppendUnique(LIBPATH = [boostLibPath])
  194.     if not uniqueCheckLib(conf, boostSystemLib):
  195.         errorMissingLib(boostSystemLib, 'Boost')
  196.     if not uniqueCheckLib(conf, boostThreadLib):
  197.         errorMissingLib(boostThreadLib, 'Boost')
  198. env.AppendUnique(CPPPATH = [boostRootPath])
  199. if not conf.CheckCXXHeader('boost/array.hpp'):
  200.     errorMissingHeader('boost/array.hpp', 'Boost')
  201.    
  202.    
  203. if not env["spirit2"]:
  204.     env.Append(CPPDEFINES = ['PRECICE_NO_SPIRIT2'])
  205.     env["buildpath"] += "-nospirit2"
  206.      
  207.  
  208. if env["mpi"]:
  209.     if not env["compiler"].startswith('mpic'):
  210.         env.AppendUnique(LIBPATH = [mpiLibPath])
  211.         if not uniqueCheckLib(conf, mpiLib):
  212.             errorMissingLib(mpiLib, 'MPI')
  213.         if (mpiLib == 'mpich'): # MPICH1/2/3 library
  214.             uniqueCheckLib(conf, 'mpl')
  215.             uniqueCheckLib(conf, 'pthread')
  216.             #conf.CheckLib('pthread')
  217.         elif (mpiLib == 'mpi'): # OpenMPI library
  218.             uniqueCheckLib(conf, 'mpi_cxx')  
  219.         env.AppendUnique(CPPPATH = [mpiIncPath])
  220.         if not conf.CheckHeader('mpi.h'):
  221.             errorMissingHeader('mpi.h', 'MPI')
  222. elif not env["mpi"]:
  223.     env.Append(CPPDEFINES = ['PRECICE_NO_MPI'])
  224.     buildpath += "-nompi"
  225. uniqueCheckLib(conf, 'rt') # To work with tarch::utils::Watch::clock_gettime
  226.  
  227.  
  228.  
  229. if env["sockets"]:
  230.     env.AppendUnique(LIBPATH = [socketLibPath])
  231.     uniqueCheckLib(conf, socketLib)
  232.     env.AppendUnique(CPPPATH = [socketIncPath])
  233.     if socketLib == 'pthread':
  234.         if not conf.CheckHeader('pthread.h'):
  235.             errorMissingHeader('pthread.h', 'Sockets')
  236.     #env.Append(LINKFLAGS = ['-pthread']) # Maybe better???
  237. else:
  238.     env.Append(CPPDEFINES = ['PRECICE_NO_SOCKETS'])
  239.     buildpath += "-nosockets"
  240.  
  241. if env["python"]:
  242.     env.AppendUnique(LIBPATH = [pythonLibPath])
  243.     if not uniqueCheckLib(conf, pythonLib):
  244.         errorMissingLib(pythonLib, 'Python')
  245.     env.AppendUnique(CPPPATH = [pythonIncPath, numpyIncPath])
  246.     if not conf.CheckHeader('Python.h'):
  247.         errorMissingHeader('Python.h', 'Python')
  248.     # Check for numpy header needs python header first to compile
  249.     if not conf.CheckHeader(['Python.h', 'arrayobject.h']):
  250.         errorMissingHeader('arrayobject.h', 'Python NumPy')
  251. else:
  252.     buildpath += "-nopython"
  253.     env.Append(CPPDEFINES = ['PRECICE_NO_PYTHON'])
  254.  
  255.  
  256. if env["gprof"]:
  257.     env.Append(CCFLAGS = ['-p', '-pg'])
  258.     env.Append(LINKFLAGS = ['-p', '-pg'])
  259.     buildpath += "-gprof"
  260.  
  261. print '... done'
  262.  
  263.  
  264. env = conf.Finish() # Used to check libraries
  265.  
  266. #--------------------------------------------- Define sources and build targets
  267.    
  268. (sourcesPreCICE, sourcesPreCICEMain) = SConscript (
  269.     'src/SConscript-linux',
  270.     variant_dir = buildpath,
  271.     duplicate = 0
  272. )
  273.  
  274. sourcesBoost = []
  275. if env["sockets"] and not env["boost_inst"]:
  276.     print
  277.     print "Copy boost sources for socket communication to build ..."
  278.     if not os.path.exists(buildpath + "/boost/"):
  279.         Execute(Mkdir(buildpath + "/boost/"))
  280.     for file in Glob(boostRootPath + "/libs/system/src/*"):
  281.         Execute(Copy(buildpath + "/boost/", file))  
  282.     for file in Glob(boostRootPath + "/libs/thread/src/pthread/*"):
  283.         Execute(Copy(buildpath + "/boost/", file))  
  284.     sourcesBoost = Glob(buildpath + '/boost/*.cpp')
  285.     print "... done"
  286.    
  287.  
  288. lib = env.StaticLibrary (
  289.     target = buildpath + '/libprecice',
  290.     source = [sourcesPreCICE,
  291.               sourcesBoost]
  292. )
  293.    
  294. bin = env.Program (
  295.     target = buildpath + '/binprecice',
  296.     source = [sourcesPreCICEMain,
  297.               sourcesBoost]
  298. )
  299.  
  300. Default(lib, bin)
  301. givenBuildTargets = map(str, BUILD_TARGETS)
  302. #print "Build targets before conversion:", buildtargets
  303. for i in range(len(givenBuildTargets)):
  304.     if givenBuildTargets[i] == "lib":
  305.         BUILD_TARGETS[i] = lib[0]
  306.     elif givenBuildTargets[i] == "bin":
  307.         BUILD_TARGETS[i] = bin[0]
  308.      
  309.  
  310. buildTargets = ""
  311. for target in map(str, BUILD_TARGETS):
  312.     if buildTargets != "":
  313.         buildTargets += ", "
  314.     buildTargets += target
  315.  
  316.  
  317. ##### Print build summary
  318.  
  319. print
  320. print "Targets:   " + buildTargets
  321. print "Buildpath: " + buildpath
  322. print
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement