1import config.package 2import os 3 4class Configure(config.package.Package): 5 def __init__(self, framework): 6 config.package.Package.__init__(self, framework) 7 self.functions = [] 8 self.includes = [] 9 self.useddirectly = 0 10 self.linkedbypetsc = 0 11 self.builtafterpetsc = 1 12 self.PrefixWriteCheck = 0 13 return 14 15 def setupHelp(self,help): 16 import nargs 17 help.addArgument('PETSc', '-with-petsc4py=<bool>', nargs.ArgBool(None, False, 'Build PETSc Python bindings (petsc4py)')) 18 help.addArgument('PETSc', '-with-petsc4py-test-np=<np>',nargs.ArgInt(None, None, min=1, help='Number of processes to use for petsc4py tests')) 19 help.addArgument('PETSc', '-with-numpy-include=<dir>', nargs.Arg(None, None, 'Path to numpy headers from numpy.get_include() (default: autodetect)')) 20 return 21 22 def __str__(self): 23 if self.found: 24 s = 'petsc4py:\n' 25 if hasattr(self,'pythonpath'): 26 s += ' PYTHONPATH: '+self.pythonpath+'\n' 27 return s 28 return '' 29 30 def setupDependencies(self, framework): 31 config.package.Package.setupDependencies(self, framework) 32 self.python = framework.require('config.packages.Python',self) 33 self.setCompilers = framework.require('config.setCompilers',self) 34 self.sharedLibraries = framework.require('PETSc.options.sharedLibraries', self) 35 self.installdir = framework.require('PETSc.options.installDir',self) 36 self.mpi = framework.require('config.packages.MPI',self) 37 self.cython = framework.require('config.packages.Cython',self) 38 self.slepc = framework.require('config.packages.SLEPc',self) # build SLEPc first 39 self.bamg = framework.require('config.packages.BAMG',self) # build BAMG first 40 self.odeps = [self.cython,self.slepc,self.bamg] 41 return 42 43 def getDir(self): 44 return os.path.join('src','binding','petsc4py') 45 46 def Install(self): 47 import os 48 installLibPath = os.path.join(self.installDir, 'lib') 49 if self.setCompilers.isDarwin(self.log): 50 apple = 'You may need to\n (csh/tcsh) setenv MACOSX_DEPLOYMENT_TARGET 10.X\n (sh/bash) MACOSX_DEPLOYMENT_TARGET=10.X; export MACOSX_DEPLOYMENT_TARGET\nbefore running make on PETSc' 51 else: 52 apple = '' 53 self.logClearRemoveDirectory() 54 self.logResetRemoveDirectory() 55 archflags = "" 56 if self.setCompilers.isDarwin(self.log): 57 if self.setCompilers.isARM(self.log): 58 archflags = "ARCHFLAGS=\'-arch arm64\' " 59 elif self.types.sizes['void-p'] == 4: 60 archflags = "ARCHFLAGS=\'-arch i386\' " 61 else: 62 archflags = "ARCHFLAGS=\'-arch x86_64\' " 63 64 # Set PETSC_DIR/PETSC_ARCH to point at the dir with the PETSc installation: 65 # if DESTDIR is non-empty, then PETSc has been installed into staging dir 66 # if prefix has been specified at config time, path to PETSc includes that prefix 67 if self.argDB['prefix'] and not 'package-prefix-hash' in self.argDB: 68 newdir = 'PETSC_DIR=${DESTDIR}' + os.path.abspath(os.path.expanduser(self.argDB['prefix'])) + ' PETSC_ARCH= ' 69 else: 70 newdir = '' 71 72 # Pass to setup.py if given, otherwise setup.py will autodetect 73 numpy_include = self.argDB.get('with-numpy-include') 74 if numpy_include is not None: 75 newdir += 'NUMPY_INCLUDE="'+numpy_include+'" ' 76 77 self.addDefine('PETSC4PY_INSTALL_PATH','"'+os.path.join(self.installdir.dir,'lib')+'"') 78 cflags = '' 79 # by default, multiple flags are added by setup.py (-DNDEBUG -O3 -g), no matter the type of PETSc build 80 # this is problematic with Intel compilers, which take extremely long to compile bindings when using -g 81 # so we instead force no additional flags (other than the ones already used by PETSc, i.e., CFLAGS) 82 # TODO FIXME: this observation was made with Intel(R) oneAPI DPC++/C++ Compiler 2025.1.0 (2025.1.0.20250317), but it may be fixed in a subsequent release 83 if config.setCompilers.Configure.isIntel(self.getCompiler(), self.log): 84 cflags = 'CFLAGS=\'\' ' 85 self.addPost(self.packageDir, ['${RM} -rf build', 86 newdir + archflags + cflags + ' PYTHONPATH=${PETSCPYTHONPATH} ' + self.python.pyexe + ' setup.py build', 87 'MPICC=${PCC} ' + newdir + archflags + self.python.pyexe +' setup.py install --install-lib=' + installLibPath + ' $(if $(DESTDIR),--root=\'$(DESTDIR)\')']) 88 self.pythonpath = installLibPath 89 np = self.make.make_test_np 90 if self.mpi.usingMPIUni: 91 np = 1 92 # TODO: some tests currently have issues with np > 4, this should be fixed 93 np = min(np,4) 94 if 'with-petsc4py-test-np' in self.argDB and self.argDB['with-petsc4py-test-np']: 95 np = self.argDB['with-petsc4py-test-np'] 96 self.addMakeMacro('PETSC4PY_NP',np) 97 self.addTest('.', 'PYTHONPATH=%s:${PETSCPYTHONPATH} PETSC_OPTIONS="%s" ${MPIEXEC} -n ${PETSC4PY_NP} %s %s --verbose' % (installLibPath, '${PETSC_OPTIONS} -check_pointer_intensity 0 -error_output_stdout -malloc_dump ${PETSC_TEST_OPTIONS}', self.python.pyexe, os.path.join(self.packageDir, 'test', 'runtests.py'))) 98 self.found = True 99 self.python.path.add(installLibPath) 100 return self.installDir 101 102 def configureLibrary(self): 103 import sys 104 if not self.sharedLibraries.useShared and not self.setCompilers.isCygwin(self.log): 105 raise RuntimeError('petsc4py requires PETSc be built with shared libraries; rerun with --with-shared-libraries') 106 if sys.version_info < (3, 6): 107 raise RuntimeError('petsc4py requires Python 3.6 at least') 108 chkpkgs = ['numpy'] 109 if sys.version_info >= (3, 12): 110 chkpkgs.append('setuptools') 111 npkgs = [] 112 for pkg in chkpkgs: 113 if not getattr(self.python,pkg): npkgs.append(pkg) 114 if npkgs: 115 raise RuntimeError('petsc4py requires Python with "%s" module(s) installed!\n' 116 'Please install using package managers - for ex: "apt" or "dnf" (on linux),\n' 117 'or with "pip" using: %s -m pip install %s' % (" ".join(npkgs), self.python.pyexe, " ".join(npkgs))) 118 self.getInstallDir() 119 120 def alternateConfigureLibrary(self): 121 '''This is ugly but currently .gitlab-ci.yml is hardwired to use petsc4pytest''' 122 self.addMakeRule('petsc4pytest','') 123