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