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