ntplogtemp: Record nvme temperatures on Asahi
[ntpsec.git] / wscript
blob1c4118ed82156111f918c3ff5f4aa9bf52cda8cb
1 # Copyright the NTPsec project contributors
3 # SPDX-License-Identifier: BSD-2-Clause
5 from __future__ import print_function
7 from datetime import datetime
8 import itertools
9 import os
10 import shlex
11 import sys
12 import time
14 from waflib import Build
15 from waflib import Context
16 from waflib import Scripting
17 from waflib import Utils
18 from waflib.Build import (BuildContext, CleanContext, InstallContext,
19                           StepContext, ListContext)
20 from waflib.Context import BOTH
21 from waflib.Errors import WafError
22 from waflib.Logs import pprint
23 from waflib.Tools import waf_unit_test
25 # Avoid writing .pyc files in wafhelpers/
26 sys.dont_write_bytecode = True
28 from wafhelpers.options import options_cmd
29 from wafhelpers.probes import probe_header, probe_function
30 from wafhelpers.test import test_write_log, test_print_log
33 pprint.__doc__ = None
35 APPNAME = 'ntpsec'
37 out = "build"
39 config = {
40     "out": out,
41     "OPT_STORE": {}
45 def help(ctx):
46     "Be helpful, give a usage"
47     print('''
48 Usage: waf <command>
49     build       Build the project
50     check       Run tests
51     configure   Configure the project
52     dist        Create a release
53     install     Install the project
54     loccount    Show SLOC count of the source tree
55     uninstall   Uninstall the project
57 ''')
60 def options(ctx):
61     options_cmd(ctx, config)
62     ctx.load('asciidoc', tooldir='wafhelpers/')
63     ctx.recurse("pylib")
66 def configure(ctx):
67     ctx.load('asciidoc', tooldir='wafhelpers/')
69     class oc(Build.BuildContext):
70         cmd = 'oc'
72         def exec_command(self, cmd, **kw):
73             kw['output'] = BOTH
74             try:
75                 err, out = self.cmd_and_log(cmd, **kw)
76             except WafError as e:
77                 self.logger.debug('WafError')
78                 return e.returncode
79             if (len(out) and any(word in out for word
80                                  in ['err', 'err:', 'error', 'error:',
81                                      'ignored', 'illegal', 'unknown',
82                                      'unrecognized', 'warning'])):
83                 self.logger.debug('noooo %r' % out)
84                 return 1
85             if err:
86                 self.logger.debug('noooo %r' % err)
87                 return 1
88             return 0
90     def msg(str):
91         pprint("YELLOW", str)
93     def msg_setting(name, val):
94         pprint("NORMAL", "  %-30s: " % name, sep="")
95         pprint("YELLOW", val)
97     srcnode = ctx.srcnode.abspath()
98     bldnode = ctx.bldnode.abspath()
100     ctx.run_build_cls = 'check'
101     ctx.load('waf', tooldir='wafhelpers/')
102     ctx.load('waf_unit_test')
103     ctx.load('gnu_dirs')
105     with open("VERSION", "r") as f:
106         ntpsec_release = f.read().split(" ")[0].strip()
108     ctx.env.OPT_STORE = config["OPT_STORE"]
110     opt_map = {}
111     # Wipe out and override flags with those from the commandline
112     for flag in ctx.env.OPT_STORE:
113         if flag == "--undefine":
114             for sym in ctx.env.OPT_STORE[flag]:
115                 ctx.undefine(sym)
116         elif flag == "--define":
117             for symval in ctx.env.OPT_STORE[flag]:
118                 (sym, val) = symval.split("=")
119                 try:
120                     ctx.define(sym, int(val))
121                 except ValueError:
122                     ctx.define(sym, val)
123         else:
124             opt = flag.replace("--", "").upper()
125             opt_map[opt] = ctx.env.OPT_STORE[flag]
127     ctx.env['ntpc'] = ctx.options.enable_pylib
128     ctx.env['ntpcver'] = '1.1.0'
130     msg("--- Configuring host ---")
131     ctx.setenv('host', ctx.env.derive())
133     ctx.load('compiler_c')
134     ctx.start_msg('Checking compiler version')
135     ctx.end_msg("%s" % ".".join(ctx.env.CC_VERSION))
137     # Some distros do not have /sbin in the PATH for non-root users.  We honor
138     # the real PATH first, but append the sbin directories.
139     ctx.find_program(
140         "ldconfig", var="BIN_LDCONFIG", mandatory=False,
141         path_list=(os.environ.get('PATH','').split(os.pathsep) +
142             ["/sbin", "/usr/sbin", "/usr/local/sbin"]))
144     # Ensure m4 is present, or bison will fail with SIGPIPE
145     ctx.find_program('m4')
146     ctx.load('bison')
148     for opt in opt_map:
149         ctx.env[opt] = opt_map[opt]
151     # Not needed to build.  Used by utility scripts.
152     ctx.find_program("awk", var="BIN_AWK", mandatory=False)
153     ctx.find_program("sh", var="BIN_SH", mandatory=False)
155     ctx.check_cfg(
156         package='systemd', variables=['systemdsystemunitdir'],
157         uselib_store='SYSTEMD', mandatory=False,
158         msg="Checking for systemd")
159     if ctx.env.SYSTEMD_systemdsystemunitdir:
160         ctx.start_msg("systemd unit directory:")
161         ctx.end_msg(ctx.env.SYSTEMD_systemdsystemunitdir)
163     ctx.env.BIN_GIT = False
164     if os.path.exists(".git"):
165         ctx.find_program("git", var="BIN_GIT", mandatory=False)
167     build_desc = ctx.options.build_desc.strip()
168     if build_desc:
169         build_desc = ' ' + build_desc
170     if ctx.env.BIN_GIT:
171         # 'tag', '7', and 'deadbeef' are fill ins for
172         # a previous tag (always dropped), commits since that tag,
173         # the short commit hash. I can see 5 'git describe' outputs
174         # buildbots and prepush should get: tag-7-gdeadbeef
175         # working developers should get: tag-7-gdeadbeef-dirty
176         # patched shallow builders should get: gdeadbeef-dirty
177         # other shallow builder should get: gdeadbeef
178         # the thorium poisoned get errors and burst into flame
179         # 1-2 tokens gets appended verbatim
180         # 3-4 gets the first token dropped and the rest added
181         # I have never seen 5+ tokens, we should be safe
182         cmd = ctx.env.BIN_GIT + shlex.split("describe --tags --dirty --always")
183         git_short_hash = ctx.cmd_and_log(cmd).strip().split('-')
184         clip = 1 if len(git_short_hash) > 2 else 0
185         git_short_hash = '-'.join(git_short_hash[clip:])
187         ctx.env.NTPSEC_VERSION = "%s+" % ntpsec_release
188         ctx.env.NTPSEC_VERSION_EXTENDED = ("%s+%s%s" %
189                                            (ntpsec_release,
190                                             git_short_hash,
191                                             build_desc))
192     else:
193         ctx.env.NTPSEC_VERSION = "%s" % ntpsec_release
194         ctx.env.NTPSEC_VERSION_EXTENDED = ("%s%s" % (ntpsec_release,
195                                                       build_desc))
196     ctx.define("NTPSEC_VERSION", ctx.env.NTPSEC_VERSION)
197     ctx.define("NTPSEC_VERSION_EXTENDED", ctx.env.NTPSEC_VERSION_EXTENDED)
199     # We require some things that C99 doesn't enable, like pthreads.
200     # These flags get propagated to both the host and main parts of the build.
201     #
202     # _POSIX_C_SOURCE
203     #      If ==1, like _POSIX_SOURCE;
204     #      if >=2 add IEEE Std 1003.2;
205     #      if >=199309L, add IEEE Std 1003.1b-1993;
206     #      if >=199506L, add IEEE Std 1003.1c-1995;
207     #      if >=200112L, all of IEEE 1003.1-2004
208     #      if >=200809L, all of IEEE 1003.1-2008
209     #
210     # FIXME: We'd like this to be -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700
211     # rather than -D_GNU_SOURCE, but that runs into problems in two places:
212     # (1) The ISC net handling stuff, where struct in6_addr’ loses a member
213     # named s6_addr32 that the macros need, and (2) three BSD functions
214     # related to chroot jailing in the sandbox code.
215     #
216     # Note that _POSIX_C_SOURCE >= 199506L and _GNU_SOURCE both turn on
217     # _POSIX_PTHREAD_SEMANTICS and _REENTRANT
218     #
219     ctx.env.CFLAGS = ["-std=c99", "-D_GNU_SOURCE"] + ctx.env.CFLAGS
221     msg("--- Configuring main ---")
222     ctx.setenv("main", ctx.env.derive())
224     from wafhelpers.check_sizeof import check_sizeof
226     for opt in opt_map:
227         ctx.env[opt] = opt_map[opt]
229     if ctx.options.cross_compiler:
230         ctx.env.ENABLE_CROSS = True
232         ctx.start_msg("Using Cross compiler CC:")
233 #           ctx.get_cc_version(ctx.env.CC, gcc=True)
234         ctx.end_msg(ctx.options.cross_compiler)
236         ctx.env.CC = shlex.split(ctx.options.cross_compiler)
237         ctx.env.LINK_CC = shlex.split(ctx.options.cross_compiler)
239         if ctx.env["CROSS-CFLAGS"]:
240             # Lexically split each part of the CFLAGS, then chain the lists
241             iter = [shlex.split(x) for x in opt_map["CROSS-CFLAGS"]]
242             ctx.env.CFLAGS = list(itertools.chain.from_iterable(iter))
244         if ctx.env["CROSS-LDFLAGS"]:
245             # Lexically split each part of the LDFLAGS, then chain the lists
246             iter = [shlex.split(x) for x in opt_map["CROSS-LDFLAGS"]]
247             ctx.env.LDFLAGS = list(itertools.chain.from_iterable(iter))
249     if ctx.options.list:
250         from wafhelpers.refclock import refclock_map
251         print("ID    Description")
252         print("~~    ~~~~~~~~~~~")
253         for id in refclock_map:
254             print("%-5s %s" % (id, refclock_map[id]["descr"]))
256         return
258     # These are required by various refclocks
259     # needs to be tested before CFLAGS are set
260     if ctx.check_endianness() == "big":
261         ctx.define("WORDS_BIGENDIAN", 1)
263     if ctx.options.enable_leap_testing:
264         ctx.define("ENABLE_LEAP_TESTING", 1,
265                    comment="Enable leap seconds on other than 1st of month.")
267     # check for some libs first.  some options, like stack protector,
268     # may depend on some libs, like -lssp
269     ctx.check_cc(lib="m", comment="Math library")
270     ctx.check_cc(lib="rt", mandatory=False, comment="realtime library")
271     ctx.check_cc(lib="pthread", mandatory=False, comment="threads library")
272     ctx.check_cc(lib="execinfo", mandatory=False,
273                  comment="BSD backtrace library")
274     ret = ctx.check_cc(lib="bsd", mandatory=False,
275                        comment="BSD compatibility library")
276     if ret:
277         ctx.env.LDFLAGS += ["-lbsd"]
279     # -lssp and -lssp_nonshared may be needed by older gcc to
280     # support "-fstack-protector-all"
281     ret = ctx.check_cc(lib="ssp", mandatory=False,
282                        comment="libssp")
283     if ret:
284         ctx.env.LDFLAGS += ["-lssp"]
286     ret = ctx.check_cc(lib="ssp_nonshared", mandatory=False,
287                        comment="libssp_nonshared")
288     if ret:
289         ctx.env.LDFLAGS += ["-lssp_nonshared"]
291     cc_test_flags = [
292         ('PIC', '-fPIC'),
293         ('PIE', '-pie -fPIE'),
294         # this quiets most of macOS warnings on -fpie
295         ('unused', '-Qunused-arguments'),
296         # This is a useless warning on any architecture with a barrel
297         # shifter, which includes Intel and ARM and basically
298         # everything nowadays. Even so, we'd enable it out of
299         # perfectionism, but the GCC directives that ought to be
300         # useful for forcing structure alignment in order to suppress
301         # it locally don't seem to be working quite right.
302         # ('w_cast_align', "-Wcast-align"),
303         ('w_cast_qual', "-Wcast-qual"),
304         ('w_disabled_optimization', "-Wdisabled-optimization"),
305         ('w_float_equal', "-Wfloat-equal"),
306         ('w_format', '-Wformat'),
307         ('w_format_security', '-Wformat-security'),
308         # fails on OpenBSD 6
309         ('w_format_signedness', '-Wformat-signedness'),
310         ('w_implicit_function_declaration', "-Wimplicit-function-declaration"),
311         ('w_init_self', '-Winit-self'),
312         ('w_invalid_pch', '-Winvalid-pch'),
313         ('w_missing_declarations', '-Wmissing-declarations'),
314         ('w_multichar', '-Wmultichar'),
315         ('w_packed', '-Wpacked'),
316         ('w_pointer_arith', '-Wpointer-arith'),
317         ('w_shadow', '-Wshadow'),
318         # fails on clang
319         ('w_suggest_attribute_noreturn', "-Wsuggest-attribute=noreturn"),
320         ('w_write_strings', '-Wwrite-strings'),
321         ]
323     # Check which linker flags are supported
324     ld_hardening_flags = [
325         ('f_stack_protector_all', '-fstack-protector-all'),
326         ("z_now", "-Wl,-z,now"),     # no deferred symbol resolution
327     ]
329     # we prepend our options to CFLAGS, this allows user provided
330     # CFLAGS to override our computed CFLAGS
331     if not ctx.options.disable_debug_gdb:
332         ctx.env.CFLAGS = ["-g"] + ctx.env.CFLAGS
333         ctx.define("USEBACKTRACE", "1", quote=False)
334     else:
335         # not gdb debugging
336         cc_test_flags += [
337             ('LTO', '-flto'),                   # link time optimization
338             ]
339         ld_hardening_flags += [
340             ('stripall', "-Wl,--strip-all"),    # Strip binaries
341             ]
343     if ctx.options.enable_debug:
344         ctx.define("DEBUG", 1, comment="Enable debug mode")
345         ctx.env.BISONFLAGS += ["--debug"]
347     if ctx.options.enable_warnings:
348         # turn on some annoying warnings
349         ctx.env.CFLAGS = [
350             # "-Wall",                # for masochists
351             # "-Waggregate-return",   # breaks ldiv(), ntpcal_daysplit(),  etc.
352             # "-Wcast-align",         # fails on RasPi, needs fixing.
353             # "-Wbad-function-cast",  # ntpd casts long<->double a lot
354             # "-Wformat-nonliteral",  # complains about a used feature
355             "-Winline",               # some OS have inline issues.
356             # "-Wmissing-format-attribute", # false positives
357             # "-Wnested-externs",     # incompatible w/ Unity...
358             # "-Wpadded",             # duck... over 3k warnings
359             # "-Wredundant-decls",    # incompatible w/ Unity
360             "-Wswitch-default",       # warns on missing switch-default
361                                         # old Bison triggers this
362             "-Wswitch-enum",          # warns on missing enum case handler
363         ] + ctx.env.CFLAGS
364         cc_test_flags += [
365             ('w_implicit_fallthru', "-Wimplicit-fallthrough=3"),
366             # Fails on Solaris, OpenBSD 6, and RasPi
367             # Complains about a Bison bug
368             # Cannot be suppressed
369             # ('w_sign_conversion', "-Wsign-conversion"),
370             # fails on clang, lots of false positives and Unity complaints
371             # ('w_suggest_attribute_const', "-Wsuggest-attribute=const"),
372             # fails on clang, lot's of false positives and Unity complaints
373             # ('w_suggest_attribute_pure', "-Wsuggest-attribute=pure"),
374             ]
376     ctx.env.CFLAGS = [
377         # -O1 will turn on -D_FORTIFY_SOURCE=2 for us
378         "-O1",
379         "-Wall",
380         "-Wextra",
381         "-Wmissing-prototypes",
382         "-Wstrict-prototypes",
383         "-Wundef",
384         "-Wunused",
385         ] + ctx.env.CFLAGS
387     # gotta be tricky to test for -Wsuggest-attribute=const
388     FRAGMENT = '''
389 int tmp;
390 int main(int argc, char **argv) {
391         (void)argc; (void)argv;
392         tmp = argc;
393         return argc;
397     # check if C compiler supports some flags
398     old_run_build_cls = ctx.run_build_cls
399     ctx.run_build_cls = 'oc'
400     for (name, ccflag) in cc_test_flags:
401         ctx.check(cflags=ccflag,
402                   define_name='HAS_' + name,
403                   fragment=FRAGMENT,
404                   mandatory=False,
405                   msg='Checking if C compiler supports ' + ccflag,
406                   run_build_cls='oc')
408     ctx.run_build_cls = old_run_build_cls
410     if ctx.env.HAS_PIC:
411         ctx.env.CFLAGS = ["-fPIC"] + ctx.env.CFLAGS
413     if ctx.env.HAS_PIE:
414         ctx.env.LINKFLAGS_NTPD += [
415             "-pie",
416             ]
417         ctx.env.CFLAGS_bin = ["-fPIE", "-pie"] + ctx.env.CFLAGS
418         ld_hardening_flags += [
419             ('relro', "-Wl,-z,relro"),  # hardening, marks some read only,
420             ]
422     if ctx.env.HAS_unused:
423         ctx.env.CFLAGS = ['-Qunused-arguments'] + ctx.env.CFLAGS
425     # XXX: -flto currently breaks link of ntpd
426     if ctx.env.HAS_LTO and False:
427         ctx.env.CFLAGS = ["-flto"] + ctx.env.CFLAGS
429     # debug warnings that are not available with all compilers
430     if ctx.env.HAS_w_implicit_fallthru:
431         ctx.env.CFLAGS = ['-Wimplicit-fallthrough=3'] + ctx.env.CFLAGS
432     if ctx.env.HAS_w_suggest_attribute_const:
433         ctx.env.CFLAGS = ['-Wsuggest-attribute=const'] + ctx.env.CFLAGS
434     if ctx.env.HAS_w_suggest_attribute_noreturn:
435         ctx.env.CFLAGS = ['-Wsuggest-attribute=noreturn'] + ctx.env.CFLAGS
436     if ctx.env.HAS_w_suggest_attribute_pure:
437         ctx.env.CFLAGS = ['-Wsuggest-attribute=pure'] + ctx.env.CFLAGS
438     if ctx.env.HAS_w_format_security:
439         ctx.env.CFLAGS = ['-Wformat-security'] + ctx.env.CFLAGS
440     if ctx.env.HAS_w_format_signedness:
441         ctx.env.CFLAGS = ['-Wformat-signedness'] + ctx.env.CFLAGS
442     # should be before other -Wformat-* in CFLAGS
443     if ctx.env.HAS_w_format:
444         ctx.env.CFLAGS = ['-Wformat'] + ctx.env.CFLAGS
445     if ctx.env.HAS_w_float_equal:
446         ctx.env.CFLAGS = ['-Wfloat-equal'] + ctx.env.CFLAGS
447     if ctx.env.HAS_w_init_self:
448         ctx.env.CFLAGS = ['-Winit-self'] + ctx.env.CFLAGS
449     if ctx.env.HAS_w_write_strings:
450         ctx.env.CFLAGS = ['-Wwrite-strings'] + ctx.env.CFLAGS
451     if ctx.env.HAS_w_pointer_arith:
452         ctx.env.CFLAGS = ['-Wpointer-arith'] + ctx.env.CFLAGS
453     if ctx.env.HAS_w_invalid_pch:
454         ctx.env.CFLAGS = ['-Winvalid-pch'] + ctx.env.CFLAGS
455     if ctx.env.HAS_w_implicit_function_declaration:
456         ctx.env.CFLAGS = ['-Wimplicit-function-declaration'] + ctx.env.CFLAGS
457     if ctx.env.HAS_w_disabled_optimization:
458         ctx.env.CFLAGS = ['-Wdisabled-optimization'] + ctx.env.CFLAGS
459     # if ctx.env.HAS_w_cast_align:
460     #     ctx.env.CFLAGS = ['-Wcast-align'] + ctx.env.CFLAGS
461     if ctx.env.HAS_w_missing_declarations:
462         ctx.env.CFLAGS = ['-Wmissing-declarations'] + ctx.env.CFLAGS
463     if ctx.env.HAS_w_cast_qual:
464         ctx.env.CFLAGS = ['-Wcast-qual'] + ctx.env.CFLAGS
465     if ctx.env.HAS_w_packed:
466         ctx.env.CFLAGS = ['-Wpacked'] + ctx.env.CFLAGS
467     if ctx.env.HAS_w_shadow:
468         ctx.env.CFLAGS = ['-Wshadow'] + ctx.env.CFLAGS
469     # if ctx.env.HAS_w_sign_conversion:
470     #     ctx.env.CFLAGS = ['-Wsign-conversion'] + ctx.env.CFLAGS
471     if ctx.env.HAS_f_stack_protector_all:
472         ctx.env.CFLAGS = ['-fstack-protector-all'] + ctx.env.CFLAGS
474     # old gcc takes -z,relro, but then barfs if -fPIE available and used.
475     # ("relro", "-Wl,-z,relro"), # marks some sections read only
476     old_run_build_cls = ctx.run_build_cls
477     ctx.run_build_cls = 'oc'
478     for (name, ldflag) in ld_hardening_flags:
479         ctx.check(define_name='HAS_' + name,
480                   fragment=FRAGMENT,
481                   ldflags=ldflag,
482                   mandatory=False,
483                   msg='Checking if linker supports ' + ldflag,
484                   run_build_cls='oc')
485         if ctx.env['HAS_' + name]:
486             ctx.env.LDFLAGS += [ldflag]
488     ctx.run_build_cls = old_run_build_cls
490     if ctx.env.CC_NAME == "sun":
491         # we are sun, placeholder
492         ctx.env.CFLAGS += []
493     elif ctx.env.CC_NAME == "clang":
494         # used on macOS, FreeBSD,
495         # FORTIFY needs LTO to work well
496         if ctx.env.DEST_OS not in ["darwin", "freebsd"]:
497             # -flto and friends breaks tests on macOS
498             # ctx.env.CFLAGS = [
499             #    "-flto"
500             #    "-fsanitize=cfi",           # hardening
501             #    "-fsanitize=safe-stack",    # hardening
502             #    ] + ctx.env.CFLAGS
503             ctx.env.LDFLAGS += [
504                 "-Wl,-z,relro",  # hardening, marks some section read only,
505                 ]
506     # else:  # gcc, probably
508     # Exclude Unity's support for printing floating point numbers
509     # since it triggers warnings
510     # with -Wfloat-equal
511     ctx.env.CFLAGS = ['-DUNITY_EXCLUDE_FLOAT_PRINT'] + ctx.env.CFLAGS
513     # XXX: hack
514     if ctx.env.DEST_OS in ["freebsd"]:
515         ctx.env.INCLUDES = ["/usr/local/include"]
516         ctx.env.LIBPATH = ["/usr/local/lib"]
517         if os.path.isdir("/usr/local/ssl/"):
518           # This assumes OpenSSL is the only thing that was in /usr/local/
519           ctx.env.INCLUDES = ["/usr/local/ssl/include"]
520           ctx.env.LIBPATH = ["/usr/local/ssl/lib"]
521     elif ctx.env.DEST_OS == "netbsd" and os.path.isdir("/usr/pkg/include"):
522         ctx.env.INCLUDES = ["/usr/pkg/include"]
523         ctx.env.LIBPATH = ["/usr/pkg/lib"]
524         ctx.env.LDFLAGS += ["-rpath=/usr/pkg/lib"]
525         if os.path.isdir("/usr/local/ssl/"):
526           # This assumes OpenSSL is the only thing that was in /usr/pkg/
527           ctx.env.INCLUDES = ["/usr/local/ssl/include"]
528           ctx.env.LIBPATH = ["/usr/local/ssl/lib"]
529     elif ctx.env.DEST_OS == "linux" and os.path.isdir("/usr/local/ssl/"):
530         # This supports building OpenSSL from source
531         # That allows using OpenSSL 1.1.1 on older CentOS
532         # or testing pre-release versions of OpenSSL
533         # see HOWTO-OpenSSL
534         ctx.env.INCLUDES = ["/usr/local/ssl/include"]
535         if os.path.isdir("/usr/local/ssl/lib64/"):
536           ctx.env.LIBPATH = ["/usr/local/ssl/lib64"]
537         else:
538           ctx.env.LIBPATH = ["/usr/local/ssl/lib"]
539     elif ctx.env.DEST_OS == "darwin":
540         # macports location
541         if os.path.isdir("/opt/local/include"):
542             ctx.env.INCLUDES = ["/opt/local/include"]
543         if os.path.isdir("/opt/local/lib"):
544             ctx.env.LIBPATH = ["/opt/local/lib"]
545         # OS X needs this for IPv6
546         ctx.define("__APPLE_USE_RFC_3542", 1,
547                    comment="Needed for IPv6 support")
548     elif ctx.env.DEST_OS == "sunos":
549         # Declare compatibility with the POSIX.1-2001 standard, and any
550         # headers/interfaces not in conflict with that standard
551         ctx.define("_POSIX_C_SOURCE", "200112L", quote=False)
552         ctx.define("__EXTENSIONS__", "1", quote=False)
554     # Borrowed from waf-1.9, when type_name and field_name were valid keywords
555     SNIP_TYPE = '''
556     int main(int argc, char **argv) {
557         (void)argc; (void)argv;
558         if ((%(type_name)s *) 0) return 0;
559         if (sizeof (%(type_name)s)) return 0;
560         return 1;
561     }
562     '''
564     SNIP_FIELD = '''
565     #include <stddef.h>
566     int main(int argc, char **argv) {
567         char *off;
568         (void)argc; (void)argv;
569         off = (char*) &((%(type_name)s*)0)->%(field_name)s;
570         return (size_t) off < sizeof(%(type_name)s);
571     }
572     '''
574     def to_header(header_name):
575         return ''.join(['#include <%s>\n' %
576                        x for x in Utils.to_list(header_name)])
578     structures = (
579         ("struct if_laddrconf", ["sys/types.h", "net/if6.h"], False),
580         ("struct if_laddrreq", ["sys/types.h", "net/if6.h"], False),
581         ("struct timex", ["sys/time.h", "sys/timex.h"], True),
582         ("struct ntptimeval", ["sys/time.h", "sys/timex.h"], False),
583     )
584     for (s, h, r) in structures:
585         ctx.check_cc(
586             fragment=to_header(h) + SNIP_TYPE % {'type_name': s},
587             msg='Checking for type %s' % s,
588             define_name=ctx.have_define(s.upper()),
589             mandatory=r,
590         )
592     structure_fields = (
593         ("struct timex", "time_tick", ["sys/time.h", "sys/timex.h"]),
594         ("struct timex", "modes", ["sys/time.h", "sys/timex.h"]),
595         ("struct ntptimeval", "time.tv_nsec", ["sys/time.h", "sys/timex.h"]),
596         ("struct ntptimeval", "tai", ["sys/time.h", "sys/timex.h"]),
597         # first in glibc 2.12
598     )
599     for (s, f, h) in structure_fields:
600         ctx.check_cc(
601             fragment=(to_header(h) + SNIP_FIELD %
602                       {'type_name': s, 'field_name': f}),
603             msg='Checking for field %s in %s' % (f, s),
604             define_name=ctx.have_define((s + '_' + f).upper()),
605             mandatory=False,
606         )
608     # mostly used by timespecops.h
609     sizeofs = [
610         ("time.h",      "time_t"),
611         (None,          "long"),
612     ]
614     for header, sizeof in sorted(sizeofs, key=lambda x: x[1:]):
615         check_sizeof(ctx, header, sizeof)
617     # Parts of attic need libssl
618     if not ctx.options.disable_nts or ctx.options.enable_attic:
619         # Check via pkg-config first, then fall back to a direct search
620         if not ctx.check_cfg(
621             package='libssl', uselib_store='SSL',
622             args=['--cflags', '--libs'],
623             msg="Checking for OpenSSL/libssl (via pkg-config)",
624             define_name='', mandatory=False,
625         ):
626             ctx.check_cc(msg="Checking for OpenSSL's ssl library",
627                          lib="ssl", mandatory=True)
629     # Check via pkg-config first, then fall back to a direct search
630     if not ctx.check_cfg(
631         package='libcrypto', uselib_store='CRYPTO',
632         args=['--cflags', '--libs'],
633         msg="Checking for OpenSSL/libcrypto (via pkg-config)",
634         define_name='', mandatory=False,
635     ):
636         ctx.check_cc(msg="Checking for OpenSSL's crypto library",
637                      lib="crypto", mandatory=True)
639     # Optional functions.  Do all function checks here, otherwise
640     # we're likely to duplicate them.
641     optional_functions = (
642         ('_Unwind_Backtrace', ["unwind.h"]),
643         ('adjtimex', ["sys/time.h", "sys/timex.h"]),
644         ('backtrace_symbols_fd', ["execinfo.h"]),
645         ('ntp_adjtime', ["sys/time.h", "sys/timex.h"]),     # BSD
646         ('ntp_gettime', ["sys/time.h", "sys/timex.h"]),     # BSD
647         ('res_init', ["netinet/in.h", "arpa/nameser.h", "resolv.h"]),
648         ('strlcpy', ["string.h"]),
649         ('strlcat', ["string.h"]),
650         ('timegm', ["time.h"]),
651         # Hack.  It's not a function, but this works.
652         ('PRIV_NTP_ADJTIME', ["sys/priv.h"])            # FreeBSD
653     )
654     for ft in optional_functions:
655         probe_function(ctx, function=ft[0], prerequisites=ft[1])
657     # This area is still work in progress
658     # Need to disable making symbols
659     #   but not until killing off HAVE_TIMER_CREATE
661     # Sanity checks to give a sensible error message
662     required_functions = (
663         # Check for ancient version of OpenSSL.
664         ('EVP_MD_CTX_new', ["openssl/evp.h"], "CRYPTO", False),
665         # MacOS doesn't have timer_create ??
666         ('timer_create', ["signal.h", "time.h"], "RT", False),
667         # Very old versions of OpenSSL don't have cmac.h
668         #  We could add ifdefs, but old crypto is deprecated in favor of CMAC
669         #  and so far, all the systems that we want to support are new enough.
670         ('CMAC_CTX_new', ["openssl/cmac.h"], "CRYPTO", True),
671         # Next should be above, but it needs a library
672         # EVP_PKEY_new_CMAC_key added in OpenSSL 1.1.1
673         ('EVP_PKEY_new_CMAC_key', ["openssl/cmac.h"], "CRYPTO", False))
674     for ft in required_functions:
675         probe_function(ctx, function=ft[0],
676                        prerequisites=ft[1], use=ft[2],
677                        mandatory=ft[3])
679     # check for BSD versions outside of libc
680     if not ctx.get_define("HAVE_STRLCAT"):
681         ret = probe_function(ctx, function='strlcat',
682                              prerequisites=['bsd/string.h'])
683         if ret:
684             ctx.define("HAVE_STRLCAT", 1, comment="Using bsd/strlcat")
686     if not ctx.get_define("HAVE_STRLCPY"):
687         ret = probe_function(ctx, function='strlcpy',
688                              prerequisites=['bsd/string.h'])
689         if ret:
690             ctx.define("HAVE_STRLCPY", 1, comment="Using bsd/strlcpy")
692     # Nobody uses the symbol, but this seems like a good sanity check.
693     ctx.check_cc(header_name="stdbool.h", mandatory=True,
694                  comment="Sanity check.")
696     # This is a list of every optional include header in the
697     # codebase that is guarded by a directly corresponding HAVE_*_H symbol.
698     #
699     # In some cases one HAVE symbol controls inclusion of more
700     # than one header.  In these cases only the one header name
701     # matching the pattern of the HAVE_*_H symbol name is listed
702     # here, so we can invert the relationship to generate tests
703     # for all the symbols.
704     #
705     # Some of these are cruft from ancient big-iron systems and should
706     # be removed.
707     optional_headers = (
708         "alloca.h",
709         ("arpa/nameser.h", ["sys/types.h"]),
710         "bsd/string.h",     # bsd emulation
711         ("ifaddrs.h", ["sys/types.h"]),
712         ("linux/if_addr.h", ["sys/socket.h"]),
713         ("linux/rtnetlink.h", ["sys/socket.h"]),
714         "linux/serial.h",
715         "net/if6.h",
716         ("net/route.h", ["sys/types.h", "sys/socket.h", "net/if.h"]),
717         "openssl/opensslv.h",  # just for wafhelper OpenSSL 
718         "priv.h",           # Solaris
719         "stdatomic.h",
720         "sys/clockctl.h",   # NetBSD
721         "sys/ioctl.h",
722         "sys/modem.h",      # Apple
723         "sys/sockio.h",
724         ("sys/sysctl.h", ["sys/types.h"]),
725         ("timepps.h", ["inttypes.h"]),
726         ("sys/timepps.h", ["inttypes.h", "sys/time.h"]),
727         ("sys/timex.h", ["sys/time.h"]),
728     )
729     for hdr in optional_headers:
730         if isinstance(hdr, str):
731             if ctx.check_cc(header_name=hdr, mandatory=False,
732                             comment="<%s> header" % hdr):
733                 continue
734         else:
735             (hdr, prereqs) = hdr
736             if probe_header(ctx, hdr, prereqs):
737                 continue
738         if os.path.exists("/usr/include/" + hdr):
739             # Sanity check...
740             print("Compilation check failed but include exists %s" % hdr)
742     if ((ctx.get_define("HAVE_TIMEPPS_H") or
743             ctx.get_define("HAVE_SYS_TIMEPPS_H"))):
744         ctx.define("HAVE_PPSAPI", 1, comment="Enable the PPS API")
746     # Check for Solaris capabilities
747     if ctx.get_define("HAVE_PRIV_H") and ctx.env.DEST_OS == "sunos":
748         ctx.define("HAVE_SOLARIS_PRIVS", 1,
749                    comment="Enable Solaris Privileges (Solaris only)")
751     from wafhelpers.check_sockaddr import check_sockaddr
752     check_sockaddr(ctx)
754     from wafhelpers.check_strerror import check_strerror
755     check_strerror(ctx)
757     # Check for Solaris's service configuration facility library
758     ctx.check_cc(header_name="libscf.h", lib="scf", mandatory=False,
759                  uselib_store="SCF")
761     # Some systems don't have sys/timex.h eg OS X, OpenBSD...
762     if ctx.get_define("HAVE_SYS_TIMEX_H"):
763         ctx.env.HEADER_SYS_TIMEX_H = True
765     if ctx.options.refclocks:
766         from wafhelpers.refclock import refclock_config
767         refclock_config(ctx)
768         # timegm needed by refclock_nmea, it's not in POSIX
769         # It's in Linux, FreeBSD, and NetBSD
770         if not ctx.get_define("HAVE_TIMEGM") and ctx.get_define("CLOCK_NMEA"):
771             ctx.fatal("Refclock NMEA needs timegm")
772             # We should provide an implementation.
773             # Like we do for BSD string functions.
775     # NetBSD (used to) need to recreate sockets on changed routing.
776     # Perhaps it still does. If so, this should be set.  The autoconf
777     # build set it "if the OS clears cached routes when more specifics
778     # become available".
779     # ctx.define("OS_MISSES_SPECIFIC_ROUTE_UPDATES", 1)
781     if ctx.options.enable_leap_smear:
782         ctx.define("ENABLE_LEAP_SMEAR", 1,
783                    comment="Enable experimental leap smearing code")
785     if ctx.options.enable_mssntp:
786         ctx.define("ENABLE_MSSNTP", 1,
787                    comment="Enable MS-SNTP extensions "
788                    " https://msdn.microsoft.com/en-us/library/cc212930.aspx")
790     if ctx.options.enable_attic:
791         ctx.env.ENABLE_ATTIC = True
793     if ctx.options.disable_nts:
794         ctx.env.DISABLE_NTS = True
795         ctx.define("DISABLE_NTS", 1,
796                    comment="Disable NTS")
798     if not ctx.options.disable_droproot:
799         ctx.define("ENABLE_DROPROOT", 1,
800                    comment="Drop root after initialising")
801     if ctx.options.enable_early_droproot:
802         ctx.define("ENABLE_EARLY_DROPROOT", 1,
803                    comment="Enable early drop root")
804     if ctx.options.disable_fuzz:
805         pprint("YELLOW", "--disable-fuzz is now standard.  Clock fuzzing is gone.")
807     # SO_REUSEADDR socket option is needed to open a socket on an
808     # interface when the port number is already in use on another
809     # interface. Linux needs this, NetBSD does not, status on
810     # other platforms is unknown.  It is probably harmless to
811     # have it on everywhere.
812     ctx.define("NEED_REUSEADDR_FOR_IFADDRBIND", 1,
813                comment="Whether SO_REUSEADDR is needed to open "
814                "same sockets on alternate interfaces, required "
815                "by Linux at least")
817     # Check for directory separator
818     if ctx.env.DEST_OS == "win32":
819         sep = "\\"
820     else:
821         sep = "/"
823     ctx.define("DIR_SEP", "'%s'" % sep, quote=False,
824                comment="Directory separator used")
826     if ctx.get_define("HAVE_SYS_SYSCTL_H"):
827         ctx.define("HAVE_IFLIST_SYSCTL", 1,
828                    comment="Whether sysctl interface exists")
830     # Header/library checks
832     if not ctx.options.disable_droproot and ctx.env.DEST_OS == "linux":
833         ctx.check_cc(header_name="sys/prctl.h", mandatory=False)
834         ctx.check_cc(header_name="sys/capability.h", mandatory=False)
835         ctx.check_cc(lib="cap", comment="Capability library", mandatory=False)
837         if ((ctx.get_define("HAVE_SYS_CAPABILITY_H") and
838                 ctx.get_define("HAVE_SYS_PRCTL_H") and ctx.env.LIB_CAP)):
839             ctx.define("HAVE_LINUX_CAPABILITY", 1)
841     if ctx.options.enable_seccomp:
842         if ctx.env.DEST_OS != "linux":
843             ctx.fatal("seccomp is only supported on Linux")
845         # Check via pkg-config first, then fall back to a direct search
846         if not ctx.check_cfg(
847             package='libseccomp', args=['--libs', '--cflags'],
848             uselib_store='SECCOMP', define_name='HAVE_SECCOMP_H',
849             mandatory=False
850         ):
851             ctx.check_cc(header_name="seccomp.h")
852             ctx.check_cc(lib="seccomp")
854     if not ctx.options.disable_mdns_registration:
855         ctx.check_cc(header_name="dns_sd.h", lib="dns_sd", mandatory=False,
856                      uselib_store="DNS_SD")
858     # Solaris needs -lsocket and -lnsl for socket code
859     if ctx.env.DEST_OS == "sunos":
860         ctx.check(features="c cshlib", lib="socket", mandatory=False)
861         ctx.check(features="c cshlib", lib="nsl", mandatory=False)
863     if ctx.options.enable_classic_mode:
864         ctx.define("ENABLE_CLASSIC_MODE", 1)
865     else:
866         ctx.undefine("ENABLE_CLASSIC_MODE")
868     # Ugly hack to examine config symbols
869     for sym in ctx.env.DEFINES:
870         if sym.startswith("NTP_SIZEOF_TIME_T="):
871             timesize = int(sym.split("=")[1])
872             if timesize < 8:
873                 msg("WARNING: This system has a 32-bit time_t.")
874                 msg("WARNING: Your ntpd will fail on 2038-01-19T03:14:07Z.")
876     if not ctx.env.DISABLE_NTS:
877         from wafhelpers.openssl import check_libssl_tls13
878         from wafhelpers.openssl import check_openssl_bad_version
879         from wafhelpers.openssl import dump_openssl_version
880         check_libssl_tls13(ctx)
881         check_openssl_bad_version(ctx)
882         dump_openssl_version(ctx)
884     # before write_config()
885     if ctx.is_defined("HAVE_LINUX_CAPABILITY"):
886         droproot_type = "Linux"
887     elif ctx.is_defined("HAVE_SOLARIS_PRIVS"):
888         droproot_type = "Solaris"
889     elif ctx.is_defined("HAVE_SYS_CLOCKCTL_H"):
890         droproot_type = "NetBSD"
891     elif ctx.is_defined("HAVE_PRIV_NTP_ADJTIME"):
892         droproot_type = "FreeBSD"
893     else:
894         droproot_type = "None"
896     # write_config() removes symbols
897     ctx.start_msg("Writing configuration header:")
898     ctx.write_config_header("config.h")
899     ctx.end_msg("config.h", "PINK")
901     def yesno(x):
902         if x:
903             return "Yes"
904         return "No"
906     msg("")
907     msg("Build Options")
908     msg_setting("CC", " ".join(ctx.env.CC))
909     msg_setting("CFLAGS", " ".join(ctx.env.CFLAGS))
910     msg_setting("LDFLAGS", " ".join(ctx.env.LDFLAGS))
911     msg_setting("LINKFLAGS_NTPD", " ".join(ctx.env.LINKFLAGS_NTPD))
912     msg_setting("PREFIX", ctx.env.PREFIX)
913     msg_setting("LIBDIR", ctx.env.LIBDIR)
914     msg_setting("Droproot Support", droproot_type)
915     msg_setting("Debug Support", yesno(ctx.options.enable_debug))
916     msg_setting("Refclocks", ", ".join(sorted(ctx.env.REFCLOCK_LIST)))
917     msg_setting("Build Docs", yesno(ctx.env.BUILD_DOC))
918     msg_setting("Build Manpages", yesno(ctx.env.BUILD_MAN))
920     ctx.recurse("pylib")
921     ctx.env.PYSHEBANG = ctx.options.pyshebang
922     msg_setting("PYSHEBANG", ctx.env.PYSHEBANG)
923     # Convert the Python directories to absolute paths.
924     # This makes them behave the same as PREFIX.
925     ctx.env.PYTHONDIR = os.path.abspath(ctx.env.PYTHONDIR)
926     ctx.env.PYTHONARCHDIR = os.path.abspath(ctx.env.PYTHONARCHDIR)
927     msg_setting("PYTHONDIR", ctx.env.PYTHONDIR)
928     msg_setting("PYTHONARCHDIR", ctx.env.PYTHONARCHDIR)
931 class check(BuildContext):
932     cmd = 'check'
933     variant = "main"
936 def bin_test(ctx):
937     """Run binary check, use after tests."""
938     from wafhelpers.bin_test import cmd_bin_test
939     cmd_bin_test(ctx)
942 def bin_test_summary(ctx):
943     """Display results of binary check, use after tests."""
944     from wafhelpers.bin_test import bin_test_summary
945     bin_test_summary(ctx)
948 variant_cmd = (
949     ("build", BuildContext),
950     ("clean", CleanContext),
951     ("install", InstallContext),
952     ("step", StepContext),
953     ("list", ListContext),
954     # ("check", BuildContext)
957 for v in ["host", "main"]:
958     # the reason for creating these subclasses is just for __doc__ below...
959     for cmd, cls in variant_cmd:
960         class tmp(cls):
961             __doc__ = "%s %s" % (cmd, v)
962             cmd = "%s_%s" % (cmd, v)
963             variant = v
966 def init_handler(ctx):
967     cmd = ctx.cmd
968     if cmd == 'init_handler':
969         cmd = 'build'
971     def make_context(name):
972         for x in Context.classes:
973             if x.cmd == name and x.fun != 'init_handler':
974                 return x()
975         ctx.fatal('No class for %r' % cmd)
977     # By default we want to iterate over each variant.
978     for v in ["host", "main"]:
979         obj = make_context(cmd)
980         obj.variant = v
981         pprint("YELLOW", "--- %sing %s ---" % (cmd, v))
982         obj.execute()
985 commands = (
986     ("install", "init_handler", None),
987     ("uninstall", "init_handler", None),
988     ("build", "init_handler", None),
989     ("clean", "init_handler", None),
990     ("list", "init_handler", None),
991     ("step", "init_handler", None),
995 for command, func, descr in commands:
996     class tmp1(Context.Context):
997         if descr:
998             __doc__ = descr
999         cmd = command
1000         fun = func
1001         if ((command in
1002             'install uninstall build clean list step'
1003              )):
1004             execute = Scripting.autoconfigure(Context.Context.execute)
1005 # end borrowed code
1008 def afterparty(ctx):
1009     # Make magic links to support in-tree testing.
1010     #
1011     # The idea is that all directories where the Python tools live should
1012     # have an 'ntp' symlink so they can import Python modules from the pylib
1013     # directory.
1014     #
1015     # Note that this setup is applied to the build tree, not the
1016     # source tree.  Only the build-tree copies of the programs are
1017     # expected to work.
1018     for x in ("ntpclients", "tests/pylib",):
1019         # List used to be longer...
1020         path_build = ctx.bldnode.make_node("pylib")
1021         path_source = ctx.bldnode.make_node(x + "/ntp")
1022         relpath = (("../" * (x.count("/")+1)) +
1023                    path_build.path_from(ctx.bldnode))
1024         if ctx.cmd in ('install', 'build'):
1025             if ((not path_source.exists() or
1026                     os.readlink(path_source.abspath()) != relpath)):
1027                 try:
1028                     os.remove(path_source.abspath())
1029                 except OSError:
1030                     pass
1031                 os.symlink(relpath, path_source.abspath())
1034 python_scripts = set([
1035     "ntpclients/ntpdig.py",
1036     "ntpclients/ntpkeygen.py",
1037     "ntpclients/ntpq.py",
1038     "ntpclients/ntpsweep.py",
1039     "ntpclients/ntptrace.py",
1040     "ntpclients/ntpwait.py",
1041     "ntpclients/ntpsnmpd.py",
1045 def build(ctx):
1046     from waflib.Logs import verbose
1047     ctx.load('waf', tooldir='wafhelpers/')
1048     ctx.load('asciidoc', tooldir='wafhelpers/')
1050     if ctx.variant == "host":
1051         ctx.recurse("ntpd")
1052         return
1054     if ctx.cmd == "build":
1055         # It's a waf gotcha that if there are object files (including
1056         # .pyc and .pyo files) in a source directory, compilation to
1057         # the build directory never happens.  This is how we foil that.
1058         ctx.add_pre_fun(lambda ctx: ctx.exec_command("rm -f pylib/*.py[co]"))
1059         # Start purging ntp.ntpc files from build dir
1060         # so old extension won't clobber FFI or reverse
1061         bldnode = ctx.bldnode.make_node('pylib')
1062         bldnode.mkdir()
1063         target3 = bldnode.ant_glob('*ntpc*')
1064         for _ in target3:
1065             ctx.exec_command("rm -f %s" % _.abspath())
1066         # Finish purging ntp.ntpc
1067         ctx.add_group()
1069     if ctx.env.REFCLOCK_GENERIC or ctx.env.REFCLOCK_TRIMBLE:
1070         # required by the generic and Trimble refclocks
1071         ctx.recurse("libparse")
1072     ctx.recurse("libntp")
1073     if not ctx.env.DISABLE_NTS:
1074       ctx.recurse("libaes_siv")
1075     ctx.recurse("ntpd")
1076     ctx.recurse("ntpfrob")
1077     ctx.recurse("ntptime")
1078     ctx.recurse("pylib")
1079     if ctx.env.ENABLE_ATTIC:
1080       ctx.recurse("attic")
1081     ctx.recurse("etc")
1082     ctx.recurse("tests")
1084     if ctx.env['PYTHON_ARGPARSE']:
1085         python_scripts.add("ntpclients/ntplogtemp.py")
1086         python_scripts.add("ntpclients/ntpviz.py")
1087     if ctx.env['PYTHON_ARGPARSE'] and ctx.env['PYTHON_GPS']:
1088         python_scripts.add("ntpclients/ntploggps.py")
1089     if ctx.env['PYTHON_CURSES']:
1090         python_scripts.add("ntpclients/ntpmon.py")
1092     # Make sure the python scripts compile, but don't install them
1093     ctx(
1094         features="py",
1095         source=python_scripts,
1096         install_path=None,
1097     )
1099     scripts = ["ntpclients/ntpleapfetch"] + list(python_scripts)
1101     ctx(
1102         features="subst",
1103         source=scripts,
1104         target=[x.replace('.py', '') for x in scripts],
1105         chmod=Utils.O755,
1106         install_path='${BINDIR}',
1107     )
1109     ctx.add_post_fun(afterparty)
1110     if ctx.cmd == 'clean':
1111         afterparty(ctx)
1113     if ctx.env['PYTHON_ARGPARSE']:
1114         ctx.manpage(1, "ntpclients/ntplogtemp-man.adoc")
1115         ctx.manpage(1, "ntpclients/ntpviz-man.adoc")
1116     if ctx.env['PYTHON_ARGPARSE'] and ctx.env['PYTHON_GPS']:
1117         ctx.manpage(1, "ntpclients/ntploggps-man.adoc")
1118     if ctx.env['PYTHON_CURSES']:
1119         ctx.manpage(1, "ntpclients/ntpmon-man.adoc")
1120     ctx.manpage(1, "ntpclients/ntpdig-man.adoc")
1121     ctx.manpage(1, "ntpclients/ntpq-man.adoc")
1122     ctx.manpage(1, "ntpclients/ntpsweep-man.adoc")
1123     ctx.manpage(1, "ntpclients/ntptrace-man.adoc")
1124     ctx.manpage(8, "ntpclients/ntpkeygen-man.adoc")
1125     ctx.manpage(8, "ntpclients/ntpleapfetch-man.adoc")
1126     ctx.manpage(8, "ntpclients/ntpwait-man.adoc")
1127     ctx.manpage(8, "ntpclients/ntpsnmpd-man.adoc")
1129     # Skip running unit tests on a cross compile build
1130     from waflib import Options
1131     if not ctx.env.ENABLE_CROSS:
1132         # Force re-running of tests.  Same as 'waf --alltests'
1133         if ctx.cmd == "check":
1134             ctx.options.all_tests = True
1136             # Print log if -v is supplied
1137             if verbose > 0:
1138                 ctx.add_post_fun(test_print_log)
1139         elif Options.options.no_tests:
1140             return
1142         # Test binaries
1143         ctx.add_post_fun(bin_test)
1145         # Write test log to a file
1146         ctx.add_post_fun(test_write_log)
1148         # Print a summary at the end
1149         ctx.add_post_fun(waf_unit_test.summary)
1150         ctx.add_post_fun(waf_unit_test.set_exit_code)
1151         ctx.add_post_fun(bin_test_summary)
1152     else:
1153         pprint("YELLOW", "Unit test runner skipped on a cross-compiled build.")
1154         Options.options.no_tests = True
1156     if ctx.cmd == "build":
1157         if "PYTHONPATH" not in os.environ:
1158             print("--- PYTHONPATH is not set, "
1159                   "loading the Python ntp library may be troublesome ---")
1160         elif ctx.env.PYTHONARCHDIR not in os.environ["PYTHONPATH"]:
1161             print("--- PYTHONARCHDIR not in PYTHONPATH, "
1162                   "loading the Python ntp library may be troublesome ---")
1165 # Miscellaneous utility productions
1169 def ifdex(ctx):
1170     "Get a report on configuration symbols not accounted for."
1171     ctx.exec_command("ifdex -X build/config.h -X devel/ifdex-ignores .")
1174 # See https://gitlab.com/esr/loccount
1175 def loccount(ctx):
1176     "Report the SLOC count of the source tree."
1177     ctx.exec_command("loccount -x=build .")
1180 def cxfreeze(ctx):
1181     "Create standalone binaries from Python scripts."
1182     ctx.exec_command("for prog in " + " ".join(python_scripts) +
1183                      "; do cxfreeze $prog; done")
1186 def linkcheck(ctx):
1187     "Report references without anchors in the documentation."
1188     ctx.exec_command("devel/linkcheck docs/")
1190 # The following sets edit modes for GNU EMACS
1191 # Local Variables:
1192 # mode:python
1193 # End:
1194 # end