build: more complete implementation of waf configure -C
[amitay/samba.git] / buildtools / wafsamba / samba_autoconf.py
1 # a waf tool to add autoconf-like macros to the configure section
2
3 import Build, os, Options, preproc
4 import string
5 from Configure import conf
6 from samba_utils import *
7
8 ####################################################
9 # some autoconf like helpers, to make the transition
10 # to waf a bit easier for those used to autoconf
11 # m4 files
12
13 @runonce
14 @conf
15 def DEFINE(conf, d, v, add_to_cflags=False):
16     '''define a config option'''
17     conf.define(d, v, quote=False)
18     if add_to_cflags:
19         conf.env.append_value('CCDEFINES', d + '=' + str(v))
20
21
22 def CHECK_HEADER(conf, h, add_headers=True):
23     '''check for a header'''
24     d = 'HAVE_%s' % string.replace(h.upper(), '/', '_')
25     if CONFIG_SET(conf, d):
26         if add_headers:
27             conf.env.hlist.append(h)
28             conf.env.hlist = unique_list(conf.env.hlist)
29         return True
30     ret = conf.check(header_name=h)
31     if ret and add_headers:
32         conf.env.hlist.append(h)
33         conf.env.hlist = unique_list(conf.env.hlist)
34     return ret
35
36
37 @conf
38 def CHECK_HEADERS(conf, list, add_headers=True):
39     '''check for a list of headers'''
40     ret = True
41     for hdr in TO_LIST(list):
42         if not CHECK_HEADER(conf, hdr, add_headers):
43             ret = False
44     return ret
45
46
47 @conf
48 def CHECK_TYPES(conf, list):
49     '''check for a list of types'''
50     ret = True
51     lst = TO_LIST(list)
52     for t in TO_LIST(list):
53         if not conf.check(type_name=t, header_name=conf.env.hlist):
54             ret = False
55     return ret
56
57
58 @conf
59 def CHECK_TYPE_IN(conf, t, hdr, define=None):
60     '''check for a type in a specific header'''
61     if conf.check(header_name=hdr):
62         if define is None:
63             ret = conf.check(type_name=t, header_name=hdr)
64         else:
65             ret = conf.check(type_name=t, header_name=hdr, define_name=define)
66         return ret
67     return False
68
69
70 @conf
71 def CHECK_TYPE(conf, t, alternate=None, headers=None, define=None):
72     '''check for a type with an alternate'''
73     if headers is None:
74         headers = conf.env.hlist
75     if define is not None:
76         ret = conf.check(type_name=t, header_name=headers, define_name=define)
77     else:
78         ret = conf.check(type_name=t, header_name=headers)
79     if not ret and alternate is not None:
80         conf.DEFINE(t, alternate)
81     return ret
82
83
84 @conf
85 def CHECK_VARIABLE(conf, v, define=None, always=False, headers=None):
86     '''check for a variable declaration (or define)'''
87     hdrs=''
88     if headers is not None:
89         hlist = TO_LIST(headers)
90     else:
91         hlist = conf.env.hlist
92     for h in hlist:
93         hdrs += '#include <%s>\n' % h
94     if define is None:
95         define = 'HAVE_%s' % v.upper()
96     if conf.check(fragment=
97                   '''
98                   %s
99                   int main(void) {
100                     #ifndef %s
101                     void *_x; _x=(void *)&%s;
102                     #endif
103                     return 0;
104                   }
105                   ''' % (hdrs, v, v),
106                   execute=0,
107                   msg="Checking for variable %s" % v):
108         conf.DEFINE(define, 1)
109         return True
110     elif always:
111         conf.DEFINE(define, 0)
112         return False
113
114 @conf
115 def CHECK_DECLS(conf, vars, reverse=False, headers=None):
116     '''check a list of variable declarations, using the HAVE_DECL_xxx form
117        of define
118
119        When reverse==True then use HAVE_xxx_DECL instead of HAVE_DECL_xxx
120        '''
121     ret = True
122     for v in TO_LIST(vars):
123         if not reverse:
124             define='HAVE_DECL_%s' % v.upper()
125         else:
126             define='HAVE_%s_DECL' % v.upper()
127         if not CHECK_VARIABLE(conf, v, define=define, headers=headers):
128             ret = False
129     return ret
130
131
132 def CHECK_FUNC(conf, f, checklink=False, header=''):
133     '''check for a function'''
134     hlist = conf.env.hlist[:]
135     for h in TO_LIST(header):
136         if CHECK_HEADER(conf, h, add_headers=False):
137             hlist.append(h)
138     define='HAVE_%s' % f.upper()
139     if CONFIG_SET(conf, define):
140         return True
141     if checklink:
142         return CHECK_CODE(conf, 'void *x = (void *)%s' % f,
143                           execute=False, define=define,
144                           msg='Checking for %s' % f)
145
146     return conf.check_cc(function_name=f, header_name=hlist)
147
148
149 @conf
150 def CHECK_FUNCS(conf, list, checklink=False, header=''):
151     '''check for a list of functions'''
152     ret = True
153     for f in TO_LIST(list):
154         if not CHECK_FUNC(conf, f, checklink=checklink, header=header):
155             ret = False
156     return ret
157
158
159 @conf
160 def CHECK_SIZEOF(conf, vars, headers=None, define=None):
161     '''check the size of a type'''
162     hdrs=''
163     if headers is not None:
164         hlist = TO_LIST(headers)
165     else:
166         hlist = conf.env.hlist
167     for h in hlist:
168         hdrs += '#include <%s>\n' % h
169     for v in TO_LIST(vars):
170         if define is None:
171             define_name = 'SIZEOF_%s' % string.replace(v.upper(), ' ', '_')
172         else:
173             define_name = define
174         conf.check(fragment=
175                    '''
176                   %s
177                   int main(void) {
178                     printf("%%u\\n", (unsigned)sizeof(%s));
179                     return 0;
180                   }
181                   ''' % (hdrs, v),
182                    execute=1,
183                    define_ret=True,
184                    define_name=define_name,
185                    quote=False,
186                    msg="Checking size of %s" % v)
187
188
189 @conf
190 def CHECK_CODE(conf, code, define,
191                always=False, execute=False, addmain=True, mandatory=False,
192                headers=None, msg=None, cflags='', includes='# .',
193                local_include=True):
194     '''check if some code compiles and/or runs'''
195     hdrs=''
196     if headers is not None:
197         hlist = TO_LIST(headers)
198     else:
199         hlist = conf.env.hlist
200     for h in hlist:
201         hdrs += '#include <%s>\n' % h
202
203     if execute:
204         execute = 1
205     else:
206         execute = 0
207
208     if addmain:
209         fragment='#include "__confdefs.h"\n%s\n int main(void) { %s; return 0; }' % (hdrs, code)
210     else:
211         fragment='#include "__confdefs.h"\n%s\n%s' % (hdrs, code)
212
213     conf.write_config_header('__confdefs.h', top=True)
214
215     if msg is None:
216         msg="Checking for %s" % define
217
218     # include the directory containing __confdefs.h
219     cflags += ' -I../../default'
220
221     if local_include:
222         cflags += ' -I%s' % conf.curdir
223
224     if conf.check(fragment=fragment,
225                   execute=execute,
226                   define_name = define,
227                   mandatory = mandatory,
228                   ccflags=TO_LIST(cflags),
229                   includes=includes,
230                   msg=msg):
231         conf.DEFINE(define, 1)
232         return True
233     if always:
234         conf.DEFINE(define, 0)
235     return False
236
237
238
239 @conf
240 def CHECK_STRUCTURE_MEMBER(conf, structname, member,
241                            always=False, define=None, headers=None):
242     '''check for a structure member'''
243     hdrs=''
244     if headers is not None:
245         hlist = TO_LIST(headers)
246     else:
247         hlist = conf.env.hlist
248     for h in hlist:
249         hdrs += '#include <%s>\n' % h
250     if define is None:
251         define = 'HAVE_%s' % member.upper()
252     if conf.check(fragment=
253                   '''
254                   %s
255                   int main(void) {
256                     %s s;
257                     void *_x; _x=(void *)&s.%s;
258                     return 0;
259                   }
260                   ''' % (hdrs, structname, member),
261                   execute=0,
262                   msg="Checking for member %s in %s" % (member, structname)):
263         conf.DEFINE(define, 1)
264         return True
265     elif always:
266         conf.DEFINE(define, 0)
267         return False
268
269
270 @conf
271 def CHECK_CFLAGS(conf, cflags, variable):
272     '''check if the given cflags are accepted by the compiler'''
273     if conf.check(fragment='int main(void) { return 0; }',
274                   execute=0,
275                   ccflags=cflags,
276                   msg="Checking compiler accepts %s" % cflags):
277         conf.env[variable] = cflags
278         return True
279     return False
280
281
282 #################################################
283 # return True if a configuration option was found
284 @conf
285 def CONFIG_SET(conf, option):
286     return (option in conf.env) and (conf.env[option] != ())
287 Build.BuildContext.CONFIG_SET = CONFIG_SET
288
289
290 ###########################################################
291 # check that the functions in 'list' are available in 'library'
292 # if they are, then make that library available as a dependency
293 #
294 # if the library is not available and mandatory==True, then
295 # raise an error.
296 #
297 # If the library is not available and mandatory==False, then
298 # add the library to the list of dependencies to remove from
299 # build rules
300 #
301 # optionally check for the functions first in libc
302 @conf
303 def CHECK_FUNCS_IN(conf, list, library, mandatory=False, checklibc=False, header=''):
304     remaining = TO_LIST(list)
305     liblist   = TO_LIST(library)
306
307     hlist = conf.env.hlist[:]
308     for h in TO_LIST(header):
309         if CHECK_HEADER(conf, h, add_headers=False):
310             hlist.append(h)
311
312     # check if some already found
313     for f in remaining[:]:
314         if CONFIG_SET(conf, 'HAVE_%s' % f.upper()):
315             remaining.remove(f)
316
317     # see if the functions are in libc
318     if checklibc:
319         for f in remaining[:]:
320             if CHECK_FUNC(conf, f, checklink=True, header=header):
321                 remaining.remove(f)
322
323     if remaining == []:
324         for lib in liblist:
325             if GET_TARGET_TYPE(conf, lib) != 'SYSLIB':
326                 SET_TARGET_TYPE(conf, lib, 'EMPTY')
327         return True
328
329     ret = True
330     for lib in liblist[:]:
331         if GET_TARGET_TYPE(conf, lib):
332             continue
333         if not conf.check(lib=lib, uselib_store=lib):
334             conf.ASSERT(not mandatory,
335                         "Mandatory library '%s' not found for functions '%s'" % (lib, list))
336             # if it isn't a mandatory library, then remove it from dependency lists
337             SET_TARGET_TYPE(conf, lib, 'EMPTY')
338             ret = False
339         else:
340             conf.define('HAVE_LIB%s' % string.replace(lib.upper(),'-','_'), 1)
341             conf.env['LIB_' + lib.upper()] = lib
342             LOCAL_CACHE_SET(conf, 'TARGET_TYPE', lib, 'SYSLIB')
343
344     if not ret:
345         return ret
346
347     ret = True
348     for f in remaining:
349         if not conf.check_cc(function_name=f, lib=liblist, header_name=hlist):
350             ret = False
351
352     return ret
353
354
355 #################################################
356 # write out config.h in the right directory
357 @conf
358 def SAMBA_CONFIG_H(conf, path=None):
359     # we don't want to produce a config.h in places like lib/replace
360     # when we are building projects that depend on lib/replace
361     if os.path.realpath(conf.curdir) != os.path.realpath(Options.launch_dir):
362         return
363
364     if Options.options.developer:
365         # we add these here to ensure that -Wstrict-prototypes is not set during configure
366         conf.ADD_CFLAGS('-Wall -g -Wfatal-errors -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Werror-implicit-function-declaration -Wformat=2 -Wno-format-y2k')
367
368     if path is None:
369         conf.write_config_header('config.h', top=True)
370     else:
371         conf.write_config_header(path)
372
373
374 ##############################################################
375 # setup a configurable path
376 @conf
377 def CONFIG_PATH(conf, name, default):
378     if not name in conf.env:
379         if default[0] == '/':
380             conf.env[name] = default
381         else:
382             conf.env[name] = conf.env['PREFIX'] + default
383     conf.define(name, conf.env[name], quote=True)
384
385 ##############################################################
386 # add some CFLAGS to the command line
387 @conf
388 def ADD_CFLAGS(conf, flags):
389     if not 'EXTRA_CFLAGS' in conf.env:
390         conf.env['EXTRA_CFLAGS'] = []
391     conf.env['EXTRA_CFLAGS'].extend(TO_LIST(flags))
392
393 ##############################################################
394 # add some extra include directories to all builds
395 @conf
396 def ADD_EXTRA_INCLUDES(conf, includes):
397     if not 'EXTRA_INCLUDES' in conf.env:
398         conf.env['EXTRA_INCLUDES'] = []
399     conf.env['EXTRA_INCLUDES'].extend(TO_LIST(includes))
400
401
402 ##############################################################
403 # work out the current flags. local flags are added first
404 def CURRENT_CFLAGS(bld, target, cflags):
405     if not 'EXTRA_CFLAGS' in bld.env:
406         list = []
407     else:
408         list = bld.env['EXTRA_CFLAGS'];
409     ret = TO_LIST(cflags)
410     ret.extend(list)
411     return ret
412
413 @conf
414 def CHECK_RPATH_SUPPORT(conf):
415     '''see if the system supports rpath'''
416     return conf.CHECK_CODE('int x',
417                            define='HAVE_RPATH_SUPPORT',
418                            execute=True,
419                            msg='Checking for rpath support',
420                            cflags='-Wl,-rpath=.')
421
422 @conf
423 def CHECK_CC_ENV(conf):
424     '''trim whitespaces from 'CC'.
425     The build farm sometimes puts a space at the start'''
426     if os.environ.get('CC'):
427         conf.env.CC = TO_LIST(os.environ.get('CC'))
428         if len(conf.env.CC) == 1:
429             # make for nicer logs if just a single command
430             conf.env.CC = conf.env.CC[0]
431
432
433 @conf
434 def SETUP_CONFIGURE_CACHE(conf, enable):
435     '''enable/disable cache of configure results'''
436     if enable:
437         # when -C is chosen, we will use a private cache and will
438         # not look into system includes. This roughtly matches what
439         # autoconf does with -C
440         cache_path = os.path.join(conf.blddir, '.confcache')
441         mkdir_p(cache_path)
442         Options.cache_global = os.environ['WAFCACHE'] = cache_path
443     else:
444         # when -C is not chosen we will not cache configure checks
445         # We set the recursion limit low to prevent waf from spending
446         # a lot of time on the signatures of the files.
447         Options.cache_global = os.environ['WAFCACHE'] = ''
448         preproc.recursion_limit = 1
449     # in either case we don't need to scan system includes
450     preproc.go_absolute = False