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