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