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