#!/usr/bin/python3 #Python3 compilation library #Aaron M. Schinder #29 Dec 2020 # #Cleanup and refactor from 2017 python2 version compilation libraries import os,sys,math,subprocess ##################### #Directory Functions# ##################### ##flist - list all files in a given directory pth ##optional arguments: # recurse - (T/F): Whether to recursively search for files in directory tree # exts - (list): A list of file extensions to filter on # normpath (T/F): whether to normalize path variables after #filelist = flist(pth,**kwargs): def flist(pth,**kwargs): flst = [] if(not('recurse' in kwargs)): recurse_ = False else: recurse_ = kwargs['recurse'] if(not('exts' in kwargs)): filterexts_ = False else: filterexts_ = True exts = kwargs['exts'] if(not('normpath' in kwargs)): normpath_ = True else: normpath_ = kwargs['normpath'] if(not('linuxpath' in kwargs)): linuxpath_ = False else: linuxpath_ = kwargs['linuxpath'] if(not('followlinks' in kwargs)): followlinks_ = False else: followlinks_ = kwargs['followlinks'] dirlist = [] rawlist = os.listdir(pth) for F in rawlist: F2 = os.path.join(pth,F) if(os.path.isdir(F2)): b = (followlinks_) or ((not followlinks_) and not(os.path.islink(F2))) if(b): if((F2!=".")&(F2!="..")): dirlist.append(F2) elif(os.path.isfile(F2)): flst.append(F2) #Recurse through directories if(recurse_): for D in dirlist: lst = flist(D,**kwargs) for L in lst: flst.append(L) #Postprocess: #Filter out all extensions except the selected ext list if(filterexts_): flst = filterexts(flst,exts) #Normalize filename path according to os if(normpath_): flst2 = list(flst) for I in range(0,len(flst2)): flst[I] = os.path.normpath(flst2[I]) #If linuxpath, convert all \\ to / #if(linuxpath_): # flst2 = list(flst) # for I in range(0,len(flst2)): # flst[I] = linuxpath(flst2[I]) return flst #Filters by extensions in a list of files #flst = def filterexts(flst,exts): def filterexts(flst,exts): flst2 = [] if(isinstance(exts,str)): exts = list([exts]) for F in flst: b = False for ext in exts: if(ext[0]!='.'): ext = '.'+ext F2 = os.path.splitext(F) if(len(F2)>=2): ex = F2[1] if(len(ex)>0): if(ex[0]!='.'): ex = '.'+ex if(ex==ext): b = True if(b): flst2.append(F) return flst2 #Find a file fname, starting in pth and recursing #Used for finding library files to link def findfile(fname,pth,**kwargs): fullfname = "" flst = flist(pth,recurse=True) for F in flst: F2 = os.path.split(F)[1] if(F2 == fname): fullfname = F return fullfname #List to space-seperated-string def list_to_sss(lst): lout = "" for I in range(0,len(lst)-1): lout = lout + lst[I] + " " if(len(lst)>0): lout = lout + lst[len(lst)-1] return lout def strip_whitespace(strin): strout = "" I1 = -1 I2 = -1 for I in range(0,len(strin)): if(strin[I]!=' ' and strin[I]!='\t' and strin[I]!='\r'and strin[I]!='\n'): I1 = I break q = list(range(0,len(strin))) q.reverse() for I in q: if(strin[I]!=' ' and strin[I]!='\t' and strin[I]!='\r'and strin[I]!='\n'): I2 = I+1 break if(I1>=0 and I2>=0): strout = strin[I1:I2] return strout def sss_to_list(sss): lout = [] l1 = sss.split(' ') for l in l1: l2 = strip_whitespace(l) lout.append(l2) return lout def replaceext(fname,ext): fname2 = "" if(len(ext)>0): if(ext[0]!='.'): ext = '.'+ext fname2 = os.path.splitext(fname)[0]+ext else: fname2 = os.path.splitext(fname)[0] return fname2 def replaceexts(fnamelist,ext): fname2list = [] for F in fnamelist: F2 = replaceext(F,ext) fname2list.append(F2) return fname2list # def except_contains_oldv(lst1,exc): # lst2 = [] # for item in lst1: # b = 1 # for item2 in exc: # if(item.find(item2)>=0): # b = 0 # break # if(b==1): # lst2.append(item) # return lst2 #filenames must match def except_contains(lst1,exc): lst2 = [] for item in lst1: b = 1 for item2 in exc: fsplit = os.path.split(item) fn = fsplit[len(fsplit)-1] if(fn==item2): b = 0 break if(b==1): lst2.append(item) return lst2 ########################## ##System Call Procedures## ########################## def callproc(cmd, **kwargs): if(not('logfile' in kwargs)): use_lf = False else: logfile = kwargs['logfile'] if(logfile!=""): fp = open(kwargs['logfile'],'a+') use_lf = True else: use_lf = False if(not('echo' in kwargs)): echo = True else: echo = kwargs['echo'] if(echo): print(cmd) #encoding/deconding to/from bytes is necessary to use the subprocess command #in python3.7 cmd2 = cmd.encode(encoding='utf-8') proc = subprocess.Popen(cmd2,stderr = subprocess.STDOUT, stdout=subprocess.PIPE, shell=True) (out, err) = proc.communicate() out = out.decode(encoding='utf-8') if(echo): print(out) #print(err); if(use_lf): fp.writelines(cmd+'\n') fp.writelines(out+'\n') if(use_lf): fp.close() ####################################### ##Compiler, Archive, and Linker Calls## ####################################### def smartcompile(srcfile,objext='.o'): mtsrc = os.path.getmtime(srcfile) objfile = replaceext(srcfile,objext) objexists = os.path.exists(objfile) ret = True if(objexists): mtobj = os.path.getmtime(objfile) if(mtobj>=mtsrc): ret = False return ret #gnu-style compiler compile: Should work with gcc, g++, gfortran def gs_compile(compiler,srcfile,**kwargs): if(not('include' in kwargs)): include = '' else: include = kwargs['include'] if(isinstance(include,list)): include = list_to_sss(include) if(not('flags' in kwargs)): flags = '' else: flags = kwargs['flags'] if(isinstance(flags,list)): flags = list_to_sss(flags) if(not('objext' in kwargs)): objext = '.o' else: objext = kwargs['objext'] if(not('srcfileflag' in kwargs)): srcfileflag = '-c' else: srcfileflag = kwargs['srcfileflag'] if(not('outfileflag' in kwargs)): outfileflag = '-o' else: outfileflag = kwargs['outfileflag'] if(not('logfile' in kwargs)): logfile = "" else: logfile = kwargs['logfile'] if(not('smartcompile' in kwargs)): _smartcompile = True else: _smartcompile = kwargs['smartcompile'] #Do I want to make this thing this general? if(not(_smartcompile) or smartcompile(srcfile,objext)): outfile = replaceext(srcfile,objext) ln = compiler+" "+flags+" " + outfileflag+" "+outfile+" "+srcfileflag+" "+srcfile ln = ln + " " + include callproc(ln,echo=True,logfile=logfile) return def gs_compile_list(compiler,srclist,**kwargs): for S in srclist: gs_compile(compiler,S,**kwargs) return def gs_compile_all(compiler,srcdir,srcexts,**kwargs): if(not('recurse' in kwargs)): recurse = True else: recurse = kwargs['recurse'] srcfils = flist(srcdir,exts=srcexts,recurse=recurse) for S in srcfils: gs_compile(compiler,S,**kwargs) return def gs_link_all(linker,srcpath,target,**kwargs): if(not('objext' in kwargs)): objext = '.o' else: objext = kwargs['objext'] if(not('recurse' in kwargs)): recurse = True else: recurse = kwargs['recurse'] objfils = flist(srcpath,exts=objext,recurse=recurse) oflst = list_to_sss(objfils) gs_link_list(linker,oflst,target,**kwargs) return def gs_link_list(linker,objlist,target,**kwargs): if(not('objext' in kwargs)): objext = '.o' else: objext = kwargs['objext'] if(not('libdir' in kwargs)): libdir = '' else: libdir = kwargs['libdir'] if(not('staticlibs' in kwargs)): staticlibs = '' else: staticlibs = kwargs['staticlibs'] if(not('libflags' in kwargs)): libflags = '' else: libflags = kwargs['libflags'] if(not('linkerflags' in kwargs)): linkerflags = '' else: linkerflags = kwargs['linkerflags'] if(not('recurse' in kwargs)): recurse = True else: recurse = kwargs['recurse'] if(not('logfile' in kwargs)): logfile = '' else: logfile = kwargs['logfile'] ln = linker+" -o "+target+" "+libdir ln = ln+" "+objlist+" "+staticlibs+" "+libflags+" "+linkerflags callproc(ln,logfile=logfile) return def ar_all(srcpath,arname,**kwargs): if(not('recurse' in kwargs)): recurse = True else: recurse = kwargs['recurse'] if(not('objext' in kwargs)): objext = '.o' else: objext = kwargs['objext'] objlist = flist(srcpath,exts=objext,recurse=recurse) ar_list(objlist,arname,**kwargs) return def ar_list(objlist,arname,**kwargs): objlist2 = list_to_sss(objlist) ln = "ar cr "+ arname+" "+objlist2 callproc(ln) return def ar_add_list(objlist,arname,**kwargs): objlist2 = list_to_sss(objlist) ln = "ar t "+arname+" "+objlist2 callproc(ln) return ############################## ##Derived Compiler Functions## ############################## def gcc_compile(srcfile,**kwargs): compiler = 'gcc' kwargs['objext'] = '.o' #srcexts = ['.c'] gs_compile(compiler,srcfile,**kwargs) return def gcc_compile_all(srcdir,**kwargs): compiler = 'gcc' kwargs['objext'] = '.o' srcexts = ['.c'] gs_compile_all(compiler,srcdir,srcexts,**kwargs) return def gcc_compile_list(srclist,**kwargs): compiler = 'gcc' kwargs['objext'] = '.o' #srcexts = ['.c'] gs_compile_list(compiler,srclist,**kwargs) return def gpp_compile(srcfile,**kwargs): compiler = 'g++' kwargs['objext'] = '.o' #srcexts = ['.c','.cpp'] gs_compile(compiler,srcfile,**kwargs) return def gpp_compile_all(srcdir,**kwargs): compiler = 'g++' kwargs['objext'] = '.o' srcexts = ['.c','.cpp'] gs_compile_all(compiler,srcdir,srcexts,**kwargs) return def gpp_compile_list(srclist,**kwargs): compiler = 'g++' kwargs['objext'] = '.o' #srcexts = ['.c','.cpp'] gs_compile_list(compiler,srclist,**kwargs) return def gfortran_compile(srcfile,**kwargs): compiler = 'gfortran' kwargs['objext'] = '.o' #srcexts = ['.f','.f90','.f77'] gs_compile(compiler,srcfile,**kwargs) return def gfortran_compile_all(srcdir,**kwargs): compiler = 'gfortran' kwargs['objext'] = '.o' srcexts = ['.f','.f90','.f77'] gs_compile_all(compiler,srcdir,srcexts,**kwargs) return def gfortran_compile_list(srclist,**kwargs): compiler = 'gfortran' kwargs['objext'] = '.o' #srcexts = ['.f','.f90','.f77'] gs_compile_list(compiler,srclist,**kwargs) return def clang_compile(srcfile,**kwargs): compiler = 'clang++' kwargs['objext'] = '.o' #srcexts = ['.c','.cpp'] gs_compile(compiler,srcfile,**kwargs) return def clang_compile_all(srcdir,**kwargs): compiler = 'clang++' kwargs['objext'] = '.o' srcexts = ['.c','.cpp'] gs_compile_all(compiler,srcdir,srcexts,**kwargs) return def clang_compile_list(srclist,**kwargs): compiler = 'clang++' kwargs['objext'] = '.o' #srcexts = ['.c','.cpp'] gs_compile_list(compiler,srclist,**kwargs) return