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