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