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