From b3c52b2fcb0153eb13269f0fe8110ef4d595bc3f Mon Sep 17 00:00:00 2001 From: Peter Barker Date: Fri, 11 Sep 2026 16:21:16 +1000 Subject: [PATCH] waf: apply coverage flags after the configure checks have run The coverage flags were added in configure_env, so every probe program built by cfg.check() was compiled with -fprofile-arcs and linked with -lgcov. On boards which also link with -Wl,--wrap,malloc (SITL, Linux, QURT) libgcov's malloc call is rewritten to __wrap_malloc, which the probe does not define, so the probe fails to link and the feature under test is silently recorded as absent. Under --coverage every header check ("endian.h", "byteswap.h", the cmath checks, memrchr) reported "not found"; HAVE_BYTESWAP_H was never defined and the fallback in AP_Common/missing/byteswap.h was compiled instead. That fallback collides with glibc's own __bswap_16/32/64 as soon as a translation unit also includes netinet/in.h, which broke build.unit_tests in the weekly coverage workflow. Move the flags into Board.configure_coverage() and call it from the top-level configure once the checks are done, so the probes are never instrumented and the coverage configuration produces the same ap_config.h as a normal one. Co-authored-by: Pierre Kancir --- Tools/ardupilotwaf/boards.py | 35 ++++++++++++++++++----------------- wscript | 1 + 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/Tools/ardupilotwaf/boards.py b/Tools/ardupilotwaf/boards.py index 7ef8e1e51e4..25d7b020767 100644 --- a/Tools/ardupilotwaf/boards.py +++ b/Tools/ardupilotwaf/boards.py @@ -248,6 +248,24 @@ class Board: return (int(major) < want_major or (int(major) == want_major and int(minor) <= want_minor)) + def configure_coverage(self, cfg): + """Apply the coverage flags. + + Called after the configure checks have run, rather than from + configure_env: cfg.check() links small probe programs, and + instrumenting those drags in libgcov, whose malloc call + -Wl,--wrap,malloc rewrites into an undefined __wrap_malloc. The + probe then fails to link and waf records the feature it was + probing for as missing. + """ + if not cfg.env.COVERAGE: + return + cfg.env.CFLAGS += ['-fprofile-arcs', '-ftest-coverage'] + cfg.env.CXXFLAGS += ['-fprofile-arcs', '-ftest-coverage'] + cfg.env.LINKFLAGS += ['-lgcov', '-coverage'] + # cfg.env is post-merge, where DEFINES is a list of NAME=value + cfg.env.DEFINES += ['HAL_COVERAGE_BUILD=1'] + def configure_env(self, cfg, env): # Use a dictionary instead of the conventional list for definitions to # make easy to override them. Convert back to list before consumption. @@ -342,23 +360,6 @@ class Board: env.CFLAGS += [ '-g', ] - if cfg.env.COVERAGE: - env.CFLAGS += [ - '-fprofile-arcs', - '-ftest-coverage', - ] - env.CXXFLAGS += [ - '-fprofile-arcs', - '-ftest-coverage', - ] - env.LINKFLAGS += [ - '-lgcov', - '-coverage', - ] - env.DEFINES.update( - HAL_COVERAGE_BUILD = 1, - ) - if cfg.options.bootloader: # don't let bootloaders try and pull scripting in cfg.options.disable_scripting = True diff --git a/wscript b/wscript index fdefe1073b2..f4201de9eef 100644 --- a/wscript +++ b/wscript @@ -628,6 +628,7 @@ def configure(cfg): else: cfg.end_msg('disabled', color='YELLOW') + cfg.get_board().configure_coverage(cfg) cfg.start_msg('Coverage build') if cfg.env.COVERAGE: cfg.end_msg('enabled')