1import config.package 2 3class Configure(config.package.Package): 4 def __init__(self, framework): 5 config.package.Package.__init__(self, framework) 6 #disable version checking 7 #self.minversion = '4.6' 8 #self.version = '4.6' 9 #self.versionname = 'MFEM_VERSION_STRING' 10 #self.versioninclude = 'mfem/config.hpp' 11 self.gitcommit = '9cd8f53dc6183c1421be3b67d07b02325d0eef4b' # https://github.com/mfem/mfem/pull/5215 12 self.download = ['git://https://github.com/mfem/mfem.git','https://github.com/mfem/mfem/archive/'+self.gitcommit+'.tar.gz'] 13 self.linkedbypetsc = 0 14 self.downloadonWindows = 1 15 self.buildLanguages = ['Cxx'] 16 self.minCxxVersion = 'c++17' 17 self.skippackagewithoptions = 1 18 self.useddirectly = 0 19 self.builtafterpetsc = 1 20 self.noMPIUni = 1 21 self.precisions = ['single', 'double'] 22 return 23 24 def setupHelp(self, help): 25 import nargs 26 config.package.Package.setupHelp(self, help) 27 help.addArgument('MFEM', '-download-mfem-ghv-cxx=<prog>', nargs.Arg(None, None, 'CXX Front-end compiler to compile get_hypre_version')) 28 return 29 30 def setupDependencies(self, framework): 31 config.package.Package.setupDependencies(self, framework) 32 self.hypre = framework.require('config.packages.hypre',self) 33 self.mpi = framework.require('config.packages.MPI',self) 34 self.metis = framework.require('config.packages.METIS',self) 35 self.slepc = framework.require('config.packages.SLEPc',self) 36 self.ceed = framework.require('config.packages.libCEED',self) 37 self.cuda = framework.require('config.packages.CUDA',self) 38 self.hip = framework.require('config.packages.HIP',self) 39 self.openmp = framework.require('config.packages.OpenMP',self) 40 self.superlu_dist = framework.require('config.packages.SuperLU_DIST',self) 41 self.netcdf = framework.require('config.packages.netCDF',self) 42 self.scalar = framework.require('PETSc.options.scalarTypes',self) 43 self.deps = [self.mpi,self.hypre,self.metis] 44 self.odeps = [self.slepc,self.ceed,self.cuda,self.openmp,self.superlu_dist,self.netcdf] 45 return 46 47 def writeConfig(self, g, lib_name, lib_data): 48 lib_name_upper = lib_name.upper() 49 if lib_data.found: 50 g.write('MFEM_USE_{0} = YES\n'.format(lib_name_upper)) 51 g.write('{0}_DIR = {1}\n'.format(lib_name_upper, lib_data.directory)) 52 g.write('{0}_OPT = {1}\n'.format(lib_name_upper, self.headers.toString(lib_data.include))) 53 g.write('{0}_LIB = {1}\n'.format(lib_name_upper, self.libraries.toString(lib_data.lib))) 54 if self.cuda.found: 55 g.write('{0}_LIB := $(subst -Wl,-Xlinker=,$({0}_LIB))\n'.format(lib_name_upper)) 56 57 def Install(self): 58 import os 59 import re 60 61 buildDir = os.path.join(self.packageDir,'petsc-build') 62 configDir = os.path.join(buildDir,'config') 63 if not os.path.exists(configDir): 64 os.makedirs(configDir) 65 66 if self.framework.argDB['prefix'] and not 'package-prefix-hash' in self.argDB: 67 PETSC_DIR = os.path.abspath(os.path.expanduser(self.argDB['prefix'])) 68 PETSC_ARCH = '' 69 prefix = os.path.abspath(os.path.expanduser(self.argDB['prefix'])) 70 else: 71 PETSC_DIR = self.petscdir.dir 72 PETSC_ARCH = self.arch 73 prefix = os.path.join(self.petscdir.dir,self.arch) 74 75 PETSC_OPT = self.headers.toStringNoDupes([os.path.join(PETSC_DIR,'include'),os.path.join(PETSC_DIR,PETSC_ARCH,'include')]) 76 77 self.pushLanguage('Cxx') 78 cxx = self.getCompiler() 79 cxxflags = self.updatePackageCxxFlags(self.getCompilerFlags()) 80 self.popLanguage() 81 if 'download-mfem-ghv-cxx' in self.argDB and self.argDB['download-mfem-ghv-cxx']: 82 ghv = self.argDB['download-mfem-ghv-cxx'] 83 else: 84 ghv = cxx 85 86 # On CRAY with shared libraries, libmfem.so is linked as 87 # $ cc -shared -o libmfem.so ...a bunch of .o files.... ...libraries.... -dynamic 88 # The -dynamic at the end makes cc think it is creating an executable 89 ldflags = self.setCompilers.LDFLAGS.replace('-dynamic','') 90 91 strip_rpath='' 92 if self.cuda.found: 93 strip_rpath=' | sed "s/-Wl,-rpath,/-Xlinker=-rpath,/g"' 94 if self.openmp.found: 95 ldflags = ldflags.replace(self.openmp.ompflag,'') 96 97 makedepend = '' 98 with open(os.path.join(configDir,'user.mk'),'w') as g: 99 g.write('PREFIX = '+prefix+'\n') 100 g.write('MPICXX = '+cxx+'\n') 101 g.write('GHV_CXX = '+ghv+'\n') 102 if not self.hip.found: #MFEM uses hipcc as compiler for everything 103 g.write('CXXFLAGS = '+cxxflags+'\n') 104 if self.argDB['with-shared-libraries']: 105 g.write('SHARED = YES\n') 106 g.write('STATIC = NO\n') 107 else: 108 g.write('SHARED = NO\n') 109 g.write('STATIC = YES\n') 110 g.write('AR = '+self.setCompilers.AR+'\n') 111 g.write('ARFLAGS = '+self.setCompilers.AR_FLAGS+'\n') 112 g.write('LDFLAGS = '+ldflags+'\n') 113 if self.cuda.found: 114 g.write('LDFLAGS := $(addprefix -Xlinker ,$(LDFLAGS))\n') 115 g.write('MFEM_USE_MPI = YES\n') 116 g.write('MFEM_MPIEXEC = '+self.mpi.getMakeMacro('MPIEXEC')+'\n') 117 g.write('MFEM_USE_METIS_5 = YES\n') 118 g.write('MFEM_USE_METIS = YES\n') 119 if self.scalar.precision == 'single': 120 g.write('MFEM_PRECISION = single\n') 121 g.write('MFEM_USE_PETSC = YES\n') 122 g.write('HYPRE_OPT = '+self.headers.toString(self.hypre.include)+'\n') 123 g.write('HYPRE_LIB = '+self.libraries.toString(self.hypre.lib)+'\n') 124 g.write('METIS_OPT = '+self.headers.toString(self.metis.include)+'\n') 125 g.write('METIS_LIB = '+self.libraries.toString(self.metis.lib)+'\n') 126 if self.cuda.found: 127 g.write('HYPRE_LIB := $(subst -Wl,-Xlinker=,$(HYPRE_LIB))\n') 128 g.write('METIS_LIB := $(subst -Wl,-Xlinker=,$(METIS_LIB))\n') 129 g.write('PETSC_VARS = '+prefix+'/lib/petsc/conf/petscvariables\n') 130 g.write('PETSC_OPT = '+PETSC_OPT+'\n') 131 # MFEM's config/defaults.mk overwrites these 132 g.write('PETSC_DIR = '+PETSC_DIR+'\n') 133 g.write('PETSC_ARCH = '+PETSC_ARCH+'\n') 134 # Adding all externals should not be needed when PETSc is a shared library, but it is no harm. 135 # When the HYPRE library is built statically, we need to resolve blas symbols 136 # It would be nice to have access to the conf variables during postProcess, and access petsclib and other variables, instead of using a shell here 137 # but I do not know how to do so 138 petscext = '$(shell sed -n "s/PETSC_EXTERNAL_LIB_BASIC = *//p" $(PETSC_VARS)'+strip_rpath+')' 139 140 if self.argDB['with-single-library']: 141 petsclib = '-L'+prefix+'/lib -lpetsc' 142 else: 143 petsclib = '-L'+prefix+'/lib -lpetscml -lpetsctao -lpetscts -lpetscsnes -lpetscksp -lpetscdm -lpetscmat -lpetscvec -lpetscsys' 144 if self.argDB['with-shared-libraries']: 145 if self.cuda.found: 146 petscrpt = '-Xlinker=-rpath,'+prefix+'/lib' 147 else: 148 petscrpt = '-Wl,-rpath,'+prefix+'/lib' 149 else: 150 petscrpt = '' 151 g.write('PETSC_LIB = '+petscrpt+' '+petsclib+' '+petscext+'\n') 152 if self.slepc.found: 153 g.write('MFEM_USE_SLEPC = YES\n') 154 g.write('SLEPC_OPT = '+PETSC_OPT+'\n') 155 g.write('SLEPC_DIR = '+PETSC_DIR+'\n') 156 g.write('SLEPC_ARCH = '+PETSC_ARCH+'\n') 157 g.write('SLEPC_VARS = '+prefix+'/lib/slepc/conf/slepc_variables\n') 158 slepclib = '-L'+prefix+'/lib -lslepc' 159 slepcext = '' 160 g.write('SLEPC_LIB = '+petscrpt+' '+slepclib+' '+slepcext+' $(PETSC_LIB)\n') 161 if self.argDB['prefix'] and not 'package-prefix-hash' in self.argDB: 162 makedepend = 'slepc-install' 163 else: 164 makedepend = 'slepc-build' 165 self.writeConfig(g, 'ceed', self.ceed) 166 self.writeConfig(g, 'superlu', self.superlu_dist) 167 self.writeConfig(g, 'netcdf', self.netcdf) 168 169 if self.cuda.found: 170 self.pushLanguage('CUDA') 171 petscNvcc = self.getCompiler() 172 cudaFlags = self.updatePackageCUDAFlags(self.getCompilerFlags()) 173 self.popLanguage() 174 cudaFlags = re.sub(r'-std=([^\s]+) ','',cudaFlags) 175 g.write('MFEM_USE_CUDA = YES\n') 176 g.write('CUDA_CXX = '+petscNvcc+'\n') 177 g.write('CXXFLAGS := '+cudaFlags+' $(addprefix -Xcompiler ,$(CXXFLAGS))\n') 178 g.write('CUDA_ARCH = sm_' + self.cuda.cudaArchSingle() + '\n') 179 if self.hip.found: 180 self.pushLanguage('HIP') 181 hipcc = self.getCompiler() 182 hipFlags = self.updatePackageCxxFlags(self.getCompilerFlags()) 183 self.popLanguage() 184 hipFlags = re.sub(r'-std=([^\s]+) ','',hipFlags) 185 g.write('MFEM_USE_HIP = YES\n') 186 g.write('HIP_CXX = '+hipcc+'\n') 187 hipFlags = hipFlags.replace('-fvisibility=hidden','') 188 g.write('HIP_FLAGS = '+hipFlags+'\n') 189 g.write('MPI_OPT = '+self.mpi.includepaths+'\n') 190 g.write('MPI_LIB = '+self.mpi.libpaths+' '+self.mpi.mpilibs+'\n') 191 g.close() 192 193 with open(os.path.join(configDir,'petsc.mk'),'w') as f: 194 f.write(''' 195MAKEOVERRIDES := $(filter-out CXXFLAGS=%,$(MAKEOVERRIDES)) 196unexport CXXFLAGS 197unexport CPPFLAGS 198.PHONY: run-config 199run-config: 200\t$(MAKE) -f {mfile} config MFEM_DIR={mfemdir} 201'''.format(mfile=os.path.join(self.packageDir,'makefile'), mfemdir=self.packageDir)) 202 203 self.addPost(buildDir, ['${OMAKE} -f ' + os.path.join(configDir,'petsc.mk') + ' run-config', 204 '${OMAKE} clean', 205 self.make.make_jnp, 206 '${OMAKE} install']) 207 # this checks MFEM using the pre-installed libraries, I think that is wrong and it should use the post-installed prefix location 208 self.addMakeCheck(os.path.join(buildDir, 'examples', 'petsc'), '${OMAKE} -i ex1p-test-par ex9p-test-par') 209 self.logClearRemoveDirectory() 210 self.logPrintBox('MFEM examples are available at ' + os.path.join(self.packageDir,'examples')) 211 self.logResetRemoveDirectory() 212 return self.installDir 213