1# a waf tool to add autoconf-like macros to the configure section
2
3import os, sys
4from waflib import Build, Options, Logs, Context
5from waflib.Configure import conf
6from waflib.TaskGen import feature
7from waflib.Tools import c_preproc as preproc
8from samba_utils import TO_LIST, GET_TARGET_TYPE, SET_TARGET_TYPE, unique_list, mkdir_p
9
10missing_headers = set()
11
12####################################################
13# some autoconf like helpers, to make the transition
14# to waf a bit easier for those used to autoconf
15# m4 files
16
17@conf
18def DEFINE(conf, d, v, add_to_cflags=False, quote=False):
19    '''define a config option'''
20    conf.define(d, v, quote=quote)
21    if add_to_cflags:
22        conf.env.append_value('CFLAGS', '-D%s=%s' % (d, str(v)))
23
24def hlist_to_string(conf, headers=None):
25    '''convert a headers list to a set of #include lines'''
26    hdrs=''
27    hlist = conf.env.hlist
28    if headers:
29        hlist = hlist[:]
30        hlist.extend(TO_LIST(headers))
31    for h in hlist:
32        hdrs += '#include <%s>\n' % h
33    return hdrs
34
35
36@conf
37def COMPOUND_START(conf, msg):
38    '''start a compound test'''
39    def null_check_message_1(self,*k,**kw):
40        return
41    def null_check_message_2(self,*k,**kw):
42        return
43
44    v = getattr(conf.env, 'in_compound', [])
45    if v != [] and v != 0:
46        conf.env.in_compound = v + 1
47        return
48    conf.start_msg(msg)
49    conf.saved_check_message_1 = conf.start_msg
50    conf.start_msg = null_check_message_1
51    conf.saved_check_message_2 = conf.end_msg
52    conf.end_msg = null_check_message_2
53    conf.env.in_compound = 1
54
55
56@conf
57def COMPOUND_END(conf, result):
58    '''start a compound test'''
59    conf.env.in_compound -= 1
60    if conf.env.in_compound != 0:
61        return
62    conf.start_msg = conf.saved_check_message_1
63    conf.end_msg = conf.saved_check_message_2
64    p = conf.end_msg
65    if result is True:
66        p('ok')
67    elif not result:
68        p('not found', 'YELLOW')
69    else:
70        p(result)
71
72
73@feature('nolink')
74def nolink(self):
75    '''using the nolink type in conf.check() allows us to avoid
76       the link stage of a test, thus speeding it up for tests
77       that where linking is not needed'''
78    pass
79
80
81def CHECK_HEADER(conf, h, add_headers=False, lib=None):
82    '''check for a header'''
83    if h in missing_headers and lib is None:
84        return False
85    d = h.upper().replace('/', '_')
86    d = d.replace('.', '_')
87    d = d.replace('-', '_')
88    d = 'HAVE_%s' % d
89    if CONFIG_SET(conf, d):
90        if add_headers:
91            if not h in conf.env.hlist:
92                conf.env.hlist.append(h)
93        return True
94
95    (ccflags, ldflags, cpppath) = library_flags(conf, lib)
96
97    hdrs = hlist_to_string(conf, headers=h)
98    if lib is None:
99        lib = ""
100    ret = conf.check(fragment='%s\nint main(void) { return 0; }\n' % hdrs,
101                     type='nolink',
102                     execute=0,
103                     cflags=ccflags,
104                     mandatory=False,
105                     includes=cpppath,
106                     uselib=lib.upper(),
107                     msg="Checking for header %s" % h)
108    if not ret:
109        missing_headers.add(h)
110        return False
111
112    conf.DEFINE(d, 1)
113    if add_headers and not h in conf.env.hlist:
114        conf.env.hlist.append(h)
115    return ret
116
117
118@conf
119def CHECK_HEADERS(conf, headers, add_headers=False, together=False, lib=None):
120    '''check for a list of headers
121
122    when together==True, then the headers accumulate within this test.
123    This is useful for interdependent headers
124    '''
125    ret = True
126    if not add_headers and together:
127        saved_hlist = conf.env.hlist[:]
128        set_add_headers = True
129    else:
130        set_add_headers = add_headers
131    for hdr in TO_LIST(headers):
132        if not CHECK_HEADER(conf, hdr, set_add_headers, lib=lib):
133            ret = False
134    if not add_headers and together:
135        conf.env.hlist = saved_hlist
136    return ret
137
138
139def header_list(conf, headers=None, lib=None):
140    '''form a list of headers which exist, as a string'''
141    hlist=[]
142    if headers is not None:
143        for h in TO_LIST(headers):
144            if CHECK_HEADER(conf, h, add_headers=False, lib=lib):
145                hlist.append(h)
146    return hlist_to_string(conf, headers=hlist)
147
148
149@conf
150def CHECK_TYPE(conf, t, alternate=None, headers=None, define=None, lib=None, msg=None):
151    '''check for a single type'''
152    if define is None:
153        define = 'HAVE_' + t.upper().replace(' ', '_')
154    if msg is None:
155        msg='Checking for %s' % t
156    ret = CHECK_CODE(conf, '%s _x' % t,
157                     define,
158                     execute=False,
159                     headers=headers,
160                     local_include=False,
161                     msg=msg,
162                     lib=lib,
163                     link=False)
164    if not ret and alternate:
165        conf.DEFINE(t, alternate)
166    return ret
167
168
169@conf
170def CHECK_TYPES(conf, list, headers=None, define=None, alternate=None, lib=None):
171    '''check for a list of types'''
172    ret = True
173    for t in TO_LIST(list):
174        if not CHECK_TYPE(conf, t, headers=headers,
175                          define=define, alternate=alternate, lib=lib):
176            ret = False
177    return ret
178
179
180@conf
181def CHECK_TYPE_IN(conf, t, headers=None, alternate=None, define=None):
182    '''check for a single type with a header'''
183    return CHECK_TYPE(conf, t, headers=headers, alternate=alternate, define=define)
184
185
186@conf
187def CHECK_VARIABLE(conf, v, define=None, always=False,
188                   headers=None, msg=None, lib=None):
189    '''check for a variable declaration (or define)'''
190    if define is None:
191        define = 'HAVE_%s' % v.upper()
192
193    if msg is None:
194        msg="Checking for variable %s" % v
195
196    return CHECK_CODE(conf,
197                      # we need to make sure the compiler doesn't
198                      # optimize it out...
199                      '''
200                      #ifndef %s
201                      void *_x; _x=(void *)&%s; return (int)_x;
202                      #endif
203                      return 0
204                      ''' % (v, v),
205                      execute=False,
206                      link=False,
207                      msg=msg,
208                      local_include=False,
209                      lib=lib,
210                      headers=headers,
211                      define=define,
212                      always=always)
213
214
215@conf
216def CHECK_DECLS(conf, vars, reverse=False, headers=None, always=False):
217    '''check a list of variable declarations, using the HAVE_DECL_xxx form
218       of define
219
220       When reverse==True then use HAVE_xxx_DECL instead of HAVE_DECL_xxx
221       '''
222    ret = True
223    for v in TO_LIST(vars):
224        if not reverse:
225            define='HAVE_DECL_%s' % v.upper()
226        else:
227            define='HAVE_%s_DECL' % v.upper()
228        if not CHECK_VARIABLE(conf, v,
229                              define=define,
230                              headers=headers,
231                              msg='Checking for declaration of %s' % v,
232                              always=always):
233            if not CHECK_CODE(conf,
234                      '''
235                      return (int)%s;
236                      ''' % (v),
237                      execute=False,
238                      link=False,
239                      msg='Checking for declaration of %s (as enum)' % v,
240                      local_include=False,
241                      headers=headers,
242                      define=define,
243                      always=always):
244                ret = False
245    return ret
246
247
248def CHECK_FUNC(conf, f, link=True, lib=None, headers=None):
249    '''check for a function'''
250    define='HAVE_%s' % f.upper()
251
252    ret = False
253
254    in_lib_str = ""
255    if lib:
256        in_lib_str = " in %s" % lib
257    conf.COMPOUND_START('Checking for %s%s' % (f, in_lib_str))
258
259    if link is None or link:
260        ret = CHECK_CODE(conf,
261                         # this is based on the autoconf strategy
262                         '''
263                         #define %s __fake__%s
264                         #ifdef HAVE_LIMITS_H
265                         # include <limits.h>
266                         #else
267                         # include <assert.h>
268                         #endif
269                         #undef %s
270                         #if defined __stub_%s || defined __stub___%s
271                         #error "bad glibc stub"
272                         #endif
273                         extern char %s();
274                         int main() { return %s(); }
275                         ''' % (f, f, f, f, f, f, f),
276                         execute=False,
277                         link=True,
278                         addmain=False,
279                         add_headers=False,
280                         define=define,
281                         local_include=False,
282                         lib=lib,
283                         headers=headers,
284                         msg='Checking for %s' % f)
285
286        if not ret:
287            ret = CHECK_CODE(conf,
288                             # it might be a macro
289                             # we need to make sure the compiler doesn't
290                             # optimize it out...
291                             'void *__x = (void *)%s; return (int)__x' % f,
292                             execute=False,
293                             link=True,
294                             addmain=True,
295                             add_headers=True,
296                             define=define,
297                             local_include=False,
298                             lib=lib,
299                             headers=headers,
300                             msg='Checking for macro %s' % f)
301
302    if not ret and (link is None or not link):
303        ret = CHECK_VARIABLE(conf, f,
304                             define=define,
305                             headers=headers,
306                             msg='Checking for declaration of %s' % f)
307    conf.COMPOUND_END(ret)
308    return ret
309
310
311@conf
312def CHECK_FUNCS(conf, list, link=True, lib=None, headers=None):
313    '''check for a list of functions'''
314    ret = True
315    for f in TO_LIST(list):
316        if not CHECK_FUNC(conf, f, link=link, lib=lib, headers=headers):
317            ret = False
318    return ret
319
320
321@conf
322def CHECK_SIZEOF(conf, vars, headers=None, define=None, critical=True):
323    '''check the size of a type'''
324    for v in TO_LIST(vars):
325        v_define = define
326        ret = False
327        if v_define is None:
328            v_define = 'SIZEOF_%s' % v.upper().replace(' ', '_')
329        for size in list((1, 2, 4, 8, 16, 32, 64)):
330            if CHECK_CODE(conf,
331                      'static int test_array[1 - 2 * !(((long int)(sizeof(%s))) <= %d)];' % (v, size),
332                      define=v_define,
333                      quote=False,
334                      headers=headers,
335                      local_include=False,
336                      msg="Checking if size of %s == %d" % (v, size)):
337                conf.DEFINE(v_define, size)
338                ret = True
339                break
340        if not ret and critical:
341            Logs.error("Couldn't determine size of '%s'" % v)
342            sys.exit(1)
343    return ret
344
345@conf
346def CHECK_VALUEOF(conf, v, headers=None, define=None):
347    '''check the value of a variable/define'''
348    ret = True
349    v_define = define
350    if v_define is None:
351        v_define = 'VALUEOF_%s' % v.upper().replace(' ', '_')
352    if CHECK_CODE(conf,
353                  'printf("%%u", (unsigned)(%s))' % v,
354                  define=v_define,
355                  execute=True,
356                  define_ret=True,
357                  quote=False,
358                  headers=headers,
359                  local_include=False,
360                  msg="Checking value of %s" % v):
361        return int(conf.env[v_define])
362
363    return None
364
365@conf
366def CHECK_CODE(conf, code, define,
367               always=False, execute=False, addmain=True,
368               add_headers=True, mandatory=False,
369               headers=None, msg=None, cflags='', includes='# .',
370               local_include=True, lib=None, link=True,
371               define_ret=False, quote=False,
372               on_target=True, strict=False):
373    '''check if some code compiles and/or runs'''
374
375    if CONFIG_SET(conf, define):
376        return True
377
378    if headers is not None:
379        CHECK_HEADERS(conf, headers=headers, lib=lib)
380
381    if add_headers:
382        hdrs = header_list(conf, headers=headers, lib=lib)
383    else:
384        hdrs = ''
385    if execute:
386        execute = 1
387    else:
388        execute = 0
389
390    if addmain:
391        fragment='%s\n int main(void) { %s; return 0; }\n' % (hdrs, code)
392    else:
393        fragment='%s\n%s\n' % (hdrs, code)
394
395    if msg is None:
396        msg="Checking for %s" % define
397
398    cflags = TO_LIST(cflags)
399
400    # Be strict when relying on a compiler check
401    # Some compilers (e.g. xlc) ignore non-supported features as warnings
402    if strict:
403        if 'WERROR_CFLAGS' in conf.env:
404            cflags.extend(conf.env['WERROR_CFLAGS'])
405
406    if local_include:
407        cflags.append('-I%s' % conf.path.abspath())
408
409    if not link:
410        type='nolink'
411    else:
412        type='cprogram'
413
414    uselib = TO_LIST(lib)
415
416    (ccflags, ldflags, cpppath) = library_flags(conf, uselib)
417
418    includes = TO_LIST(includes)
419    includes.extend(cpppath)
420
421    uselib = [l.upper() for l in uselib]
422
423    cflags.extend(ccflags)
424
425    if on_target:
426        test_args = conf.SAMBA_CROSS_ARGS(msg=msg)
427    else:
428        test_args = []
429
430    conf.COMPOUND_START(msg)
431
432    try:
433        ret = conf.check(fragment=fragment,
434                     execute=execute,
435                     define_name = define,
436                     cflags=cflags,
437                     ldflags=ldflags,
438                     includes=includes,
439                     uselib=uselib,
440                     type=type,
441                     msg=msg,
442                     quote=quote,
443                     test_args=test_args,
444                     define_ret=define_ret)
445    except Exception:
446        if always:
447            conf.DEFINE(define, 0)
448        else:
449            conf.undefine(define)
450        conf.COMPOUND_END(False)
451        if mandatory:
452            raise
453        return False
454    else:
455        # Success is indicated by ret but we should unset
456        # defines set by WAF's c_config.check() because it
457        # defines it to int(ret) and we want to undefine it
458        if not ret:
459            conf.undefine(define)
460            conf.COMPOUND_END(False)
461            return False
462        if not define_ret:
463            conf.DEFINE(define, 1)
464            conf.COMPOUND_END(True)
465        else:
466            conf.DEFINE(define, ret, quote=quote)
467            conf.COMPOUND_END(ret)
468        return True
469
470
471@conf
472def CHECK_STRUCTURE_MEMBER(conf, structname, member,
473                           always=False, define=None, headers=None,
474                           lib=None):
475    '''check for a structure member'''
476    if define is None:
477        define = 'HAVE_%s' % member.upper()
478    return CHECK_CODE(conf,
479                      '%s s; void *_x; _x=(void *)&s.%s' % (structname, member),
480                      define,
481                      execute=False,
482                      link=False,
483                      lib=lib,
484                      always=always,
485                      headers=headers,
486                      local_include=False,
487                      msg="Checking for member %s in %s" % (member, structname))
488
489
490@conf
491def CHECK_CFLAGS(conf, cflags, fragment='int main(void) { return 0; }\n'):
492    '''check if the given cflags are accepted by the compiler
493    '''
494    check_cflags = TO_LIST(cflags)
495    if 'WERROR_CFLAGS' in conf.env:
496        check_cflags.extend(conf.env['WERROR_CFLAGS'])
497    return conf.check(fragment=fragment,
498                      execute=0,
499                      mandatory=False,
500                      type='nolink',
501                      cflags=check_cflags,
502                      msg="Checking compiler accepts %s" % cflags)
503
504@conf
505def CHECK_LDFLAGS(conf, ldflags):
506    '''check if the given ldflags are accepted by the linker
507    '''
508    return conf.check(fragment='int main(void) { return 0; }\n',
509                      execute=0,
510                      ldflags=ldflags,
511                      mandatory=False,
512                      msg="Checking linker accepts %s" % ldflags)
513
514
515@conf
516def CONFIG_GET(conf, option):
517    '''return True if a configuration option was found'''
518    if (option in conf.env):
519        return conf.env[option]
520    else:
521        return None
522
523@conf
524def CONFIG_SET(conf, option):
525    '''return True if a configuration option was found'''
526    if option not in conf.env:
527        return False
528    v = conf.env[option]
529    if v is None:
530        return False
531    if v == []:
532        return False
533    if v == ():
534        return False
535    return True
536
537@conf
538def CONFIG_RESET(conf, option):
539    if option not in conf.env:
540        return
541    del conf.env[option]
542
543Build.BuildContext.CONFIG_RESET = CONFIG_RESET
544Build.BuildContext.CONFIG_SET = CONFIG_SET
545Build.BuildContext.CONFIG_GET = CONFIG_GET
546
547
548def library_flags(self, libs):
549    '''work out flags from pkg_config'''
550    ccflags = []
551    ldflags = []
552    cpppath = []
553    for lib in TO_LIST(libs):
554        # note that we do not add the -I and -L in here, as that is added by the waf
555        # core. Adding it here would just change the order that it is put on the link line
556        # which can cause system paths to be added before internal libraries
557        extra_ccflags = TO_LIST(getattr(self.env, 'CFLAGS_%s' % lib.upper(), []))
558        extra_ldflags = TO_LIST(getattr(self.env, 'LDFLAGS_%s' % lib.upper(), []))
559        extra_cpppath = TO_LIST(getattr(self.env, 'CPPPATH_%s' % lib.upper(), []))
560        ccflags.extend(extra_ccflags)
561        ldflags.extend(extra_ldflags)
562        cpppath.extend(extra_cpppath)
563
564        extra_cpppath = TO_LIST(getattr(self.env, 'INCLUDES_%s' % lib.upper(), []))
565        cpppath.extend(extra_cpppath)
566    if 'EXTRA_LDFLAGS' in self.env:
567        ldflags.extend(self.env['EXTRA_LDFLAGS'])
568
569    ccflags = unique_list(ccflags)
570    ldflags = unique_list(ldflags)
571    cpppath = unique_list(cpppath)
572    return (ccflags, ldflags, cpppath)
573
574
575@conf
576def CHECK_LIB(conf, libs, mandatory=False, empty_decl=True, set_target=True, shlib=False, msg=None):
577    '''check if a set of libraries exist as system libraries
578
579    returns the sublist of libs that do exist as a syslib or []
580    '''
581
582    fragment= '''
583int foo()
584{
585    int v = 2;
586    return v*2;
587}
588'''
589    ret = []
590    liblist  = TO_LIST(libs)
591    for lib in liblist[:]:
592        if GET_TARGET_TYPE(conf, lib) == 'SYSLIB':
593            ret.append(lib)
594            continue
595
596        if msg is None:
597            msg = 'Checking for library %s' % lib
598
599        (ccflags, ldflags, cpppath) = library_flags(conf, lib)
600
601        if shlib:
602            res = conf.check(features='c cshlib',
603                             fragment=fragment,
604                             lib=lib,
605                             uselib_store=lib,
606                             cflags=ccflags,
607                             ldflags=ldflags,
608                             uselib=lib.upper(),
609                             mandatory=False,
610                             msg=msg)
611        else:
612            res = conf.check(lib=lib,
613                             uselib_store=lib,
614                             cflags=ccflags,
615                             ldflags=ldflags,
616                             uselib=lib.upper(),
617                             mandatory=False,
618                             msg=msg)
619
620        if not res:
621            if mandatory:
622                Logs.error("Mandatory library '%s' not found for functions '%s'" % (lib, list))
623                sys.exit(1)
624            if empty_decl:
625                # if it isn't a mandatory library, then remove it from dependency lists
626                if set_target:
627                    SET_TARGET_TYPE(conf, lib, 'EMPTY')
628        else:
629            conf.define('HAVE_LIB%s' % lib.upper().replace('-','_').replace('.','_'), 1)
630            conf.env['LIB_' + lib.upper()] = lib
631            if set_target:
632                conf.SET_TARGET_TYPE(lib, 'SYSLIB')
633            ret.append(lib)
634
635    return ret
636
637
638
639@conf
640def CHECK_FUNCS_IN(conf, list, library, mandatory=False, checklibc=False,
641                   headers=None, link=True, empty_decl=True, set_target=True):
642    """
643    check that the functions in 'list' are available in 'library'
644    if they are, then make that library available as a dependency
645
646    if the library is not available and mandatory==True, then
647    raise an error.
648
649    If the library is not available and mandatory==False, then
650    add the library to the list of dependencies to remove from
651    build rules
652
653    optionally check for the functions first in libc
654    """
655    remaining = TO_LIST(list)
656    liblist   = TO_LIST(library)
657
658    # check if some already found
659    for f in remaining[:]:
660        if CONFIG_SET(conf, 'HAVE_%s' % f.upper()):
661            remaining.remove(f)
662
663    # see if the functions are in libc
664    if checklibc:
665        for f in remaining[:]:
666            if CHECK_FUNC(conf, f, link=True, headers=headers):
667                remaining.remove(f)
668
669    if remaining == []:
670        for lib in liblist:
671            if GET_TARGET_TYPE(conf, lib) != 'SYSLIB' and empty_decl:
672                SET_TARGET_TYPE(conf, lib, 'EMPTY')
673        return True
674
675    checklist = conf.CHECK_LIB(liblist, empty_decl=empty_decl, set_target=set_target)
676    for lib in liblist[:]:
677        if not lib in checklist and mandatory:
678            Logs.error("Mandatory library '%s' not found for functions '%s'" % (lib, list))
679            sys.exit(1)
680
681    ret = True
682    for f in remaining:
683        if not CHECK_FUNC(conf, f, lib=' '.join(checklist), headers=headers, link=link):
684            ret = False
685
686    return ret
687
688
689@conf
690def IN_LAUNCH_DIR(conf):
691    '''return True if this rule is being run from the launch directory'''
692    return os.path.realpath(conf.path.abspath()) == os.path.realpath(Context.launch_dir)
693Options.OptionsContext.IN_LAUNCH_DIR = IN_LAUNCH_DIR
694
695
696@conf
697def SAMBA_CONFIG_H(conf, path=None):
698    '''write out config.h in the right directory'''
699    # we don't want to produce a config.h in places like lib/replace
700    # when we are building projects that depend on lib/replace
701    if not IN_LAUNCH_DIR(conf):
702        return
703
704    # we need to build real code that can't be optimized away to test
705    stack_protect_list = ['-fstack-protector-strong', '-fstack-protector']
706    for stack_protect_flag in stack_protect_list:
707        flag_supported = conf.check(fragment='''
708                                    #include <stdio.h>
709
710                                    int main(void)
711                                    {
712                                        char t[100000];
713                                        while (fgets(t, sizeof(t), stdin));
714                                        return 0;
715                                    }
716                                    ''',
717                                    execute=0,
718                                    cflags=[ '-Werror', '-Wp,-D_FORTIFY_SOURCE=2', stack_protect_flag],
719                                    mandatory=False,
720                                    msg='Checking if compiler accepts %s' % (stack_protect_flag))
721        if flag_supported:
722            conf.ADD_CFLAGS('%s' % (stack_protect_flag))
723            break
724
725    flag_supported = conf.check(fragment='''
726                                #include <stdio.h>
727
728                                int main(void)
729                                {
730                                    char t[100000];
731                                    while (fgets(t, sizeof(t), stdin));
732                                    return 0;
733                                }
734                                ''',
735                                execute=0,
736                                cflags=[ '-Werror', '-fstack-clash-protection'],
737                                mandatory=False,
738                                msg='Checking if compiler accepts -fstack-clash-protection')
739    if flag_supported:
740        conf.ADD_CFLAGS('-fstack-clash-protection')
741
742    if Options.options.debug:
743        conf.ADD_CFLAGS('-g', testflags=True)
744
745    if Options.options.developer:
746        conf.env.DEVELOPER_MODE = True
747
748        conf.ADD_CFLAGS('-g', testflags=True)
749        conf.ADD_CFLAGS('-Wall', testflags=True)
750        conf.ADD_CFLAGS('-Wshadow', testflags=True)
751        conf.ADD_CFLAGS('-Wmissing-prototypes', testflags=True)
752        if CHECK_CODE(conf,
753                      'struct a { int b; }; struct c { struct a d; } e = { };',
754                      'CHECK_C99_INIT',
755                      link=False,
756                      cflags='-Wmissing-field-initializers -Werror=missing-field-initializers',
757                      msg="Checking C99 init of nested structs."):
758            conf.ADD_CFLAGS('-Wmissing-field-initializers', testflags=True)
759        conf.ADD_CFLAGS('-Wformat-overflow=2', testflags=True)
760        conf.ADD_CFLAGS('-Wformat-zero-length', testflags=True)
761        conf.ADD_CFLAGS('-Wcast-align -Wcast-qual', testflags=True)
762        conf.ADD_CFLAGS('-fno-common', testflags=True)
763
764        conf.ADD_CFLAGS('-Werror=address', testflags=True)
765        # we add these here to ensure that -Wstrict-prototypes is not set during configure
766        conf.ADD_CFLAGS('-Werror=strict-prototypes -Wstrict-prototypes',
767                        testflags=True)
768        conf.ADD_CFLAGS('-Werror=write-strings -Wwrite-strings',
769                        testflags=True)
770        conf.ADD_CFLAGS('-Werror-implicit-function-declaration',
771                        testflags=True)
772        conf.ADD_CFLAGS('-Werror=pointer-arith -Wpointer-arith',
773                        testflags=True)
774        conf.ADD_CFLAGS('-Werror=declaration-after-statement -Wdeclaration-after-statement',
775                        testflags=True)
776        conf.ADD_CFLAGS('-Werror=return-type -Wreturn-type',
777                        testflags=True)
778        conf.ADD_CFLAGS('-Werror=uninitialized -Wuninitialized',
779                        testflags=True)
780        conf.ADD_CFLAGS('-Wimplicit-fallthrough',
781                        testflags=True)
782        conf.ADD_CFLAGS('-Werror=strict-overflow -Wstrict-overflow=2',
783                        testflags=True)
784
785        conf.ADD_CFLAGS('-Wformat=2 -Wno-format-y2k', testflags=True)
786        conf.ADD_CFLAGS('-Wno-format-zero-length', testflags=True)
787        conf.ADD_CFLAGS('-Werror=format-security -Wformat-security',
788                        testflags=True, prereq_flags='-Wformat')
789        # This check is because for ldb_search(), a NULL format string
790        # is not an error, but some compilers complain about that.
791        if CHECK_CFLAGS(conf, ["-Werror=format", "-Wformat=2"], '''
792int testformat(char *format, ...) __attribute__ ((format (__printf__, 1, 2)));
793
794int main(void) {
795        testformat(0);
796        return 0;
797}
798
799'''):
800            if not 'EXTRA_CFLAGS' in conf.env:
801                conf.env['EXTRA_CFLAGS'] = []
802            conf.env['EXTRA_CFLAGS'].extend(TO_LIST("-Werror=format"))
803
804    if Options.options.picky_developer:
805        conf.ADD_NAMED_CFLAGS('PICKY_CFLAGS', '-Werror -Wno-error=deprecated-declarations', testflags=True)
806        conf.ADD_NAMED_CFLAGS('PICKY_CFLAGS', '-Wno-error=tautological-compare', testflags=True)
807
808    if Options.options.fatal_errors:
809        conf.ADD_CFLAGS('-Wfatal-errors', testflags=True)
810
811    if Options.options.pedantic:
812        conf.ADD_CFLAGS('-W', testflags=True)
813
814    if (Options.options.address_sanitizer or
815        Options.options.undefined_sanitizer):
816        conf.ADD_CFLAGS('-g -O1', testflags=True)
817    if Options.options.address_sanitizer:
818        conf.ADD_CFLAGS('-fno-omit-frame-pointer', testflags=True)
819        conf.ADD_CFLAGS('-fsanitize=address', testflags=True)
820        conf.ADD_LDFLAGS('-fsanitize=address', testflags=True)
821        conf.env['ADDRESS_SANITIZER'] = True
822    if Options.options.undefined_sanitizer:
823        conf.ADD_CFLAGS('-fsanitize=undefined', testflags=True)
824        conf.ADD_CFLAGS('-fsanitize=null', testflags=True)
825        conf.ADD_CFLAGS('-fsanitize=alignment', testflags=True)
826        conf.ADD_LDFLAGS('-fsanitize=undefined', testflags=True)
827        conf.env['UNDEFINED_SANITIZER'] = True
828
829
830    # Let people pass an additional ADDITIONAL_{CFLAGS,LDFLAGS}
831    # environment variables which are only used the for final build.
832    #
833    # The CFLAGS and LDFLAGS environment variables are also
834    # used for the configure checks which might impact their results.
835    conf.add_os_flags('ADDITIONAL_CFLAGS')
836    if conf.env.ADDITIONAL_CFLAGS and conf.CHECK_CFLAGS(conf.env['ADDITIONAL_CFLAGS']):
837        conf.env['EXTRA_CFLAGS'].extend(conf.env['ADDITIONAL_CFLAGS'])
838    conf.add_os_flags('ADDITIONAL_LDFLAGS')
839    if conf.env.ADDITIONAL_LDFLAGS and conf.CHECK_LDFLAGS(conf.env['ADDITIONAL_LDFLAGS']):
840        conf.env['EXTRA_LDFLAGS'].extend(conf.env['ADDITIONAL_LDFLAGS'])
841
842    if path is None:
843        conf.write_config_header('default/config.h', top=True, remove=False)
844    else:
845        conf.write_config_header(os.path.join(conf.variant, path), remove=False)
846    for key in conf.env.define_key:
847        conf.undefine(key, from_env=False)
848    conf.env.define_key = []
849    conf.SAMBA_CROSS_CHECK_COMPLETE()
850
851
852@conf
853def CONFIG_PATH(conf, name, default):
854    '''setup a configurable path'''
855    if not name in conf.env:
856        if default[0] == '/':
857            conf.env[name] = default
858        else:
859            conf.env[name] = conf.env['PREFIX'] + default
860
861@conf
862def ADD_NAMED_CFLAGS(conf, name, flags, testflags=False, prereq_flags=[]):
863    '''add some CFLAGS to the command line
864       optionally set testflags to ensure all the flags work
865    '''
866    prereq_flags = TO_LIST(prereq_flags)
867    if testflags:
868        ok_flags=[]
869        for f in flags.split():
870            if CHECK_CFLAGS(conf, [f] + prereq_flags):
871                ok_flags.append(f)
872        flags = ok_flags
873    if not name in conf.env:
874        conf.env[name] = []
875    conf.env[name].extend(TO_LIST(flags))
876
877@conf
878def ADD_CFLAGS(conf, flags, testflags=False, prereq_flags=[]):
879    '''add some CFLAGS to the command line
880       optionally set testflags to ensure all the flags work
881    '''
882    ADD_NAMED_CFLAGS(conf, 'EXTRA_CFLAGS', flags, testflags=testflags,
883                     prereq_flags=prereq_flags)
884
885@conf
886def ADD_LDFLAGS(conf, flags, testflags=False):
887    '''add some LDFLAGS to the command line
888       optionally set testflags to ensure all the flags work
889
890       this will return the flags that are added, if any
891    '''
892    if testflags:
893        ok_flags=[]
894        for f in flags.split():
895            if CHECK_LDFLAGS(conf, f):
896                ok_flags.append(f)
897        flags = ok_flags
898    if not 'EXTRA_LDFLAGS' in conf.env:
899        conf.env['EXTRA_LDFLAGS'] = []
900    conf.env['EXTRA_LDFLAGS'].extend(TO_LIST(flags))
901    return flags
902
903
904@conf
905def ADD_EXTRA_INCLUDES(conf, includes):
906    '''add some extra include directories to all builds'''
907    if not 'EXTRA_INCLUDES' in conf.env:
908        conf.env['EXTRA_INCLUDES'] = []
909    conf.env['EXTRA_INCLUDES'].extend(TO_LIST(includes))
910
911
912
913def CURRENT_CFLAGS(bld, target, cflags, allow_warnings=False, hide_symbols=False):
914    '''work out the current flags. local flags are added first'''
915    ret = TO_LIST(cflags)
916    if not 'EXTRA_CFLAGS' in bld.env:
917        list = []
918    else:
919        list = bld.env['EXTRA_CFLAGS'];
920    ret.extend(list)
921    if not allow_warnings and 'PICKY_CFLAGS' in bld.env:
922        list = bld.env['PICKY_CFLAGS'];
923        ret.extend(list)
924    if hide_symbols and bld.env.HAVE_VISIBILITY_ATTR:
925        ret.append(bld.env.VISIBILITY_CFLAGS)
926    return ret
927
928
929@conf
930def CHECK_CC_ENV(conf):
931    """trim whitespaces from 'CC'.
932    The build farm sometimes puts a space at the start"""
933    if os.environ.get('CC'):
934        conf.env.CC = TO_LIST(os.environ.get('CC'))
935
936
937@conf
938def SETUP_CONFIGURE_CACHE(conf, enable):
939    '''enable/disable cache of configure results'''
940    if enable:
941        # when -C is chosen, we will use a private cache and will
942        # not look into system includes. This roughtly matches what
943        # autoconf does with -C
944        cache_path = os.path.join(conf.bldnode.abspath(), '.confcache')
945        mkdir_p(cache_path)
946        Options.cache_global = os.environ['WAFCACHE'] = cache_path
947    else:
948        # when -C is not chosen we will not cache configure checks
949        # We set the recursion limit low to prevent waf from spending
950        # a lot of time on the signatures of the files.
951        Options.cache_global = os.environ['WAFCACHE'] = ''
952        preproc.recursion_limit = 1
953    # in either case we don't need to scan system includes
954    preproc.go_absolute = False
955
956
957@conf
958def SAMBA_CHECK_UNDEFINED_SYMBOL_FLAGS(conf):
959    if not sys.platform.startswith("openbsd"):
960        # we don't want any libraries or modules to rely on runtime
961        # resolution of symbols
962        conf.env.undefined_ldflags = conf.ADD_LDFLAGS('-Wl,-no-undefined', testflags=True)
963
964        if (conf.env.undefined_ignore_ldflags == [] and
965            conf.CHECK_LDFLAGS(['-undefined', 'dynamic_lookup'] + conf.env.WERROR_CFLAGS)):
966            conf.env.undefined_ignore_ldflags = ['-undefined', 'dynamic_lookup']
967