xref: /petsc/config/BuildSystem/config/functions.py (revision 3cca18fc1526ce0cac20e967ea546a5c32665257)
1import config.base
2import os.path
3
4class Configure(config.base.Configure):
5  def __init__(self, framework, functions = []):
6    config.base.Configure.__init__(self, framework)
7    self.headerPrefix = ''
8    self.substPrefix  = ''
9    self.functions    = functions
10    return
11
12  def getDefineName(self, funcName):
13    return 'HAVE_'+funcName.upper()
14
15  def setupDependencies(self, framework):
16    config.base.Configure.setupDependencies(self, framework)
17    self.compilers = self.framework.require('config.compilers', self)
18    self.libraries = self.framework.require('config.libraries', self) # setCompilers.LIBS is setup here
19    self.headers   = self.framework.require('config.headers', self)
20    return
21
22  def haveFunction(self, function):
23    return self.getDefineName(function) in self.defines
24
25  def check(self, funcs, libraries = None, examineOutput=lambda ret,out,err:None):
26    '''Checks for the function "funcName", and if found defines HAVE_"funcName"'''
27    if isinstance(funcs, set): funcs = list(funcs)
28    if isinstance(funcs, str): funcs = [funcs]
29    self.log.write('Checking for functions ['+' '.join(funcs)+']\n')
30    def genIncludes(funcName):
31      return 'char %s(void);\n' % funcName
32    def genBody(funcName):
33      # The GNU C library defines __stub_* for functions that it implements
34      # to always fail with ENOSYS.  Some functions are actually named
35      # something starting with __ and the normal name is an alias.
36      return '''
37#if defined (__stub_%(func)s) || defined (__stub___%(func)s)
38%(func)s_will_always_fail_with_ENOSYS();
39#else
40%(func)s();
41#endif
42''' % dict(func=funcName)
43
44    # Don't include <ctype.h> because on OSF/1 3.0 it includes <sys/types.h>
45    # which includes <sys/select.h> which contains a prototype for
46    # select.  Similarly for bzero.
47    includes = '''
48/* System header to define __stub macros and hopefully no other prototypes since they would conflict with our 'char funcname()' declaration below. */
49#include <assert.h>
50/* Override any gcc2 internal prototype to avoid an error. */
51#ifdef __cplusplus
52extern "C" {
53#endif
54'''
55    includes += '''
56/* We use char because int might match the return type of a gcc2
57builtin and then its argument prototype would still apply. */
58'''
59    includes += ''.join(map(genIncludes,funcs))
60    includes += '''
61#ifdef __cplusplus
62}
63#endif
64'''
65    body = ''.join(map(genBody,funcs))
66    if libraries:
67      #  TODO: Same code as libraries.toStringNoDupes() should call that and not repeat code here
68      oldLibs = self.compilers.LIBS
69      if not isinstance(libraries, list):
70        libraries = [libraries]
71      for library in libraries:
72        root,ext=os.path.splitext(library)
73        if library.strip()[0] == '-' or ext == '.a' or ext == '.so' or ext == '.o':
74          self.compilers.LIBS += ' '+library
75        else:
76          self.compilers.LIBS += ' -l'+library
77    found = self.checkLink(includes, body, examineOutput=examineOutput)
78    if libraries:
79      self.compilers.LIBS = oldLibs
80    if found:
81      for funcName in funcs:
82        self.addDefine(self.getDefineName(funcName), 1)
83    return found
84
85  def checkClassify(self, funcs, libraries = None):
86    '''Recursive decompose to rapidly classify functions as found or missing
87    To confirm that a function is missing, we require a compile/link
88    failure with only that function in a compilation unit.  In contrast,
89    we can confirm that many functions are present by compiling them all
90    together in a large compilation unit.  We optimistically compile
91    everything together, then trim all functions that were named in the
92    error message and bisect the result.  The trimming is only an
93    optimization to increase the likelihood of a big-batch compile
94    succeeding; we do not rely on the compiler naming missing functions.
95    '''
96    def functional(funcs):
97      named = config.NamedInStderr(funcs)
98      if self.check(funcs, libraries, named.examineStderr):
99        return True
100      else:
101        return named.named
102    import config
103    found, missing = config.classify(funcs, functional)
104    return found, missing
105
106  def checkVSNPrintf(self):
107    '''Checks whether vsnprintf requires a char * last argument, and if it does defines HAVE_VSNPRINTF_CHAR'''
108    if self.checkLink('#include <stdio.h>\n#include <stdarg.h>\n', 'va_list Argp = { 0 };char str[6];\nvsnprintf(str,5, "%d", Argp )'):
109      self.addDefine('HAVE_VSNPRINTF', 1)
110    return
111
112  def checkSignalHandlerType(self):
113    '''Checks the type of C++ signals handlers, and defines SIGNAL_CAST to the correct value'''
114    self.pushLanguage('C++')
115    if not self.checkLink('#include <signal.h>\nstatic void myhandler(int sig) { (void)sig; }\n', 'signal(SIGFPE,myhandler)'):
116      self.addDefine('SIGNAL_CAST', '(void (*)(int))')
117    else:
118      self.addDefine('SIGNAL_CAST', ' ')
119    self.popLanguage()
120    return
121
122  def checkFreeReturnType(self):
123    '''Checks whether free returns void or int, and defines HAVE_FREE_RETURN_INT'''
124    if self.checkLink('#include <stdlib.h>\n', 'int ierr; void *p; ierr = free(p); return ierr'):
125      self.addDefine('HAVE_FREE_RETURN_INT', 1)
126    return
127
128  def checkVariableArgumentLists(self):
129    '''Checks whether the variable argument list functionality is working'''
130    if self.checkLink('#include <stdarg.h>\n', '  va_list l1, l2;\n  va_copy(l1, l2)'):
131      self.addDefine('HAVE_VA_COPY', 1)
132    elif self.checkLink('#include <stdarg.h>\n', '  va_list l1, l2;\n  __va_copy(l1, l2)'):
133      self.addDefine('HAVE___VA_COPY', 1)
134    return
135
136  def checkNanosleep(self):
137    '''Check for functional nanosleep() - as time.h behaves differently for different compiler flags - like -std=c89'''
138    if self.checkLink('#include <time.h>','struct timespec tp;\n tp.tv_sec = 0;\n tp.tv_nsec = (long)(1e9);\n nanosleep(&tp,0)'):
139      self.addDefine('HAVE_NANOSLEEP', 1)
140    return
141
142  def checkMemmove(self):
143    '''Check for functional memmove() - as MS VC requires correct includes to for this test'''
144    if self.checkLink('#include <string.h>',' char c1[1], c2[1] = "c";\n size_t n=1;\n memmove(c1,c2,n)'):
145      self.addDefine('HAVE_MEMMOVE', 1)
146    return
147
148  def checkMmap(self):
149    '''Check for functional mmap() to allocate shared memory and define HAVE_MMAP'''
150    if self.checkLink('#include <sys/mman.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <fcntl.h>\n','int fd;\n fd=open("/tmp/file",O_RDWR);\n mmap(NULL,100,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0)'):
151      self.addDefine('HAVE_MMAP', 1)
152    return
153
154  def checkMkstemp(self):
155    '''Check for mkstemp() to avoid using tmpnam as it is often deprecated'''
156    if self.checkLink('#define _XOPEN_SOURCE 600\n#include <stdlib.h>\n#include <string.h>', 'char filename[100];\n strcpy(filename, "/tmp/fileXXXXXX");\n mkstemp(filename)'):
157      self.addDefine('HAVE_MKSTEMP', 1)
158
159  def checkTmpnam_s(self):
160    '''Check for tmpnam_s() to avoid using tmpnam as it is often deprecated'''
161    if self.checkLink('#include <stdio.h>', 'char filename[L_tmpnam];\n tmpnam_s(filename, sizeof(filename))'):
162      self.addDefine('HAVE_TMPNAM_S', 1)
163
164  def configure(self):
165    self.executeTest(self.checkVSNPrintf)
166    self.executeTest(self.checkNanosleep)
167    self.executeTest(self.checkMemmove)
168    if hasattr(self.compilers, 'CXX'):
169      self.executeTest(self.checkSignalHandlerType)
170    self.executeTest(self.checkFreeReturnType)
171    self.executeTest(self.checkVariableArgumentLists)
172    self.executeTest(self.checkClassify, set(self.functions))
173    if 'HAVE_GETPAGESIZE' in self.defines and self.compilers.setCompilers.isMINGW(self.framework.getCompiler(), self.log):
174      self.delDefine('HAVE_GETPAGESIZE')
175    self.executeTest(self.checkMmap)
176    self.executeTest(self.checkMkstemp)
177    self.executeTest(self.checkTmpnam_s)
178    return
179