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