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