build: more careful library list handling
[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
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 @runonce
22 def CHECK_HEADER(conf, h, add_headers=True):
23     '''check for a header'''
24     if conf.check(header_name=h) and add_headers:
25         conf.env.hlist.append(h)
26         return True
27     return False
28
29
30 @conf
31 def CHECK_HEADERS(conf, list, add_headers=True):
32     '''check for a list of headers'''
33     ret = True
34     for hdr in TO_LIST(list):
35         if not CHECK_HEADER(conf, hdr, add_headers):
36             ret = False
37     return ret
38
39
40 @conf
41 def CHECK_TYPES(conf, list):
42     '''check for a list of types'''
43     ret = True
44     lst = TO_LIST(list)
45     for t in TO_LIST(list):
46         if not conf.check(type_name=t, header_name=conf.env.hlist):
47             ret = False
48     return ret
49
50
51 @conf
52 def CHECK_TYPE_IN(conf, t, hdr, define=None):
53     '''check for a type in a specific header'''
54     if conf.check(header_name=hdr):
55         if define is None:
56             ret = conf.check(type_name=t, header_name=hdr)
57         else:
58             ret = conf.check(type_name=t, header_name=hdr, define_name=define)
59         return ret
60     return False
61
62
63 @conf
64 def CHECK_TYPE(conf, t, alternate=None, headers=None, define=None):
65     '''check for a type with an alternate'''
66     if headers is None:
67         headers = conf.env.hlist
68     if define is not None:
69         ret = conf.check(type_name=t, header_name=headers, define_name=define)
70     else:
71         ret = conf.check(type_name=t, header_name=headers)
72     if not ret and alternate is not None:
73         conf.DEFINE(t, alternate)
74     return ret
75
76
77 @conf
78 def CHECK_VARIABLE(conf, v, define=None, always=False, headers=None):
79     '''check for a variable declaration (or define)'''
80     hdrs=''
81     if headers is not None:
82         hlist = TO_LIST(headers)
83     else:
84         hlist = conf.env.hlist
85     for h in hlist:
86         hdrs += '#include <%s>\n' % h
87     if define is None:
88         define = 'HAVE_%s' % v.upper()
89     if conf.check(fragment=
90                   '''
91                   %s
92                   int main(void) {
93                     #ifndef %s
94                     void *_x; _x=(void *)&%s;
95                     #endif
96                     return 0;
97                   }
98                   ''' % (hdrs, v, v),
99                   execute=0,
100                   msg="Checking for variable %s" % v):
101         conf.DEFINE(define, 1)
102         return True
103     elif always:
104         conf.DEFINE(define, 0)
105         return False
106
107 @conf
108 def CHECK_DECLS(conf, vars, reverse=False, headers=None):
109     '''check a list of variable declarations, using the HAVE_DECL_xxx form
110        of define
111
112        When reverse==True then use HAVE_xxx_DECL instead of HAVE_DECL_xxx
113        '''
114     ret = True
115     for v in TO_LIST(vars):
116         if not reverse:
117             define='HAVE_DECL_%s' % v.upper()
118         else:
119             define='HAVE_%s_DECL' % v.upper()
120         if not CHECK_VARIABLE(conf, v, define=define, headers=headers):
121             ret = False
122     return ret
123
124
125 @runonce
126 def CHECK_FUNC(conf, f, checklink=False):
127     '''check for a function'''
128     define='HAVE_%s' % f.upper()
129     if CONFIG_SET(conf, define):
130         return True
131     if checklink:
132         return CHECK_CODE(conf, '%s()' % f, execute=False, define=define)
133     return conf.check(function_name=f, header_name=conf.env.hlist)
134
135
136 @conf
137 def CHECK_FUNCS(conf, list, checklink=False):
138     '''check for a list of functions'''
139     ret = True
140     for f in TO_LIST(list):
141         if not CHECK_FUNC(conf, f, checklink):
142             ret = False
143     return ret
144
145
146 @conf
147 def CHECK_SIZEOF(conf, vars, headers=None, define=None):
148     '''check the size of a type'''
149     hdrs=''
150     if headers is not None:
151         hlist = TO_LIST(headers)
152     else:
153         hlist = conf.env.hlist
154     for h in hlist:
155         hdrs += '#include <%s>\n' % h
156     for v in TO_LIST(vars):
157         if define is None:
158             define_name = 'SIZEOF_%s' % string.replace(v.upper(), ' ', '_')
159         else:
160             define_name = define
161         conf.check(fragment=
162                    '''
163                   %s
164                   int main(void) {
165                     printf("%%u\\n", (unsigned)sizeof(%s));
166                     return 0;
167                   }
168                   ''' % (hdrs, v),
169                    execute=1,
170                    define_ret=True,
171                    define_name=define_name,
172                    quote=False,
173                    msg="Checking size of %s" % v)
174
175
176 @conf
177 def CHECK_CODE(conf, code, define,
178                always=False, execute=False, addmain=True, mandatory=False,
179                headers=None, msg=None, cflags='', includes='# .',
180                local_include=True):
181     '''check if some code compiles and/or runs'''
182     hdrs=''
183     if headers is not None:
184         hlist = TO_LIST(headers)
185     else:
186         hlist = conf.env.hlist
187     for h in hlist:
188         hdrs += '#include <%s>\n' % h
189
190     if execute:
191         execute = 1
192     else:
193         execute = 0
194
195     if addmain:
196         fragment='#include "__confdefs.h"\n%s\n int main(void) { %s; return 0; }' % (hdrs, code)
197     else:
198         fragment='#include "__confdefs.h"\n%s\n%s' % (hdrs, code)
199
200     conf.write_config_header('__confdefs.h', top=True)
201
202     if msg is None:
203         msg="Checking for %s" % define
204
205     # include the directory containing __confdefs.h
206     cflags += ' -I../../default'
207
208     if local_include:
209         cflags += ' -I%s' % conf.curdir
210
211     if conf.check(fragment=fragment,
212                   execute=execute,
213                   define_name = define,
214                   mandatory = mandatory,
215                   ccflags=TO_LIST(cflags),
216                   includes=includes,
217                   msg=msg):
218         conf.DEFINE(define, 1)
219         return True
220     if always:
221         conf.DEFINE(define, 0)
222     return False
223
224
225
226 @conf
227 def CHECK_STRUCTURE_MEMBER(conf, structname, member,
228                            always=False, define=None, headers=None):
229     '''check for a structure member'''
230     hdrs=''
231     if headers is not None:
232         hlist = TO_LIST(headers)
233     else:
234         hlist = conf.env.hlist
235     for h in hlist:
236         hdrs += '#include <%s>\n' % h
237     if define is None:
238         define = 'HAVE_%s' % member.upper()
239     if conf.check(fragment=
240                   '''
241                   %s
242                   int main(void) {
243                     %s s;
244                     void *_x; _x=(void *)&s.%s;
245                     return 0;
246                   }
247                   ''' % (hdrs, structname, member),
248                   execute=0,
249                   msg="Checking for member %s in %s" % (member, structname)):
250         conf.DEFINE(define, 1)
251         return True
252     elif always:
253         conf.DEFINE(define, 0)
254         return False
255
256
257 @conf
258 def CHECK_CFLAGS(conf, cflags, variable):
259     '''check if the given cflags are accepted by the compiler'''
260     if conf.check(fragment='int main(void) { return 0; }',
261                   execute=0,
262                   ccflags=cflags,
263                   msg="Checking compiler accepts %s" % cflags):
264         conf.env[variable] = cflags
265         return True
266     return False
267
268
269 #################################################
270 # return True if a configuration option was found
271 @conf
272 def CONFIG_SET(conf, option):
273     return (option in conf.env) and (conf.env[option] != ())
274 Build.BuildContext.CONFIG_SET = CONFIG_SET
275
276
277 ###########################################################
278 # check that the functions in 'list' are available in 'library'
279 # if they are, then make that library available as a dependency
280 #
281 # if the library is not available and mandatory==True, then
282 # raise an error.
283 #
284 # If the library is not available and mandatory==False, then
285 # add the library to the list of dependencies to remove from
286 # build rules
287 #
288 # optionally check for the functions first in libc
289 @conf
290 def CHECK_FUNCS_IN(conf, list, library, mandatory=False, checklibc=False):
291     remaining = TO_LIST(list)
292     liblist   = TO_LIST(library)
293
294     # check if some already found
295     for f in remaining[:]:
296         if CONFIG_SET(conf, 'HAVE_%s' % f.upper()):
297             remaining.remove(f)
298
299     # see if the functions are in libc
300     if checklibc:
301         for f in remaining[:]:
302             if CHECK_FUNC(conf, f):
303                 remaining.remove(f)
304
305     if remaining == []:
306         for lib in liblist:
307             if GET_TARGET_TYPE(conf, lib) != 'SYSLIB':
308                 SET_TARGET_TYPE(conf, lib, 'EMPTY')
309         return True
310
311     ret = True
312     for lib in liblist[:]:
313         if GET_TARGET_TYPE(conf, lib):
314             continue
315         if not conf.check(lib=lib, uselib_store=lib):
316             conf.ASSERT(not mandatory,
317                         "Mandatory library '%s' not found for functions '%s'" % (lib, list))
318             # if it isn't a mandatory library, then remove it from dependency lists
319             SET_TARGET_TYPE(conf, lib, 'EMPTY')
320             ret = False
321         else:
322             conf.define('HAVE_LIB%s' % string.replace(lib.upper(),'-','_'), 1)
323
324     if not ret:
325         return ret
326
327     ret = True
328     for f in remaining:
329         if not conf.check(function_name=f, lib=liblist, header_name=conf.env.hlist):
330             ret = False
331
332     if not ret:
333         return ret
334
335     for lib in liblist:
336         if GET_TARGET_TYPE(conf, lib):
337             continue
338         conf.env['LIB_' + lib.upper()] = lib
339         LOCAL_CACHE_SET(conf, 'TARGET_TYPE', lib, 'SYSLIB')
340
341     return ret
342
343
344 #################################################
345 # write out config.h in the right directory
346 @conf
347 def SAMBA_CONFIG_H(conf, path=None):
348     # we don't want to produce a config.h in places like lib/replace
349     # when we are building projects that depend on lib/replace
350     if os.path.realpath(conf.curdir) != os.path.realpath(Options.launch_dir):
351         return
352     if path is None:
353         conf.write_config_header('config.h', top=True)
354     else:
355         conf.write_config_header(path)
356
357
358 ##############################################################
359 # setup a configurable path
360 @conf
361 def CONFIG_PATH(conf, name, default):
362     if not name in conf.env:
363         if default[0] == '/':
364             conf.env[name] = default
365         else:
366             conf.env[name] = conf.env['PREFIX'] + default
367     conf.define(name, conf.env[name], quote=True)
368
369 ##############################################################
370 # add some CFLAGS to the command line
371 @conf
372 def ADD_CFLAGS(conf, flags):
373     if not 'EXTRA_CFLAGS' in conf.env:
374         conf.env['EXTRA_CFLAGS'] = []
375     conf.env['EXTRA_CFLAGS'].extend(TO_LIST(flags))
376
377 ##############################################################
378 # add some extra include directories to all builds
379 @conf
380 def ADD_EXTRA_INCLUDES(conf, includes):
381     if not 'EXTRA_INCLUDES' in conf.env:
382         conf.env['EXTRA_INCLUDES'] = []
383     conf.env['EXTRA_INCLUDES'].extend(TO_LIST(includes))
384
385
386 ##############################################################
387 # work out the current flags. local flags are added first
388 def CURRENT_CFLAGS(bld, target, cflags):
389     if not 'EXTRA_CFLAGS' in bld.env:
390         list = []
391     else:
392         list = bld.env['EXTRA_CFLAGS'];
393     ret = TO_LIST(cflags)
394     ret.extend(list)
395     return ret