1 # Copyright the NTPsec project contributors
3 # SPDX-License-Identifier: BSD-2-Clause
5 from __future__ import print_function
7 from datetime import datetime
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
46 "Be helpful, give a usage"
49 build Build the project
51 configure Configure the project
53 install Install the project
54 loccount Show SLOC count of the source tree
55 uninstall Uninstall the project
61 options_cmd(ctx, config)
62 ctx.load('asciidoc', tooldir='wafhelpers/')
67 ctx.load('asciidoc', tooldir='wafhelpers/')
69 class oc(Build.BuildContext):
72 def exec_command(self, cmd, **kw):
75 err, out = self.cmd_and_log(cmd, **kw)
77 self.logger.debug('WafError')
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)
86 self.logger.debug('noooo %r' % err)
93 def msg_setting(name, val):
94 pprint("NORMAL", " %-30s: " % name, sep="")
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')
105 with open("VERSION", "r") as f:
106 ntpsec_release = f.read().split(" ")[0].strip()
108 ctx.env.OPT_STORE = config["OPT_STORE"]
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]:
116 elif flag == "--define":
117 for symval in ctx.env.OPT_STORE[flag]:
118 (sym, val) = symval.split("=")
120 ctx.define(sym, int(val))
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.
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')
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,
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,
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)
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()
182 build_desc = ' ' + build_desc
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" %
206 ctx.env.NTPSEC_VERSION = "%s" % ntpsec_release
207 ctx.env.NTPSEC_VERSION_EXTENDED = ("%s%s" % (ntpsec_release,
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.
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
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.
229 # Note that _POSIX_C_SOURCE >= 199506L and _GNU_SOURCE both turn on
230 # _POSIX_PTHREAD_SEMANTICS and _REENTRANT
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
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))
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"]))
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")
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,
297 ctx.env.LDFLAGS += ["-lssp"]
299 ret = ctx.check_cc(lib="ssp_nonshared", mandatory=False,
300 comment="libssp_nonshared")
302 ctx.env.LDFLAGS += ["-lssp_nonshared"]
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'),
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'),
332 ('w_suggest_attribute_noreturn', "-Wsuggest-attribute=noreturn"),
333 ('w_write_strings', '-Wwrite-strings'),
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
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)
350 ('LTO', '-flto'), # link time optimization
352 ld_hardening_flags += [
353 ('stripall', "-Wl,--strip-all"), # Strip binaries
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
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
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"),
390 # -O1 will turn on -D_FORTIFY_SOURCE=2 for us
394 "-Wmissing-prototypes",
395 "-Wstrict-prototypes",
400 # gotta be tricky to test for -Wsuggest-attribute=const
403 int main(int argc, char **argv) {
404 (void)argc; (void)argv;
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,
418 msg='Checking if C compiler supports ' + ccflag,
421 ctx.run_build_cls = old_run_build_cls
424 ctx.env.CFLAGS = ["-fPIC"] + ctx.env.CFLAGS
427 ctx.env.LINKFLAGS_NTPD += [
430 ctx.env.CFLAGS_bin = ["-fPIE", "-pie"] + ctx.env.CFLAGS
431 ld_hardening_flags += [
432 ('relro', "-Wl,-z,relro"), # hardening, marks some read only,
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,
496 msg='Checking if linker supports ' + ldflag,
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
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
513 # "-fsanitize=cfi", # hardening
514 # "-fsanitize=safe-stack", # hardening
517 "-Wl,-z,relro", # hardening, marks some section read only,
519 # else: # gcc, probably
521 # Exclude Unity's support for printing floating point numbers
522 # since it triggers warnings
524 ctx.env.CFLAGS = ['-DUNITY_EXCLUDE_FLOAT_PRINT'] + ctx.env.CFLAGS
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
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"]
551 ctx.env.LIBPATH = ["/usr/local/ssl/lib"]
552 elif ctx.env.DEST_OS == "darwin":
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
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;
579 int main(int argc, char **argv) {
581 (void)argc; (void)argv;
582 off = (char*) &((%(type_name)s*)0)->%(field_name)s;
583 return (size_t) off < sizeof(%(type_name)s);
587 def to_header(header_name):
588 return ''.join(['#include <%s>\n' %
589 x for x in Utils.to_list(header_name)])
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),
597 for (s, h, r) in structures:
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()),
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
612 for (s, f, h) in structure_fields:
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()),
621 # mostly used by timespecops.h
623 ("time.h", "time_t"),
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,
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,
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
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],
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'])
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'])
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.
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.
716 # Some of these are cruft from ancient big-iron systems and should
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"]),
727 ("net/route.h", ["sys/types.h", "sys/socket.h", "net/if.h"]),
728 "openssl/opensslv.h", # just for wafhelper OpenSSL
731 "sys/clockctl.h", # NetBSD
733 "sys/modem.h", # Apple
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"]),
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):
747 if probe_header(ctx, hdr, prereqs):
749 if os.path.exists("/usr/include/" + hdr):
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
765 from wafhelpers.check_strerror import check_strerror
768 # Check for Solaris's service configuration facility library
769 ctx.check_cc(header_name="libscf.h", lib="scf", mandatory=False,
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
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
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 "
829 # Check for directory separator
830 if ctx.env.DEST_OS == "win32":
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',
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)
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])
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"
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")
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))
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):
949 """Run binary check, use after tests."""
950 from wafhelpers.bin_test import cmd_bin_test
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/
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:
974 __doc__ = "%s %s" % (cmd, v)
975 cmd = "%s_%s" % (cmd, v)
979 def init_handler(ctx):
981 if cmd == 'init_handler':
984 def make_context(name):
985 for x in Context.classes:
986 if x.cmd == name and x.fun != 'init_handler':
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)
994 pprint("YELLOW", "--- %sing %s ---" % (cmd, v))
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):
1015 'install uninstall build clean list step'
1017 execute = Scripting.autoconfigure(Context.Context.execute)
1021 def afterparty(ctx):
1022 # Make magic links to support in-tree testing.
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
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
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)):
1041 os.remove(path_source.abspath())
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",
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":
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')
1077 target3 = bldnode.ant_glob('*ntpc*')
1079 ctx.exec_command("rm -f %s" % _.abspath())
1080 # Finish purging ntp.ntpc
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")
1090 ctx.recurse("ntpfrob")
1091 ctx.recurse("ntptime")
1092 ctx.recurse("pylib")
1093 if ctx.env.ENABLE_ATTIC:
1094 ctx.recurse("attic")
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
1109 source=python_scripts,
1113 scripts = ["ntpclients/ntpleapfetch"] + list(python_scripts)
1118 target=[x.replace('.py', '') for x in scripts],
1120 install_path='${BINDIR}',
1123 ctx.add_post_fun(afterparty)
1124 if ctx.cmd == 'clean':
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
1152 ctx.add_post_fun(test_print_log)
1153 elif Options.options.no_tests:
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)
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
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
1190 "Report the SLOC count of the source tree."
1191 ctx.exec_command("loccount -x=build .")
1195 "Create standalone binaries from Python scripts."
1196 ctx.exec_command("for prog in " + " ".join(python_scripts) +
1197 "; do cxfreeze $prog; done")
1201 "Report references without anchors in the documentation."
1202 ctx.exec_command("devel/linkcheck docs/")
1204 # The following sets edit modes for GNU EMACS