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