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