xref: /petsc/config/PETSc/Configure.py (revision 732e2eb99afef1b984167973f126bbed28c96039)
1import config.base
2
3import os
4import re
5
6# The sorted() builtin is not available with python-2.3
7try: sorted
8except NameError:
9  def sorted(lst):
10    lst.sort()
11    return lst
12
13class Configure(config.base.Configure):
14  def __init__(self, framework):
15    config.base.Configure.__init__(self, framework)
16    self.headerPrefix = 'PETSC'
17    self.substPrefix  = 'PETSC'
18    return
19
20  def __str2__(self):
21    desc = []
22    desc.append('xxx=========================================================================xxx')
23    desc.append('   Configure stage complete. Now build PETSc libraries with:')
24    desc.append('   make PETSC_DIR='+self.petscdir.dir+' PETSC_ARCH='+self.arch.arch+' all')
25    desc.append('xxx=========================================================================xxx')
26    return '\n'.join(desc)+'\n'
27
28  def setupHelp(self, help):
29    import nargs
30    help.addArgument('PETSc',  '-prefix=<dir>',                  nargs.Arg(None, '', 'Specifiy location to install PETSc (eg. /usr/local)'))
31    help.addArgument('Windows','-with-windows-graphics=<bool>',   nargs.ArgBool(None, 1,'Enable check for Windows Graphics'))
32    help.addArgument('PETSc', '-with-default-arch=<bool>',        nargs.ArgBool(None, 1, 'Allow using the last configured arch without setting PETSC_ARCH'))
33    help.addArgument('PETSc','-with-single-library=<bool>',       nargs.ArgBool(None, 1,'Put all PETSc code into the single -lpetsc library'))
34    help.addArgument('PETSc', '-with-iphone=<bool>',              nargs.ArgBool(None, 0, 'Build an iPhone version of PETSc'))
35    return
36
37  def setupDependencies(self, framework):
38    config.base.Configure.setupDependencies(self, framework)
39    self.setCompilers  = framework.require('config.setCompilers',      self)
40    self.arch          = framework.require('PETSc.utilities.arch',     self.setCompilers)
41    self.petscdir      = framework.require('PETSc.utilities.petscdir', self.setCompilers)
42    self.languages     = framework.require('PETSc.utilities.languages',self.setCompilers)
43    self.debugging     = framework.require('PETSc.utilities.debugging',self.setCompilers)
44    self.CHUD          = framework.require('PETSc.utilities.CHUD',     self)
45    self.compilers     = framework.require('config.compilers',         self)
46    self.types         = framework.require('config.types',             self)
47    self.headers       = framework.require('config.headers',           self)
48    self.functions     = framework.require('config.functions',         self)
49    self.libraries     = framework.require('config.libraries',         self)
50    if os.path.isdir(os.path.join('config', 'PETSc')):
51      for d in ['utilities', 'packages']:
52        for utility in os.listdir(os.path.join('config', 'PETSc', d)):
53          (utilityName, ext) = os.path.splitext(utility)
54          if not utilityName.startswith('.') and not utilityName.startswith('#') and ext == '.py' and not utilityName == '__init__':
55            utilityObj                    = self.framework.require('PETSc.'+d+'.'+utilityName, self)
56            utilityObj.headerPrefix       = self.headerPrefix
57            utilityObj.archProvider       = self.arch
58            utilityObj.languageProvider   = self.languages
59            utilityObj.installDirProvider = self.petscdir
60            setattr(self, utilityName.lower(), utilityObj)
61
62    for package in config.packages.all:
63      if not package == 'PETSc':
64        packageObj                    = framework.require('config.packages.'+package, self)
65        packageObj.archProvider       = self.arch
66        packageObj.languageProvider   = self.languages
67        packageObj.installDirProvider = self.petscdir
68        setattr(self, package.lower(), packageObj)
69    # Force blaslapack to depend on scalarType so precision is set before BlasLapack is built
70    framework.require('PETSc.utilities.scalarTypes', self.blaslapack)
71    self.blaslapack.precisionProvider = self.scalartypes
72
73    self.compilers.headerPrefix  = self.headerPrefix
74    self.types.headerPrefix      = self.headerPrefix
75    self.headers.headerPrefix    = self.headerPrefix
76    self.functions.headerPrefix  = self.headerPrefix
77    self.libraries.headerPrefix  = self.headerPrefix
78    self.blaslapack.headerPrefix = self.headerPrefix
79    self.mpi.headerPrefix        = self.headerPrefix
80    headersC = map(lambda name: name+'.h', ['dos', 'endian', 'fcntl', 'float', 'io', 'limits', 'malloc', 'pwd', 'search', 'strings',
81                                            'unistd', 'machine/endian', 'sys/param', 'sys/procfs', 'sys/resource',
82                                            'sys/systeminfo', 'sys/times', 'sys/utsname','string', 'stdlib','memory',
83                                            'sys/socket','sys/wait','netinet/in','netdb','Direct','time','Ws2tcpip','sys/types',
84                                            'WindowsX', 'cxxabi','float','ieeefp','stdint','fenv'])
85    functions = ['access', '_access', 'clock', 'drand48', 'getcwd', '_getcwd', 'getdomainname', 'gethostname', 'getpwuid',
86                 'gettimeofday', 'getwd', 'memalign', 'memmove', 'mkstemp', 'popen', 'PXFGETARG', 'rand', 'getpagesize',
87                 'readlink', 'realpath',  'sigaction', 'signal', 'sigset', 'nanosleep', 'usleep', 'sleep', '_sleep', 'socket',
88                 'times', 'gethostbyname', 'uname','snprintf','_snprintf','_fullpath','lseek','_lseek','time','fork','stricmp',
89                 'strcasecmp', 'bzero', 'dlopen', 'dlsym', 'dlclose', 'dlerror',
90                 '_intel_fast_memcpy','_intel_fast_memset']
91    libraries1 = [(['socket', 'nsl'], 'socket'), (['fpe'], 'handle_sigfpes')]
92    self.headers.headers.extend(headersC)
93    self.functions.functions.extend(functions)
94    self.libraries.libraries.extend(libraries1)
95    return
96
97  def Dump(self):
98    ''' Actually put the values into the configuration files '''
99    # eventually everything between -- should be gone
100#-----------------------------------------------------------------------------------------------------
101
102    # Sometimes we need C compiler, even if built with C++
103    self.setCompilers.pushLanguage('C')
104    self.addMakeMacro('CC_FLAGS',self.setCompilers.getCompilerFlags())
105    self.setCompilers.popLanguage()
106
107    # C preprocessor values
108    self.addMakeMacro('CPP_FLAGS',self.setCompilers.CPPFLAGS+self.CHUD.CPPFLAGS)
109
110    # compiler values
111    self.setCompilers.pushLanguage(self.languages.clanguage)
112    self.addMakeMacro('PCC',self.setCompilers.getCompiler())
113    self.addMakeMacro('PCC_FLAGS',self.setCompilers.getCompilerFlags())
114    self.setCompilers.popLanguage()
115    # .o or .obj
116    self.addMakeMacro('CC_SUFFIX','o')
117
118    # executable linker values
119    self.setCompilers.pushLanguage(self.languages.clanguage)
120    pcc_linker = self.setCompilers.getLinker()
121    self.addMakeMacro('PCC_LINKER',pcc_linker)
122    self.addMakeMacro('PCC_LINKER_FLAGS',self.setCompilers.getLinkerFlags())
123    self.setCompilers.popLanguage()
124    # '' for Unix, .exe for Windows
125    self.addMakeMacro('CC_LINKER_SUFFIX','')
126
127    if hasattr(self.compilers, 'FC'):
128      self.setCompilers.pushLanguage('FC')
129      # need FPPFLAGS in config/setCompilers
130      self.addDefine('HAVE_FORTRAN','1')
131      self.addMakeMacro('FPP_FLAGS',self.setCompilers.CPPFLAGS)
132
133      # compiler values
134      self.addMakeMacro('FC_FLAGS',self.setCompilers.getCompilerFlags())
135      self.setCompilers.popLanguage()
136      # .o or .obj
137      self.addMakeMacro('FC_SUFFIX','o')
138
139      # executable linker values
140      self.setCompilers.pushLanguage('FC')
141      # Cannot have NAG f90 as the linker - so use pcc_linker as fc_linker
142      fc_linker = self.setCompilers.getLinker()
143      if config.setCompilers.Configure.isNAG(fc_linker):
144        self.addMakeMacro('FC_LINKER',pcc_linker)
145      else:
146        self.addMakeMacro('FC_LINKER',fc_linker)
147      self.addMakeMacro('FC_LINKER_FLAGS',self.setCompilers.getLinkerFlags())
148      # apple requires this shared library linker flag on SOME versions of the os
149      if self.setCompilers.getLinkerFlags().find('-Wl,-commons,use_dylibs') > -1:
150        self.addMakeMacro('DARWIN_COMMONS_USE_DYLIBS',' -Wl,-commons,use_dylibs ')
151      self.setCompilers.popLanguage()
152
153      # F90 Modules
154      if self.setCompilers.fortranModuleIncludeFlag:
155        self.addMakeMacro('FC_MODULE_FLAG', self.setCompilers.fortranModuleIncludeFlag)
156      else: # for non-f90 compilers like g77
157        self.addMakeMacro('FC_MODULE_FLAG', '-I')
158      if self.setCompilers.fortranModuleIncludeFlag:
159        self.addMakeMacro('FC_MODULE_OUTPUT_FLAG', self.setCompilers.fortranModuleOutputFlag)
160    else:
161      self.addMakeMacro('FC','')
162
163    if hasattr(self.compilers, 'CUDAC'):
164      self.setCompilers.pushLanguage('CUDA')
165      self.addMakeMacro('CUDAC_FLAGS',self.setCompilers.getCompilerFlags())
166      self.setCompilers.popLanguage()
167
168    # shared library linker values
169    self.setCompilers.pushLanguage(self.languages.clanguage)
170    # need to fix BuildSystem to collect these separately
171    self.addMakeMacro('SL_LINKER',self.setCompilers.getLinker())
172    self.addMakeMacro('SL_LINKER_FLAGS','${PCC_LINKER_FLAGS}')
173    self.setCompilers.popLanguage()
174    # One of 'a', 'so', 'lib', 'dll', 'dylib' (perhaps others also?) depending on the library generator and architecture
175    # Note: . is not included in this macro, consistent with AR_LIB_SUFFIX
176    if self.setCompilers.sharedLibraryExt == self.setCompilers.AR_LIB_SUFFIX:
177      self.addMakeMacro('SL_LINKER_SUFFIX', '')
178      self.addDefine('SLSUFFIX','""')
179    else:
180      self.addMakeMacro('SL_LINKER_SUFFIX', self.setCompilers.sharedLibraryExt)
181      self.addDefine('SLSUFFIX','"'+self.setCompilers.sharedLibraryExt+'"')
182
183    self.addMakeMacro('SL_LINKER_LIBS','${PETSC_EXTERNAL_LIB_BASIC}')
184
185#-----------------------------------------------------------------------------------------------------
186
187    # CONLY or CPP. We should change the PETSc makefiles to do this better
188    if self.languages.clanguage == 'C': lang = 'CONLY'
189    else: lang = 'CXXONLY'
190    self.addMakeMacro('PETSC_LANGUAGE',lang)
191
192    # real or complex
193    self.addMakeMacro('PETSC_SCALAR',self.scalartypes.scalartype)
194    # double or float
195    self.addMakeMacro('PETSC_PRECISION',self.scalartypes.precision)
196
197    if self.framework.argDB['with-batch']:
198      self.addMakeMacro('PETSC_WITH_BATCH','1')
199
200    # Test for compiler-specific macros that need to be defined.
201    if self.setCompilers.isCrayVector('CC'):
202      self.addDefine('HAVE_CRAY_VECTOR','1')
203
204#-----------------------------------------------------------------------------------------------------
205    if self.functions.haveFunction('gethostbyname') and self.functions.haveFunction('socket'):
206      self.addDefine('USE_SOCKET_VIEWER','1')
207
208#-----------------------------------------------------------------------------------------------------
209    # print include and lib for makefiles
210    self.framework.packages.reverse()
211    includes = [os.path.join(self.petscdir.dir,'include'),os.path.join(self.petscdir.dir,self.arch.arch,'include')]
212    libs = []
213    for i in self.framework.packages:
214      if i.useddirectly:
215        self.addDefine('HAVE_'+i.PACKAGE, 1)  # ONLY list package if it is used directly by PETSc (and not only by another package)
216      if not isinstance(i.lib, list):
217        i.lib = [i.lib]
218      libs.extend(i.lib)
219      self.addMakeMacro(i.PACKAGE+'_LIB', self.libraries.toStringNoDupes(i.lib))
220      if hasattr(i,'include'):
221        if not isinstance(i.include,list):
222          i.include = [i.include]
223        includes.extend(i.include)
224        self.addMakeMacro(i.PACKAGE+'_INCLUDE',self.headers.toStringNoDupes(i.include))
225    if self.framework.argDB['with-single-library']:
226      self.addMakeMacro('PETSC_WITH_EXTERNAL_LIB',self.libraries.toStringNoDupes(['-L'+os.path.join(self.petscdir.dir,self.arch.arch,'lib'),' -lpetsc']+libs+self.libraries.math+self.compilers.flibs+self.compilers.cxxlibs+self.compilers.LIBS.split(' '))+self.CHUD.LIBS)
227    self.addMakeMacro('PETSC_EXTERNAL_LIB_BASIC',self.libraries.toStringNoDupes(libs+self.libraries.math+self.compilers.flibs+self.compilers.cxxlibs+self.compilers.LIBS.split(' '))+self.CHUD.LIBS)
228    self.PETSC_EXTERNAL_LIB_BASIC = self.libraries.toStringNoDupes(libs+self.libraries.math+self.compilers.flibs+self.compilers.cxxlibs+self.compilers.LIBS.split(' '))+self.CHUD.LIBS
229    self.addMakeMacro('PETSC_CC_INCLUDES',self.headers.toStringNoDupes(includes))
230    self.PETSC_CC_INCLUDES = self.headers.toStringNoDupes(includes)
231    if hasattr(self.compilers, 'FC'):
232      if self.compilers.fortranIsF90:
233        self.addMakeMacro('PETSC_FC_INCLUDES',self.headers.toStringNoDupes(includes,includes))
234      else:
235        self.addMakeMacro('PETSC_FC_INCLUDES',self.headers.toStringNoDupes(includes))
236
237    self.addMakeMacro('DESTDIR',self.installdir)
238    self.addDefine('LIB_DIR','"'+os.path.join(self.installdir,'lib')+'"')
239
240    if self.framework.argDB['with-single-library']:
241      # overrides the values set in conf/variables
242      self.addMakeMacro('LIBNAME','${INSTALL_LIB_DIR}/libpetsc.${AR_LIB_SUFFIX}')
243      self.addMakeMacro('SHLIBS','libpetsc')
244      self.addMakeMacro('PETSC_LIB_BASIC','-lpetsc')
245      self.addMakeMacro('PETSC_KSP_LIB_BASIC','-lpetsc')
246      self.addMakeMacro('PETSC_TS_LIB_BASIC','-lpetsc')
247      self.addDefine('USE_SINGLE_LIBRARY', '1')
248      if self.sharedlibraries.useShared:
249        self.addMakeMacro('PETSC_SYS_LIB','${C_SH_LIB_PATH} ${PETSC_WITH_EXTERNAL_LIB}')
250        self.addMakeMacro('PETSC_VEC_LIB','${C_SH_LIB_PATH} ${PETSC_WITH_EXTERNAL_LIB}')
251        self.addMakeMacro('PETSC_MAT_LIB','${C_SH_LIB_PATH} ${PETSC_WITH_EXTERNAL_LIB}')
252        self.addMakeMacro('PETSC_DM_LIB','${C_SH_LIB_PATH} ${PETSC_WITH_EXTERNAL_LIB}')
253        self.addMakeMacro('PETSC_KSP_LIB','${C_SH_LIB_PATH} ${PETSC_WITH_EXTERNAL_LIB}')
254        self.addMakeMacro('PETSC_SNES_LIB','${C_SH_LIB_PATH} ${PETSC_WITH_EXTERNAL_LIB}')
255        self.addMakeMacro('PETSC_TS_LIB','${C_SH_LIB_PATH} ${PETSC_WITH_EXTERNAL_LIB}')
256        self.addMakeMacro('PETSC_CHARACTERISTIC_LIB','${C_SH_LIB_PATH} ${PETSC_WITH_EXTERNAL_LIB}')
257        self.addMakeMacro('PETSC_LIB','${C_SH_LIB_PATH} ${PETSC_WITH_EXTERNAL_LIB}')
258        self.addMakeMacro('PETSC_CONTRIB','${C_SH_LIB_PATH} ${PETSC_WITH_EXTERNAL_LIB}')
259      else:
260        self.addMakeMacro('PETSC_SYS_LIB','${PETSC_WITH_EXTERNAL_LIB}')
261        self.addMakeMacro('PETSC_VEC_LIB','${PETSC_WITH_EXTERNAL_LIB}')
262        self.addMakeMacro('PETSC_MAT_LIB','${PETSC_WITH_EXTERNAL_LIB}')
263        self.addMakeMacro('PETSC_DM_LIB','${PETSC_WITH_EXTERNAL_LIB}')
264        self.addMakeMacro('PETSC_KSP_LIB','${PETSC_WITH_EXTERNAL_LIB}')
265        self.addMakeMacro('PETSC_SNES_LIB','${PETSC_WITH_EXTERNAL_LIB}')
266        self.addMakeMacro('PETSC_TS_LIB','${PETSC_WITH_EXTERNAL_LIB}')
267        self.addMakeMacro('PETSC_CHARACTERISTIC_LIB','${PETSC_WITH_EXTERNAL_LIB}')
268        self.addMakeMacro('PETSC_LIB','${PETSC_WITH_EXTERNAL_LIB}')
269        self.addMakeMacro('PETSC_CONTRIB','${PETSC_WITH_EXTERNAL_LIB}')
270
271    if not os.path.exists(os.path.join(self.petscdir.dir,self.arch.arch,'lib')):
272      os.makedirs(os.path.join(self.petscdir.dir,self.arch.arch,'lib'))
273
274    # add a makefile entry for configure options
275    self.addMakeMacro('CONFIGURE_OPTIONS', self.framework.getOptionsString(['configModules', 'optionsModule']).replace('\"','\\"'))
276    return
277
278  def dumpConfigInfo(self):
279    import time
280    fd = file(os.path.join(self.arch.arch,'include','petscconfiginfo.h'),'w')
281    fd.write('static const char *petscconfigureruntime = "'+time.ctime(time.time())+'";\n')
282    fd.write('static const char *petscconfigureoptions = "'+self.framework.getOptionsString(['configModules', 'optionsModule']).replace('\"','\\"')+'";\n')
283    fd.close()
284    return
285
286  def dumpMachineInfo(self):
287    import platform
288    import time
289    import script
290    fd = file(os.path.join(self.arch.arch,'include','petscmachineinfo.h'),'w')
291    fd.write('static const char *petscmachineinfo = \"\\n\"\n')
292    fd.write('\"-----------------------------------------\\n\"\n')
293    fd.write('\"Libraries compiled on %s on %s \\n\"\n' % (time.ctime(time.time()), platform.node()))
294    fd.write('\"Machine characteristics: %s\\n\"\n' % (platform.platform()))
295    fd.write('\"Using PETSc directory: %s\\n\"\n' % (self.petscdir.dir))
296    fd.write('\"Using PETSc arch: %s\\n\"\n' % (self.arch.arch))
297    fd.write('\"-----------------------------------------\\n\";\n')
298    fd.write('static const char *petsccompilerinfo = \"\\n\"\n')
299    self.setCompilers.pushLanguage(self.languages.clanguage)
300    fd.write('\"Using C compiler: %s %s ${COPTFLAGS} ${CFLAGS}\\n\"\n' % (self.setCompilers.getCompiler(), self.setCompilers.getCompilerFlags()))
301    self.setCompilers.popLanguage()
302    if hasattr(self.compilers, 'FC'):
303      self.setCompilers.pushLanguage('FC')
304      fd.write('\"Using Fortran compiler: %s %s ${FOPTFLAGS} ${FFLAGS} %s\\n\"\n' % (self.setCompilers.getCompiler(), self.setCompilers.getCompilerFlags(), self.setCompilers.CPPFLAGS))
305      self.setCompilers.popLanguage()
306    fd.write('\"-----------------------------------------\\n\";\n')
307    fd.write('static const char *petsccompilerflagsinfo = \"\\n\"\n')
308    fd.write('\"Using include paths: %s %s %s\\n\"\n' % ('-I'+os.path.join(self.petscdir.dir, self.arch.arch, 'include'), '-I'+os.path.join(self.petscdir.dir, 'include'), self.PETSC_CC_INCLUDES))
309    fd.write('\"-----------------------------------------\\n\";\n')
310    fd.write('static const char *petsclinkerinfo = \"\\n\"\n')
311    self.setCompilers.pushLanguage(self.languages.clanguage)
312    fd.write('\"Using C linker: %s\\n\"\n' % (self.setCompilers.getLinker()))
313    self.setCompilers.popLanguage()
314    if hasattr(self.compilers, 'FC'):
315      self.setCompilers.pushLanguage('FC')
316      fd.write('\"Using Fortran linker: %s\\n\"\n' % (self.setCompilers.getLinker()))
317      self.setCompilers.popLanguage()
318    fd.write('\"Using libraries: %s%s -L%s %s %s\\n\"\n' % (self.setCompilers.CSharedLinkerFlag, os.path.join(self.petscdir.dir, self.arch.arch, 'lib'), os.path.join(self.petscdir.dir, self.arch.arch, 'lib'), '-lpetscts -lpetscsnes -lpetscksp -lpetscdm -lpetscmat -lpetscvec -lpetscsys', self.PETSC_EXTERNAL_LIB_BASIC))
319    fd.write('\"-----------------------------------------\\n\";\n')
320    fd.close()
321    return
322
323  def dumpCMakeConfig(self):
324    '''
325    Writes configuration-specific values to ${PETSC_ARCH}/conf/PETScConfig.cmake.
326    This file is private to PETSc and should not be included by third parties
327    (a suitable file can be produced later by CMake, but this is not it).
328    '''
329    def cmakeset(fd,key,val=True):
330      if val == True: val = 'YES'
331      if val == False: val = 'NO'
332      fd.write('set (' + key + ' ' + val + ')\n')
333    def ensurelist(a):
334      if isinstance(a,list):
335        return a
336      else:
337        return [a]
338    def libpath(lib):
339      'Returns a search path if that is what this item provides, else "" which will be cleaned out later'
340      if not isinstance(lib,str): return ''
341      if lib.startswith('-L'): return lib[2:]
342      if lib.startswith('-R'): return lib[2:]
343      if lib.startswith('-Wl,-rpath,'):
344        # This case occurs when an external package needs a specific system library that is normally provided by the compiler.
345        # In other words, the -L path is builtin to the wrapper or compiler, here we provide it so that CMake can locate the
346        # corresponding library.
347        return lib[len('-Wl,-rpath,'):]
348      if lib.startswith('-'): return ''
349      return os.path.dirname(lib)
350    def cleanlib(lib):
351      'Returns a library name if that is what this item provides, else "" which will be cleaned out later'
352      if lib.startswith('-l'):  return lib[2:]
353      if lib.startswith('-Wl') or lib.startswith('-L'): return ''
354      lib = os.path.splitext(os.path.basename(lib))[0]
355      if lib.startswith('lib'): return lib[3:]
356      return lib
357    def nub(lst):
358      'Return a list containing the first occurrence of each unique element'
359      unique = []
360      for elem in lst:
361        if elem not in unique and elem != '':
362          unique.append(elem)
363      return unique
364    def nublast(lst):
365      'Return a list containing the last occurrence of each unique entry in a list'
366      return reversed(nub(reversed(lst)))
367    def cmakeexpand(varname):
368      return r'"${' + varname + r'}"'
369    def uniqextend(lst,new):
370      for x in ensurelist(new):
371        if x not in lst:
372          lst.append(x)
373    def notstandardinclude(path):
374      return path not in '/usr/include /usr/local/include'.split()
375    def writeMacroDefinitions(fd):
376      if self.mpi.usingMPIUni:
377        cmakeset(fd,'PETSC_HAVE_MPIUNI')
378      for pkg in self.framework.packages:
379        if pkg.useddirectly:
380          cmakeset(fd,'PETSC_HAVE_' + pkg.PACKAGE)
381      for name,val in self.functions.defines.items():
382        cmakeset(fd,'PETSC_'+name,val)
383      for dct in [self.defines, self.libraryoptions.defines]:
384        for k,v in dct.items():
385          if k.startswith('USE_'):
386            cmakeset(fd,'PETSC_' + k, v)
387      cmakeset(fd,'PETSC_USE_COMPLEX', self.scalartypes.scalartype == 'complex')
388      cmakeset(fd,'PETSC_USE_REAL_' + self.scalartypes.precision.upper())
389      cmakeset(fd,'PETSC_CLANGUAGE_'+self.languages.clanguage)
390      if hasattr(self.compilers, 'FC'):
391        cmakeset(fd,'PETSC_HAVE_FORTRAN')
392        if self.compilers.fortranIsF90:
393          cmakeset(fd,'PETSC_USING_F90')
394      if self.sharedlibraries.useShared:
395        cmakeset(fd,'BUILD_SHARED_LIBS')
396    def writeBuildFlags(fd):
397      def extendby(lib):
398        libs = ensurelist(lib)
399        lib_paths.extend(map(libpath,libs))
400        lib_libs.extend(map(cleanlib,libs))
401        uniqextend(includes,pkg.include)
402      lib_paths = []
403      lib_libs  = []
404      includes  = []
405      libvars   = []
406      for pkg in self.framework.packages:
407        extendby(pkg.lib)
408      extendby(self.libraries.math)
409      extendby(self.libraries.rt)
410      extendby(self.compilers.flibs)
411      extendby(self.compilers.cxxlibs)
412      extendby(self.compilers.LIBS.split())
413      for libname in nublast(lib_libs):
414        libvar = 'PETSC_' + libname.upper() + '_LIB'
415        addpath = ''
416        for lpath in nublast(lib_paths):
417          addpath += '"' + str(lpath) + '" '
418        fd.write('find_library (' + libvar + ' ' + libname + ' HINTS ' + addpath + ')\n')
419        libvars.append(libvar)
420      fd.write('mark_as_advanced (' + ' '.join(libvars) + ')\n')
421      fd.write('set (PETSC_PACKAGE_LIBS ' + ' '.join(map(cmakeexpand,libvars)) + ')\n')
422      fd.write('set (PETSC_PACKAGE_INCLUDES ' + ' '.join(map(lambda i: '"'+i+'"',filter(notstandardinclude,includes))) + ')\n')
423    fd = open(os.path.join(self.arch.arch,'conf','PETScConfig.cmake'), 'w')
424    writeMacroDefinitions(fd)
425    writeBuildFlags(fd)
426    fd.close()
427    return
428
429  def dumpCMakeLists(self):
430    import sys
431    if sys.version_info >= (2,5):
432      import cmakegen
433      try:
434        cmakegen.main(self.petscdir.dir)
435      except (OSError), e:
436        self.framework.logPrint('Generating CMakeLists.txt failed:\n' + str(e))
437
438  def cmakeBoot(self):
439    import sys
440    if sys.version_info >= (2,5) and hasattr(self.cmake,'cmake'):
441      try:
442        import cmakeboot
443        cmakeboot.main(petscdir=self.petscdir.dir,petscarch=self.arch.arch,argDB=self.argDB,framework=self.framework,log=self.framework.log)
444      except (OSError), e:
445        self.framework.logPrint('Booting CMake in PETSC_ARCH failed:\n' + str(e))
446      except (ImportError, KeyError), e:
447        self.framework.logPrint('Importing cmakeboot failed:\n' + str(e))
448    return
449
450  def configurePrefetch(self):
451    '''Sees if there are any prefetch functions supported'''
452    if config.setCompilers.Configure.isSolaris() or self.framework.argDB['with-iphone'] or self.framework.argDB['with-cuda']:
453      self.addDefine('Prefetch(a,b,c)', ' ')
454      return
455    self.pushLanguage(self.languages.clanguage)
456    if self.checkLink('#include <xmmintrin.h>', 'void *v = 0;_mm_prefetch((const char*)v,_MM_HINT_NTA);\n'):
457      # The Intel Intrinsics manual [1] specifies the prototype
458      #
459      #   void _mm_prefetch(char const *a, int sel);
460      #
461      # but other vendors seem to insist on using subtly different
462      # prototypes, including void* for the pointer, and an enum for
463      # sel.  These are both reasonable changes, but negatively impact
464      # portability.
465      #
466      # [1] http://software.intel.com/file/6373
467      self.addDefine('HAVE_XMMINTRIN_H', 1)
468      self.addDefine('Prefetch(a,b,c)', '_mm_prefetch((const char*)(a),(c))')
469      self.addDefine('PREFETCH_HINT_NTA', '_MM_HINT_NTA')
470      self.addDefine('PREFETCH_HINT_T0',  '_MM_HINT_T0')
471      self.addDefine('PREFETCH_HINT_T1',  '_MM_HINT_T1')
472      self.addDefine('PREFETCH_HINT_T2',  '_MM_HINT_T2')
473    elif self.checkLink('#include <xmmintrin.h>', 'void *v = 0;_mm_prefetch(v,_MM_HINT_NTA);\n'):
474      self.addDefine('HAVE_XMMINTRIN_H', 1)
475      self.addDefine('Prefetch(a,b,c)', '_mm_prefetch((const void*)(a),(c))')
476      self.addDefine('PREFETCH_HINT_NTA', '_MM_HINT_NTA')
477      self.addDefine('PREFETCH_HINT_T0',  '_MM_HINT_T0')
478      self.addDefine('PREFETCH_HINT_T1',  '_MM_HINT_T1')
479      self.addDefine('PREFETCH_HINT_T2',  '_MM_HINT_T2')
480    elif self.checkLink('', 'void *v = 0;__builtin_prefetch(v,0,0);\n'):
481      # From GCC docs: void __builtin_prefetch(const void *addr,int rw,int locality)
482      #
483      #   The value of rw is a compile-time constant one or zero; one
484      #   means that the prefetch is preparing for a write to the memory
485      #   address and zero, the default, means that the prefetch is
486      #   preparing for a read. The value locality must be a compile-time
487      #   constant integer between zero and three. A value of zero means
488      #   that the data has no temporal locality, so it need not be left
489      #   in the cache after the access. A value of three means that the
490      #   data has a high degree of temporal locality and should be left
491      #   in all levels of cache possible. Values of one and two mean,
492      #   respectively, a low or moderate degree of temporal locality.
493      #
494      # Here we adopt Intel's x86/x86-64 naming scheme for the locality
495      # hints.  Using macros for these values in necessary since some
496      # compilers require an enum.
497      self.addDefine('Prefetch(a,b,c)', '__builtin_prefetch((a),(b),(c))')
498      self.addDefine('PREFETCH_HINT_NTA', '0')
499      self.addDefine('PREFETCH_HINT_T0',  '3')
500      self.addDefine('PREFETCH_HINT_T1',  '2')
501      self.addDefine('PREFETCH_HINT_T2',  '1')
502    else:
503      self.addDefine('Prefetch(a,b,c)', ' ')
504    self.popLanguage()
505
506  def configureUnused(self):
507    '''Sees if __attribute((unused)) is supported'''
508    if self.framework.argDB['with-iphone'] or self.framework.argDB['with-cuda']:
509      self.addDefine('UNUSED', ' ')
510      return
511    self.pushLanguage(self.languages.clanguage)
512    if self.checkLink('__attribute((unused)) static int myfunc(void){ return 1;}', 'int i = myfunc();\n'):
513      self.addDefine('UNUSED', '__attribute((unused))')
514    else:
515      self.addDefine('UNUSED', ' ')
516    self.popLanguage()
517
518  def configureExpect(self):
519    '''Sees if the __builtin_expect directive is supported'''
520    self.pushLanguage(self.languages.clanguage)
521    if self.checkLink('', 'if (__builtin_expect(0,1)) return 1;'):
522      self.addDefine('HAVE_BUILTIN_EXPECT', 1)
523    self.popLanguage()
524
525  def configureFunctionName(self):
526    '''Sees if the compiler supports __func__ or a variant.  Falls back
527    on __FUNCT__ which PETSc source defines, but most users do not, thus
528    stack traces through user code are better when the compiler's
529    variant is used.'''
530    def getFunctionName(lang):
531      name = '__FUNCT__'
532      self.pushLanguage(lang)
533      if self.checkLink('', "if (__func__[0] != 'm') return 1;"):
534        name = '__func__'
535      elif self.checkLink('', "if (__FUNCTION__[0] != 'm') return 1;"):
536        name = '__FUNCTION__'
537      self.popLanguage()
538      return name
539    langs = []
540
541    self.addDefine('FUNCTION_NAME_C', getFunctionName('C'))
542    if hasattr(self.compilers, 'CXX'):
543      self.addDefine('FUNCTION_NAME_CXX', getFunctionName('Cxx'))
544    else:
545      self.addDefine('FUNCTION_NAME_CXX', '__FUNCT__')
546
547  def configureIntptrt(self):
548    '''Determine what to use for uintptr_t'''
549    def staticAssertSizeMatchesVoidStar(inc,typename):
550      # The declaration is an error if either array size is negative.
551      # It should be okay to use an int that is too large, but it would be very unlikely for this to be the case
552      return self.checkCompile(inc, ('#define STATIC_ASSERT(cond) char negative_length_if_false[2*(!!(cond))-1]\n'
553                                     + 'STATIC_ASSERT(sizeof(void*) == sizeof(%s));'%typename))
554    self.pushLanguage(self.languages.clanguage)
555    if self.checkCompile('#include <stdint.h>', 'int x; uintptr_t i = (uintptr_t)&x;'):
556      self.addDefine('UINTPTR_T', 'uintptr_t')
557    elif staticAssertSizeMatchesVoidStar('','unsigned long long'):
558      self.addDefine('UINTPTR_T', 'unsigned long long')
559    elif staticAssertSizeMatchesVoidStar('#include <stdlib.h>','size_t') or staticAssertSizeMatchesVoidStar('#include <string.h>', 'size_t'):
560      self.addDefine('UINTPTR_T', 'size_t')
561    elif staticAssertSizeMatchesVoidStar('','unsigned long'):
562      self.addDefine('UINTPTR_T', 'unsigned long')
563    elif staticAssertSizeMatchesVoidStar('','unsigned'):
564      self.addDefine('UINTPTR_T', 'unsigned')
565    else:
566      raise RuntimeError('Could not find any unsigned integer type matching void*')
567    self.popLanguage()
568
569  def configureInline(self):
570    '''Get a generic inline keyword, depending on the language'''
571    if self.languages.clanguage == 'C':
572      self.addDefine('STATIC_INLINE', self.compilers.cStaticInlineKeyword)
573      self.addDefine('RESTRICT', self.compilers.cRestrict)
574    elif self.languages.clanguage == 'Cxx':
575      self.addDefine('STATIC_INLINE', self.compilers.cxxStaticInlineKeyword)
576      self.addDefine('RESTRICT', self.compilers.cxxRestrict)
577    return
578
579  def configureSolaris(self):
580    '''Solaris specific stuff'''
581    if os.path.isdir(os.path.join('/usr','ucblib')):
582      try:
583        flag = getattr(self.setCompilers, self.language[-1]+'SharedLinkerFlag')
584      except AttributeError:
585        flag = None
586      if flag is None:
587        self.compilers.LIBS += ' -L/usr/ucblib'
588      else:
589        self.compilers.LIBS += ' '+flag+'/usr/ucblib'
590    return
591
592  def configureLinux(self):
593    '''Linux specific stuff'''
594    # TODO: Test for this by mallocing an odd number of floats and checking the address
595    self.addDefine('HAVE_DOUBLE_ALIGN_MALLOC', 1)
596    return
597
598  def configureWin32(self):
599    '''Win32 non-cygwin specific stuff'''
600    kernel32=0
601    if self.libraries.add('Kernel32.lib','GetComputerName',prototype='#include <Windows.h>', call='GetComputerName(NULL,NULL);'):
602      self.addDefine('HAVE_WINDOWS_H',1)
603      self.addDefine('HAVE_GETCOMPUTERNAME',1)
604      kernel32=1
605    elif self.libraries.add('kernel32','GetComputerName',prototype='#include <Windows.h>', call='GetComputerName(NULL,NULL);'):
606      self.addDefine('HAVE_WINDOWS_H',1)
607      self.addDefine('HAVE_GETCOMPUTERNAME',1)
608      kernel32=1
609    if kernel32:
610      if self.framework.argDB['with-windows-graphics']:
611        self.addDefine('USE_WINDOWS_GRAPHICS',1)
612      if self.checkLink('#include <Windows.h>','LoadLibrary(0)'):
613        self.addDefine('HAVE_LOADLIBRARY',1)
614      if self.checkLink('#include <Windows.h>','GetProcAddress(0,0)'):
615        self.addDefine('HAVE_GETPROCADDRESS',1)
616      if self.checkLink('#include <Windows.h>','FreeLibrary(0)'):
617        self.addDefine('HAVE_FREELIBRARY',1)
618      if self.checkLink('#include <Windows.h>','GetLastError()'):
619        self.addDefine('HAVE_GETLASTERROR',1)
620      if self.checkLink('#include <Windows.h>','SetLastError(0)'):
621        self.addDefine('HAVE_SETLASTERROR',1)
622      if self.checkLink('#include <Windows.h>\n','QueryPerformanceCounter(0);\n'):
623        self.addDefine('USE_NT_TIME',1)
624    if self.libraries.add('Advapi32.lib','GetUserName',prototype='#include <Windows.h>', call='GetUserName(NULL,NULL);'):
625      self.addDefine('HAVE_GET_USER_NAME',1)
626    elif self.libraries.add('advapi32','GetUserName',prototype='#include <Windows.h>', call='GetUserName(NULL,NULL);'):
627      self.addDefine('HAVE_GET_USER_NAME',1)
628
629    if not self.libraries.add('User32.lib','GetDC',prototype='#include <Windows.h>',call='GetDC(0);'):
630      self.libraries.add('user32','GetDC',prototype='#include <Windows.h>',call='GetDC(0);')
631    if not self.libraries.add('Gdi32.lib','CreateCompatibleDC',prototype='#include <Windows.h>',call='CreateCompatibleDC(0);'):
632      self.libraries.add('gdi32','CreateCompatibleDC',prototype='#include <Windows.h>',call='CreateCompatibleDC(0);')
633
634    self.types.check('int32_t', 'int')
635    if not self.checkCompile('#include <sys/types.h>\n','uid_t u;\n'):
636      self.addTypedef('int', 'uid_t')
637      self.addTypedef('int', 'gid_t')
638    if not self.checkLink('#if defined(PETSC_HAVE_UNISTD_H)\n#include <unistd.h>\n#endif\n','int a=R_OK;\n'):
639      self.framework.addDefine('R_OK', '04')
640      self.framework.addDefine('W_OK', '02')
641      self.framework.addDefine('X_OK', '01')
642    if not self.checkLink('#include <sys/stat.h>\n','int a=0;\nif (S_ISDIR(a)){}\n'):
643      self.framework.addDefine('S_ISREG(a)', '(((a)&_S_IFMT) == _S_IFREG)')
644      self.framework.addDefine('S_ISDIR(a)', '(((a)&_S_IFMT) == _S_IFDIR)')
645    if self.checkCompile('#include <Windows.h>\n','LARGE_INTEGER a;\nDWORD b=a.u.HighPart;\n'):
646      self.addDefine('HAVE_LARGE_INTEGER_U',1)
647
648    # Windows requires a Binary file creation flag when creating/opening binary files.  Is a better test in order?
649    if self.checkCompile('#include <Windows.h>\n', 'int flags = O_BINARY;'):
650      self.addDefine('HAVE_O_BINARY',1)
651
652    if self.compilers.CC.find('win32fe') >= 0:
653      self.addDefine('PATH_SEPARATOR','\';\'')
654      self.addDefine('DIR_SEPARATOR','\'\\\\\'')
655      self.addDefine('REPLACE_DIR_SEPARATOR','\'/\'')
656      self.addDefine('CANNOT_START_DEBUGGER',1)
657    else:
658      self.addDefine('PATH_SEPARATOR','\':\'')
659      self.addDefine('REPLACE_DIR_SEPARATOR','\'\\\\\'')
660      self.addDefine('DIR_SEPARATOR','\'/\'')
661    return
662
663#-----------------------------------------------------------------------------------------------------
664  def configureDefaultArch(self):
665    conffile = os.path.join('conf', 'petscvariables')
666    if self.framework.argDB['with-default-arch']:
667      fd = file(conffile, 'w')
668      fd.write('PETSC_ARCH='+self.arch.arch+'\n')
669      fd.write('PETSC_DIR='+self.petscdir.dir+'\n')
670      fd.write('include ${PETSC_DIR}/${PETSC_ARCH}/conf/petscvariables\n')
671      fd.close()
672      self.framework.actions.addArgument('PETSc', 'Build', 'Set default architecture to '+self.arch.arch+' in '+conffile)
673    elif os.path.isfile(conffile):
674      try:
675        os.unlink(conffile)
676      except:
677        raise RuntimeError('Unable to remove file '+conffile+'. Did a different user create it?')
678    return
679
680#-----------------------------------------------------------------------------------------------------
681  def configureScript(self):
682    '''Output a script in the conf directory which will reproduce the configuration'''
683    import nargs
684    import sys
685    scriptName = os.path.join(self.arch.arch,'conf', 'reconfigure-'+self.arch.arch+'.py')
686    args = dict([(nargs.Arg.parseArgument(arg)[0], arg) for arg in self.framework.clArgs])
687    if 'configModules' in args:
688      if nargs.Arg.parseArgument(args['configModules'])[1] == 'PETSc.Configure':
689        del args['configModules']
690    if 'optionsModule' in args:
691      if nargs.Arg.parseArgument(args['optionsModule'])[1] == 'PETSc.compilerOptions':
692        del args['optionsModule']
693    if not 'PETSC_ARCH' in args:
694      args['PETSC_ARCH'] = 'PETSC_ARCH='+str(self.arch.arch)
695    f = file(scriptName, 'w')
696    f.write('#!'+sys.executable+'\n')
697    f.write('if __name__ == \'__main__\':\n')
698    f.write('  import sys\n')
699    f.write('  import os\n')
700    f.write('  sys.path.insert(0, os.path.abspath(\'config\'))\n')
701    f.write('  import configure\n')
702    # pretty print repr(args.values())
703    f.write('  configure_options = [\n')
704    for itm in sorted(args.values()):
705      f.write('    \''+str(itm)+'\',\n')
706    f.write('  ]\n')
707    f.write('  configure.petsc_configure(configure_options)\n')
708    f.close()
709    try:
710      os.chmod(scriptName, 0775)
711    except OSError, e:
712      self.framework.logPrint('Unable to make reconfigure script executable:\n'+str(e))
713    self.framework.actions.addArgument('PETSc', 'File creation', 'Created '+scriptName+' for automatic reconfiguration')
714    return
715
716  def configureInstall(self):
717    '''Setup the directories for installation'''
718    if self.framework.argDB['prefix']:
719      self.installdir = self.framework.argDB['prefix']
720      self.addMakeRule('shared_install','',['-@echo "Now to install the libraries do:"',\
721                                              '-@echo "make PETSC_DIR=${PETSC_DIR} PETSC_ARCH=${PETSC_ARCH} install"',\
722                                              '-@echo "========================================="'])
723    else:
724      self.installdir = os.path.join(self.petscdir.dir,self.arch.arch)
725      self.addMakeRule('shared_install','',['-@echo "Now to check if the libraries are working do:"',\
726                                              '-@echo "make PETSC_DIR=${PETSC_DIR} PETSC_ARCH=${PETSC_ARCH} test"',\
727                                              '-@echo "========================================="'])
728      return
729
730  def configureGCOV(self):
731    if self.framework.argDB['with-gcov']:
732      self.addDefine('USE_GCOV','1')
733    return
734
735  def configureFortranFlush(self):
736    if hasattr(self.compilers, 'FC'):
737      for baseName in ['flush','flush_']:
738        if self.libraries.check('', baseName, otherLibs = self.compilers.flibs, fortranMangle = 1):
739          self.addDefine('HAVE_'+baseName.upper(), 1)
740          return
741
742
743  def configure(self):
744    if not os.path.samefile(self.petscdir.dir, os.getcwd()):
745      raise RuntimeError('Wrong PETSC_DIR option specified: '+str(self.petscdir.dir) + '\n  Configure invoked in: '+os.path.realpath(os.getcwd()))
746    if self.framework.argDB['prefix'] and os.path.isdir(self.framework.argDB['prefix']) and os.path.samefile(self.framework.argDB['prefix'],self.petscdir.dir):
747      raise RuntimeError('Incorrect option --prefix='+self.framework.argDB['prefix']+' specified. It cannot be same as PETSC_DIR!')
748    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)):
749      raise RuntimeError('Incorrect option --prefix='+self.framework.argDB['prefix']+' specified. It cannot be same as PETSC_DIR/PETSC_ARCH!')
750    self.framework.header          = os.path.join(self.arch.arch,'include','petscconf.h')
751    self.framework.cHeader         = os.path.join(self.arch.arch,'include','petscfix.h')
752    self.framework.makeMacroHeader = os.path.join(self.arch.arch,'conf','petscvariables')
753    self.framework.makeRuleHeader  = os.path.join(self.arch.arch,'conf','petscrules')
754    if self.libraries.math is None:
755      raise RuntimeError('PETSc requires a functional math library. Please send configure.log to petsc-maint@mcs.anl.gov.')
756    if self.languages.clanguage == 'Cxx' and not hasattr(self.compilers, 'CXX'):
757      raise RuntimeError('Cannot set C language to C++ without a functional C++ compiler.')
758    self.executeTest(self.configureInline)
759    self.executeTest(self.configurePrefetch)
760    self.executeTest(self.configureUnused)
761    self.executeTest(self.configureExpect);
762    self.executeTest(self.configureFunctionName);
763    self.executeTest(self.configureIntptrt);
764    self.executeTest(self.configureSolaris)
765    self.executeTest(self.configureLinux)
766    self.executeTest(self.configureWin32)
767    self.executeTest(self.configureDefaultArch)
768    self.executeTest(self.configureScript)
769    self.executeTest(self.configureInstall)
770    self.executeTest(self.configureGCOV)
771    self.executeTest(self.configureFortranFlush)
772    # dummy rules, always needed except for remote builds
773    self.addMakeRule('remote','')
774    self.addMakeRule('remoteclean','')
775
776    self.Dump()
777    self.dumpConfigInfo()
778    self.dumpMachineInfo()
779    self.dumpCMakeConfig()
780    self.dumpCMakeLists()
781    self.cmakeBoot()
782    self.framework.log.write('================================================================================\n')
783    self.logClear()
784    return
785