waf: Document the confusing --nonshared-binary, --builtin-libraries, --private-librar...
[samba.git] / buildtools / wafsamba / wscript
1 #!/usr/bin/env python
2
3 # this is a base set of waf rules that everything else pulls in first
4
5 import os, sys
6 from waflib import Configure, Logs, Options, Utils, Context, Errors
7 import wafsamba
8 from samba_utils import symlink
9 from optparse import SUPPRESS_HELP
10
11 # this forces configure to be re-run if any of the configure
12 # sections of the build scripts change. We have to check
13 # for this in sys.argv as options have not yet been parsed when
14 # we need to set this. This is off by default until some issues
15 # are resolved related to WAFCACHE. It will need a lot of testing
16 # before it is enabled by default.
17 if '--enable-auto-reconfigure' in sys.argv:
18     Configure.autoconfig = 'clobber'
19
20 def default_value(option, default=''):
21     if option in Options.options.__dict__:
22         return Options.options.__dict__[option]
23     return default
24
25 def options(opt):
26     opt.load('compiler_cc')
27
28     opt.load('gnu_dirs')
29
30     gr = opt.option_group('library handling options')
31
32     gr.add_option('--bundled-libraries',
33                    help=(f'''comma separated list of bundled libraries.
34
35 {Context.g_module.APPNAME} includes copies of externally maintained
36 system libraries (such as popt, cmokca) as well as Samba-maintained
37 libraries that can be found on the system already (such as talloc,
38 tdb).
39
40 This option, most useful for packagers, controls if each library
41 should be forced to be obtained from inside Samba (bundled), forced to
42 be obtained from the system (bundling disabled, ensuing that
43 dependency errors are not silently missed) or if that choice should be
44 automatic (best for end users).
45
46 May include !LIBNAME to disable bundling a library.
47
48 Can be 'NONE' or 'ALL' [auto]'''),
49                    action="store", dest='BUNDLED_LIBS', default='')
50
51     gr.add_option('--private-libraries',
52                    help=(f'''comma separated list of normally public libraries to build instead as private libraries.
53
54 By default {Context.g_module.APPNAME} will publish a number of public
55 libraries for use by other software.  For Samba this would include
56 libwbclient, libsmbclient and others.
57
58 This allows that to be disabled, to ensure that other software does
59 not use these libraries and they are placed in a private filesystem
60 prefix.
61
62 May include !LIBNAME to disable making a library private in order to
63 limit the effect of 'ALL' '''),
64                    action="store", dest='PRIVATE_LIBS', default='')
65
66     extension_default = default_value('PRIVATE_EXTENSION_DEFAULT')
67     gr.add_option('--private-library-extension',
68                    help=("name extension for private libraries [%s]" % extension_default),
69                    action="store", dest='PRIVATE_EXTENSION', default=extension_default)
70
71     extension_exception = default_value('PRIVATE_EXTENSION_EXCEPTION')
72     gr.add_option('--private-extension-exception',
73                    help=("comma separated list of libraries to not apply extension to [%s]" % extension_exception),
74                    action="store", dest='PRIVATE_EXTENSION_EXCEPTION', default=extension_exception)
75
76     builtin_default = default_value('BUILTIN_LIBRARIES_DEFAULT')
77     gr.add_option('--builtin-libraries', help=(
78 f'''comma separated list of libraries to build directly into binaries.
79
80 By default {Context.g_module.APPNAME} will build a large number of
81 shared libraries, to reduce binary size.  This overrides this
82 behaviour and essentially statically links the specified libraries into
83 each binary [{builtin_default}]'''),
84                   action="store",
85                   dest='BUILTIN_LIBRARIES', default=builtin_default)
86
87     gr.add_option('--minimum-library-version',
88                    help=(
89 f'''list of minimum system library versions for otherwise bundled
90 libraries.
91
92 {Context.g_module.APPNAME} by default requires that, in order to match
93 what is tested in our continuous integration (CI) test-suite, that the
94 versions of libraries that we include match that found on the system,
95 before we will select not to 'bundle'.
96
97 This option, possibly useful for packagers, allows that specified
98 version to be overridden (say, if it is absolutely known that a the
99 newer version included in this tarball has no relevant changes).
100
101 Use this with extreme care
102
103 (LIBNAME1:version,LIBNAME2:version)'''),
104                    action="store", dest='MINIMUM_LIBRARY_VERSION', default='')
105
106     gr.add_option('--disable-rpath',
107                    help=("Disable use of rpath for build binaries"),
108                    action="store_true", dest='disable_rpath_build', default=False)
109     gr.add_option('--disable-rpath-install',
110                    help=("Disable use of rpath for library path in installed files"),
111                    action="store_true", dest='disable_rpath_install', default=False)
112     gr.add_option('--disable-rpath-private-install',
113                    help=("Disable use of rpath for private library path in installed files"),
114                    action="store_true", dest='disable_rpath_private_install', default=False)
115     gr.add_option('--nonshared-binary',
116                    help=(
117 f'''Disable use of shared libaries internal to {Context.g_module.APPNAME} for the listed binaries.
118
119 The resulting binaries are 'statically linked' with regard to components provided by
120 {Context.g_module.APPNAME}, but remain dynamically linked to (eg) libc.so and libgnutls.so
121
122 Currently the only tested value is 'smbtorture,smbd/smbd' for Samba'''),
123                    action="store", dest='NONSHARED_BINARIES', default='')
124     gr.add_option('--disable-symbol-versions',
125                    help=("Disable use of the --version-script linker option"),
126                    action="store_true", dest='disable_symbol_versions', default=False)
127
128     opt.add_option('--with-modulesdir',
129                    help=("modules directory [PREFIX/modules]"),
130                    action="store", dest='MODULESDIR', default='${PREFIX}/modules')
131
132     opt.add_option('--with-privatelibdir',
133                    help=("private library directory [PREFIX/lib/%s]" % Context.g_module.APPNAME),
134                    action="store", dest='PRIVATELIBDIR', default=None)
135
136     opt.add_option('--with-libiconv',
137                    help='additional directory to search for libiconv',
138                    action='store', dest='iconv_open', default='/usr/local',
139                    match = ['Checking for library iconv', 'Checking for iconv_open', 'Checking for header iconv.h'])
140     opt.add_option('--without-gettext',
141                    help=("Disable use of gettext"),
142                    action="store_true", dest='disable_gettext', default=False)
143
144     gr = opt.option_group('developer options')
145
146     gr.add_option('-C',
147                    help='enable configure caching',
148                    action='store_true', dest='enable_configure_cache')
149     gr.add_option('--enable-auto-reconfigure',
150                    help='enable automatic reconfigure on build',
151                    action='store_true', dest='enable_auto_reconfigure')
152     gr.add_option('--enable-debug',
153                    help=("Turn on debugging symbols"),
154                    action="store_true", dest='debug', default=False)
155     gr.add_option('--enable-developer',
156                    help=("Turn on developer warnings and debugging"),
157                    action="store_true", dest='developer', default=False)
158     gr.add_option('--pidl-developer',
159                    help=("annotate PIDL-generated code for developers"),
160                    action="store_true", dest='pidl_developer', default=False)
161     gr.add_option('--disable-warnings-as-errors',
162                    help=("Do not treat all warnings as errors (disable -Werror)"),
163                    action="store_true", dest='disable_warnings_as_errors', default=False)
164     opt.add_option('--enable-coverage',
165                    help=("enable options necessary for code coverage "
166                          "reporting on selftest (default=no)"),
167                    action="store_true", dest='enable_coverage', default=False)
168     gr.add_option('--fatal-errors',
169                    help=("Stop compilation on first error (enable -Wfatal-errors)"),
170                    action="store_true", dest='fatal_errors', default=False)
171     gr.add_option('--enable-gccdeps',
172                    help=("Enable use of gcc -MD dependency module"),
173                    action="store_true", dest='enable_gccdeps', default=True)
174     gr.add_option('--pedantic',
175                    help=("Enable even more compiler warnings"),
176                    action='store_true', dest='pedantic', default=False)
177     gr.add_option('--git-local-changes',
178                    help=("mark version with + if local git changes"),
179                    action='store_true', dest='GIT_LOCAL_CHANGES', default=False)
180     gr.add_option('--address-sanitizer',
181                    help=("Enable address sanitizer compile and linker flags"),
182                    action="store_true", dest='address_sanitizer', default=False)
183     gr.add_option('--undefined-sanitizer',
184         help=("Enable undefined behaviour sanitizer compile and linker flags"),
185         action="store_true",
186         dest='undefined_sanitizer',
187         default=False)
188     gr.add_option('--enable-libfuzzer',
189                   help=("Build fuzzing binaries (use ADDITIONAL_CFLAGS to specify compiler options for libFuzzer or use CC=honggfuzz/hfuzz-cc)"),
190                   action="store_true", dest='enable_libfuzzer', default=False)
191     gr.add_option('--enable-afl-fuzzer',
192                   help=("Build fuzzing binaries AFL-style (typically use with CC=afl-gcc)"),
193                   action="store_true", dest='enable_afl_fuzzer', default=False)
194
195     # Fuzz targets may need additional LDFLAGS that we can't use on
196     # internal binaries like asn1_compile
197
198     gr.add_option('--fuzz-target-ldflags',
199                   help=("Linker flags to be used when building fuzz targets"),
200                   action="store", dest='FUZZ_TARGET_LDFLAGS', default='')
201
202     gr.add_option('--abi-check',
203                    help=("Check ABI signatures for libraries"),
204                    action='store_true', dest='ABI_CHECK', default=False)
205     gr.add_option('--abi-check-disable',
206                    help=("Disable ABI checking (used with --enable-developer)"),
207                    action='store_true', dest='ABI_CHECK_DISABLE', default=False)
208     gr.add_option('--abi-update',
209                    help=("Update ABI signature files for libraries"),
210                    action='store_true', dest='ABI_UPDATE', default=False)
211
212     gr.add_option('--show-deps',
213                    help=("Show dependency tree for the given target"),
214                    dest='SHOWDEPS', default='')
215
216     gr.add_option('--symbol-check',
217                   help=("check symbols in object files against project rules"),
218                   action='store_true', dest='SYMBOLCHECK', default=False)
219
220     gr.add_option('--dup-symbol-check',
221                   help=("check for duplicate symbols in object files and system libs (must be configured with --enable-developer)"),
222                   action='store_true', dest='DUP_SYMBOLCHECK', default=False)
223
224     gr.add_option('--why-needed',
225                   help=("TARGET:DEPENDENCY check why TARGET needs DEPENDENCY"),
226                   action='store', type='str', dest='WHYNEEDED', default=None)
227
228     gr.add_option('--show-duplicates',
229                   help=("Show objects which are included in multiple binaries or libraries"),
230                   action='store_true', dest='SHOW_DUPLICATES', default=False)
231
232     gr = opt.add_option_group('cross compilation options')
233
234     gr.add_option('--cross-compile',
235                    help=("configure for cross-compilation"),
236                    action='store_true', dest='CROSS_COMPILE', default=False)
237     gr.add_option('--cross-execute',
238                    help=("command prefix to use for cross-execution in configure"),
239                    action='store', dest='CROSS_EXECUTE', default='')
240     gr.add_option('--cross-answers',
241                    help=("answers to cross-compilation configuration (auto modified)"),
242                    action='store', dest='CROSS_ANSWERS', default='')
243     gr.add_option('--hostcc',
244                    help=("set host compiler when cross compiling"),
245                    action='store', dest='HOSTCC', default=False)
246
247     # we use SUPPRESS_HELP for these, as they are ignored, and are there only
248     # to allow existing RPM spec files to work
249     opt.add_option('--build',
250                    help=SUPPRESS_HELP,
251                    action='store', dest='AUTOCONF_BUILD', default='')
252     opt.add_option('--host',
253                    help=SUPPRESS_HELP,
254                    action='store', dest='AUTOCONF_HOST', default='')
255     opt.add_option('--target',
256                    help=SUPPRESS_HELP,
257                    action='store', dest='AUTOCONF_TARGET', default='')
258     opt.add_option('--program-prefix',
259                    help=SUPPRESS_HELP,
260                    action='store', dest='AUTOCONF_PROGRAM_PREFIX', default='')
261     opt.add_option('--disable-dependency-tracking',
262                    help=SUPPRESS_HELP,
263                    action='store_true', dest='AUTOCONF_DISABLE_DEPENDENCY_TRACKING', default=False)
264     opt.add_option('--disable-silent-rules',
265                    help=SUPPRESS_HELP,
266                    action='store_true', dest='AUTOCONF_DISABLE_SILENT_RULES', default=False)
267
268     gr = opt.option_group('dist options')
269     gr.add_option('--sign-release',
270                    help='sign the release tarball created by waf dist',
271                    action='store_true', dest='SIGN_RELEASE')
272     gr.add_option('--tag',
273                    help='tag release in git at the same time',
274                    type='string', action='store', dest='TAG_RELEASE')
275
276     opt.add_option('--disable-python',
277                     help='do not generate python modules',
278                     action='store_true', dest='disable_python', default=False)
279
280
281 @Utils.run_once
282 def configure(conf):
283     conf.env.hlist = []
284     conf.env.srcdir = conf.srcnode.abspath()
285
286     conf.define('SRCDIR', conf.env['srcdir'])
287
288     conf.SETUP_CONFIGURE_CACHE(Options.options.enable_configure_cache)
289
290     # load our local waf extensions
291     conf.load('gnu_dirs')
292     conf.load('wafsamba')
293
294     conf.CHECK_CC_ENV()
295
296     conf.load('compiler_c')
297
298     conf.CHECK_STANDARD_LIBPATH()
299
300     # we need git for 'waf dist'
301     conf.find_program('git', var='GIT')
302
303     # older gcc versions (< 4.4) does not work with gccdeps, so we have to see if the .d file is generated
304     if Options.options.enable_gccdeps:
305         # stale file removal - the configuration may pick up the old .pyc file
306         p = os.path.join(conf.env.srcdir, 'buildtools/wafsamba/gccdeps.pyc')
307         if os.path.exists(p):
308             os.remove(p)
309         conf.load('gccdeps')
310
311     # make the install paths available in environment
312     conf.env.LIBDIR = Options.options.LIBDIR or '${PREFIX}/lib'
313     conf.env.BINDIR = Options.options.BINDIR or '${PREFIX}/bin'
314     conf.env.SBINDIR = Options.options.SBINDIR or '${PREFIX}/sbin'
315     conf.env.MODULESDIR = Options.options.MODULESDIR
316     conf.env.PRIVATELIBDIR = Options.options.PRIVATELIBDIR
317     conf.env.BUNDLED_LIBS = Options.options.BUNDLED_LIBS.split(',')
318     conf.env.SYSTEM_LIBS = ()
319     conf.env.PRIVATE_LIBS = Options.options.PRIVATE_LIBS.split(',')
320     conf.env.BUILTIN_LIBRARIES = Options.options.BUILTIN_LIBRARIES.split(',')
321     conf.env.NONSHARED_BINARIES = Options.options.NONSHARED_BINARIES.split(',')
322
323     conf.env.PRIVATE_EXTENSION = Options.options.PRIVATE_EXTENSION
324     conf.env.PRIVATE_EXTENSION_EXCEPTION = Options.options.PRIVATE_EXTENSION_EXCEPTION.split(',')
325     conf.env.PRIVATE_VERSION = "%s_%s_%s" % (Context.g_module.APPNAME,
326         Context.g_module.VERSION, conf.env.PRIVATE_EXTENSION)
327
328     conf.env.CROSS_COMPILE = Options.options.CROSS_COMPILE
329     conf.env.CROSS_EXECUTE = Options.options.CROSS_EXECUTE
330     conf.env.CROSS_ANSWERS = Options.options.CROSS_ANSWERS
331     conf.env.HOSTCC        = Options.options.HOSTCC
332
333     conf.env.AUTOCONF_BUILD = Options.options.AUTOCONF_BUILD
334     conf.env.AUTOCONF_HOST  = Options.options.AUTOCONF_HOST
335     conf.env.AUTOCONF_PROGRAM_PREFIX = Options.options.AUTOCONF_PROGRAM_PREFIX
336
337     conf.env.disable_python = Options.options.disable_python
338
339     if (conf.env.AUTOCONF_HOST and
340         conf.env.AUTOCONF_BUILD and
341         conf.env.AUTOCONF_BUILD != conf.env.AUTOCONF_HOST):
342         Logs.error('ERROR: Mismatch between --build and --host. Please use --cross-compile instead')
343         sys.exit(1)
344     if conf.env.AUTOCONF_PROGRAM_PREFIX:
345         Logs.error('ERROR: --program-prefix not supported')
346         sys.exit(1)
347
348     # enable ABI checking for developers
349     conf.env.ABI_CHECK = Options.options.ABI_CHECK or Options.options.developer
350     if Options.options.ABI_CHECK_DISABLE:
351         conf.env.ABI_CHECK = False
352     try:
353         conf.find_program('gdb', mandatory=True)
354     except:
355         conf.env.ABI_CHECK = False
356
357     conf.env.enable_coverage = Options.options.enable_coverage
358     if conf.env.enable_coverage:
359         conf.ADD_LDFLAGS('-lgcov', testflags=True)
360         conf.ADD_CFLAGS('--coverage', testflags=True)
361         # disable abi check for coverage, otherwise ld will fail
362         conf.env.ABI_CHECK = False
363
364     conf.env.GIT_LOCAL_CHANGES = Options.options.GIT_LOCAL_CHANGES
365
366     conf.CHECK_UNAME()
367
368     # see if we can compile and run a simple C program
369     conf.CHECK_CODE('printf("hello world")',
370                     define='HAVE_SIMPLE_C_PROG',
371                     mandatory=True,
372                     execute=True,
373                     headers='stdio.h',
374                     msg='Checking simple C program')
375
376     # Try to find the right extra flags for -Werror behaviour
377     for f in ["-Werror",       # GCC
378               "-errwarn=%all", # Sun Studio
379               "-qhalt=w",     # IBM xlc
380               "-w2",           # Tru64
381              ]:
382         if conf.CHECK_CFLAGS([f]):
383             if not 'WERROR_CFLAGS' in conf.env:
384                 conf.env['WERROR_CFLAGS'] = []
385             conf.env['WERROR_CFLAGS'].extend([f])
386             break
387
388     # check which compiler/linker flags are needed for rpath support
389     if conf.CHECK_LDFLAGS(['-Wl,-rpath,.']):
390         conf.env['RPATH_ST'] = '-Wl,-rpath,%s'
391     elif conf.CHECK_LDFLAGS(['-Wl,-R,.']):
392         conf.env['RPATH_ST'] = '-Wl,-R,%s'
393
394     # check for rpath
395     if conf.CHECK_LIBRARY_SUPPORT(rpath=True):
396         support_rpath = True
397         conf.env.RPATH_ON_BUILD   = not Options.options.disable_rpath_build
398         conf.env.RPATH_ON_INSTALL = (conf.env.RPATH_ON_BUILD and
399                                      not Options.options.disable_rpath_install)
400         if not conf.env.PRIVATELIBDIR:
401             conf.env.PRIVATELIBDIR = '%s/%s' % (conf.env.LIBDIR, Context.g_module.APPNAME)
402         conf.env.RPATH_ON_INSTALL_PRIVATE = (
403             not Options.options.disable_rpath_private_install)
404     else:
405         support_rpath = False
406         conf.env.RPATH_ON_INSTALL = False
407         conf.env.RPATH_ON_BUILD   = False
408         conf.env.RPATH_ON_INSTALL_PRIVATE = False
409         if not conf.env.PRIVATELIBDIR:
410             # rpath is not possible so there is no sense in having a
411             # private library directory by default.
412             # the user can of course always override it.
413             conf.env.PRIVATELIBDIR = conf.env.LIBDIR
414
415     if (not Options.options.disable_symbol_versions and
416         conf.CHECK_LIBRARY_SUPPORT(rpath=support_rpath,
417                                    version_script=True,
418                                    msg='-Wl,--version-script support')):
419         conf.env.HAVE_LD_VERSION_SCRIPT = True
420     else:
421         conf.env.HAVE_LD_VERSION_SCRIPT = False
422
423     if conf.CHECK_CFLAGS(['-fvisibility=hidden']):
424         conf.env.VISIBILITY_CFLAGS = '-fvisibility=hidden'
425         conf.CHECK_CODE('''int main(void) { return 0; }
426                            __attribute__((visibility("default"))) void vis_foo2(void) {}\n''',
427                         cflags=conf.env.VISIBILITY_CFLAGS,
428                         strict=True,
429                         define='HAVE_VISIBILITY_ATTR', addmain=False)
430
431     # check HAVE_CONSTRUCTOR_ATTRIBUTE
432     conf.CHECK_CODE('''
433             void test_constructor_attribute(void) __attribute__ ((constructor));
434
435             void test_constructor_attribute(void)
436             {
437                 return;
438             }
439
440             int main(void) {
441                 return 0;
442             }
443             ''',
444             'HAVE_CONSTRUCTOR_ATTRIBUTE',
445             addmain=False,
446             strict=True,
447             msg='Checking for library constructor support')
448
449     # check HAVE_PRAGMA_INIT alternatively
450     if not conf.env.HAVE_CONSTRUCTOR_ATTRIBUTE:
451             conf.CHECK_CODE('''
452                 #pragma init (test_init)
453
454                 void test_init(void)
455                 {
456                     return;
457                 }
458
459                 int main(void) {
460                     return 0;
461                 }
462                 ''',
463                 'HAVE_PRAGMA_INIT',
464                 addmain=False,
465                 strict=True,
466                 msg='Checking for pragma init support')
467
468     # check HAVE_DESTRUCTOR_ATTRIBUTE
469     conf.CHECK_CODE('''
470             void test_destructor_attribute(void) __attribute__ ((destructor));
471
472             void test_destructor_attribute(void)
473             {
474                 return;
475             }
476
477             int main(void) {
478                 return 0;
479             }
480             ''',
481             'HAVE_DESTRUCTOR_ATTRIBUTE',
482             addmain=False,
483             strict=True,
484             msg='Checking for library destructor support')
485
486     # check HAVE_PRAGMA_FINI alternatively
487     if not conf.env.HAVE_DESTRUCTOR_ATTRIBUTE:
488             conf.CHECK_CODE('''
489                 #pragma fini (test_fini)
490
491                 void test_fini(void)
492                 {
493                     return;
494                 }
495
496                 int main(void) {
497                     return 0;
498                 }
499                 ''',
500                 'HAVE_PRAGMA_FINI',
501                 addmain=False,
502                 strict=True,
503                 msg='Checking for pragma fini support')
504
505     conf.CHECK_CODE('''
506             void test_attribute(void) __attribute__ (());
507
508             void test_attribute(void)
509             {
510                 return;
511             }
512
513             int main(void) {
514                 return 0;
515             }
516             ''',
517             'HAVE___ATTRIBUTE__',
518             addmain=False,
519             strict=True,
520             msg='Checking for __attribute__')
521
522     # Solaris by defauls uses draft versions of some functions unless you set _POSIX_PTHREAD_SEMANTICS
523     if sys.platform.startswith('sunos'):
524         conf.DEFINE('_POSIX_PTHREAD_SEMANTICS', 1)
525
526     if sys.platform.startswith('aix'):
527         conf.DEFINE('_ALL_SOURCE', 1, add_to_cflags=True)
528         # Might not be needed if ALL_SOURCE is defined
529         # conf.DEFINE('_XOPEN_SOURCE', 600, add_to_cflags=True)
530
531     # we should use the PIC options in waf instead
532     # Some compilo didn't support -fPIC but just print a warning
533     if conf.env['COMPILER_CC'] == "suncc":
534         conf.ADD_CFLAGS('-KPIC', testflags=True)
535         # we really want define here as we need to have this
536         # define even during the tests otherwise detection of
537         # boolean is broken
538         conf.DEFINE('_STDC_C99', 1, add_to_cflags=True)
539         conf.DEFINE('_XPG6', 1, add_to_cflags=True)
540     else:
541         conf.ADD_CFLAGS('-fPIC', testflags=True)
542
543     # On Solaris 8 with suncc (at least) the flags for the linker to define the name of the
544     # library are not always working (if the command line is very very long and with a lot
545     # files)
546
547     if conf.env['COMPILER_CC'] == "suncc":
548         save = conf.env['SONAME_ST']
549         conf.env['SONAME_ST'] = '-Wl,-h,%s'
550         if not conf.CHECK_SHLIB_INTRASINC_NAME_FLAGS("Checking if flags %s are ok" % conf.env['SONAME_ST']):
551             conf.env['SONAME_ST'] = save
552
553     conf.CHECK_INLINE()
554
555     # check for pkgconfig
556     conf.CHECK_CFG(atleast_pkgconfig_version='0.0.0')
557
558     conf.DEFINE('_GNU_SOURCE', 1, add_to_cflags=True)
559     conf.DEFINE('_XOPEN_SOURCE_EXTENDED', 1, add_to_cflags=True)
560
561     #
562     # Needs to be defined before std*.h and string*.h are included
563     # As Python.h already brings string.h we need it in CFLAGS.
564     # See memset_s() details here:
565     # https://en.cppreference.com/w/c/string/byte/memset
566     #
567     if conf.CHECK_CFLAGS(['-D__STDC_WANT_LIB_EXT1__=1']):
568         conf.ADD_CFLAGS('-D__STDC_WANT_LIB_EXT1__=1')
569
570     # on Tru64 certain features are only available with _OSF_SOURCE set to 1
571     # and _XOPEN_SOURCE set to 600
572     if conf.env['SYSTEM_UNAME_SYSNAME'] == 'OSF1':
573         conf.DEFINE('_OSF_SOURCE', 1, add_to_cflags=True)
574         conf.DEFINE('_XOPEN_SOURCE', 600, add_to_cflags=True)
575
576     # SCM_RIGHTS is only avail if _XOPEN_SOURCE iŃ• defined on IRIX
577     if conf.env['SYSTEM_UNAME_SYSNAME'] == 'IRIX':
578         conf.DEFINE('_XOPEN_SOURCE', 600, add_to_cflags=True)
579         conf.DEFINE('_BSD_TYPES', 1, add_to_cflags=True)
580
581     # Try to find the right extra flags for C99 initialisers
582     for f in ["", "-AC99", "-qlanglvl=extc99", "-qlanglvl=stdc99", "-c99"]:
583         if conf.CHECK_CFLAGS([f], '''
584 struct foo {int x;char y;};
585 struct foo bar = { .y = 'X', .x = 1 };
586 '''):
587             if f != "":
588                 conf.ADD_CFLAGS(f)
589             break
590
591     # get the base headers we'll use for the rest of the tests
592     conf.CHECK_HEADERS('stdio.h sys/types.h sys/stat.h stdlib.h stddef.h memory.h string.h',
593                        add_headers=True)
594     conf.CHECK_HEADERS('strings.h inttypes.h stdint.h unistd.h minix/config.h', add_headers=True)
595     conf.CHECK_HEADERS('ctype.h', add_headers=True)
596
597     if sys.platform == 'darwin':
598         conf.DEFINE('_DARWIN_C_SOURCE', 1, add_to_cflags=True)
599         conf.DEFINE('_DARWIN_UNLIMITED_GETGROUPS', 1, add_to_cflags=True)
600     else:
601         conf.CHECK_HEADERS('standards.h', add_headers=True)
602
603     conf.CHECK_HEADERS('stdbool.h stdint.h stdarg.h vararg.h', add_headers=True)
604     conf.CHECK_HEADERS('limits.h assert.h')
605
606     # see if we need special largefile flags
607     if not conf.CHECK_LARGEFILE():
608         raise Errors.WafError('Samba requires large file support support, but not available on this platform: sizeof(off_t) < 8')
609
610     if conf.env.HAVE_STDDEF_H and conf.env.HAVE_STDLIB_H:
611         conf.DEFINE('STDC_HEADERS', 1)
612
613     conf.CHECK_HEADERS('sys/time.h time.h', together=True)
614
615     if conf.env.HAVE_SYS_TIME_H and conf.env.HAVE_TIME_H:
616         conf.DEFINE('TIME_WITH_SYS_TIME', 1)
617
618     # cope with different extensions for libraries
619     (root, ext) = os.path.splitext(conf.env.cshlib_PATTERN)
620     if ext[0] == '.':
621         conf.define('SHLIBEXT', ext[1:], quote=True)
622     else:
623         conf.define('SHLIBEXT', "so", quote=True)
624
625     # First try a header check for cross-compile friendlyness
626     conf.CHECK_CODE(code = """#ifdef __BYTE_ORDER
627                         #define B __BYTE_ORDER
628                         #elif defined(BYTE_ORDER)
629                         #define B BYTE_ORDER
630                         #endif
631
632                         #ifdef __LITTLE_ENDIAN
633                         #define LITTLE __LITTLE_ENDIAN
634                         #elif defined(LITTLE_ENDIAN)
635                         #define LITTLE LITTLE_ENDIAN
636                         #endif
637
638                         #if !defined(LITTLE) || !defined(B) || LITTLE != B
639                         #error Not little endian.
640                         #endif
641                         int main(void) { return 0; }\n""",
642                             addmain=False,
643                             headers="endian.h sys/endian.h",
644                             define="HAVE_LITTLE_ENDIAN")
645     conf.CHECK_CODE(code = """#ifdef __BYTE_ORDER
646                         #define B __BYTE_ORDER
647                         #elif defined(BYTE_ORDER)
648                         #define B BYTE_ORDER
649                         #endif
650
651                         #ifdef __BIG_ENDIAN
652                         #define BIG __BIG_ENDIAN
653                         #elif defined(BIG_ENDIAN)
654                         #define BIG BIG_ENDIAN
655                         #endif
656
657                         #if !defined(BIG) || !defined(B) || BIG != B
658                         #error Not big endian.
659                         #endif
660                         int main(void) { return 0; }\n""",
661                             addmain=False,
662                             headers="endian.h sys/endian.h",
663                             define="HAVE_BIG_ENDIAN")
664
665     if not conf.CONFIG_SET("HAVE_BIG_ENDIAN") and not conf.CONFIG_SET("HAVE_LITTLE_ENDIAN"):
666         # That didn't work!  Do runtime test.
667         conf.CHECK_CODE("""union { int i; char c[sizeof(int)]; } u;
668             u.i = 0x01020304;
669             return u.c[0] == 0x04 && u.c[1] == 0x03 && u.c[2] == 0x02 && u.c[3] == 0x01 ? 0 : 1;""",
670                           addmain=True, execute=True,
671                           define='HAVE_LITTLE_ENDIAN',
672                           msg="Checking for HAVE_LITTLE_ENDIAN - runtime")
673         conf.CHECK_CODE("""union { int i; char c[sizeof(int)]; } u;
674             u.i = 0x01020304;
675             return u.c[0] == 0x01 && u.c[1] == 0x02 && u.c[2] == 0x03 && u.c[3] == 0x04 ? 0 : 1;""",
676                           addmain=True, execute=True,
677                           define='HAVE_BIG_ENDIAN',
678                           msg="Checking for HAVE_BIG_ENDIAN - runtime")
679
680     # Extra sanity check.
681     if conf.CONFIG_SET("HAVE_BIG_ENDIAN") == conf.CONFIG_SET("HAVE_LITTLE_ENDIAN"):
682         Logs.error("Failed endian determination.  The PDP-11 is back?")
683         sys.exit(1)
684     else:
685         if conf.CONFIG_SET("HAVE_BIG_ENDIAN"):
686             conf.DEFINE('WORDS_BIGENDIAN', 1)
687
688     # check if signal() takes a void function
689     if conf.CHECK_CODE('return *(signal (0, 0)) (0) == 1',
690                        define='RETSIGTYPE_INT',
691                        execute=False,
692                        headers='signal.h',
693                        msg='Checking if signal handlers return int'):
694         conf.DEFINE('RETSIGTYPE', 'int')
695     else:
696         conf.DEFINE('RETSIGTYPE', 'void')
697
698     conf.CHECK_VARIABLE('__FUNCTION__', define='HAVE_FUNCTION_MACRO')
699
700     conf.CHECK_CODE('va_list ap1,ap2; va_copy(ap1,ap2)',
701                     define="HAVE_VA_COPY",
702                     msg="Checking for va_copy")
703
704     conf.CHECK_CODE('''
705                     #define eprintf(...) fprintf(stderr, __VA_ARGS__)
706                     eprintf("bla", "bar")
707                     ''', define='HAVE__VA_ARGS__MACRO')
708
709     conf.env.enable_fuzzing = False
710
711     conf.env.enable_libfuzzer = Options.options.enable_libfuzzer
712     conf.env.enable_afl_fuzzer = Options.options.enable_afl_fuzzer
713     if conf.env.enable_libfuzzer or conf.env.enable_afl_fuzzer:
714         conf.env.enable_fuzzing = True
715         conf.DEFINE('FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION', 1)
716         conf.env.FUZZ_TARGET_LDFLAGS = Options.options.FUZZ_TARGET_LDFLAGS
717
718     # Create a symlink of the compile db for clangd
719     symlink(os.path.join(conf.bldnode.abspath(), 'default/compile_commands.json'),
720             os.path.join(conf.srcnode.abspath(), 'compile_commands.json'),
721             force=True)
722
723     conf.SAMBA_BUILD_ENV()
724
725
726 def build(bld):
727     # give a more useful message if the source directory has moved
728     curdir = bld.path.abspath()
729     srcdir = bld.srcnode.abspath()
730     relpath = os.path.relpath(curdir, srcdir)
731     if relpath.find('../') != -1:
732         Logs.error('bld.path %s is not a child of %s' % (curdir, srcdir))
733         raise Errors.WafError('''The top source directory has moved. Please run distclean and reconfigure''')
734
735     bld.SETUP_BUILD_GROUPS()
736     bld.ENFORCE_GROUP_ORDERING()
737     bld.CHECK_PROJECT_RULES()