xref: /petsc/config/PETSc/Configure.py (revision 98d129c30f3ee9fdddc40fdbc5a989b7be64f888)
1import config.base
2
3import os
4import sys
5import re
6import pickle
7
8class Configure(config.base.Configure):
9  def __init__(self, framework):
10    config.base.Configure.__init__(self, framework)
11    self.headerPrefix = 'PETSC'
12    self.substPrefix  = 'PETSC'
13    self.installed    = 0 # 1 indicates that Configure itself has already compiled and installed PETSc
14    self.found        = 1
15    return
16
17  def __str2__(self):
18    import logger
19
20    desc = ['  Using GNU make: ' + self.make.make]
21    if self.defines.get('USE_COVERAGE'):
22      desc.extend([
23        '  Code coverage: yes',
24        '  Using code coverage executable: {}'.format(self.getMakeMacro('PETSC_COVERAGE_EXEC'))
25      ])
26    banner_ends   = 'xxx'
27    banner_middle = '=' * (logger.get_global_divider_length() - 2 * len(banner_ends))
28    banner_line   = banner_middle.join((banner_ends, banner_ends))
29    desc.append(banner_line)
30    if not self.installed:
31      desc.append(' Configure stage complete. Now build PETSc libraries with:')
32      desc.append('   %s PETSC_DIR=%s PETSC_ARCH=%s all' % (self.make.make_user, self.petscdir.dir, self.arch.arch))
33    else:
34      desc.append(' Installation complete. You do not need to run make to compile or install the software')
35    desc.extend([banner_line, ''])
36    return '\n'.join(desc)
37
38  def setupHelp(self, help):
39    import nargs
40    help.addArgument('PETSc',  '-prefix=<dir>',                              nargs.Arg(None, '', 'Specifiy location to install PETSc (eg. /usr/local)'))
41    help.addArgument('PETSc',  '-with-prefetch=<bool>',                      nargs.ArgBool(None, 1,'Enable checking for prefetch instructions'))
42    help.addArgument('Windows','-with-windows-graphics=<bool>',              nargs.ArgBool(None, 1,'Enable check for Windows Graphics'))
43    help.addArgument('PETSc', '-with-default-arch=<bool>',                   nargs.ArgBool(None, 1, 'Allow using the last configured arch without setting PETSC_ARCH'))
44    help.addArgument('PETSc','-with-single-library=<bool>',                  nargs.ArgBool(None, 1,'Put all PETSc code into the single -lpetsc library'))
45    help.addArgument('PETSc','-with-fortran-bindings=<bool>',                nargs.ArgBool(None, 1,'Build PETSc fortran bindings in the library and corresponding module files'))
46    help.addArgument('PETSc', '-with-ios=<bool>',                            nargs.ArgBool(None, 0, 'Build an iPhone/iPad version of PETSc library'))
47    help.addArgument('PETSc', '-with-display=<x11display>',                  nargs.Arg(None, '', 'Specifiy DISPLAY environmental variable for use with MATLAB test)'))
48    help.addArgument('PETSc', '-with-package-scripts=<pyscripts>',           nargs.ArgFileList(None,None,'Specify configure package scripts for user provided packages'))
49    help.addArgument('PETSc', '-with-coverage=<bool>',                       nargs.ArgFuzzyBool(None, value=0, help='Enable or disable code-coverage collection'))
50    help.addArgument('PETSc', '-with-coverage-exec=<executable>',            nargs.ArgExecutable(None, value='default-auto', mustExist=0, help='Name of executable to use for post-processing coverage data, e.g. \'gcov\' or \'llvm-cov\'. Pass \'auto\' to let configure infer from compiler'))
51    help.addArgument('PETSc', '-with-tau-perfstubs=<bool>',                  nargs.ArgBool(None, 1,'Enable TAU profiler stubs'))
52    help.addArgument('PETSc', '-with-strict-petscerrorcode=<bool>',          nargs.ArgFuzzyBool(None, value=0, help='Enable strict PetscErrorCode mode, which enables additional compile-time checking for misuse of PetscErrorCode and error handling'))
53    return
54
55  def registerPythonFile(self,filename,directory):
56    ''' Add a python file to the framework and registers its headerprefix, ... externalpackagedir
57        directory is the directory where the file relative to the BuildSystem or config path in python notation with . '''
58    (utilityName, ext) = os.path.splitext(filename)
59    if not utilityName.startswith('.') and not utilityName.startswith('#') and ext == '.py' and not utilityName == '__init__':
60      if directory: directory = directory+'.'
61      utilityObj                             = self.framework.require(directory+utilityName, self)
62      utilityObj.headerPrefix                = self.headerPrefix
63      utilityObj.archProvider                = self.arch
64      utilityObj.languageProvider            = self.languages
65      utilityObj.installDirProvider          = self.installdir
66      utilityObj.externalPackagesDirProvider = self.externalpackagesdir
67      utilityObj.precisionProvider           = self.scalartypes
68      utilityObj.indexProvider               = self.indexTypes
69      setattr(self, utilityName.lower(), utilityObj)
70      return utilityObj
71    return None
72
73  def setupDependencies(self, framework):
74    config.base.Configure.setupDependencies(self, framework)
75    self.programs      = framework.require('config.programs',           self)
76    self.setCompilers  = framework.require('config.setCompilers',       self)
77    self.compilerFlags = framework.require('config.compilerFlags',      self)
78    self.compilers     = framework.require('config.compilers',          self)
79    self.arch          = framework.require('PETSc.options.arch',        self.setCompilers)
80    self.petscdir      = framework.require('PETSc.options.petscdir',    self.arch)
81    self.installdir    = framework.require('PETSc.options.installDir',  self)
82    self.dataFilesPath = framework.require('PETSc.options.dataFilesPath',self)
83    self.scalartypes   = framework.require('PETSc.options.scalarTypes', self)
84    self.indexTypes    = framework.require('PETSc.options.indexTypes',  self)
85    self.languages     = framework.require('PETSc.options.languages',   self.setCompilers)
86    self.indexTypes    = framework.require('PETSc.options.indexTypes',  self.compilers)
87    self.types         = framework.require('config.types',              self)
88    self.headers       = framework.require('config.headers',            self)
89    self.functions     = framework.require('config.functions',          self)
90    self.libraries     = framework.require('config.libraries',          self)
91    self.atomics       = framework.require('config.atomics',            self)
92    self.make          = framework.require('config.packages.make',      self)
93    self.blasLapack    = framework.require('config.packages.BlasLapack',self)
94    self.mpi           = framework.require('config.packages.MPI',       self)
95    self.fortran       = framework.require('config.compilersFortran',   self)
96    self.ftncmdline    = framework.require('config.utilities.fortranCommandLine',self)
97    self.externalpackagesdir = framework.require('PETSc.options.externalpackagesdir',self)
98
99    for utility in sorted(os.listdir(os.path.join('config','PETSc','options'))):
100      self.registerPythonFile(utility,'PETSc.options')
101
102    for utility in sorted(os.listdir(os.path.join('config','BuildSystem','config','utilities'))):
103      self.registerPythonFile(utility,'config.utilities')
104
105    for package in sorted(os.listdir(os.path.join('config', 'BuildSystem', 'config', 'packages'))):
106      obj = self.registerPythonFile(package,'config.packages')
107      if obj:
108        obj.archProvider                = self.framework.requireModule(obj.archProvider, obj)
109        obj.languageProvider            = self.framework.requireModule(obj.languageProvider, obj)
110        obj.installDirProvider          = self.framework.requireModule(obj.installDirProvider, obj)
111        obj.externalPackagesDirProvider = self.framework.requireModule(obj.externalPackagesDirProvider, obj)
112        obj.precisionProvider           = self.framework.requireModule(obj.precisionProvider, obj)
113        obj.indexProvider               = self.framework.requireModule(obj.indexProvider, obj)
114
115    # Force blaslapack and opencl to depend on scalarType so precision is set before BlasLapack is built
116    framework.require('PETSc.options.scalarTypes', self.f2cblaslapack)
117    framework.require('PETSc.options.scalarTypes', self.fblaslapack)
118    framework.require('PETSc.options.scalarTypes', self.blaslapack)
119    framework.require('PETSc.options.scalarTypes', self.opencl)
120
121    self.programs.headerPrefix     = self.headerPrefix
122    self.setCompilers.headerPrefix = self.headerPrefix
123    self.compilers.headerPrefix    = self.headerPrefix
124    self.fortran.headerPrefix      = self.headerPrefix
125    self.types.headerPrefix        = self.headerPrefix
126    self.headers.headerPrefix      = self.headerPrefix
127    self.functions.headerPrefix    = self.headerPrefix
128    self.libraries.headerPrefix    = self.headerPrefix
129
130    # Register user provided package scripts
131    if 'with-package-scripts' in self.framework.argDB:
132      for script in self.framework.argDB['with-package-scripts']:
133        if os.path.splitext(script)[1] != '.py':
134          raise RuntimeError('Only python scripts compatible with configure package script format should be specified! Invalid option -with-package-scripts='+script)
135        self.framework.logPrint('User is registering a new package script: '+script)
136        dname,fname = os.path.split(script)
137        if dname: sys.path.append(dname)
138        self.registerPythonFile(fname,'')
139
140    # test for a variety of basic headers and functions
141    headersC = map(lambda name: name+'.h',['setjmp','dos','fcntl','float','io','malloc','pwd','strings',
142                                            'unistd','machine/endian','sys/param','sys/procfs','sys/resource',
143                                            'sys/systeminfo','sys/times','sys/utsname',
144                                            'sys/socket','sys/wait','netinet/in','netdb','direct','time','Ws2tcpip','sys/types',
145                                            'WindowsX','float','ieeefp','stdint','inttypes','immintrin'])
146    functions = ['access','_access','clock','drand48','getcwd','_getcwd','getdomainname','gethostname',
147                 'posix_memalign','popen','PXFGETARG','rand','getpagesize',
148                 'readlink','realpath','usleep','sleep','_sleep',
149                 'uname','snprintf','_snprintf','lseek','_lseek','time','fork','stricmp',
150                 'strcasecmp','bzero','dlopen','dlsym','dlclose','dlerror',
151                 '_set_output_format','_mkdir','socket','gethostbyname','fpresetsticky',
152                 'fpsetsticky','__gcov_dump']
153    libraries = [(['fpe'],'handle_sigfpes')]
154    librariessock = [(['socket','nsl'],'socket')]
155    self.headers.headers.extend(headersC)
156    self.functions.functions.extend(functions)
157    self.libraries.libraries.extend(libraries)
158    if not hasattr(self,'socket'):
159      self.libraries.libraries.extend(librariessock)
160    return
161
162  def DumpPkgconfig(self, petsc_pc):
163    ''' Create a pkg-config file '''
164    if not os.path.exists(os.path.join(self.petscdir.dir,self.arch.arch,'lib','pkgconfig')):
165      os.makedirs(os.path.join(self.petscdir.dir,self.arch.arch,'lib','pkgconfig'))
166    with open(os.path.join(self.petscdir.dir,self.arch.arch,'lib','pkgconfig',petsc_pc),'w') as fd:
167      cflags_inc = ['-I${includedir}']
168      if self.framework.argDB['prefix']:
169        fd.write('prefix='+self.installdir.dir+'\n')
170      else:
171        fd.write('prefix='+os.path.join(self.petscdir.dir, self.arch.arch)+'\n')
172        cflags_inc.append('-I' + os.path.join(self.petscdir.dir, 'include'))
173      fd.write('exec_prefix=${prefix}\n')
174      fd.write('includedir=${prefix}/include\n')
175      fd.write('libdir=${prefix}/lib\n')
176
177      with self.setCompilers.Language('C'):
178        fd.write('ccompiler='+self.setCompilers.getCompiler()+'\n')
179        fd.write('cflags_extra='+self.setCompilers.getCompilerFlags().strip()+'\n')
180        fd.write('cflags_dep='+self.compilers.dependenciesGenerationFlag.get('C','')+'\n')
181        fd.write('ldflag_rpath='+self.setCompilers.CSharedLinkerFlag+'\n')
182      if hasattr(self.compilers, 'CXX'):
183        with self.setCompilers.Language('C++'):
184          fd.write('cxxcompiler='+self.setCompilers.getCompiler()+'\n')
185          fd.write('cxxflags_extra='+self.setCompilers.getCompilerFlags().strip()+'\n')
186      if hasattr(self.compilers, 'FC'):
187        with self.setCompilers.Language('FC'):
188          fd.write('fcompiler='+self.setCompilers.getCompiler()+'\n')
189          fd.write('fflags_extra='+self.setCompilers.getCompilerFlags().strip()+'\n')
190      if hasattr(self.compilers, 'CUDAC'):
191        with self.setCompilers.Language('CUDA'):
192          fd.write('cudacompiler='+self.setCompilers.getCompiler()+'\n')
193          fd.write('cudaflags_extra='+self.setCompilers.getCompilerFlags().strip()+'\n')
194          p = self.framework.require('config.packages.cuda')
195          fd.write('cudalib='+self.libraries.toStringNoDupes(p.lib)+'\n')
196          fd.write('cudainclude='+self.headers.toStringNoDupes(p.include)+'\n')
197          if hasattr(self.setCompilers,'CUDA_CXX'):
198            fd.write('cuda_cxx='+self.setCompilers.CUDA_CXX+'\n')
199            fd.write('cuda_cxxflags='+self.setCompilers.CUDA_CXXFLAGS+'\n')
200
201      fd.write('\n')
202      fd.write('Name: PETSc\n')
203      fd.write('Description: Library to solve ODEs and algebraic equations\n')
204      fd.write('Version: %s\n' % self.petscdir.version)
205      fd.write('Cflags: ' + ' '.join([self.setCompilers.CPPFLAGS] + cflags_inc) + '\n')
206      fd.write('Libs: '+self.libraries.toStringNoDupes(['-L${libdir}', self.petsclib], with_rpath=False)+'\n')
207      # Remove RPATH flags from library list.  User can add them using
208      # pkg-config --variable=ldflag_rpath and pkg-config --libs-only-L
209      fd.write('Libs.private: '+self.libraries.toStringNoDupes([f for f in self.packagelibs+self.complibs if not f.startswith(self.setCompilers.CSharedLinkerFlag)], with_rpath=False)+'\n')
210    return
211
212  def DumpModule(self):
213    ''' Create a module file '''
214    if not os.path.exists(os.path.join(self.petscdir.dir,self.arch.arch,'lib','petsc','conf','modules')):
215      os.makedirs(os.path.join(self.petscdir.dir,self.arch.arch,'lib','petsc','conf','modules'))
216    if not os.path.exists(os.path.join(self.petscdir.dir,self.arch.arch,'lib','petsc','conf','modules','petsc')):
217      os.makedirs(os.path.join(self.petscdir.dir,self.arch.arch,'lib','petsc','conf','modules','petsc'))
218    if self.framework.argDB['prefix']:
219      installdir  = self.installdir.dir
220      installarch = ''
221      installpath = os.path.join(installdir,'bin')
222    else:
223      installdir  = self.petscdir.dir
224      installarch = self.arch.arch
225      installpath = os.path.join(installdir,installarch,'bin')+':'+os.path.join(installdir,'bin')
226    fd = open(os.path.join(self.petscdir.dir,self.arch.arch,'lib','petsc','conf','modules','petsc',self.petscdir.version),'w')
227    fd.write('''\
228#%%Module
229
230proc ModulesHelp { } {
231    puts stderr "This module sets the path and environment variables for petsc-%s"
232    puts stderr "     see https://petsc.org/ for more information      "
233    puts stderr ""
234}
235module-whatis "PETSc - Portable, Extensible Toolkit for Scientific Computation"
236
237set petsc_dir   "%s"
238set petsc_arch  "%s"
239
240setenv PETSC_ARCH "$petsc_arch"
241setenv PETSC_DIR "$petsc_dir"
242prepend-path PATH "%s"
243''' % (self.petscdir.version, installdir, installarch, installpath))
244    fd.close()
245    return
246
247  def Dump(self):
248    ''' Actually put the values into the configuration files '''
249    # eventually everything between -- should be gone
250    if self.mpi.usingMPIUni:
251      #
252      # Remove any MPI/MPICH include files that may have been put here by previous runs of ./configure
253      self.executeShellCommand('rm -rf  '+os.path.join(self.petscdir.dir,self.arch.arch,'include','mpi*')+' '+os.path.join(self.petscdir.dir,self.arch.arch,'include','opa*'), log = self.log)
254
255    self.logPrintDivider()
256    # Test for compiler-specific macros that need to be defined.
257    if self.setCompilers.isCrayVector('CC', self.log):
258      self.addDefine('HAVE_CRAY_VECTOR','1')
259
260    if self.functions.haveFunction('gethostbyname') and self.functions.haveFunction('socket') and self.headers.haveHeader('netinet/in.h'):
261      self.addDefine('USE_SOCKET_VIEWER','1')
262      if self.checkCompile('#include <sys/socket.h>','setsockopt(0,SOL_SOCKET,SO_REUSEADDR,0,0)'):
263        self.addDefine('HAVE_SO_REUSEADDR','1')
264
265    self.logPrintDivider()
266    self.setCompilers.pushLanguage('C')
267    compiler = self.setCompilers.getCompiler()
268    if [s for s in ['mpicc','mpiicc'] if os.path.basename(compiler).find(s)>=0]:
269      try:
270        output   = self.executeShellCommand(compiler + ' -show', log = self.log)[0]
271        compiler = output.split(' ')[0]
272        self.addDefine('MPICC_SHOW','"'+output.strip().replace('\n','\\\\n').replace('"','')+'"')
273      except:
274        self.addDefine('MPICC_SHOW','"Unavailable"')
275    else:
276      self.addDefine('MPICC_SHOW','"Unavailable"')
277    self.setCompilers.popLanguage()
278#-----------------------------------------------------------------------------------------------------
279
280    # Sometimes we need C compiler, even if built with C++
281    self.setCompilers.pushLanguage('C')
282    # do not use getCompilerFlags() because that automatically includes the CPPFLAGS so one ends up with duplication flags in makefile usage
283    self.addMakeMacro('CC_FLAGS',self.setCompilers.CFLAGS)
284    self.setCompilers.popLanguage()
285
286    # And sometimes we need a C++ compiler even when PETSc is built with C
287    if hasattr(self.compilers, 'CXX'):
288      self.setCompilers.pushLanguage('Cxx')
289      self.addDefine('HAVE_CXX','1')
290      self.addMakeMacro('CXXPP_FLAGS',self.setCompilers.CXXPPFLAGS)
291      # do not use getCompilerFlags() because that automatically includes the CXXPPFLAGS so one ends up with duplication flags in makefile usage
292      self.addMakeMacro('CXX_FLAGS',self.setCompilers.CXXFLAGS+' '+self.setCompilers.CXX_CXXFLAGS)
293      cxx_linker = self.setCompilers.getLinker()
294      self.addMakeMacro('CXX_LINKER',cxx_linker)
295      self.addMakeMacro('CXX_LINKER_FLAGS',self.setCompilers.getLinkerFlags())
296      self.setCompilers.popLanguage()
297    else:
298      self.addMakeMacro('CXX','')
299
300    # C preprocessor values
301    self.addMakeMacro('CPP_FLAGS',self.setCompilers.CPPFLAGS)
302
303    # compiler values
304    self.setCompilers.pushLanguage(self.languages.clanguage)
305    self.addMakeMacro('PCC',self.setCompilers.getCompiler())
306    # do not use getCompilerFlags() because that automatically includes the preprocessor flags so one ends up with duplication flags in makefile usage
307    if self.languages.clanguage == 'C':
308      self.addMakeMacro('PCC_FLAGS','$(CC_FLAGS)')
309    else:
310      self.addMakeMacro('PCC_FLAGS','$(CXX_FLAGS)')
311    self.setCompilers.popLanguage()
312    # .o or .obj
313    self.addMakeMacro('CC_SUFFIX','o')
314
315    # executable linker values
316    self.setCompilers.pushLanguage(self.languages.clanguage)
317    pcc_linker = self.setCompilers.getLinker()
318    self.addMakeMacro('PCC_LINKER',pcc_linker)
319    # We need to add sycl flags when linking petsc. See more in sycl.py.
320    if hasattr(self.compilers, 'SYCLC'):
321      self.addMakeMacro('PCC_LINKER_FLAGS',self.setCompilers.getLinkerFlags()+' '+self.setCompilers.SYCLFLAGS+' '+self.setCompilers.SYCLC_LINKER_FLAGS)
322    else:
323      self.addMakeMacro('PCC_LINKER_FLAGS',self.setCompilers.getLinkerFlags())
324    self.setCompilers.popLanguage()
325    # '' for Unix, .exe for Windows
326    self.addMakeMacro('CC_LINKER_SUFFIX','')
327
328    if hasattr(self.compilers, 'FC'):
329      if self.framework.argDB['with-fortran-bindings']:
330        if not self.fortran.fortranIsF90:
331          raise RuntimeError('Error! Fortran compiler "'+self.compilers.FC+'" does not support F90! PETSc fortran bindings require a F90 compiler')
332        self.addDefine('USE_FORTRAN_BINDINGS','1')
333        if not self.ftncmdline.have_command_argument:
334          raise RuntimeError('Error! Fortran compiler "'+self.compilers.FC+'" does not support F2003 GET_COMMAND_ARGUMENT()!')
335      self.setCompilers.pushLanguage('FC')
336      # need FPPFLAGS in config/setCompilers
337      self.addMakeMacro('FPP_FLAGS',self.setCompilers.FPPFLAGS)
338
339      # compiler values
340      self.addMakeMacro('FC_FLAGS',self.setCompilers.getCompilerFlags())
341      self.setCompilers.popLanguage()
342      # .o or .obj
343      self.addMakeMacro('FC_SUFFIX','o')
344
345      # executable linker values
346      self.setCompilers.pushLanguage('FC')
347      self.addMakeMacro('FC_LINKER',self.setCompilers.getLinker())
348      self.addMakeMacro('FC_LINKER_FLAGS',self.setCompilers.getLinkerFlags())
349      self.setCompilers.popLanguage()
350
351      # F90 Modules
352      if self.setCompilers.fortranModuleIncludeFlag:
353        self.addMakeMacro('FC_MODULE_FLAG', self.setCompilers.fortranModuleIncludeFlag)
354      else: # for non-f90 compilers like g77
355        self.addMakeMacro('FC_MODULE_FLAG', '-I')
356      if self.setCompilers.fortranModuleIncludeFlag:
357        self.addMakeMacro('FC_MODULE_OUTPUT_FLAG', self.setCompilers.fortranModuleOutputFlag)
358    else:
359      self.addMakeMacro('FC','')
360
361    if hasattr(self.compilers, 'CUDAC'):
362      self.setCompilers.pushLanguage('CUDA')
363      self.addMakeMacro('CUDAC_FLAGS',self.setCompilers.getCompilerFlags())
364      self.addMakeMacro('CUDAPP_FLAGS',self.setCompilers.CUDAPPFLAGS)
365      self.setCompilers.popLanguage()
366
367    if hasattr(self.compilers, 'HIPC'):
368      self.setCompilers.pushLanguage('HIP')
369      self.addMakeMacro('HIPC_FLAGS',self.setCompilers.getCompilerFlags())
370      self.addMakeMacro('HIPPP_FLAGS',self.setCompilers.HIPPPFLAGS)
371      self.setCompilers.popLanguage()
372
373    if hasattr(self.compilers, 'SYCLC'):
374      self.setCompilers.pushLanguage('SYCL')
375      self.addMakeMacro('SYCLC_FLAGS',self.setCompilers.getCompilerFlags())
376      self.addMakeMacro('SYCLC_LINKER_FLAGS',self.setCompilers.getLinkerFlags())
377      self.addMakeMacro('SYCLPP_FLAGS',self.setCompilers.SYCLPPFLAGS)
378      self.setCompilers.popLanguage()
379
380    # shared library linker values
381    self.setCompilers.pushLanguage(self.languages.clanguage)
382    # need to fix BuildSystem to collect these separately
383    self.addMakeMacro('SL_LINKER',self.setCompilers.getLinker())
384    self.addMakeMacro('SL_LINKER_FLAGS','${PCC_LINKER_FLAGS}')
385    self.setCompilers.popLanguage()
386    # One of 'a', 'so', 'lib', 'dll', 'dylib' (perhaps others also?) depending on the library generator and architecture
387    # Note: . is not included in this macro, consistent with AR_LIB_SUFFIX
388    if self.setCompilers.sharedLibraryExt == self.setCompilers.AR_LIB_SUFFIX:
389      self.addMakeMacro('SL_LINKER_SUFFIX', '')
390      self.addDefine('SLSUFFIX','""')
391    else:
392      self.addMakeMacro('SL_LINKER_SUFFIX', self.setCompilers.sharedLibraryExt)
393      self.addDefine('SLSUFFIX','"'+self.setCompilers.sharedLibraryExt+'"')
394
395    self.addMakeMacro('SL_LINKER_LIBS','${PETSC_EXTERNAL_LIB_BASIC}')
396
397#-----------------------------------------------------------------------------------------------------
398
399    # CONLY or CPP. We should change the PETSc makefiles to do this better
400    if self.languages.clanguage == 'C': lang = 'CONLY'
401    else: lang = 'CXXONLY'
402    self.addMakeMacro('PETSC_LANGUAGE',lang)
403
404    # real or complex
405    self.addMakeMacro('PETSC_SCALAR',self.scalartypes.scalartype)
406    # double or float
407    self.addMakeMacro('PETSC_PRECISION',self.scalartypes.precision)
408
409    if self.framework.argDB['with-batch']:
410      self.addMakeMacro('PETSC_WITH_BATCH','1')
411
412#-----------------------------------------------------------------------------------------------------
413    # print include and lib for makefiles
414    self.logPrintDivider()
415    self.framework.packages.reverse()
416    petscincludes = [os.path.join(self.petscdir.dir,'include'),os.path.join(self.petscdir.dir,self.arch.arch,'include')]
417    petscincludes_install = [os.path.join(self.installdir.dir, 'include')] if self.framework.argDB['prefix'] else petscincludes
418    includes = []
419    self.packagelibs = []
420    for i in self.framework.packages:
421      if not i.required:
422        if i.devicePackage:
423          self.addDefine('HAVE_DEVICE',1)
424        self.addDefine('HAVE_'+i.PACKAGE.replace('-','_'), 1)  # ONLY list package if it is used directly by PETSc (and not only by another package)
425      if not isinstance(i.lib, list):
426        i.lib = [i.lib]
427      if i.linkedbypetsc: self.packagelibs.extend(i.lib)
428      self.addMakeMacro(i.PACKAGE.replace('-','_')+'_LIB', self.libraries.toStringNoDupes(i.lib))
429      if hasattr(i,'include'):
430        if not isinstance(i.include,list):
431          i.include = [i.include]
432        includes.extend(i.include)
433        self.addMakeMacro(i.PACKAGE.replace('-','_')+'_INCLUDE',self.headers.toStringNoDupes(i.include))
434
435    self.complibs = self.compilers.flibs+self.compilers.cxxlibs+self.compilers.LIBS.split()
436    self.PETSC_EXTERNAL_LIB_BASIC = self.libraries.toStringNoDupes(self.packagelibs+self.complibs)
437
438    self.addMakeMacro('PETSC_EXTERNAL_LIB_BASIC',self.PETSC_EXTERNAL_LIB_BASIC)
439    allincludes = petscincludes + includes
440    allincludes_install = petscincludes_install + includes
441    self.PETSC_CC_INCLUDES = self.headers.toStringNoDupes(allincludes)
442    self.PETSC_CC_INCLUDES_INSTALL = self.headers.toStringNoDupes(allincludes_install)
443    self.addMakeMacro('PETSC_CC_INCLUDES',self.PETSC_CC_INCLUDES)
444    self.addMakeMacro('PETSC_CC_INCLUDES_INSTALL', self.PETSC_CC_INCLUDES_INSTALL)
445    if hasattr(self.compilers, 'FC'):
446      def modinc(includes):
447        return includes if self.fortran.fortranIsF90 else []
448      self.addMakeMacro('PETSC_FC_INCLUDES',self.headers.toStringNoDupes(allincludes,modinc(allincludes)))
449      self.addMakeMacro('PETSC_FC_INCLUDES_INSTALL',self.headers.toStringNoDupes(allincludes_install,modinc(allincludes_install)))
450
451    LIB_DIR = os.path.join(self.installdir.dir,'lib')
452    self.addDefine('LIB_DIR','"'+LIB_DIR+'"')
453
454    if self.framework.argDB['with-single-library']:
455      self.petsclib = '-lpetsc'
456      self.addDefine('USE_SINGLE_LIBRARY', '1')
457      self.addMakeMacro('LIBNAME','${INSTALL_LIB_DIR}/libpetsc.${AR_LIB_SUFFIX}')
458      self.addMakeMacro('SHLIBS','libpetsc')
459      self.addMakeMacro('PETSC_WITH_EXTERNAL_LIB',self.libraries.toStringNoDupes(['-L'+LIB_DIR, '-lpetsc']+self.packagelibs+self.complibs))
460      self.addMakeMacro('PETSC_SYS_LIB','${PETSC_WITH_EXTERNAL_LIB}')
461      self.addMakeMacro('PETSC_VEC_LIB','${PETSC_WITH_EXTERNAL_LIB}')
462      self.addMakeMacro('PETSC_MAT_LIB','${PETSC_WITH_EXTERNAL_LIB}')
463      self.addMakeMacro('PETSC_DM_LIB','${PETSC_WITH_EXTERNAL_LIB}')
464      self.addMakeMacro('PETSC_KSP_LIB','${PETSC_WITH_EXTERNAL_LIB}')
465      self.addMakeMacro('PETSC_SNES_LIB','${PETSC_WITH_EXTERNAL_LIB}')
466      self.addMakeMacro('PETSC_TS_LIB','${PETSC_WITH_EXTERNAL_LIB}')
467      self.addMakeMacro('PETSC_TAO_LIB','${PETSC_WITH_EXTERNAL_LIB}')
468    else:
469      self.petsclib = '-lpetsctao -lpetscts -lpetscsnes -lpetscksp -lpetscdm -lpetscmat -lpetscvec -lpetscsys'
470      self.addMakeMacro('PETSC_SYS_LIB', self.libraries.toStringNoDupes(['-L'+LIB_DIR,'-lpetscsys']+self.packagelibs+self.complibs))
471      self.addMakeMacro('PETSC_VEC_LIB', self.libraries.toStringNoDupes(['-L'+LIB_DIR,'-lpetscvec','-lpetscsys']+self.packagelibs+self.complibs))
472      self.addMakeMacro('PETSC_MAT_LIB', self.libraries.toStringNoDupes(['-L'+LIB_DIR,'-lpetscmat','-lpetscvec','-lpetscsys']+self.packagelibs+self.complibs))
473      self.addMakeMacro('PETSC_DM_LIB',  self.libraries.toStringNoDupes(['-L'+LIB_DIR,'-lpetscdm','-lpetscmat','-lpetscvec','-lpetscsys']+self.packagelibs+self.complibs))
474      self.addMakeMacro('PETSC_KSP_LIB', self.libraries.toStringNoDupes(['-L'+LIB_DIR,'-lpetscksp','-lpetscdm','-lpetscmat','-lpetscvec','-lpetscsys']+self.packagelibs+self.complibs))
475      self.addMakeMacro('PETSC_SNES_LIB',self.libraries.toStringNoDupes(['-L'+LIB_DIR,'-lpetscsnes','-lpetscksp','-lpetscdm','-lpetscmat','-lpetscvec','-lpetscsys']+self.packagelibs+self.complibs))
476      self.addMakeMacro('PETSC_TS_LIB',  self.libraries.toStringNoDupes(['-L'+LIB_DIR,'-lpetscts','-lpetscsnes','-lpetscksp','-lpetscdm','-lpetscmat','-lpetscvec','-lpetscsys']+self.packagelibs+self.complibs))
477      self.addMakeMacro('PETSC_TAO_LIB', self.libraries.toStringNoDupes(['-L'+LIB_DIR,'-lpetsctao','-lpetscts','-lpetscsnes','-lpetscksp','-lpetscdm','-lpetscmat','-lpetscvec','-lpetscsys']+self.packagelibs+self.complibs))
478    self.addMakeMacro('PETSC_LIB','${PETSC_TAO_LIB}')
479    self.addMakeMacro('PETSC_LIB_BASIC',self.petsclib)
480
481    if not os.path.exists(os.path.join(self.petscdir.dir,self.arch.arch,'lib')):
482      os.makedirs(os.path.join(self.petscdir.dir,self.arch.arch,'lib'))
483
484# add a makefile endtry for display
485    if self.framework.argDB['with-display']:
486      self.addMakeMacro('DISPLAY',self.framework.argDB['with-display'])
487
488    # add a makefile entry for configure options
489    self.addMakeMacro('CONFIGURE_OPTIONS', self.framework.getOptionsString(['configModules', 'optionsModule']).replace('\"','\\"'))
490
491    if self.framework.argDB['with-tau-perfstubs']:
492      self.addDefine('HAVE_TAU_PERFSTUBS',1)
493    return
494
495  def dumpConfigInfo(self):
496    import time
497    fd = open(os.path.join(self.arch.arch,'include','petscconfiginfo.h'),'w')
498    fd.write('static const char *petscconfigureoptions = "'+self.framework.getOptionsString(['configModules', 'optionsModule']).replace('\"','\\"').replace('\\ ','\\\\ ')+'";\n')
499    fd.close()
500    return
501
502  def dumpMachineInfo(self):
503    import platform
504    import datetime
505    import time
506    import script
507    def escape(s):
508      return s.replace('"',r'\"').replace(r'\ ',r'\\ ') # novermin
509    fd = open(os.path.join(self.arch.arch,'include','petscmachineinfo.h'),'w')
510    fd.write('static const char *petscmachineinfo = \"\\n\"\n')
511    fd.write('\"-----------------------------------------\\n\"\n')
512    buildhost = platform.node()
513    if os.environ.get('SOURCE_DATE_EPOCH'):
514      buildhost = "reproducible"
515    buildtime = datetime.datetime.utcfromtimestamp(int(os.environ.get('SOURCE_DATE_EPOCH', time.time())))
516    fd.write('\"Libraries compiled on %s on %s \\n\"\n' % (buildtime, buildhost))
517    fd.write('\"Machine characteristics: %s\\n\"\n' % (platform.platform()))
518    fd.write('\"Using PETSc directory: %s\\n\"\n' % (escape(self.installdir.petscDir)))
519    fd.write('\"Using PETSc arch: %s\\n\"\n' % (escape(self.installdir.petscArch)))
520    fd.write('\"-----------------------------------------\\n\";\n')
521    fd.write('static const char *petsccompilerinfo = \"\\n\"\n')
522    self.setCompilers.pushLanguage(self.languages.clanguage)
523    fd.write('\"Using C compiler: %s %s \\n\"\n' % (escape(self.setCompilers.getCompiler()), escape(self.setCompilers.getCompilerFlags())))
524    self.setCompilers.popLanguage()
525    if hasattr(self.compilers, 'FC'):
526      self.setCompilers.pushLanguage('FC')
527      fd.write('\"Using Fortran compiler: %s %s  %s\\n\"\n' % (escape(self.setCompilers.getCompiler()), escape(self.setCompilers.getCompilerFlags()), escape(self.setCompilers.CPPFLAGS)))
528      self.setCompilers.popLanguage()
529    fd.write('\"-----------------------------------------\\n\";\n')
530    fd.write('static const char *petsccompilerflagsinfo = \"\\n\"\n')
531    fd.write('\"Using include paths: %s\\n\"\n' % (escape(self.PETSC_CC_INCLUDES_INSTALL.replace('${PETSC_DIR}', self.installdir.petscDir))))
532    fd.write('\"-----------------------------------------\\n\";\n')
533    fd.write('static const char *petsclinkerinfo = \"\\n\"\n')
534    self.setCompilers.pushLanguage(self.languages.clanguage)
535    fd.write('\"Using C linker: %s\\n\"\n' % (escape(self.setCompilers.getLinker())))
536    self.setCompilers.popLanguage()
537    if hasattr(self.compilers, 'FC'):
538      self.setCompilers.pushLanguage('FC')
539      fd.write('\"Using Fortran linker: %s\\n\"\n' % (escape(self.setCompilers.getLinker())))
540      self.setCompilers.popLanguage()
541    fd.write('\"Using libraries: %s%s -L%s %s %s\\n\"\n' % (escape(self.setCompilers.CSharedLinkerFlag), escape(os.path.join(self.installdir.petscDir, self.installdir.petscArch, 'lib')), escape(os.path.join(self.installdir.petscDir, self.installdir.petscArch, 'lib')), escape(self.petsclib), escape(self.PETSC_EXTERNAL_LIB_BASIC)))
542    fd.write('\"-----------------------------------------\\n\";\n')
543    fd.close()
544    return
545
546  def configurePrefetch(self):
547    '''Sees if there are any prefetch functions supported'''
548    if config.setCompilers.Configure.isSolaris(self.log) or self.framework.argDB['with-ios'] or not self.framework.argDB['with-prefetch']:
549      self.addDefine('Prefetch(a,b,c)', ' ')
550      return
551    self.pushLanguage(self.languages.clanguage)
552    if self.checkLink('#include <xmmintrin.h>', 'void *v = 0;_mm_prefetch((const char*)v,_MM_HINT_NTA);\n'):
553      # The Intel Intrinsics manual [1] specifies the prototype
554      #
555      #   void _mm_prefetch(char const *a, int sel);
556      #
557      # but other vendors seem to insist on using subtly different
558      # prototypes, including void* for the pointer, and an enum for
559      # sel.  These are both reasonable changes, but negatively impact
560      # portability.
561      #
562      # [1] https://software.intel.com/file/6373
563      self.addDefine('HAVE_XMMINTRIN_H', 1)
564      self.addDefine('Prefetch(a,b,c)', '_mm_prefetch((const char*)(a),(c))')
565      self.addDefine('PREFETCH_HINT_NTA', '_MM_HINT_NTA')
566      self.addDefine('PREFETCH_HINT_T0',  '_MM_HINT_T0')
567      self.addDefine('PREFETCH_HINT_T1',  '_MM_HINT_T1')
568      self.addDefine('PREFETCH_HINT_T2',  '_MM_HINT_T2')
569    elif self.checkLink('#include <xmmintrin.h>', 'void *v = 0;_mm_prefetch(v,_MM_HINT_NTA);\n'):
570      self.addDefine('HAVE_XMMINTRIN_H', 1)
571      self.addDefine('Prefetch(a,b,c)', '_mm_prefetch((const void*)(a),(c))')
572      self.addDefine('PREFETCH_HINT_NTA', '_MM_HINT_NTA')
573      self.addDefine('PREFETCH_HINT_T0',  '_MM_HINT_T0')
574      self.addDefine('PREFETCH_HINT_T1',  '_MM_HINT_T1')
575      self.addDefine('PREFETCH_HINT_T2',  '_MM_HINT_T2')
576    elif self.checkLink('', 'void *v = 0;__builtin_prefetch(v,0,0);\n'):
577      # From GCC docs: void __builtin_prefetch(const void *addr,int rw,int locality)
578      #
579      #   The value of rw is a compile-time constant one or zero; one
580      #   means that the prefetch is preparing for a write to the memory
581      #   address and zero, the default, means that the prefetch is
582      #   preparing for a read. The value locality must be a compile-time
583      #   constant integer between zero and three. A value of zero means
584      #   that the data has no temporal locality, so it need not be left
585      #   in the cache after the access. A value of three means that the
586      #   data has a high degree of temporal locality and should be left
587      #   in all levels of cache possible. Values of one and two mean,
588      #   respectively, a low or moderate degree of temporal locality.
589      #
590      # Here we adopt Intel's x86/x86-64 naming scheme for the locality
591      # hints.  Using macros for these values in necessary since some
592      # compilers require an enum.
593      self.addDefine('Prefetch(a,b,c)', '__builtin_prefetch((a),(b),(c))')
594      self.addDefine('PREFETCH_HINT_NTA', '0')
595      self.addDefine('PREFETCH_HINT_T0',  '3')
596      self.addDefine('PREFETCH_HINT_T1',  '2')
597      self.addDefine('PREFETCH_HINT_T2',  '1')
598    else:
599      self.addDefine('Prefetch(a,b,c)', ' ')
600    self.popLanguage()
601
602  def delGenFiles(self):
603    '''Delete generated files'''
604    delfile = os.path.join(self.arch.arch,'lib','petsc','conf','files')
605    try:
606      os.unlink(delfile)
607    except: pass
608
609  def configureAtoll(self):
610    '''Checks if atoll exists'''
611    if self.checkLink('#define _POSIX_C_SOURCE 200112L\n#include <stdlib.h>','long v = atoll("25");\n(void)v') or self.checkLink ('#include <stdlib.h>','long v = atoll("25");\n(void)v'):
612       self.addDefine('HAVE_ATOLL', '1')
613
614  def configureUnused(self):
615    '''Sees if __attribute((unused)) is supported'''
616    if self.framework.argDB['with-ios']:
617      self.addDefine('UNUSED', ' ')
618      return
619    self.pushLanguage(self.languages.clanguage)
620    if self.checkLink('__attribute((unused)) static int myfunc(__attribute((unused)) void *name){ return 1;}', 'int i = 0;\nint j = myfunc(&i);\n(void)j;\ntypedef void* atype;\n__attribute((unused))  atype a'):
621      self.addDefine('UNUSED', '__attribute((unused))')
622    else:
623      self.addDefine('UNUSED', ' ')
624    self.popLanguage()
625
626  def configureIsatty(self):
627    '''Check if the Unix C function isatty() works correctly
628       Actually just assumes it does not work correctly on batch systems'''
629    if not self.framework.argDB['with-batch']:
630      self.addDefine('USE_ISATTY',1)
631
632  def configureDeprecated(self):
633    '''Check if __attribute((deprecated)) is supported'''
634    def checkDeprecated(macro_base, src, is_intel):
635      '''
636      run through the various attribute deprecated combinations and define MACRO_BAS(why) to the result
637      it if it compiles.
638
639      If none of the combos work, defines MACRO_BASE(why) as empty
640      '''
641      full_macro_name = macro_base + '(string_literal_why)'
642      for prefix in ('__attribute__', '__attribute','__declspec'):
643        if prefix == '__declspec':
644          # declspec does not have an extra set of brackets around the arguments
645          attr_bodies = ('deprecated(string_literal_why)', 'deprecated')
646        else:
647          attr_bodies = ('(deprecated(string_literal_why))', '(deprecated)')
648
649        for attr_body in attr_bodies:
650          attr_def = '{}({})'.format(prefix, attr_body)
651          test_src = '\n'.join((
652            '#define {} {}'.format(full_macro_name, attr_def),
653            src.format(macro_base + '("asdasdadsasd")')
654          ))
655          if self.checkCompile(test_src, ''):
656            self.logPrint('configureDeprecated: \'{}\' appears to work'.format(attr_def))
657            if is_intel and '(why)' in attr_body:
658              self.logPrint('configureDeprecated: Intel has conspired to make a supremely environment-sensitive compiler. The Intel compiler looks at the gcc executable in the environment to determine the language compatibility that it should attempt to emulate. Some important Cray installations have built PETSc using the Intel compiler, but with a newer gcc module loaded (e.g. 4.7). Thus at PETSc configure time, the Intel compiler decides to support the string argument, but the gcc found in the default user environment is older and does not support the argument.\n'.format(attr_def))
659              self.logPrint('*** WE WILL THEREFORE REJECT \'{}\' AND CONTINUE TESTING ***'.format(attr_def))
660              continue
661            self.addDefine(full_macro_name, attr_def)
662            return
663
664      self.addDefine(full_macro_name, ' ')
665      return
666
667    lang = self.languages.clanguage
668    with self.Language(lang):
669      is_intel = self.setCompilers.isIntel(self.getCompiler(lang=lang), self.log)
670      checkDeprecated('DEPRECATED_FUNCTION_BASE', '{} int myfunc(void) {{ return 1; }}', is_intel)
671      checkDeprecated('DEPRECATED_TYPEDEF_BASE', 'typedef int my_int {};', is_intel)
672      checkDeprecated('DEPRECATED_ENUM_BASE', 'enum E {{ oldval {}, newval }};', is_intel)
673      checkDeprecated('DEPRECATED_OBJECT_BASE', '{} int x;', is_intel)
674      # I was unable to make a CPP macro that takes the old and new values as separate
675      # arguments and builds the message needed by _Pragma hence the deprecation message is
676      # handled as it is
677      if self.checkCompile('#define TEST _Pragma("GCC warning \"Testing _Pragma\"") value'):
678        self.addDefine('DEPRECATED_MACRO_BASE_(why)', '_Pragma(#why)')
679        self.addDefine('DEPRECATED_MACRO_BASE(string_literal_why)', self.substPrefix + '_DEPRECATED_MACRO_BASE_(GCC warning string_literal_why)')
680      else:
681        self.addDefine('DEPRECATED_MACRO_BASE(why)', ' ')
682
683  def configureAlign(self):
684    '''Check if __attribute(aligned) is supported'''
685    code = '''\
686struct mystruct {int myint;} __attribute((aligned(16)));
687char assert_aligned[(sizeof(struct mystruct)==16)*2-1];
688'''
689    self.pushLanguage(self.languages.clanguage)
690    if self.checkCompile(code):
691      self.addDefine('ATTRIBUTEALIGNED(size)', '__attribute((aligned(size)))')
692      self.addDefine('HAVE_ATTRIBUTEALIGNED', 1)
693    else:
694      self.framework.logPrint('Incorrect attribute(aligned)')
695      self.addDefine('ATTRIBUTEALIGNED(size)', ' ')
696    self.popLanguage()
697    return
698
699  def configureExpect(self):
700    '''Sees if the __builtin_expect directive is supported'''
701    self.pushLanguage(self.languages.clanguage)
702    if self.checkLink('', 'if (__builtin_expect(0,1)) return 1;'):
703      self.addDefine('HAVE_BUILTIN_EXPECT', 1)
704    self.popLanguage()
705
706  def configureFunctionName(self):
707    '''Sees if the compiler supports __func__ or a variant.'''
708    def getFunctionName(lang):
709      name = '"unknown"'
710      self.pushLanguage(lang)
711      for fname in ['__func__','__FUNCTION__','__extension__ __func__']:
712        code = "if ("+fname+"[0] != 'm') return 1;"
713        if self.checkCompile('',code) and self.checkLink('',code):
714          name = fname
715          break
716      self.popLanguage()
717      return name
718    langs = []
719
720    self.addDefine('FUNCTION_NAME_C', getFunctionName('C'))
721    if hasattr(self.compilers, 'CXX'):
722      self.addDefine('FUNCTION_NAME_CXX', getFunctionName('Cxx'))
723
724  def configureIntptrt(self):
725    '''Determine what to use for uintptr_t and intptr_t'''
726    def staticAssertSizeMatchesVoidStar(inc,typename):
727      # The declaration is an error if either array size is negative.
728      # It should be okay to use an int that is too large, but it would be very unlikely for this to be the case
729      return self.checkCompile(inc, ('#define STATIC_ASSERT(cond) char negative_length_if_false[2*(!!(cond))-1]\n'
730                                     + 'STATIC_ASSERT(sizeof(void*) == sizeof(%s));'%typename))
731
732    def generate_uintptr_guesses():
733      for suff in ('max', '64', '32', '16'):
734        yield '#include <stdint.h>', 'uint{}_t'.format(suff), 'PRIx{}'.format(suff.upper())
735      yield '#include <stdlib.h>\n#include <string.h>', 'size_t', 'zx'
736      yield '', 'unsigned long long', 'llx'
737      yield '', 'unsigned long', 'lx'
738      yield '', 'unsigned', 'x'
739
740    def generate_intptr_guesses():
741      for suff in ('max', '64', '32', '16'):
742        yield '#include <stdint.h>', 'int{}_t'.format(suff), 'PRIx{}'.format(suff.upper())
743      yield '', 'long long', 'llx'
744      yield '', 'long', 'lx'
745      yield '', 'int', 'x'
746
747    def check(default_typename, generator):
748      macro_name = default_typename.upper()
749      with self.Language(self.languages.clanguage):
750        if self.checkCompile(
751            '#include <stdint.h>',
752            'int x; {type_name} i = ({type_name})&x; (void)i'.format(type_name=default_typename)
753        ):
754          typename     = default_typename
755          print_format = 'PRIxPTR'
756        else:
757          for include, typename, print_format in generator():
758            if staticAssertSizeMatchesVoidStar(include, typename):
759              break
760          else:
761            raise RuntimeError('Could not find any {} type matching void*'.format(macro_name))
762      self.addDefine(macro_name         , typename)
763      self.addDefine(macro_name + '_FMT', '\"#\" ' + print_format)
764      return
765
766    check('uintptr_t', generate_uintptr_guesses)
767    check('intptr_t', generate_intptr_guesses)
768    return
769
770  def configureRTLDDefault(self):
771    '''Check for dynamic library feature'''
772    if self.checkCompile('#include <dlfcn.h>\n void *ptr =  RTLD_DEFAULT;'):
773      self.addDefine('HAVE_RTLD_DEFAULT','1')
774    return
775
776  def configureSolaris(self):
777    '''Solaris specific stuff'''
778    if os.path.isdir(os.path.join('/usr','ucblib')):
779      try:
780        flag = getattr(self.setCompilers, self.language[-1]+'SharedLinkerFlag')
781      except AttributeError:
782        flag = None
783      if flag is None:
784        self.compilers.LIBS += ' -L/usr/ucblib'
785      else:
786        self.compilers.LIBS += ' '+flag+'/usr/ucblib'
787    return
788
789  def configureDarwin(self):
790    '''Log brew configuration for Apple systems'''
791    try:
792      self.executeShellCommand(['brew', 'config'], log = self.log)
793      self.executeShellCommand(['brew', 'info', 'gcc'], log = self.log)
794    except:
795      pass
796    return
797
798  def configureLinux(self):
799    '''Linux specific stuff'''
800    # TODO: Test for this by mallocing an odd number of floats and checking the address
801    self.addDefine('HAVE_DOUBLE_ALIGN_MALLOC', 1)
802    return
803
804  def configureWin32(self):
805    '''Win32 non-cygwin specific stuff'''
806    kernel32=0
807    if self.libraries.add('Kernel32.lib','GetComputerName',prototype='#include <windows.h>', call='GetComputerName(NULL,NULL);'):
808      self.addDefine('HAVE_WINDOWS_H',1)
809      self.addDefine('HAVE_GETCOMPUTERNAME',1)
810      kernel32=1
811    elif self.libraries.add('kernel32','GetComputerName',prototype='#include <windows.h>', call='GetComputerName(NULL,NULL);'):
812      self.addDefine('HAVE_WINDOWS_H',1)
813      self.addDefine('HAVE_GETCOMPUTERNAME',1)
814      kernel32=1
815    if kernel32:
816      if self.framework.argDB['with-windows-graphics']:
817        self.addDefine('USE_WINDOWS_GRAPHICS',1)
818      if self.checkLink('#include <windows.h>','LoadLibrary(0)'):
819        self.addDefine('HAVE_LOADLIBRARY',1)
820      if self.checkLink('#include <windows.h>','GetProcAddress(0,0)'):
821        self.addDefine('HAVE_GETPROCADDRESS',1)
822      if self.checkLink('#include <windows.h>','FreeLibrary(0)'):
823        self.addDefine('HAVE_FREELIBRARY',1)
824      if self.checkLink('#include <windows.h>','GetLastError()'):
825        self.addDefine('HAVE_GETLASTERROR',1)
826      if self.checkLink('#include <windows.h>','SetLastError(0)'):
827        self.addDefine('HAVE_SETLASTERROR',1)
828      if self.checkLink('#include <windows.h>\n','QueryPerformanceCounter(0);\n'):
829        self.addDefine('USE_MICROSOFT_TIME',1)
830    if self.libraries.add('Advapi32.lib','GetUserName',prototype='#include <windows.h>', call='GetUserName(NULL,NULL);'):
831      self.addDefine('HAVE_GET_USER_NAME',1)
832    elif self.libraries.add('advapi32','GetUserName',prototype='#include <windows.h>', call='GetUserName(NULL,NULL);'):
833      self.addDefine('HAVE_GET_USER_NAME',1)
834
835    if not self.libraries.add('User32.lib','GetDC',prototype='#include <windows.h>',call='GetDC(0);'):
836      self.libraries.add('user32','GetDC',prototype='#include <windows.h>',call='GetDC(0);')
837    if not self.libraries.add('Gdi32.lib','CreateCompatibleDC',prototype='#include <windows.h>',call='CreateCompatibleDC(0);'):
838      self.libraries.add('gdi32','CreateCompatibleDC',prototype='#include <windows.h>',call='CreateCompatibleDC(0);')
839
840    if not self.checkCompile('#include <sys/types.h>\n','uid_t u;\n(void)u'):
841      self.addTypedef('int', 'uid_t')
842      self.addTypedef('int', 'gid_t')
843    if not self.checkLink('#if defined(PETSC_HAVE_UNISTD_H)\n#include <unistd.h>\n#endif\n','int a=R_OK;\n(void)a'):
844      self.framework.addDefine('R_OK', '04')
845      self.framework.addDefine('W_OK', '02')
846      self.framework.addDefine('X_OK', '01')
847    if not self.checkLink('#include <sys/stat.h>\n','int a=0;\nif (S_ISDIR(a)){}\n'):
848      self.framework.addDefine('S_ISREG(a)', '(((a)&_S_IFMT) == _S_IFREG)')
849      self.framework.addDefine('S_ISDIR(a)', '(((a)&_S_IFMT) == _S_IFDIR)')
850    if self.checkCompile('#include <windows.h>\n','LARGE_INTEGER a;\nDWORD b=a.u.HighPart;\n'):
851      self.addDefine('HAVE_LARGE_INTEGER_U',1)
852
853    # Windows requires a Binary file creation flag when creating/opening binary files.  Is a better test in order?
854    if self.checkCompile('#include <windows.h>\n#include <fcntl.h>\n', 'int flags = O_BINARY;'):
855      self.addDefine('HAVE_O_BINARY',1)
856
857    if self.compilers.CC.find('win32fe') >= 0:
858      self.addDefine('HAVE_WINDOWS_COMPILERS',1)
859      self.addDefine('DIR_SEPARATOR','\'\\\\\'')
860      self.addDefine('REPLACE_DIR_SEPARATOR','\'/\'')
861      self.addDefine('CANNOT_START_DEBUGGER',1)
862      (petscdir,error,status) = self.executeShellCommand('cygpath -w '+self.installdir.petscDir, log = self.log)
863      self.addDefine('DIR','"'+petscdir.replace('\\','\\\\')+'"')
864      (petscdir,error,status) = self.executeShellCommand('cygpath -m '+self.installdir.petscDir, log = self.log)
865      self.addMakeMacro('wPETSC_DIR',petscdir)
866      if self.dataFilesPath.datafilespath:
867        (datafilespath,error,status) = self.executeShellCommand('cygpath -m '+self.dataFilesPath.datafilespath, log = self.log)
868        self.addMakeMacro('DATAFILESPATH',datafilespath)
869
870    else:
871      self.addDefine('REPLACE_DIR_SEPARATOR','\'\\\\\'')
872      self.addDefine('DIR_SEPARATOR','\'/\'')
873      self.addDefine('DIR','"'+self.installdir.petscDir+'"')
874      self.addMakeMacro('wPETSC_DIR',self.installdir.petscDir)
875      if self.dataFilesPath.datafilespath:
876        self.addMakeMacro('DATAFILESPATH',self.dataFilesPath.datafilespath)
877    self.addDefine('ARCH','"'+self.installdir.petscArch+'"')
878    return
879
880  def configureCoverageForLang(self, log_printer_cls, lang, extra_coverage_flags=None, extra_debug_flags=None):
881    """
882    Check that a compiler accepts code-coverage flags. If the compiler does accept code-coverage flags
883    try to set debugging flags equivalent to -Og.
884
885    Arguments:
886    - lang: the language to check the coverage flag for
887    - extra_coverage_flags: a list of extra flags to use when checking the coverage flags
888    - extra_debug_flags: a list of extra flags to try when setting debug flags
889
890    On success:
891    - defines PETSC_USE_COVERAGE to 1
892    """
893    log_print = log_printer_cls(self)
894
895    def quoted(string):
896      return string.join(("'", "'"))
897
898    def make_flag_list(default, extra):
899      ret = [default]
900      if extra is not None:
901        assert isinstance(extra, list)
902        ret.extend(extra)
903      return ret
904
905    log_print('Checking coverage flag for language {}'.format(lang))
906
907    compiler = self.getCompiler(lang=lang)
908    if self.setCompilers.isGNU(compiler, self.log):
909      is_gnuish = True
910    elif self.setCompilers.isClang(compiler, self.log):
911      is_gnuish = True
912    else:
913      is_gnuish = False
914
915    # if not gnuish and we don't have a set of extra flags, bail
916    if not is_gnuish and extra_coverage_flags is None:
917      log_print('Don\'t know how to add coverage for compiler {}. Only know how to add coverage for gnu-like compilers (either gcc or clang). Skipping it!'.format(quoted(compiler)))
918      return
919
920    coverage_flags = make_flag_list('--coverage', extra_coverage_flags)
921    log_print('Checking set of coverage flags: {}'.format(coverage_flags))
922
923    found = None
924    with self.Language(lang):
925      with self.setCompilers.Language(lang):
926        for flag in coverage_flags:
927          # the linker also needs to see the coverage flag
928          with self.setCompilers.extraCompilerFlags([flag], compilerOnly=False) as skip_flags:
929            if not skip_flags and self.checkRun():
930              # flag was accepted
931              found = flag
932              break
933
934          log_print(
935            'Compiler {} did not accept coverage flag {}'.format(quoted(compiler), quoted(flag))
936          )
937
938        if found is None:
939          log_print(
940            'Compiler {} did not accept ANY coverage flags: {}, bailing!'.format(
941              quoted(compiler), coverage_flags
942            )
943          )
944          return
945
946        # must do this exactly here since:
947        #
948        # 1. setCompilers.extraCompilerFlags() will reset the compiler flags on __exit__()
949        #    (so cannot do it in the loop)
950        # 2. we need to set the compiler flag while setCompilers.Language() is still in
951        #    effect (so cannot do it outside the with statements)
952        self.setCompilers.insertCompilerFlag(flag, False)
953
954    if not self.functions.haveFunction('__gcov_dump'):
955      self.functions.checkClassify(['__gcov_dump'])
956
957    # now check if we can override the optimization level. It is only kosher to do so if
958    # the user did not explicitly set the optimization flags (via CFLAGS, CXXFLAGS,
959    # CXXOPTFLAGS, etc). If they have done so, we sternly warn them about their lapse in
960    # judgement
961    with self.Language(lang):
962      compiler_flags = self.getCompilerFlags()
963
964    user_set          = 0
965    allowed_opt_flags = re.compile(r'|'.join((r'-O[01g]', r'-g[1-9]*')))
966    for flagsname in [self.getCompilerFlagsName(lang), self.compilerFlags.getOptionalFlagsName(lang)]:
967      if flagsname in self.argDB:
968        opt_flags = [
969          f for f in self.compilerFlags.findOptFlags(compiler_flags) if not allowed_opt_flags.match(f)
970        ]
971        if opt_flags:
972          self.logPrintWarning('Coverage requested, but optimization flag(s) {} found in {}. Coverage collection will work, but may be less accurate. Suggest removing the flag and/or using -Og (or equivalent) instead'.format(', '.join(map(quoted, opt_flags)), quoted(flagsname)))
973          user_set = 1
974          break
975
976    # disable this for now, the warning should be sufficient. If the user still chooses to
977    # ignore it, then that's on them
978    if 0 and not user_set:
979      debug_flags = make_flag_list('-Og', extra_debug_flags)
980      with self.setCompilers.Language(lang):
981        for flag in debug_flags:
982          try:
983            self.setCompilers.addCompilerFlag(flag)
984          except RuntimeError:
985            continue
986          break
987
988    self.addDefine('USE_COVERAGE', 1)
989    return
990
991  def configureCoverage(self):
992    """
993    Configure coverage for all available languages.
994
995    If user did not request coverage, this function does nothing and returns immediatel.
996    Therefore the following only apply to the case where the user requested coverage.
997
998    On success:
999    - defines PETSC_USE_COVERAGE to 1
1000
1001    On failure:
1002    - If no compilers supported the coverage flag, throws RuntimeError
1003    -
1004    """
1005    class LogPrinter:
1006      def __init__(self, cfg):
1007        self.cfg = cfg
1008        try:
1009          import inspect
1010
1011          calling_func_stack = inspect.stack()[1]
1012          if sys.version_info >= (3, 5):
1013            func_name = calling_func_stack.function
1014          else:
1015            func_name = calling_func_stack[3]
1016        except:
1017          func_name = 'Unknown'
1018        self.fmt_str = func_name + '(): {}'
1019
1020      def __call__(self, msg, *args, **kwargs):
1021        return self.cfg.logPrint(self.fmt_str.format(msg), *args, **kwargs)
1022
1023    argdb_flag = 'with-coverage'
1024    log_print  = LogPrinter(self)
1025    if not self.argDB[argdb_flag]:
1026      log_print('coverage was disabled from command line or default')
1027      return
1028
1029    tested_langs = []
1030    for LANG in ['C', 'Cxx', 'CUDA', 'HIP', 'SYCL', 'FC']:
1031      compilerName = LANG.upper() if LANG in {'Cxx', 'FC'} else LANG + 'C'
1032      if hasattr(self.setCompilers, compilerName):
1033        kwargs = {}
1034        if LANG in {'CUDA'}:
1035          # nvcc preprocesses the base file into a bunch of intermediate files, which are
1036          # then compiled by the host compiler. Why is this a problem?  Because the
1037          # generated coverage data is based on these preprocessed source files! So gcov
1038          # tries to read it later, but since its in the tmp directory it cannot. Thus we
1039          # need to keep them around (in a place we know about).
1040          nvcc_tmp_dir = os.path.join(self.petscdir.dir, self.arch.arch, 'nvcc_tmp')
1041          try:
1042            os.mkdir(nvcc_tmp_dir)
1043          except FileExistsError:
1044            pass
1045          kwargs['extra_coverage_flags'] = [
1046            '-Xcompiler --coverage -Xcompiler -fPIC --keep --keep-dir={}'.format(nvcc_tmp_dir)
1047          ]
1048          if self.kokkos.found:
1049            # yet again the kokkos nvcc_wrapper goes out of its way to be as useless as
1050            # possible. Its default arch (sm_35) is actually too low to compile kokkos,
1051            # for whatever reason this works if you dont use the --keep and --keep-dir
1052            # flags above.
1053            kwargs['extra_coverage_flags'].append('-arch=native')
1054            kwargs['extra_debug_flags'] = ['-Xcompiler -Og']
1055        tested_langs.append(LANG)
1056        self.executeTest(self.configureCoverageForLang, args=[LogPrinter, LANG], kargs=kwargs)
1057
1058    if not self.defines.get('USE_COVERAGE'):
1059      # coverage was requested but no compilers accepted it, this is an error
1060      raise RuntimeError(
1061        'Coverage was requested (--{}={}) but none of the compilers supported it:\n{}\n'.format(
1062          argdb_flag, self.argDB[argdb_flag],
1063          '\n'.join(['  - {} ({})'.format(self.getCompiler(lang=lang), lang) for lang in tested_langs])
1064        )
1065      )
1066
1067    return
1068    # Disabled for now, since this does not really work. It solves the problem of
1069    # "undefined reference to __gcov_flush()" but if we add -lgcov we get:
1070    #
1071    # duplicate symbol '___gcov_reset' in:
1072    #     /Library/.../libclang_rt.profile_osx.a(GCDAProfiling.c.o)
1073    #     /opt/.../libgcov.a(_gcov_reset.o)
1074    # duplicate symbol '___gcov_dump' in:
1075    #     /opt/.../libgcov.a(_gcov_dump.o)
1076    #     /Library/.../libclang_rt.profile_osx.a(GCDAProfiling.c.o)
1077    # duplicate symbol '___gcov_fork' in:
1078    #     /opt/.../libgcov.a(_gcov_fork.o)
1079    #     /Library/.../libclang_rt.profile_osx.a(GCDAProfiling.c.o)
1080    #
1081    # I don't know how to solve this.
1082
1083    log_print('Checking if compilers can cross-link disparate coverage libraries')
1084    # At least one of the compilers has coverage enabled. Now need to make sure multiple
1085    # code coverage impls work together, specifically when using clang C/C++ compiler with
1086    # gfortran.
1087    if not hasattr(self.setCompilers, 'FC'):
1088      log_print('No fortran compiler detected. No need to check cross-linking!')
1089      return
1090
1091    c_lang = self.languages.clanguage
1092    if not self.setCompilers.isClang(self.getCompiler(lang=c_lang), self.log):
1093      # must be GCC
1094      log_print('C-language ({}) compiler is not clang, assuming it is GCC, so cross-linking with FC ({}) assumed to be OK'.format(c_lang, self.getCompiler(lang='FC')))
1095      return
1096
1097    # If we are here we:
1098    #   1. Have both C/C++ compiler and fortran compiler
1099    #   2. The C/C++ compiler is *not* the same as the fortran compiler (unless we start
1100    #      using flang)
1101    #
1102    # Now we check if we can cross-link
1103    def can_cross_link(**kwargs):
1104      f_body = "      subroutine foo()\n      print*,'testing'\n      return\n      end\n"
1105      c_body = "int main() { }"
1106
1107      return self.compilers.checkCrossLink(
1108        f_body, c_body, language1='FC', language2=c_lang, extralibs=self.compilers.flibs, **kwargs
1109      )
1110
1111    log_print('Trying to cross-link WITHOUT extra libs')
1112    if can_cross_link():
1113      log_print('Successfully cross-linked WITHOUT extra libs')
1114      # success, we already can cross-link
1115      return
1116
1117    extra_libs = ['-lgcov']
1118    log_print('Trying to cross-link with extra libs: {}'.format(extra_libs))
1119    if can_cross_link(extraObjs=extra_libs):
1120      log_print(
1121        'Successfully cross-linked using extra libs: {}, adding them to LIBS'.format(extra_libs)
1122      )
1123      self.setCompilers.LIBS += ' ' + ' '.join(extra_libs)
1124    else:
1125      # maybe should be an error?
1126      self.logPrintWarning("Could not successfully cross-link covered code between {} and FC. Sometimes this is a false positive. Assuming this does eventually end up working when the full link-line is assembled when building PETSc. If you later encounter linker errors about missing __gcov_exit(), __gcov_init(), __llvm_cov_flush() etc. this is why!".format(c_lang))
1127    return
1128
1129  def configureCoverageExecutable(self):
1130    """
1131    Check that a code-coverage collecting tool exists and is on PATH.
1132
1133    On success:
1134    - Adds PETSC_COVERAGE_EXEC make macro containing the full path to the coverage tool executable.
1135
1136    Raises RuntimeError if:
1137    - User explicitly requests auto-detection of the coverage tool from command line, and this
1138      routine fails to guess the suitable tool name.
1139    - The routine fails to find the tool, and --with-coverage is true
1140    """
1141    def log_print(msg, *args, **kwargs):
1142      self.logPrint('checkCoverage: '+str(msg), *args, **kwargs)
1143      return
1144
1145    def quoted(string):
1146      return string.join(("'", "'"))
1147
1148    required         = bool(self.argDB['with-coverage'])
1149    arg_opt          = self.argDB['with-coverage-exec']
1150    use_default_path = True
1151    search_path      = ''
1152
1153    log_print('{} to find an executable'.format('REQUIRED' if required else 'NOT required'))
1154    if arg_opt in {'auto', 'default-auto', '1'}:
1155      # detect it based on the C language compiler, hopefully this does not clash!
1156      lang     = self.setCompilers.languages.clanguage
1157      compiler = self.getCompiler(lang=lang)
1158      log_print('User did not explicitly set coverage exec (got {}), trying to auto-detect based on compiler {}'.format(quoted(arg_opt), quoted(compiler)))
1159      if self.setCompilers.isGNU(compiler, self.log):
1160        compiler_version_re = re.compile(r'[gG][cC\+\-]+[0-9]* \(.+\) (\d+)\.(\d+)\.(\d+)')
1161        exec_names          = ['gcov']
1162      elif self.setCompilers.isClang(compiler, self.log):
1163        compiler_version_re = re.compile(r'clang version (\d+)\.(\d+)\.(\d+)')
1164        exec_names          = ['llvm-cov']
1165        if self.setCompilers.isDarwin(self.log):
1166          # macOS masquerades llvm-cov as just 'gcov', so we add this to the list in case
1167          # bare llvm-cov does not work
1168          exec_names.append('gcov')
1169      elif arg_opt == 'default-auto' and not required:
1170        # default-auto implies the user did not set it via command line!
1171        log_print('Could not auto-detect coverage tool for {}, not a gnuish compiler. Bailing since user did not explicitly set exec on the commandline'.format(quoted(compiler)))
1172        return
1173      else:
1174        # implies 'auto' explicitly set by user, or we were required to find
1175        # something. either way we should error
1176        raise RuntimeError('Could not auto-detect coverage tool for {}, please set coverage tool name explicitly'.format(quoted(compiler)))
1177
1178      try:
1179        compiler_version_str = self.compilerFlags.version[lang]
1180      except KeyError:
1181        compiler_version_str = 'Unknown'
1182
1183      log_print('Searching version string {} (for compiler {}) using pattern {}'.format(quoted(compiler_version_str), quoted(compiler), quoted(compiler_version_re.pattern)))
1184      compiler_version = compiler_version_re.search(compiler_version_str)
1185      if compiler_version is not None:
1186        log_print('Found major = {}, minor = {}, patch = {}'.format(compiler_version.group(1), compiler_version.group(2), compiler_version.group(3)))
1187        # form [llvm-cov-14, llvm-cov-14.0, llvm-cov, etc.]
1188        cov_exec_name = exec_names[0]
1189        exec_names    = [
1190          # llvm-cov-14
1191          '{}-{}'.format(cov_exec_name, compiler_version.group(1)),
1192           # llvm-cov-14.0
1193          '{}-{}.{}'.format(cov_exec_name, compiler_version.group(1), compiler_version.group(2))
1194        ] + exec_names
1195    else:
1196      log_print('User explicitly set coverage exec as {}'.format(quoted(arg_opt)))
1197      par_dir = os.path.dirname(arg_opt)
1198      if os.path.exists(par_dir):
1199        # arg_opt is path-like, we should only search the provided directory when we go
1200        # looking for the tool
1201        use_default_path = False
1202        search_path      = par_dir
1203      exec_names = [arg_opt]
1204
1205    make_macro_name = 'PETSC_COVERAGE_EXEC'
1206    log_print('Checking for coverage tool(s):\n{}'.format('\n'.join('- '+t for t in exec_names)))
1207    found_exec = self.getExecutables(
1208      exec_names,
1209      path=search_path, getFullPath=True, useDefaultPath=use_default_path, resultName=make_macro_name
1210    )
1211
1212    if found_exec is None:
1213      # didn't find the coverage tool
1214      if required:
1215        raise RuntimeError('Coverage tool(s) {} could not be found. Please provide explicit path to coverage tool'.format(exec_names))
1216      return
1217
1218    found_exec_name = os.path.basename(found_exec)
1219    if 'llvm-cov' in found_exec_name and 'gcov' not in found_exec_name:
1220      # llvm-cov needs to be called as 'llvm-cov gcov' to work
1221      self.addMakeMacro(make_macro_name, found_exec + ' gcov')
1222    return
1223
1224  def configureStrictPetscErrorCode(self):
1225    """
1226    Enables or disables strict PetscErrorCode checking.
1227
1228    If --with-strict-petscerrorcode = 1:
1229    - defines PETSC_USE_STRICT_PETSCERRORCODE to 1
1230
1231    Else:
1232    - deletes any prior PETSC_USE_STRICT_PETSCERRORCODE definitions (if they exist)
1233    """
1234    define_name = 'USE_STRICT_PETSCERRORCODE'
1235    if self.argDB['with-strict-petscerrorcode']:
1236      self.addDefine(define_name, 1)
1237    else:
1238      # in case it was somehow added previously
1239      self.delDefine(define_name)
1240    return
1241
1242#-----------------------------------------------------------------------------------------------------
1243  def configureCygwinBrokenPipe(self):
1244    '''Cygwin version <= 1.7.18 had issues with pipes and long commands invoked from gnu-make
1245    http://cygwin.com/ml/cygwin/2013-05/msg00340.html '''
1246    if config.setCompilers.Configure.isCygwin(self.log):
1247      import platform
1248      import re
1249      r=re.compile("([0-9]+).([0-9]+).([0-9]+)")
1250      m=r.match(platform.release())
1251      major=int(m.group(1))
1252      minor=int(m.group(2))
1253      subminor=int(m.group(3))
1254      if ((major < 1) or (major == 1 and minor < 7) or (major == 1 and minor == 7 and subminor <= 18)):
1255        self.addMakeMacro('PETSC_CYGWIN_BROKEN_PIPE','1')
1256    return
1257
1258#-----------------------------------------------------------------------------------------------------
1259  def configureDefaultArch(self):
1260    conffile = os.path.join('lib','petsc','conf', 'petscvariables')
1261    if self.framework.argDB['with-default-arch']:
1262      fd = open(conffile, 'w')
1263      fd.write('PETSC_ARCH='+self.arch.arch+'\n')
1264      fd.write('PETSC_DIR='+self.petscdir.dir+'\n')
1265      fd.write('include '+os.path.join('$(PETSC_DIR)','$(PETSC_ARCH)','lib','petsc','conf','petscvariables')+'\n')
1266      fd.close()
1267      self.framework.actions.addArgument('PETSc', 'Build', 'Set default architecture to '+self.arch.arch+' in '+conffile)
1268    elif os.path.isfile(conffile):
1269      try:
1270        os.unlink(conffile)
1271      except:
1272        raise RuntimeError('Unable to remove file '+conffile+'. Did a different user create it?')
1273    return
1274
1275#-----------------------------------------------------------------------------------------------------
1276  def configureScript(self):
1277    '''Output a script in the conf directory which will reproduce the configuration'''
1278    import nargs
1279    import sys
1280    scriptName = os.path.join(self.arch.arch,'lib','petsc','conf', 'reconfigure-'+self.arch.arch+'.py')
1281    args = dict([(nargs.Arg.parseArgument(arg)[0], arg) for arg in self.framework.clArgs])
1282    if 'with-clean' in args:
1283      del args['with-clean']
1284    if 'force' in args:
1285      del args['force']
1286    if 'configModules' in args:
1287      if nargs.Arg.parseArgument(args['configModules'])[1] == 'PETSc.Configure':
1288        del args['configModules']
1289    if 'optionsModule' in args:
1290      if nargs.Arg.parseArgument(args['optionsModule'])[1] == 'config.compilerOptions':
1291        del args['optionsModule']
1292    if not 'PETSC_ARCH' in args:
1293      args['PETSC_ARCH'] = 'PETSC_ARCH='+str(self.arch.arch)
1294    f = open(scriptName, 'w')
1295    f.write('#!'+sys.executable+'\n')
1296    f.write('if __name__ == \'__main__\':\n')
1297    f.write('  import sys\n')
1298    f.write('  import os\n')
1299    f.write('  sys.path.insert(0, os.path.abspath(\'config\'))\n')
1300    f.write('  import configure\n')
1301    # pretty print repr(args.values())
1302    f.write('  configure_options = [\n')
1303    for itm in sorted(args.values()):
1304      f.write('    \''+str(itm)+'\',\n')
1305    f.write('  ]\n')
1306    f.write('  configure.petsc_configure(configure_options)\n')
1307    f.close()
1308    try:
1309      os.chmod(scriptName, 0o775)
1310    except OSError as e:
1311      self.framework.logPrint('Unable to make reconfigure script executable:\n'+str(e))
1312    self.framework.actions.addArgument('PETSc', 'File creation', 'Created '+scriptName+' for automatic reconfiguration')
1313    return
1314
1315  def configureInstall(self):
1316    '''Setup the directories for installation'''
1317    if self.framework.argDB['prefix']:
1318      self.addMakeRule('print_mesg_after_build','',
1319       ['-@echo "========================================="',
1320        '-@echo "Now to install the libraries do:"',
1321        '-@echo "%s${MAKE_USER} PETSC_DIR=${PETSC_DIR} PETSC_ARCH=${PETSC_ARCH} install"' % self.installdir.installSudo,
1322        '-@echo "========================================="'])
1323    else:
1324      self.addMakeRule('print_mesg_after_build','',
1325       ['-@echo "========================================="',
1326        '-@echo "Now to check if the libraries are working do:"',
1327        '-@echo "${MAKE_USER} PETSC_DIR=${PETSC_DIR} PETSC_ARCH=${PETSC_ARCH} check"',
1328        '-@echo "========================================="'])
1329      return
1330
1331  def postProcessPackages(self):
1332    postPackages=[]
1333    for i in self.framework.packages:
1334      if hasattr(i,'postProcess'): postPackages.append(i)
1335    if postPackages:
1336      # ctetgen needs petsc conf files. so attempt to create them early
1337      self.framework.dumpConfFiles()
1338      # tacky fix for dependency of Aluimia on Pflotran; requested via petsc-dev Matt provide a correct fix
1339      for i in postPackages:
1340        if i.name.upper() in ['PFLOTRAN']:
1341          i.postProcess()
1342          postPackages.remove(i)
1343      for i in postPackages: i.postProcess()
1344      for i in postPackages:
1345        if i.installedpetsc:
1346          self.installed = 1
1347          break
1348    return
1349
1350  def configure(self):
1351    if 'package-prefix-hash' in self.argDB:
1352      # turn off prefix if it was only used to for installing external packages.
1353      self.framework.argDB['prefix'] = ''
1354      self.dir = os.path.abspath(os.path.join(self.petscdir.dir, self.arch.arch))
1355      self.installdir.dir = self.dir
1356      self.installdir.petscDir = self.petscdir.dir
1357      self.petscDir = self.petscdir.dir
1358      self.petscArch = self.arch.arch
1359      self.addMakeMacro('PREFIXDIR',self.dir)
1360      self.confDir = os.path.abspath(os.path.join(self.petscdir.dir, self.arch.arch))
1361
1362    if not os.path.samefile(self.petscdir.dir, os.getcwd()):
1363      raise RuntimeError('Wrong PETSC_DIR option specified: '+str(self.petscdir.dir) + '\n  Configure invoked in: '+os.path.realpath(os.getcwd()))
1364    if self.framework.argDB['prefix'] and os.path.isdir(self.framework.argDB['prefix']) and os.path.samefile(self.framework.argDB['prefix'],self.petscdir.dir):
1365      raise RuntimeError('Incorrect option --prefix='+self.framework.argDB['prefix']+' specified. It cannot be same as PETSC_DIR!')
1366    if self.framework.argDB['prefix'] and self.framework.argDB['prefix'].find(' ') > -1:
1367      raise RuntimeError('Your --prefix '+self.framework.argDB['prefix']+' has spaces in it; this is not allowed.\n Use a --prefix that does not have spaces in it')
1368    if self.framework.argDB['prefix'] and os.path.isdir(self.framework.argDB['prefix']) and os.path.samefile(self.framework.argDB['prefix'],os.path.join(self.petscdir.dir,self.arch.arch)):
1369      raise RuntimeError('Incorrect option --prefix='+self.framework.argDB['prefix']+' specified. It cannot be same as PETSC_DIR/PETSC_ARCH!')
1370    self.framework.header          = os.path.join(self.arch.arch,'include','petscconf.h')
1371    self.framework.cHeader         = os.path.join(self.arch.arch,'include','petscfix.h')
1372    self.framework.poisonheader    = os.path.join(self.arch.arch,'include','petscconf_poison.h')
1373    self.framework.pkgheader       = os.path.join(self.arch.arch,'include','petscpkg_version.h')
1374    self.framework.makeMacroHeader = os.path.join(self.arch.arch,'lib','petsc','conf','petscvariables')
1375    self.framework.makeRuleHeader  = os.path.join(self.arch.arch,'lib','petsc','conf','petscrules')
1376    if self.libraries.math is None:
1377      raise RuntimeError('PETSc requires a functional math library. Please send configure.log to petsc-maint@mcs.anl.gov.')
1378    if self.languages.clanguage == 'Cxx' and not hasattr(self.compilers, 'CXX'):
1379      raise RuntimeError('Cannot set C language to C++ without a functional C++ compiler.')
1380    self.executeTest(self.configureRTLDDefault)
1381    self.executeTest(self.configurePrefetch)
1382    self.executeTest(self.configureUnused)
1383    self.executeTest(self.configureDeprecated)
1384    self.executeTest(self.configureIsatty)
1385    self.executeTest(self.configureExpect)
1386    self.executeTest(self.configureAlign)
1387    self.executeTest(self.configureFunctionName)
1388    self.executeTest(self.configureIntptrt)
1389    self.executeTest(self.configureSolaris)
1390    self.executeTest(self.configureLinux)
1391    self.executeTest(self.configureDarwin)
1392    self.executeTest(self.configureWin32)
1393    self.executeTest(self.configureCygwinBrokenPipe)
1394    self.executeTest(self.configureDefaultArch)
1395    self.executeTest(self.configureScript)
1396    self.executeTest(self.configureInstall)
1397    self.executeTest(self.configureAtoll)
1398    self.executeTest(self.configureCoverage)
1399    self.executeTest(self.configureCoverageExecutable)
1400    self.executeTest(self.configureStrictPetscErrorCode)
1401
1402    self.Dump()
1403    self.dumpConfigInfo()
1404    self.dumpMachineInfo()
1405    self.delGenFiles()
1406    # need to save the current state of BuildSystem so that postProcess() packages can read it in and perhaps run make install
1407    self.framework.storeSubstitutions(self.framework.argDB)
1408    self.framework.argDB['configureCache'] = pickle.dumps(self.framework)
1409    self.framework.argDB.save(force = True)
1410    self.DumpPkgconfig('PETSc.pc')
1411    self.DumpPkgconfig('petsc.pc')
1412    self.DumpModule()
1413    self.postProcessPackages()
1414    self.framework.log.write('================================================================================\n')
1415    self.logClear()
1416    return
1417