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