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