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