xref: /petsc/config/BuildSystem/config/types.py (revision a8ededdf47aa46be0940f1dfc7fe543fa88f0313)
1import config.base
2
3import os
4import re
5
6class Configure(config.base.Configure):
7  def __init__(self, framework):
8    config.base.Configure.__init__(self, framework)
9    self.headerPrefix = ''
10    self.substPrefix  = ''
11    self.sizes = {}
12    self.c99_complex = 0
13    self.cxx_complex = 0
14    return
15
16  def setupHelp(self, help):
17    import nargs
18    help.addArgument('Visibility', '-with-visibility=<bool>', nargs.ArgBool(None, 1, 'Use compiler visibility flags to limit symbol visibility'))
19    return
20
21  def setupDependencies(self, framework):
22    config.base.Configure.setupDependencies(self, framework)
23    self.compilers = framework.require('config.compilers', self)
24    self.headers   = framework.require('config.headers', self)
25    return
26
27  def check(self, typeName, defaultType = None, includes = []):
28    '''Checks that "typeName" exists, and if not defines it to "defaultType" if given'''
29    self.log.write('Checking for type: '+typeName+'\n')
30    include = '''
31#include <sys/types.h>
32#include <stdlib.h>
33#include <stddef.h>
34%s
35    ''' % ('\n'.join(['#include<%s>' % inc for inc in includes]))
36    found = self.checkCompile(include,typeName+' a;')
37    if not found and defaultType:
38      self.addTypedef(defaultType, typeName)
39    else:
40      self.log.write(typeName+' found\n')
41    return found
42
43  def check_struct_sigaction(self):
44    '''Checks if "struct sigaction" exists in signal.h. This check is for C89 check.'''
45    if self.check('struct sigaction', includes = ['signal.h']):
46      self.addDefine('HAVE_STRUCT_SIGACTION',1)
47    return
48
49  def check__int64(self):
50    '''Checks if __int64 exists. This is primarily for windows.'''
51    if self.check('__int64'):
52      self.addDefine('HAVE___INT64',1)
53    return
54
55  def checkSizeTypes(self):
56    '''Checks for types associated with sizes, such as size_t.'''
57    self.check('size_t', 'int')
58    return
59
60  def checkIntegerTypes(self):
61    '''Checks for types associated with integers, such as int32_t.'''
62    self.check('int32_t', 'int')
63    return
64
65  def checkFileTypes(self):
66    '''Checks for types associated with files, such as mode_t, off_t, etc.'''
67    self.check('mode_t', 'int')
68    self.check('off_t', 'int')
69    return
70
71  def checkPID(self):
72    '''Checks for pid_t, and defines it if necessary'''
73    return self.check('pid_t', 'int')
74
75  def checkUID(self):
76    '''Checks for uid_t and gid_t, and defines them if necessary'''
77    if self.outputPreprocess('#include <sys/types.h>').find('uid_t') < 0:
78      self.addDefine('uid_t', 'int')
79      self.addDefine('gid_t', 'int')
80    return
81
82  def checkC99Complex(self):
83    '''Check for complex numbers in in C99 std
84       Note that since PETSc source code uses _Complex we test specifically for that, not complex'''
85    includes = '#include <complex.h>\n'
86    body     = 'double _Complex x;\n x = I;\n'
87    if not self.checkCompile(includes, body): return    # checkLink can succeed even if checkCompile fails
88    if self.checkLink(includes, body):
89      self.addDefine('HAVE_C99_COMPLEX', 1)
90      self.c99_complex = 1
91    return
92
93  def checkCxxComplex(self):
94    '''Check for complex numbers in namespace std'''
95    self.pushLanguage('C++')
96    includes = '#include <complex>\n'
97    body     = 'std::complex<double> x;\n'
98    if self.checkLink(includes, body):
99      self.addDefine('HAVE_CXX_COMPLEX', 1)
100      self.cxx_complex = 1
101    self.popLanguage()
102    return
103
104  def checkFortranStar(self):
105    '''Checks whether integer*4, etc. is handled in Fortran, and if not defines MISSING_FORTRANSTAR'''
106    self.pushLanguage('FC')
107    body = '        integer*4 i\n        real*8 d\n'
108    if not self.checkCompile('', body):
109      self.addDefine('MISSING_FORTRANSTAR', 1)
110    self.popLanguage()
111    return
112
113# reverse of the above - but more standard thing to do for F90 compilers
114  def checkFortranKind(self):
115    '''Checks whether selected_int_kind etc work USE_FORTRANKIND'''
116    self.pushLanguage('FC')
117    body = '''
118        integer(kind=selected_int_kind(10)) i
119        real(kind=selected_real_kind(10)) d
120'''
121    if self.checkCompile('', body):
122      self.addDefine('USE_FORTRANKIND', 1)
123    self.popLanguage()
124    return
125
126  def checkConst(self):
127    '''Checks for working const, and if not found defines it to empty string'''
128    body = '''
129    /* Ultrix mips cc rejects this.  */
130    typedef int charset[2]; const charset x;
131    /* SunOS 4.1.1 cc rejects this.  */
132    char const *const *ccp;
133    char **p;
134    /* NEC SVR4.0.2 mips cc rejects this.  */
135    struct point {int x, y;};
136    static struct point const zero = {0,0};
137    /* AIX XL C 1.02.0.0 rejects this.
138    It does not let you subtract one const X* pointer from another in an arm
139    of an if-expression whose if-part is not a constant expression */
140    const char *g = "string";
141    ccp = &g + (g ? g-g : 0);
142    /* HPUX 7.0 cc rejects these. */
143    ++ccp;
144    p = (char**) ccp;
145    ccp = (char const *const *) p;
146    /* This section avoids unused variable warnings */
147    if (zero.x);
148    if (x[0]);
149    { /* SCO 3.2v4 cc rejects this.  */
150      char *t;
151      char const *s = 0 ? (char *) 0 : (char const *) 0;
152
153      *t++ = 0;
154      if (*s);
155    }
156    { /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
157      int x[] = {25, 17};
158      const int *foo = &x[0];
159      ++foo;
160    }
161    { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
162      typedef const int *iptr;
163      iptr p = 0;
164      ++p;
165    }
166    { /* AIX XL C 1.02.0.0 rejects this saying
167      "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
168      struct s { int j; const int *ap[3]; };
169      struct s *b; b->j = 5;
170    }
171    { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
172      const int foo = 10;
173
174      /* Get rid of unused variable warning */
175      if (foo);
176    }
177    '''
178    if not self.checkCompile('', body):
179      self.addDefine('const', '')
180    return
181
182  def checkSizeof(self, typeName, typeSizes, otherInclude = None, lang='C', save=True, codeBegin=''):
183    '''Determines the size of type "typeName", and defines SIZEOF_"typeName" to be the size'''
184    self.log.write('Checking for size of type: ' + typeName + '\n')
185    typename = typeName.replace(' ', '-').replace('*', 'p')
186    includes = '''
187#include <sys/types.h>
188#include <stdlib.h>
189#include <stdio.h>
190#include <stddef.h>'''
191    mpiFix = '''
192#define MPICH_IGNORE_CXX_SEEK
193#define MPICH_SKIP_MPICXX 1
194#define OMPI_SKIP_MPICXX 1\n'''
195    if otherInclude:
196      if otherInclude == 'mpi.h':
197        includes += mpiFix
198      includes += '#include <' + otherInclude + '>\n'
199    size = None
200    checkName = typeName
201    if typeName == 'enum':
202      checkName = 'enum{ENUM_DUMMY}'
203    with self.Language(lang):
204      for s in typeSizes:
205        body = 'char assert_sizeof[(sizeof({0})=={1})*2-1];'.format(checkName, s)
206        if self.checkCompile(includes, body, codeBegin=codeBegin, codeEnd='\n'):
207          size = s
208          break
209    if size is None:
210      raise RuntimeError('Unable to determine size of {0} not found'.format(typeName))
211    if save:
212      self.sizes[typename] = size
213      self.addDefine('SIZEOF_'+typename.replace('-', '_').upper(), str(size))
214    return size
215
216  def checkVisibility(self):
217    if not self.argDB['with-shared-libraries']:
218      self.argDB['with-visibility'] = 0
219      self.log.write('Disabled visibility attributes due to static build')
220    elif self.argDB['with-visibility']:
221      self.pushLanguage('C')
222      if self.checkCompile('','__attribute__((visibility ("default"))) int foo(void);'):
223        self.addDefine('USE_VISIBILITY_C',1)
224      else:
225        self.log.write('Cannot use visibility attributes with C')
226        self.argDB['with-visibility'] = 0
227      self.popLanguage()
228      if hasattr(self.compilers, 'CXX'):
229        self.pushLanguage('C++')
230        if self.checkCompile('','__attribute__((visibility ("default"))) int foo(void);'):
231          self.addDefine('USE_VISIBILITY_CXX',1)
232        else:
233          self.log.write('Cannot use visibility attributes with C++')
234        self.popLanguage()
235    else:
236      self.log.write('User turned off visibility attributes')
237
238
239  def configure(self):
240    self.executeTest(self.check_struct_sigaction)
241    self.executeTest(self.check__int64)
242    self.executeTest(self.checkSizeTypes)
243    self.executeTest(self.checkFileTypes)
244    self.executeTest(self.checkIntegerTypes)
245    self.executeTest(self.checkPID)
246    self.executeTest(self.checkUID)
247    self.executeTest(self.checkC99Complex)
248    if hasattr(self.compilers, 'CXX'):
249      self.executeTest(self.checkCxxComplex)
250    if hasattr(self.compilers, 'FC'):
251      #self.executeTest(self.checkFortranStar)
252      self.executeTest(self.checkFortranKind)
253    self.executeTest(self.checkConst)
254    for t, sizes in {'void *': (8, 4),
255                     'short': (2, 4, 8),
256                     'int': (4, 8, 2),
257                     'long': (8, 4),
258                     'long long': (8,),
259                     'enum': (4, 8),
260                     'size_t': (8, 4)}.items():
261      self.executeTest(self.checkSizeof, args=[t, sizes])
262    self.executeTest(self.checkVisibility)
263    return
264