xref: /petsc/config/BuildSystem/config/types.py (revision f37c82fbca2ef2d9869799d3305350a5f272bd86)
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('Types', '-known-endian=<big or little>', nargs.Arg(None, None, 'Are bytes stored in big or little endian?'))
19    help.addArgument('Visibility', '-with-visibility=<bool>', nargs.Arg(None, 0, 'Use compiler visibility flags to limit symbol visibility'))
20    return
21
22  def setupDependencies(self, framework):
23    config.base.Configure.setupDependencies(self, framework)
24    self.compilers = framework.require('config.compilers', self)
25    self.headers   = framework.require('config.headers', self)
26    return
27
28  def check(self, typeName, defaultType = None, includes = []):
29    '''Checks that "typeName" exists, and if not defines it to "defaultType" if given'''
30    self.framework.log.write('Checking for type: '+typeName+'\n')
31    include = '''
32#include <sys/types.h>
33#if STDC_HEADERS
34#include <stdlib.h>
35#include <stddef.h>
36%s
37#endif
38    ''' % ('\n'.join(['#include<%s>' % inc for inc in includes]))
39    found = self.checkCompile(include,typeName+' a;')
40    if not found and defaultType:
41      self.addTypedef(defaultType, typeName)
42    else:
43      self.framework.log.write(typeName+' found\n')
44    return found
45
46  def check_siginfo_t(self):
47    '''Checks if siginfo_t exists in signal.h. This check is for windows, and C89 check.'''
48    if self.check('siginfo_t', includes = ['signal.h']):
49      self.addDefine('HAVE_SIGINFO_T',1)
50    return
51
52  def check__int64(self):
53    '''Checks if __int64 exists. This is primarily for windows.'''
54    if self.check('__int64'):
55      self.addDefine('HAVE___INT64',1)
56    return
57
58  def checkSizeTypes(self):
59    '''Checks for types associated with sizes, such as size_t.'''
60    self.check('size_t', 'int')
61    return
62
63  def checkIntegerTypes(self):
64    '''Checks for types associated with integers, such as int32_t.'''
65    self.check('int32_t', 'int')
66    return
67
68  def checkFileTypes(self):
69    '''Checks for types associated with files, such as mode_t, off_t, etc.'''
70    self.check('mode_t', 'int')
71    self.check('off_t', 'int')
72    return
73
74  def checkPID(self):
75    '''Checks for pid_t, and defines it if necessary'''
76    return self.check('pid_t', 'int')
77
78  def checkUID(self):
79    '''Checks for uid_t and gid_t, and defines them if necessary'''
80    if self.outputPreprocess('#include <sys/types.h>').find('uid_t') < 0:
81      self.addDefine('uid_t', 'int')
82      self.addDefine('gid_t', 'int')
83    return
84
85  def checkSignal(self):
86    '''Checks the return type of signal() and defines RETSIGTYPE to that type name'''
87    includes = '''
88#include <sys/types.h>
89#include <signal.h>
90#ifdef signal
91#undef signal
92#endif
93#ifdef __cplusplus
94extern "C" void (*signal (int, void(*)(int)))(int);
95#else
96void (*signal())();
97#endif
98    '''
99    if self.checkCompile(includes, ''):
100      returnType = 'void'
101    else:
102      returnType = 'int'
103    self.addDefine('RETSIGTYPE', returnType)
104    return
105
106  def checkC99Complex(self):
107    '''Check for complex numbers in in C99 std'''
108    includes = '#include <complex.h>\n'
109    body     = 'double complex x;\n x = I;\n'
110    if self.checkLink(includes, body):
111      self.addDefine('HAVE_C99_COMPLEX', 1)
112      self.c99_complex = 1
113    return
114
115  def checkCxxComplex(self):
116    '''Check for complex numbers in namespace std'''
117    self.pushLanguage('C++')
118    includes = '#include <complex>\n'
119    body     = 'std::complex<double> x;\n'
120    if self.checkLink(includes, body):
121      self.addDefine('HAVE_CXX_COMPLEX', 1)
122      self.cxx_complex = 1
123    self.popLanguage()
124    return
125
126  def checkFortranStar(self):
127    '''Checks whether integer*4, etc. is handled in Fortran, and if not defines MISSING_FORTRANSTAR'''
128    self.pushLanguage('FC')
129    body = '        integer*4 i\n        real*8 d\n'
130    if not self.checkCompile('', body):
131      self.addDefine('MISSING_FORTRANSTAR', 1)
132    self.popLanguage()
133    return
134
135# reverse of the above - but more standard thing to do for F90 compilers
136  def checkFortranKind(self):
137    '''Checks whether selected_int_kind etc work USE_FORTRANKIND'''
138    self.pushLanguage('FC')
139    body = '''
140        integer(kind=selected_int_kind(10)) i
141        real(kind=selected_real_kind(10)) d
142'''
143    if self.checkCompile('', body):
144      self.addDefine('USE_FORTRANKIND', 1)
145    self.popLanguage()
146    return
147
148  def checkFortranDReal(self):
149    '''Checks whether dreal is provided in Fortran, and if not defines MISSING_DREAL'''
150    self.pushLanguage('FC')
151    if not self.checkLink('', '      double precision d\n      d = dreal(3.0)'):
152      self.addDefine('MISSING_DREAL', 1)
153    self.popLanguage()
154    return
155
156  def checkConst(self):
157    '''Checks for working const, and if not found defines it to empty string'''
158    body = '''
159    /* Ultrix mips cc rejects this.  */
160    typedef int charset[2]; const charset x;
161    /* SunOS 4.1.1 cc rejects this.  */
162    char const *const *ccp;
163    char **p;
164    /* NEC SVR4.0.2 mips cc rejects this.  */
165    struct point {int x, y;};
166    static struct point const zero = {0,0};
167    /* AIX XL C 1.02.0.0 rejects this.
168    It does not let you subtract one const X* pointer from another in an arm
169    of an if-expression whose if-part is not a constant expression */
170    const char *g = "string";
171    ccp = &g + (g ? g-g : 0);
172    /* HPUX 7.0 cc rejects these. */
173    ++ccp;
174    p = (char**) ccp;
175    ccp = (char const *const *) p;
176    /* This section avoids unused variable warnings */
177    if (zero.x);
178    if (x[0]);
179    { /* SCO 3.2v4 cc rejects this.  */
180      char *t;
181      char const *s = 0 ? (char *) 0 : (char const *) 0;
182
183      *t++ = 0;
184      if (*s);
185    }
186    { /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
187      int x[] = {25, 17};
188      const int *foo = &x[0];
189      ++foo;
190    }
191    { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
192      typedef const int *iptr;
193      iptr p = 0;
194      ++p;
195    }
196    { /* AIX XL C 1.02.0.0 rejects this saying
197      "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
198      struct s { int j; const int *ap[3]; };
199      struct s *b; b->j = 5;
200    }
201    { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
202      const int foo = 10;
203
204      /* Get rid of unused variable warning */
205      if (foo);
206    }
207    '''
208    if not self.checkCompile('', body):
209      self.addDefine('const', '')
210    return
211
212  def checkEndian(self):
213    '''If the machine is big endian, defines WORDS_BIGENDIAN'''
214    if 'known-endian' in self.framework.argDB:
215      endian = self.framework.argDB['known-endian']
216    else:
217      # See if sys/param.h defines the BYTE_ORDER macro
218      includes = '#include <sys/types.h>\n#ifdef HAVE_SYS_PARAM_H\n  #include <sys/param.h>\n#endif\n'
219      body     = '''
220#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
221  bogus endian macros
222#endif
223      '''
224      if self.checkCompile(includes, body):
225        # It does, so check whether it is defined to BIG_ENDIAN or not
226        body = '''
227#if BYTE_ORDER != BIG_ENDIAN
228  not big endian
229#endif
230        '''
231        if self.checkCompile(includes, body):
232          endian = 'big'
233        else:
234          endian = 'little'
235      else:
236        if not self.framework.argDB['with-batch']:
237          body = '''
238          /* Are we little or big endian?  From Harbison&Steele. */
239          union
240          {
241            long l;
242            char c[sizeof(long)];
243          } u;
244          u.l = 1;
245          exit(u.c[sizeof(long) - 1] == 1);
246          '''
247          self.pushLanguage('C')
248          if self.checkRun('#include <stdlib.h>\n', body, defaultArg = 'isLittleEndian'):
249            endian = 'little'
250          else:
251            endian = 'big'
252          self.popLanguage()
253        else:
254          self.framework.addBatchBody(['{',
255                                       '  union {long l; char c[sizeof(long)];} u;',
256                                       '  u.l = 1;',
257                                       '  fprintf(output, " \'--known-endian=%s\',\\n", (u.c[sizeof(long) - 1] == 1) ? "big" : "little");',
258                                       '}'])
259          # Dummy value
260          endian = 'little'
261    if endian == 'big':
262      self.addDefine('WORDS_BIGENDIAN', 1)
263    return
264
265  def checkSizeof(self, typeName, otherInclude = None):
266    '''Determines the size of type "typeName", and defines SIZEOF_"typeName" to be the size'''
267    self.framework.log.write('Checking for size of type: '+typeName+'\n')
268    filename = 'conftestval'
269    includes = '''
270#include <sys/types.h>
271#if STDC_HEADERS
272#include <stdlib.h>
273#include <stdio.h>
274#include <stddef.h>
275#endif\n'''
276    mpiFix = '''
277#define MPICH_IGNORE_CXX_SEEK
278#define MPICH_SKIP_MPICXX 1
279#define OMPI_SKIP_MPICXX 1\n'''
280    if otherInclude:
281      if otherInclude == 'mpi.h':
282        includes += mpiFix
283      includes += '#include <'+otherInclude+'>\n'
284    body     = 'FILE *f = fopen("'+filename+'", "w");\n\nif (!f) exit(1);\nfprintf(f, "%lu\\n", (unsigned long)sizeof('+typeName+'));\n'
285    typename = typeName.replace(' ', '-').replace('*', 'p')
286    if not 'known-sizeof-'+typename in self.framework.argDB:
287      if not self.framework.argDB['with-batch']:
288        self.pushLanguage('C')
289        if self.checkRun(includes, body) and os.path.exists(filename):
290          f    = file(filename)
291          size = int(f.read())
292          f.close()
293          os.remove(filename)
294        elif not typename == 'long-long':
295          msg = 'Cannot run executable to determine size of '+typeName+'. If this machine uses a batch system \nto submit jobs you will need to configure using ./configure with the additional option  --with-batch.\n Otherwise there is problem with the compilers. Can you compile and run code with your C/C++ (and maybe Fortran) compilers?\n'
296          raise RuntimeError(msg)
297        else:
298          self.framework.log.write('Compiler does not support long long\n')
299          size = 0
300        self.popLanguage()
301      else:
302        self.framework.addBatchInclude(['#include <stdlib.h>', '#include <stdio.h>', '#include <sys/types.h>'])
303        if otherInclude:
304          if otherInclude == 'mpi.h':
305            self.framework.addBatchInclude(mpiFix)
306          self.framework.addBatchInclude('#include <'+otherInclude+'>')
307        self.framework.addBatchBody('fprintf(output, "  \'--known-sizeof-'+typename+'=%d\',\\n", sizeof('+typeName+'));')
308        # dummy value
309        size = 4
310    else:
311      size = self.framework.argDB['known-sizeof-'+typename]
312    self.sizes['known-sizeof-'+typename] = int(size)
313    self.addDefine('SIZEOF_'+typeName.replace(' ', '_').replace('*', 'p').upper(), size)
314    return size
315
316  def checkBitsPerByte(self):
317    '''Determine the nubmer of bits per byte and define BITS_PER_BYTE'''
318    filename = 'conftestval'
319    includes = '''
320#if STDC_HEADERS
321#include <stdlib.h>
322#include <stdio.h>
323#endif\n'''
324    body     = 'FILE *f = fopen("'+filename+'", "w");\n'+'''
325    char val[2];
326    int i = 0;
327
328    if (!f) exit(1);
329    val[0]=\'\\1\';
330    val[1]=\'\\0\';
331    while(val[0]) {val[0] <<= 1; i++;}
332    fprintf(f, "%d\\n", i);\n
333    '''
334    if 'known-bits-per-byte' in self.framework.argDB:
335      bits = self.framework.argDB['known-bits-per-byte']
336    elif not self.framework.argDB['with-batch']:
337      if self.checkRun(includes, body) and os.path.exists(filename):
338        f    = file(filename)
339        bits = int(f.read())
340        f.close()
341        os.remove(filename)
342      else:
343         msg = 'Cannot run executable to determine bits per bit. If this machine uses a batch system \nto submit jobs you will need to configure using ./configure with the additional option  --with-batch.\n Otherwise there is problem with the compilers. Can you compile and run code with your C/C++ (and maybe Fortran) compilers?\n'
344         raise RuntimeError(msg)
345    else:
346      self.framework.addBatchBody(['{',
347                                   '  int i = 0;',
348                                   '  char val[2];',
349                                   '  val[0]=\'\\1\';',
350                                   '  val[1]=\'\\0\';',
351                                   '  while(val[0]) {val[0] <<= 1; i++;}',
352                                   '  fprintf(output, "  \'--known-bits-per-byte=%d\',\\n", i);',
353                                   '}'])
354      # dummy value
355      bits = 8
356
357    self.bits_per_byte = int(bits)
358    self.addDefine('BITS_PER_BYTE', bits)
359    return
360
361
362  def checkVisibility(self):
363    if self.framework.argDB['with-visibility']:
364      if not self.checkCompile('','__attribute__((visibility ("default"))) int foo(void);'):
365        raise RuntimeError('Cannot use visibility attributes')
366      self.addDefine('USE_VISIBILITY',1)
367
368  def configure(self):
369    self.executeTest(self.check_siginfo_t)
370    self.executeTest(self.check__int64)
371    self.executeTest(self.checkSizeTypes)
372    self.executeTest(self.checkFileTypes)
373    self.executeTest(self.checkIntegerTypes)
374    self.executeTest(self.checkPID)
375    self.executeTest(self.checkUID)
376    self.executeTest(self.checkSignal)
377    self.executeTest(self.checkC99Complex)
378    if hasattr(self.compilers, 'CXX'):
379      self.executeTest(self.checkCxxComplex)
380    if hasattr(self.compilers, 'FC'):
381      #self.executeTest(self.checkFortranStar)
382      self.executeTest(self.checkFortranKind)
383      self.executeTest(self.checkFortranDReal)
384    self.executeTest(self.checkConst)
385    self.executeTest(self.checkEndian)
386    map(lambda type: self.executeTest(self.checkSizeof, type), ['char','void *', 'short', 'int', 'long', 'long long', 'float', 'double', 'size_t'])
387    self.executeTest(self.checkBitsPerByte)
388    self.executeTest(self.checkVisibility)
389    return
390