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