xref: /petsc/config/BuildSystem/config/headers.py (revision 52c275a198033a26ac5c93047802d34a681c1dbf)
1import config.base
2
3class Configure(config.base.Configure):
4  def __init__(self, framework, headers = []):
5    config.base.Configure.__init__(self, framework)
6    self.headerPrefix = ''
7    self.substPrefix  = ''
8    self.headers      = headers
9    return
10
11  def setupDependencies(self, framework):
12    config.base.Configure.setupDependencies(self, framework)
13    self.compilers    = self.framework.require('config.compilers', self)
14    self.setCompilers = self.framework.require('config.setCompilers', self)
15    return
16
17  def getIncludeArgumentList(self, include):
18    '''Return the proper include line argument for the given filename as a list
19       - If the path is empty, return it unchanged
20       - If starts with - then return unchanged
21       - Otherwise return -I<include>'''
22    if not include:
23      return []
24    include = include.replace('\\ ',' ').replace(' ', '\\ ')
25    include = include.replace('\\(','(').replace('(', '\\(')
26    include = include.replace('\\)',')').replace(')', '\\)')
27    if include[0] == '-':
28      return [include]
29    return ['-I'+include]
30
31  def getIncludeModulesArgumentList(self, include):
32    '''Return the proper include line argument for the given filename as a list
33       - If the path is empty, return it unchanged
34       - If starts with - then return unchanged
35       - Otherwise return -fortranmoduleflag includedirectory'''
36    if not include:
37      return []
38    include = include.replace('\\ ',' ').replace(' ', '\\ ')
39    include = include.replace('\\(','(').replace('(', '\\(')
40    include = include.replace('\\)',')').replace(')', '\\)')
41    if include[0] == '-':
42      return [include]
43
44    self.pushLanguage('FC')
45    string = self.setCompilers.fortranModuleIncludeFlag+include
46    self.popLanguage()
47    return [string]
48
49  def getIncludeArgument(self, include):
50    '''Same as getIncludeArgumentList - except it returns a string instead of list.'''
51    return  ' '.join(self.getIncludeArgumentList(include))
52
53  def toString(self,includes):
54    '''Converts a list of includes to a string suitable for a compiler'''
55    return ' '.join([self.getIncludeArgument(include) for include in includes])
56
57  def toStringNoDupes(self,includes,modincludes=[]):
58    '''Converts a list of -Iincludes and -fmodule flags to a string suitable for a compiler, removes duplicates'''
59    newincludes = []
60    for include in includes:
61      newincludes += self.getIncludeArgumentList(include)
62    for modinclude in modincludes:
63      newincludes += self.getIncludeModulesArgumentList(modinclude)
64    includes = newincludes
65    newincludes = []
66    for j in includes:
67      if j in newincludes: continue
68      newincludes.append(j)
69    return ' '.join(newincludes)
70
71  def getDefineMacro(self, macro):
72    return 'HAVE_MACRO_'+macro
73
74  def getDefineName(self, header):
75    return 'HAVE_'+header.upper().replace('.', '_').replace('/', '_')
76
77  def haveHeader(self, header):
78    return self.getDefineName(header) in self.defines
79
80  def check(self,header, adddefine = 1):
81    '''Checks for "header", and defines HAVE_"header" if found'''
82    self.log.write('Checking for header: '+header+'\n')
83    found = 0
84    if self.checkPreprocess('#include <'+header+'>\n'):
85      found = 1
86      if adddefine: self.addDefine(self.getDefineName(header), found)
87    return found
88
89  def checkInclude(self, incl, hfiles, otherIncludes = [], macro = None, timeout = 600.0):
90    '''Checks if a particular include file can be found along particular include paths'''
91    if not isinstance(hfiles, list):
92      hfiles = [hfiles]
93    if not isinstance(incl, list):
94      incl = [incl]
95    strmac = ''
96    if macro is not None:
97      strmac = 'defined macro {} in '.format(macro)
98    self.log.write('Checking for ' + strmac + 'header files ' +str(hfiles)+ ' in '+str(incl)+'\n')
99    found = False
100    for hfile in hfiles:
101      flagsArg = self.getPreprocessorFlagsArg()
102      self.logPrint('Checking include with compiler flags var '+flagsArg+' '+str(incl+otherIncludes))
103      #oldFlags = self.compilers.CPPFLAGS
104      oldFlags = getattr(self.compilers, flagsArg)
105      #self.compilers.CPPFLAGS += ' '+' '.join([self.getIncludeArgument(inc) for inc in incl+otherIncludes])
106      setattr(self.compilers, flagsArg, getattr(self.compilers, flagsArg)+' '+' '.join([self.getIncludeArgument(inc) for inc in incl+otherIncludes]))
107      body = '#include <' +hfile+ '>\n'
108      if macro is not None:
109        body += '#if !defined({})\n#error {} not defined\n#endif\n'.format(macro,macro)
110      found = self.checkPreprocess(body, timeout = timeout)
111      #self.compilers.CPPFLAGS = oldFlags
112      setattr(self.compilers, flagsArg, oldFlags)
113      if found and macro is not None:
114        self.addDefine(self.getDefineMacro(macro), 1)
115      if not found and macro is None: return 0
116    if macro is not None and not found:
117      return 0
118    self.log.write('Found ' + strmac + 'header files ' +str(hfiles)+ ' in '+str(incl)+'\n')
119    return 1
120
121  def checkStdC(self):
122    '''Determine if C standard headers support everything PETSc needs'''
123    haveStdC = 0
124    includes = '''
125#include <stdlib.h>
126#include <stdarg.h>
127#include <string.h>
128#include <float.h>
129'''
130    haveStdC = self.checkCompile(includes)
131    # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
132    if haveStdC and not self.outputPreprocess('#include <string.h>').find('memchr'): haveStdC = 0
133    # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
134    if haveStdC and not self.outputPreprocess('#include <stdlib.h>').find('free'): haveStdC = 0
135    # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
136    if haveStdC and not self.argDB['with-batch']:
137      includes = '''
138#include <stdlib.h>
139#include <ctype.h>
140#define ISLOWER(c) (\'a\' <= (c) && (c) <= \'z\')
141#define TOUPPER(c) (ISLOWER(c) ? \'A\' + ((c) - \'a\') : (c))
142#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
143'''
144      body = '''
145        int i;
146
147        for(i = 0; i < 256; i++) if (XOR(islower(i), ISLOWER(i)) || toupper(i) != TOUPPER(i)) exit(2);
148        exit(0);
149      '''
150      if not self.checkRun(includes, body): haveStdC = 0
151    if not haveStdC:
152      raise RuntimeError("Cannot locate all the standard C header files needed by PETSc")
153    return
154
155  def checkSysWait(self):
156    '''Check for POSIX.1 compatible sys/wait.h, and defines HAVE_SYS_WAIT_H if found'''
157    includes = '''
158#include <sys/types.h>
159#include <sys/wait.h>
160#ifndef WEXITSTATUS
161#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
162#endif
163#ifndef WIFEXITED
164#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
165#endif
166'''
167    body = '''
168    int s;
169    wait (&s);
170    s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
171    '''
172    if self.checkCompile(includes, body):
173      self.addDefine('HAVE_SYS_WAIT_H', 1)
174      return 1
175    return 0
176
177  def checkTime(self):
178    '''Checks if you can safely include both <sys/time.h> and <time.h>, and if so defines TIME_WITH_SYS_TIME'''
179    self.check('time.h')
180    self.check('sys/time.h')
181    return
182
183  def checkMath(self):
184    '''Checks for the math headers and defines'''
185    haveMath = self.check('math.h',adddefine=0)
186    if haveMath:
187      if self.checkCompile('#include <math.h>\n', 'double pi = M_PI;\n(void)pi'):
188        self.logPrint('Found math #defines, like M_PI')
189      elif self.checkCompile('#define _USE_MATH_DEFINES 1\n#include <math.h>\n', 'double pi = M_PI;\n(void)pi'):
190        self.framework.addDefine('_USE_MATH_DEFINES', 1)
191        self.logPrint('Activated Windows math #defines, like M_PI')
192      else:
193        self.logPrint('Missing math #defines, like M_PI')
194    else:
195      raise RuntimeError("PETSc requires math.h")
196    return
197
198  def checkRecursiveMacros(self):
199    '''Checks that the preprocessor allows recursive macros, and if not defines HAVE_BROKEN_RECURSIVE_MACRO'''
200    includes = 'void a(int i, int j) {}\n#define a(b) a(b,__LINE__)'
201    body     = 'a(0);\n'
202    if not self.checkCompile(includes, body):
203      self.addDefine('HAVE_BROKEN_RECURSIVE_MACRO', 1)
204      return 0
205    return 1
206
207  def configure(self):
208    self.executeTest(self.checkStdC)
209    self.executeTest(self.checkSysWait)
210    self.executeTest(self.checkTime)
211    self.executeTest(self.checkMath)
212    for header in self.headers:
213      self.executeTest(self.check, header)
214    self.executeTest(self.checkRecursiveMacros)
215    return
216