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
602        if shlib:
603            res = conf.check(features='c cshlib',
604                             fragment=fragment,
605                             lib=lib,
606                             uselib_store=lib,
607                             cflags=ccflags,
608                             ldflags=ldflags,
609                             uselib=lib.upper(),
610                             mandatory=False,
611                             msg=msg)
612        else:
613            res = conf.check(lib=lib,
614                             uselib_store=lib,
615                             cflags=ccflags,
616                             ldflags=ldflags,
617                             uselib=lib.upper(),
618                             mandatory=False,
619                             msg=msg)
620
621        if not res:
622            if mandatory:
623                Logs.error("Mandatory library '%s' not found for functions '%s'" % (lib, list))
624                sys.exit(1)
625            if empty_decl:
626                # if it isn't a mandatory library, then remove it from dependency lists
627                if set_target:
628                    SET_TARGET_TYPE(conf, lib, 'EMPTY')
629        else:
630            conf.define('HAVE_LIB%s' % lib.upper().replace('-','_').replace('.','_'), 1)
631            conf.env['LIB_' + lib.upper()] = lib
632            if set_target:
633                conf.SET_TARGET_TYPE(lib, 'SYSLIB')
634            ret.append(lib)
635
636    return ret
637
638
639
640@conf
641def CHECK_FUNCS_IN(conf, list, library, mandatory=False, checklibc=False,
642                   headers=None, link=True, empty_decl=True, set_target=True):
643    """
644    check that the functions in 'list' are available in 'library'
645    if they are, then make that library available as a dependency
646
647    if the library is not available and mandatory==True, then
648    raise an error.
649
650    If the library is not available and mandatory==False, then
651    add the library to the list of dependencies to remove from
652    build rules
653
654    optionally check for the functions first in libc
655    """
656    remaining = TO_LIST(list)
657    liblist   = TO_LIST(library)
658
659    # check if some already found
660    for f in remaining[:]:
661        if CONFIG_SET(conf, 'HAVE_%s' % f.upper()):
662            remaining.remove(f)
663
664    # see if the functions are in libc
665    if checklibc:
666        for f in remaining[:]:
667            if CHECK_FUNC(conf, f, link=True, headers=headers):
668                remaining.remove(f)
669
670    if remaining == []:
671        for lib in liblist:
672            if GET_TARGET_TYPE(conf, lib) != 'SYSLIB' and empty_decl:
673                SET_TARGET_TYPE(conf, lib, 'EMPTY')
674        return True
675
676    checklist = conf.CHECK_LIB(liblist, empty_decl=empty_decl, set_target=set_target)
677    for lib in liblist[:]:
678        if not lib in checklist and mandatory:
679            Logs.error("Mandatory library '%s' not found for functions '%s'" % (lib, list))
680            sys.exit(1)
681
682    ret = True
683    for f in remaining:
684        if not CHECK_FUNC(conf, f, lib=' '.join(checklist), headers=headers, link=link):
685            ret = False
686
687    return ret
688
689
690@conf
691def IN_LAUNCH_DIR(conf):
692    '''return True if this rule is being run from the launch directory'''
693    return os.path.realpath(conf.path.abspath()) == os.path.realpath(Context.launch_dir)
694Options.OptionsContext.IN_LAUNCH_DIR = IN_LAUNCH_DIR
695
696
697@conf
698def SAMBA_CONFIG_H(conf, path=None):
699    '''write out config.h in the right directory'''
700    # we don't want to produce a config.h in places like lib/replace
701    # when we are building projects that depend on lib/replace
702    if not IN_LAUNCH_DIR(conf):
703        return
704
705    # we need to build real code that can't be optimized away to test
706    stack_protect_list = ['-fstack-protector-strong', '-fstack-protector']
707    for stack_protect_flag in stack_protect_list:
708        flag_supported = conf.check(fragment='''
709                                    #include <stdio.h>
710
711                                    int main(void)
712                                    {
713                                        char t[100000];
714                                        while (fgets(t, sizeof(t), stdin));
715                                        return 0;
716                                    }
717                                    ''',
718                                    execute=0,
719                                    cflags=[ '-Werror', '-Wp,-D_FORTIFY_SOURCE=2', stack_protect_flag],
720                                    mandatory=False,
721                                    msg='Checking if compiler accepts %s' % (stack_protect_flag))
722        if flag_supported:
723            conf.ADD_CFLAGS('%s' % (stack_protect_flag))
724            break
725
726    flag_supported = conf.check(fragment='''
727                                #include <stdio.h>
728
729                                int main(void)
730                                {
731                                    char t[100000];
732                                    while (fgets(t, sizeof(t), stdin));
733                                    return 0;
734                                }
735                                ''',
736                                execute=0,
737                                cflags=[ '-Werror', '-fstack-clash-protection'],
738                                mandatory=False,
739                                msg='Checking if compiler accepts -fstack-clash-protection')
740    if flag_supported:
741        conf.ADD_CFLAGS('-fstack-clash-protection')
742
743    if Options.options.debug:
744        conf.ADD_CFLAGS('-g', testflags=True)
745
746    if Options.options.pidl_developer:
747        conf.env.PIDL_DEVELOPER_MODE = True
748
749    if Options.options.developer:
750        conf.env.DEVELOPER_MODE = True
751
752        conf.ADD_CFLAGS('-g', testflags=True)
753        conf.ADD_CFLAGS('-Wall', testflags=True)
754        conf.ADD_CFLAGS('-Wshadow', testflags=True)
755        conf.ADD_CFLAGS('-Wmissing-prototypes', testflags=True)
756        if CHECK_CODE(conf,
757                      'struct a { int b; }; struct c { struct a d; } e = { };',
758                      'CHECK_C99_INIT',
759                      link=False,
760                      cflags='-Wmissing-field-initializers -Werror=missing-field-initializers',
761                      msg="Checking C99 init of nested structs."):
762            conf.ADD_CFLAGS('-Wmissing-field-initializers', testflags=True)
763        conf.ADD_CFLAGS('-Wformat-overflow=2', testflags=True)
764        conf.ADD_CFLAGS('-Wformat-zero-length', testflags=True)
765        conf.ADD_CFLAGS('-Wcast-align -Wcast-qual', testflags=True)
766        conf.ADD_CFLAGS('-fno-common', testflags=True)
767
768        conf.ADD_CFLAGS('-Werror=address', testflags=True)
769        # we add these here to ensure that -Wstrict-prototypes is not set during configure
770        conf.ADD_CFLAGS('-Werror=strict-prototypes -Wstrict-prototypes',
771                        testflags=True)
772        conf.ADD_CFLAGS('-Werror=write-strings -Wwrite-strings',
773                        testflags=True)
774        conf.ADD_CFLAGS('-Werror-implicit-function-declaration',
775                        testflags=True)
776        conf.ADD_CFLAGS('-Werror=pointer-arith -Wpointer-arith',
777                        testflags=True)
778        conf.ADD_CFLAGS('-Werror=declaration-after-statement -Wdeclaration-after-statement',
779                        testflags=True)
780        conf.ADD_CFLAGS('-Werror=return-type -Wreturn-type',
781                        testflags=True)
782        conf.ADD_CFLAGS('-Werror=uninitialized -Wuninitialized',
783                        testflags=True)
784        conf.ADD_CFLAGS('-Wimplicit-fallthrough',
785                        testflags=True)
786        conf.ADD_CFLAGS('-Werror=strict-overflow -Wstrict-overflow=2',
787                        testflags=True)
788
789        conf.ADD_CFLAGS('-Wformat=2 -Wno-format-y2k', testflags=True)
790        conf.ADD_CFLAGS('-Wno-format-zero-length', testflags=True)
791        conf.ADD_CFLAGS('-Werror=format-security -Wformat-security',
792                        testflags=True, prereq_flags='-Wformat')
793        # This check is because for ldb_search(), a NULL format string
794        # is not an error, but some compilers complain about that.
795        if CHECK_CFLAGS(conf, ["-Werror=format", "-Wformat=2"], '''
796int testformat(char *format, ...) __attribute__ ((format (__printf__, 1, 2)));
797
798int main(void) {
799        testformat(0);
800        return 0;
801}
802
803'''):
804            if not 'EXTRA_CFLAGS' in conf.env:
805                conf.env['EXTRA_CFLAGS'] = []
806            conf.env['EXTRA_CFLAGS'].extend(TO_LIST("-Werror=format"))
807
808        if not Options.options.disable_warnings_as_errors:
809            conf.ADD_NAMED_CFLAGS('PICKY_CFLAGS', '-Werror -Wno-error=deprecated-declarations', testflags=True)
810            conf.ADD_NAMED_CFLAGS('PICKY_CFLAGS', '-Wno-error=tautological-compare', testflags=True)
811
812    if Options.options.fatal_errors:
813        conf.ADD_CFLAGS('-Wfatal-errors', testflags=True)
814
815    if Options.options.pedantic:
816        conf.ADD_CFLAGS('-W', testflags=True)
817
818    if (Options.options.address_sanitizer or
819        Options.options.undefined_sanitizer):
820        conf.ADD_CFLAGS('-g -O1', testflags=True)
821    if Options.options.address_sanitizer:
822        conf.ADD_CFLAGS('-fno-omit-frame-pointer', testflags=True)
823        conf.ADD_CFLAGS('-fsanitize=address', testflags=True)
824        conf.ADD_LDFLAGS('-fsanitize=address', testflags=True)
825        conf.env['ADDRESS_SANITIZER'] = True
826    if Options.options.undefined_sanitizer:
827        conf.ADD_CFLAGS('-fsanitize=undefined', testflags=True)
828        conf.ADD_CFLAGS('-fsanitize=null', testflags=True)
829        conf.ADD_CFLAGS('-fsanitize=alignment', testflags=True)
830        conf.ADD_LDFLAGS('-fsanitize=undefined', testflags=True)
831        conf.env['UNDEFINED_SANITIZER'] = True
832
833
834    # Let people pass an additional ADDITIONAL_{CFLAGS,LDFLAGS}
835    # environment variables which are only used the for final build.
836    #
837    # The CFLAGS and LDFLAGS environment variables are also
838    # used for the configure checks which might impact their results.
839    #
840    # If these variables don't pass a smoke test, fail the configure
841
842    conf.add_os_flags('ADDITIONAL_CFLAGS')
843    if conf.env.ADDITIONAL_CFLAGS:
844        conf.CHECK_CFLAGS(conf.env['ADDITIONAL_CFLAGS'],
845                          mandatory=True)
846        conf.env['EXTRA_CFLAGS'].extend(conf.env['ADDITIONAL_CFLAGS'])
847
848    conf.add_os_flags('ADDITIONAL_LDFLAGS')
849    if conf.env.ADDITIONAL_LDFLAGS:
850        conf.CHECK_LDFLAGS(conf.env['ADDITIONAL_LDFLAGS'],
851                           mandatory=True)
852        conf.env['EXTRA_LDFLAGS'].extend(conf.env['ADDITIONAL_LDFLAGS'])
853
854    if path is None:
855        conf.write_config_header('default/config.h', top=True, remove=False)
856    else:
857        conf.write_config_header(os.path.join(conf.variant, path), remove=False)
858    for key in conf.env.define_key:
859        conf.undefine(key, from_env=False)
860    conf.env.define_key = []
861    conf.SAMBA_CROSS_CHECK_COMPLETE()
862
863
864@conf
865def CONFIG_PATH(conf, name, default):
866    '''setup a configurable path'''
867    if not name in conf.env:
868        if default[0] == '/':
869            conf.env[name] = default
870        else:
871            conf.env[name] = conf.env['PREFIX'] + default
872
873@conf
874def ADD_NAMED_CFLAGS(conf, name, flags, testflags=False, prereq_flags=[]):
875    '''add some CFLAGS to the command line
876       optionally set testflags to ensure all the flags work
877    '''
878    prereq_flags = TO_LIST(prereq_flags)
879    if testflags:
880        ok_flags=[]
881        for f in flags.split():
882            if CHECK_CFLAGS(conf, [f] + prereq_flags):
883                ok_flags.append(f)
884        flags = ok_flags
885    if not name in conf.env:
886        conf.env[name] = []
887    conf.env[name].extend(TO_LIST(flags))
888
889@conf
890def ADD_CFLAGS(conf, flags, testflags=False, prereq_flags=[]):
891    '''add some CFLAGS to the command line
892       optionally set testflags to ensure all the flags work
893    '''
894    ADD_NAMED_CFLAGS(conf, 'EXTRA_CFLAGS', flags, testflags=testflags,
895                     prereq_flags=prereq_flags)
896
897@conf
898def ADD_LDFLAGS(conf, flags, testflags=False):
899    '''add some LDFLAGS to the command line
900       optionally set testflags to ensure all the flags work
901
902       this will return the flags that are added, if any
903    '''
904    if testflags:
905        ok_flags=[]
906        for f in flags.split():
907            if CHECK_LDFLAGS(conf, f):
908                ok_flags.append(f)
909        flags = ok_flags
910    if not 'EXTRA_LDFLAGS' in conf.env:
911        conf.env['EXTRA_LDFLAGS'] = []
912    conf.env['EXTRA_LDFLAGS'].extend(TO_LIST(flags))
913    return flags
914
915
916@conf
917def ADD_EXTRA_INCLUDES(conf, includes):
918    '''add some extra include directories to all builds'''
919    if not 'EXTRA_INCLUDES' in conf.env:
920        conf.env['EXTRA_INCLUDES'] = []
921    conf.env['EXTRA_INCLUDES'].extend(TO_LIST(includes))
922
923
924
925def CURRENT_CFLAGS(bld, target, cflags, allow_warnings=False, hide_symbols=False):
926    '''work out the current flags. local flags are added first'''
927    ret = TO_LIST(cflags)
928    if not 'EXTRA_CFLAGS' in bld.env:
929        list = []
930    else:
931        list = bld.env['EXTRA_CFLAGS'];
932    ret.extend(list)
933    if not allow_warnings and 'PICKY_CFLAGS' in bld.env:
934        list = bld.env['PICKY_CFLAGS'];
935        ret.extend(list)
936    if hide_symbols and bld.env.HAVE_VISIBILITY_ATTR:
937        ret.append(bld.env.VISIBILITY_CFLAGS)
938    return ret
939
940
941@conf
942def CHECK_CC_ENV(conf):
943    """trim whitespaces from 'CC'.
944    The build farm sometimes puts a space at the start"""
945    if os.environ.get('CC'):
946        conf.env.CC = TO_LIST(os.environ.get('CC'))
947
948
949@conf
950def SETUP_CONFIGURE_CACHE(conf, enable):
951    '''enable/disable cache of configure results'''
952    if enable:
953        # when -C is chosen, we will use a private cache and will
954        # not look into system includes. This roughtly matches what
955        # autoconf does with -C
956        cache_path = os.path.join(conf.bldnode.abspath(), '.confcache')
957        mkdir_p(cache_path)
958        Options.cache_global = os.environ['WAFCACHE'] = cache_path
959    else:
960        # when -C is not chosen we will not cache configure checks
961        # We set the recursion limit low to prevent waf from spending
962        # a lot of time on the signatures of the files.
963        Options.cache_global = os.environ['WAFCACHE'] = ''
964        preproc.recursion_limit = 1
965    # in either case we don't need to scan system includes
966    preproc.go_absolute = False
967
968
969@conf
970def SAMBA_CHECK_UNDEFINED_SYMBOL_FLAGS(conf):
971    if Options.options.address_sanitizer or Options.options.enable_libfuzzer:
972        # Sanitizers can rely on symbols undefined at library link time and the
973        # symbols used for fuzzers are only defined by compiler wrappers.
974        return
975
976    if not sys.platform.startswith("openbsd"):
977        # we don't want any libraries or modules to rely on runtime
978        # resolution of symbols
979        conf.env.undefined_ldflags = conf.ADD_LDFLAGS('-Wl,-no-undefined', testflags=True)
980
981        if (conf.env.undefined_ignore_ldflags == [] and
982            conf.CHECK_LDFLAGS(['-undefined', 'dynamic_lookup'] + conf.env.WERROR_CFLAGS)):
983            conf.env.undefined_ignore_ldflags = ['-undefined', 'dynamic_lookup']
984