xref: /petsc/config/BuildSystem/config/packages/mpi4py.py (revision bf2b7fd48da4195b6a8ecee30732f17736b96545)
1import config.package
2import os
3import script
4
5class Configure(config.package.Package):
6  def __init__(self, framework):
7    config.package.Package.__init__(self, framework)
8    self.version           = '4.1.1'
9    self.download          = ['https://github.com/mpi4py/mpi4py/releases/download/' + self.version + '/mpi4py-' + self.version + '.tar.gz',
10                              'https://web.cels.anl.gov/projects/petsc/download/externalpackages/mpi4py-'+self.version+'.tar.gz']
11    self.functions         = []
12    self.includes          = []
13    self.useddirectly      = 0
14    self.pythonpath        = ''
15    return
16
17  def setupDependencies(self, framework):
18    config.package.Package.setupDependencies(self, framework)
19    self.python          = framework.require('config.packages.Python',self)
20    self.setCompilers    = framework.require('config.setCompilers',self)
21    self.sharedLibraries = framework.require('PETSc.options.sharedLibraries', self)
22    self.installdir      = framework.require('PETSc.options.installDir',self)
23    self.mpi             = framework.require('config.packages.MPI',self)
24    self.deps            = [self.mpi]
25    return
26
27  def __str__(self):
28    if self.found:
29      s = 'mpi4py:\n'
30      if hasattr(self,'pythonpath'):
31        s += '  PYTHONPATH: '+self.pythonpath+'\n'
32      return s
33    return ''
34
35  def Install(self):
36    installLibPath  = os.path.join(self.installDir, 'lib')
37    if self.setCompilers.isDarwin(self.log):
38      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'
39    else:
40      apple = ''
41    self.logClearRemoveDirectory()
42    self.logResetRemoveDirectory()
43    archflags = ""
44    if self.setCompilers.isDarwin(self.log):
45      if self.setCompilers.isARM(self.log):
46        archflags = "ARCHFLAGS=\'-arch arm64\' "
47      elif self.types.sizes['void-p'] == 4:
48        archflags = "ARCHFLAGS=\'-arch i386\' "
49      else:
50        archflags = "ARCHFLAGS=\'-arch x86_64\' "
51
52    self.framework.pushLanguage('C')
53    self.logPrintBox('Building mpi4py, this may take several minutes')
54    cleancmd = 'MPICC='+self.framework.getCompiler()+'  '+archflags+self.python.pyexe+' setup.py clean --all  2>&1'
55    output,err,ret  = config.base.Configure.executeShellCommand(cleancmd, cwd=self.packageDir,  checkCommand=script.Script.passCheckCommand, timeout=100, log=self.log)
56    if ret: raise RuntimeError('Error cleaning mpi4py. Check configure.log')
57
58    cflags = ''
59    # by default, multiple flags are added by setup.py (-DNDEBUG -O3 -g), no matter the type of PETSc build
60    # this is problematic with Intel compilers, which take extremely long to compile bindings when using -g
61    # so we instead force no additional flags (other than the ones already used by PETSc, i.e., CFLAGS)
62    # 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
63    if config.setCompilers.Configure.isIntel(self.getCompiler(), self.log):
64      cflags = 'CFLAGS=\''+self.getCompilerFlags()+'\' '
65    buildcmd = 'MPICC='+self.framework.getCompiler()+'  '+archflags+cflags+self.python.pyexe+' setup.py build 2>&1'
66    output,err,ret  = config.base.Configure.executeShellCommand(buildcmd, cwd=self.packageDir, checkCommand=script.Script.passCheckCommand,timeout=100, log=self.log)
67    if ret: raise RuntimeError('Error building mpi4py. Check configure.log')
68
69    self.logPrintBox('Installing mpi4py')
70    installcmd = 'MPICC='+self.framework.getCompiler()+' '+self.python.pyexe+' setup.py install --install-lib='+installLibPath+' 2>&1'
71    output,err,ret  = config.base.Configure.executeShellCommand(installcmd, cwd=self.packageDir,checkCommand=script.Script.passCheckCommand, timeout=100, log=self.log)
72    if ret: raise RuntimeError('Error installing mpi4py. Check configure.log')
73    self.framework.popLanguage()
74    return self.installDir
75
76  def configureLibrary(self):
77    self.checkDownload()
78    if not self.sharedLibraries.useShared:
79        raise RuntimeError('mpi4py requires PETSc be built with shared libraries; rerun with --with-shared-libraries')
80    if not getattr(self.python,'numpy'):
81        raise RuntimeError('mpi4py, in the context of PETSc,requires Python with numpy module installed.\n'
82                           'Please install using package managers - for ex: "apt" or "dnf" (on linux),\n'
83                           'or  using: %s -m pip install %s' % (self.python.pyexe, 'numpy'))
84    if self.argDB.get('with-mpi4py-dir'):
85      self.directory = self.argDB['with-mpi4py-dir']
86    elif self.argDB.get('download-mpi4py'):
87      self.directory = os.path.join(self.installDir)
88
89    elif self.argDB.get('with-mpi4py'):
90      try:
91        import mpi4py
92      except:
93        raise RuntimeError('mpi4py not found in default Python PATH! Suggest --download-mpi4py or --with-mpi4py-path!')
94    else:
95        raise RuntimeError('mpi4py unrecognized mode of building mpi4py! Suggest using --download-mpi4py!')
96
97    if self.directory:
98      installLibPath = os.path.join(self.directory, 'lib')
99      if not os.path.isfile(os.path.join(installLibPath,'mpi4py','__init__.py')):
100        raise RuntimeError('mpi4py not found at %s' % installLibPath)
101      self.python.path.add(installLibPath)
102      self.pythonpath = installLibPath
103
104    self.addMakeMacro('MPI4PY',"yes")
105    self.found = 1
106