#!/usr/bin/env python import os,re,sys,string,subprocess,shutil from optparse import OptionParser, Option # ----------------------------- class extendableOption(Option): # ----------------------------- # used for definition of new option parser action 'extend', which enables to take multiple option arguments # taken from online tutorial http://docs.python.org/library/optparse.html ACTIONS = Option.ACTIONS + ("extend",) STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",) TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",) ALWAYS_TYPED_ACTIONS = Option.ALWAYS_TYPED_ACTIONS + ("extend",) def take_action(self, action, dest, opt, value, values, parser): if action == "extend": lvalue = value.split(",") values.ensure_value(dest, []).extend(lvalue) else: Option.take_action(self, action, dest, opt, value, values, parser) # ----------------------------- def filePresent(paths,files,warning=False): for path in paths: for file in files: if os.path.isfile(os.path.join(path,file)): return True if warning: print "Warning: %s not found in %s"%(','.join(files),','.join(paths)) return False ######################################################## # MAIN ######################################################## parser = OptionParser(option_class=extendableOption, usage='%prog options', description = """ Configures the compilation and installation of DAMASK """ + string.replace('$Id$','\n','\\n') ) #--- determine default compiler ---------------------------------------------------------------------- compiler = os.getenv('F90') if compiler == None: compiler = 'ifort' if subprocess.call(['which', 'ifort'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0 \ else 'gfortran' #--- default option values -------------------------------------------------------------------------- BLAS_order = ['IMKL','ACML','LAPACK','OPENBLAS'] defaults={'DAMASK_BIN':'depending on access rights', 'F90':compiler, 'FFTW_ROOT':'/usr', 'MSC_ROOT' :'/msc', 'DAMASK_NUM_THREADS':4, 'MARC_VERSION':'2015', 'blasType':'LAPACK', 'blasRoot':{'LAPACK' :'/usr', 'ACML' :'/opt/acml6.1.0', 'IMKL' : os.getenv('MKLROOT') if os.getenv('MKLROOT') else '/opt/intel/composerxe/mkl', 'OPENBLAS' :'/usr', }, 'spectralOptions':{}, } #--- if local config file exists, read, otherwise assume global config file ------------------------ configFile = os.path.join(os.getenv('HOME'),'.damask/damask.conf') \ if os.path.isfile(os.path.join(os.getenv('HOME'),'.damask/damask.conf')) \ else '/etc/damask.conf' #--- set default values according to read in values ------------------------------------------------ try: with open(configFile,'r') as f: print('\n<<<<< reading default values from %s\n'%configFile) for line in f: line = line.strip() if line.startswith('#') or line == '': pass [key,value] = (re.split('[= ]',line)+[None,None])[:2] if key == 'DAMASK_NUM_THREADS': defaults['DAMASK_NUM_THREADS'] = int(value) if key == 'DAMASK_BIN': defaults['DAMASK_BIN'] = value if key in ['F90','FFTW_ROOT','MSC_ROOT','spectralOptions','MARC_VERSION']: defaults[key] = value for theKey in reversed(BLAS_order): if key == theKey+'_ROOT' and value != None and value != '': defaults['blasType'] = theKey defaults['blasRoot'][theKey] = value except IOError: pass parser.add_option('--prefix', dest='prefix', metavar='string', help='location of (links to) DAMASK executables [%default]') parser.add_option('--with-FC','--with-fc', dest='compiler', metavar='string', help='F90 compiler [%default]') parser.add_option('--with-FFTW-dir','--with-fftw-dir', dest='fftwRoot', metavar='string', help='root directory of FFTW [%default]') parser.add_option('--with-MSC-dir','--with-msc-dir', dest='mscRoot', metavar='string', help='root directory of MSC.Marc/Mentat [%default]') parser.add_option('--with-MARC-version','--with-marc-version', dest='marcVersion', metavar='string', help='version of MSC.Marc/Mentat [%default]') parser.add_option('--with-OMP-threads','--with-omp-threads', dest='threads', type='int', metavar='int', help='number of openMP threads [%default]') parser.add_option('--with-BLAS-type','--with-blas-type', dest='blasType', metavar='string', help='type of BLAS/LAPACK library [%default] {{{}}}'.format(','.join(BLAS_order))) parser.add_option('--with-BLAS-dir','--with-blas-dir', dest='blasRoot',metavar='string', help='root directory of BLAS/LAPACK library [%default]') parser.add_option('--with-spectral-options', dest='spectraloptions', action='extend', metavar='', help='options for compilation of spectral solver') parser.set_defaults(prefix = defaults['DAMASK_BIN']) parser.set_defaults(compiler = defaults['F90']) parser.set_defaults(fftwRoot = defaults['FFTW_ROOT']) parser.set_defaults(mscRoot = defaults['MSC_ROOT']) parser.set_defaults(marcVersion = defaults['MARC_VERSION']) parser.set_defaults(threads = defaults['DAMASK_NUM_THREADS']) parser.set_defaults(blasType = defaults['blasType']) #--- set default for blasRoot depending on current option (or default) for blasType -------------------- blasType = defaults['blasType'].upper() for i, arg in enumerate(sys.argv): if arg.lower().startswith('--with-blas-type'): if arg.lower().endswith('--with-blas-type'): blasType = sys.argv[i+1].upper() else: blasType = sys.argv[i][17:].upper() if blasType not in BLAS_order: blasType = defaults['blasType'].upper() parser.set_defaults(blasRoot = defaults['blasRoot'][blasType]) parser.set_defaults(spectraloptions = []) (options,filenames) = parser.parse_args() #--- consistency checks -------------------------------------------------------------------------------- options.compiler = options.compiler.lower() options.blasType = options.blasType.upper() options.fftwRoot = os.path.normpath(options.fftwRoot) options.mscRoot = os.path.normpath(options.mscRoot) options.blasRoot = os.path.normpath(options.blasRoot) locations = { 'FFTW' : [os.path.join(options.fftwRoot,'lib64'),os.path.join(options.fftwRoot,'lib')], 'LAPACK' : [os.path.join(options.blasRoot,'lib64'),os.path.join(options.blasRoot,'lib')], 'OPENBLAS': [os.path.join(options.blasRoot,'lib64'),os.path.join(options.blasRoot,'lib')], 'ACML' : [os.path.join(options.blasRoot,'%s64/lib'%options.compiler)], 'ACML_mp' : [os.path.join(options.blasRoot,'%s64_mp/lib'%options.compiler)], 'IMKL' : [os.path.join(options.blasRoot,'lib/intel64')], } libraries = { 'FFTW' : [ 'libfftw3.so','libfftw3.a', 'libfftw3_threads.so','libfftw3_threads.a', ], 'LAPACK' : [ 'liblapack.so','liblapack.a','liblapack.dylib', ], 'OPENBLAS' : [ 'libopenblas.so','libopenblas.a','libopenblas.dylib', ], 'ACML' : [ 'libacml.so','libacml.a', ], 'ACML_mp' : [ 'libacml_mp.so','libacml_mp.a', ], 'IMKL' : [ 'libmkl_core.so','libmkl_core.a', 'libmkl_sequential.so','libmkl_sequential.a', 'libmkl_intel_thread.so','libmkl_intel_thread.a', 'libmkl_intel_lp64.so','libmkl_intel_lp64.a', 'libmkl_gnu_thread.so','libmkl_gnu_thread.a', 'libmkl_gf_lp64.so','libmkl_gf_lp64.a', ], } if options.compiler not in ['ifort','gfortran']: print('Error: Unknown compiler option: %s'%options.compiler) sys.exit(1) if not subprocess.call(['which', options.compiler], stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0: print('Compiler Warning: executable %s not found!'%options.compiler) if not os.path.isdir(options.mscRoot): print('Warning: MSC root directory %s not found!'%options.mscRoot) filePresent(locations['FFTW'],libraries['FFTW'],warning=True) if options.blasType in ['LAPACK','OPENBLAS','IMKL']: filePresent(locations[options.blasType],libraries[options.blasType],warning=True) elif options.blasType == 'ACML': filePresent(locations[options.blasType],libraries[options.blasType],warning=True) filePresent(locations[options.blasType+'_mp'],libraries[options.blasType+'_mp'],warning=True) else: print('Error: Unknown BLAS/LAPACK library: %s'%options.blasType) sys.exit(1) #--- read config file if present to keep comments and order --------------------------------------- output = [] try: with open(configFile,'r') as f: for line in f: line = line.strip() items = re.split('[= ]',line) if (not line or items[0].startswith('#')): pass if items[0] == 'DAMASK_BIN': line = '%s=%s'%(items[0],options.prefix) options.prefix ='depending on access rights' if items[0] == 'F90': line = '%s=%s'%(items[0],options.compiler) options.compiler ='' if items[0] == 'FFTW_ROOT': line = '%s=%s'%(items[0],options.fftwRoot) options.fftwRoot ='' if items[0] == 'MSC_ROOT': line = '%s=%s'%(items[0],options.mscRoot) options.mscRoot ='' if items[0] == 'MARC_VERSION': line = '%s=%s'%(items[0],options.marcVersion) options.marcVersion ='' if items[0] == 'DAMASK_NUM_THREADS': line = '%s=%s'%(items[0],options.threads) options.threads ='' for blasType in defaults['blasRoot'].keys(): if items[0] == '%s_ROOT'%blasType and items[0] == '%s_ROOT'%options.blasType: line = '%s=%s'%(items[0],options.blasRoot) options.blasType='' elif items[0] == '#%s_ROOT'%blasType and items[0] == '#%s_ROOT'%options.blasType: line = '%s=%s'%(items[0][1:],options.blasRoot) options.blasType='' elif items[0] == '%s_ROOT'%blasType: line = '#'+line for spectralOption in options.spectraloptions: [key,value] = re.split('[= ]',spectralOption)[0:2] if key == items[0]: line = '%s=%s'%(items[0],value) options.spectraloptions.remove(spectralOption) output.append(line) except IOError: pass #--- write remaining options -------------------------------------------------------------------------- for opt, value in options.__dict__.items(): if opt == 'prefix' and value != 'depending on access rights': output.append('DAMASK_BIN=%s'%value) if opt == 'compiler' and value != '': output.append('F90=%s'%value) if opt == 'fftwRoot' and value != '': output.append('FFTW_ROOT=%s'%value) if opt == 'mscRoot' and value != '': output.append('MSC_ROOT=%s'%value) if opt == 'marcVersion' and value != '': output.append('MARC_VERSION=%s'%value) if opt == 'threads' and value != '': output.append('DAMASK_NUM_THREADS=%s'%value) if opt == 'blasType' and value != '': output.append('%s_ROOT=%s'%(options.blasType,options.blasRoot)) for spectralOption in options.spectraloptions: output.append(spectralOption) #--- decide where do save the data ------------------------------------------------------------------- configDir = '/etc' if os.access('/etc/', os.W_OK) \ else os.path.join(os.getenv('HOME'),'.damask') # use system-wide config if possible configFileNew = os.path.join(configDir,'damask.conf') if not os.path.isdir(configDir): os.mkdir(configDir) print('\n>>>>> writing values to %s\n'%configFileNew) with open(configFileNew,'w') as f: for line in output: print(line) f.write(line+'\n')