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