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