xref: /petsc/config/BuildSystem/config/types.py (revision e7c3096b41f9abec6d9c242264b7a5eeb864f6dd)
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.ArgBool(None, 1, '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.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.log.write(typeName+' found\n')
44    return found
45
46  def check_struct_sigaction(self):
47    '''Checks if "struct sigaction" exists in signal.h. This check is for C89 check.'''
48    if self.check('struct sigaction', includes = ['signal.h']):
49      self.addDefine('HAVE_STRUCT_SIGACTION',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       Note that since PETSc source code uses _Complex we test specifically for that, not complex'''
109    includes = '#include <complex.h>\n'
110    body     = 'double _Complex x;\n x = I;\n'
111    if not self.checkCompile(includes, body): return    # checkLink can succeed even if checkCompile fails
112    if self.checkLink(includes, body):
113      self.addDefine('HAVE_C99_COMPLEX', 1)
114      self.c99_complex = 1
115    return
116
117  def checkCxxComplex(self):
118    '''Check for complex numbers in namespace std'''
119    self.pushLanguage('C++')
120    includes = '#include <complex>\n'
121    body     = 'std::complex<double> x;\n'
122    if self.checkLink(includes, body):
123      self.addDefine('HAVE_CXX_COMPLEX', 1)
124      self.cxx_complex = 1
125    self.popLanguage()
126    return
127
128  def checkFortranStar(self):
129    '''Checks whether integer*4, etc. is handled in Fortran, and if not defines MISSING_FORTRANSTAR'''
130    self.pushLanguage('FC')
131    body = '        integer*4 i\n        real*8 d\n'
132    if not self.checkCompile('', body):
133      self.addDefine('MISSING_FORTRANSTAR', 1)
134    self.popLanguage()
135    return
136
137# reverse of the above - but more standard thing to do for F90 compilers
138  def checkFortranKind(self):
139    '''Checks whether selected_int_kind etc work USE_FORTRANKIND'''
140    self.pushLanguage('FC')
141    body = '''
142        integer(kind=selected_int_kind(10)) i
143        real(kind=selected_real_kind(10)) d
144'''
145    if self.checkCompile('', body):
146      self.addDefine('USE_FORTRANKIND', 1)
147    self.popLanguage()
148    return
149
150  def checkConst(self):
151    '''Checks for working const, and if not found defines it to empty string'''
152    body = '''
153    /* Ultrix mips cc rejects this.  */
154    typedef int charset[2]; const charset x;
155    /* SunOS 4.1.1 cc rejects this.  */
156    char const *const *ccp;
157    char **p;
158    /* NEC SVR4.0.2 mips cc rejects this.  */
159    struct point {int x, y;};
160    static struct point const zero = {0,0};
161    /* AIX XL C 1.02.0.0 rejects this.
162    It does not let you subtract one const X* pointer from another in an arm
163    of an if-expression whose if-part is not a constant expression */
164    const char *g = "string";
165    ccp = &g + (g ? g-g : 0);
166    /* HPUX 7.0 cc rejects these. */
167    ++ccp;
168    p = (char**) ccp;
169    ccp = (char const *const *) p;
170    /* This section avoids unused variable warnings */
171    if (zero.x);
172    if (x[0]);
173    { /* SCO 3.2v4 cc rejects this.  */
174      char *t;
175      char const *s = 0 ? (char *) 0 : (char const *) 0;
176
177      *t++ = 0;
178      if (*s);
179    }
180    { /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
181      int x[] = {25, 17};
182      const int *foo = &x[0];
183      ++foo;
184    }
185    { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
186      typedef const int *iptr;
187      iptr p = 0;
188      ++p;
189    }
190    { /* AIX XL C 1.02.0.0 rejects this saying
191      "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
192      struct s { int j; const int *ap[3]; };
193      struct s *b; b->j = 5;
194    }
195    { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
196      const int foo = 10;
197
198      /* Get rid of unused variable warning */
199      if (foo);
200    }
201    '''
202    if not self.checkCompile('', body):
203      self.addDefine('const', '')
204    return
205
206  def checkSizeof(self, typeName, typeSizes, otherInclude = None, lang='C', save=True, codeBegin=''):
207    '''Determines the size of type "typeName", and defines SIZEOF_"typeName" to be the size'''
208    self.log.write('Checking for size of type: ' + typeName + '\n')
209    typename = typeName.replace(' ', '-').replace('*', 'p')
210    argname = 'known-sizeof-' + typename
211    if argname in self.argDB:
212      size = int(self.argDB[argname])
213    else:
214      includes = '''
215#include <sys/types.h>
216#if STDC_HEADERS
217#include <stdlib.h>
218#include <stdio.h>
219#include <stddef.h>
220#endif\n'''
221      mpiFix = '''
222#define MPICH_IGNORE_CXX_SEEK
223#define MPICH_SKIP_MPICXX 1
224#define OMPI_SKIP_MPICXX 1\n'''
225      if otherInclude:
226        if otherInclude == 'mpi.h':
227          includes += mpiFix
228        includes += '#include <' + otherInclude + '>\n'
229      size = None
230      with self.Language(lang):
231        for s in typeSizes:
232          body = 'char assert_sizeof[(sizeof({0})=={1})*2-1];'.format(typeName, s)
233          if self.checkCompile(includes, body, codeBegin=codeBegin, codeEnd='\n'):
234            size = s
235            break
236    if size is None:
237      raise RuntimeError('Size of type {0} not found in sizes {1}; specify --known-sizeof-{2}'.format(typeName, typeSizes, typename))
238    if save:
239      self.sizes[argname] = size
240      self.addDefine('SIZEOF_'+typename.replace('-', '_').upper(), str(size))
241    return size
242
243  def checkBitsPerByte(self):
244    '''Determine the nubmer of bits per byte and define BITS_PER_BYTE'''
245    filename = 'conftestval'
246    includes = '''
247#if STDC_HEADERS
248#include <stdlib.h>
249#include <stdio.h>
250#endif\n'''
251    body     = 'FILE *f = fopen("'+filename+'", "w");\n'+'''
252    char val[2];
253    int i = 0;
254
255    if (!f) exit(1);
256    val[0]=\'\\1\';
257    val[1]=\'\\0\';
258    while(val[0]) {val[0] <<= 1; i++;}
259    fprintf(f, "%d\\n", i);\n
260    '''
261    if 'known-bits-per-byte' in self.argDB:
262      bits = self.argDB['known-bits-per-byte']
263    elif not self.argDB['with-batch']:
264      if self.checkRun(includes, body) and os.path.exists(filename):
265        f    = open(filename)
266        bits = int(f.read())
267        f.close()
268        os.remove(filename)
269      else:
270         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'
271         raise RuntimeError(msg)
272    else:
273      self.framework.addBatchBody(['{',
274                                   '  int i = 0;',
275                                   '  char val[2];',
276                                   '  val[0]=\'\\1\';',
277                                   '  val[1]=\'\\0\';',
278                                   '  while(val[0]) {val[0] <<= 1; i++;}',
279                                   '  fprintf(output, "  \'--known-bits-per-byte=%d\',\\n", i);',
280                                   '}'])
281      # dummy value
282      bits = 8
283
284    self.bits_per_byte = int(bits)
285    self.addDefine('BITS_PER_BYTE', bits)
286    return
287
288
289  def checkVisibility(self):
290    if not self.argDB['with-shared-libraries']:
291      self.argDB['with-visibility'] = 0
292      self.log.write('Disabled visibility attributes due to static build')
293    elif self.argDB['with-visibility']:
294      self.pushLanguage('C')
295      if self.checkCompile('','__attribute__((visibility ("default"))) int foo(void);'):
296        self.addDefine('USE_VISIBILITY_C',1)
297      else:
298        self.log.write('Cannot use visibility attributes with C')
299        self.argDB['with-visibility'] = 0
300      self.popLanguage()
301      if hasattr(self.compilers, 'CXX'):
302        self.pushLanguage('C++')
303        if self.checkCompile('','__attribute__((visibility ("default"))) int foo(void);'):
304          self.addDefine('USE_VISIBILITY_CXX',1)
305        else:
306          self.log.write('Cannot use visibility attributes with C++')
307        self.popLanguage()
308    else:
309      self.log.write('User turned off visibility attributes')
310
311
312  def configure(self):
313    self.executeTest(self.check_struct_sigaction)
314    self.executeTest(self.check__int64)
315    self.executeTest(self.checkSizeTypes)
316    self.executeTest(self.checkFileTypes)
317    self.executeTest(self.checkIntegerTypes)
318    self.executeTest(self.checkPID)
319    self.executeTest(self.checkUID)
320    self.executeTest(self.checkSignal)
321    self.executeTest(self.checkC99Complex)
322    if hasattr(self.compilers, 'CXX'):
323      self.executeTest(self.checkCxxComplex)
324    if hasattr(self.compilers, 'FC'):
325      #self.executeTest(self.checkFortranStar)
326      self.executeTest(self.checkFortranKind)
327    self.executeTest(self.checkConst)
328    for t, sizes in {'void *': (8, 4),
329                     'short': (2, 4, 8),
330                     'int': (4, 8, 2),
331                     'long': (8, 4),
332                     'long long': (8,),
333                     'size_t': (8, 4)}.items():
334      self.executeTest(self.checkSizeof, args=[t, sizes])
335    self.executeTest(self.checkBitsPerByte)
336    self.executeTest(self.checkVisibility)
337    return
338