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