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