diff --git a/.github/configs/smoke-test.json b/.github/configs/smoke-test.json index c60e9bc32cd..06eccfc031a 100644 --- a/.github/configs/smoke-test.json +++ b/.github/configs/smoke-test.json @@ -6,11 +6,14 @@ "cflags": "-DWOLFSSL_NO_REALLOC -fsanitize=address -fno-omit-frame-pointer -g -O1", "ldflags": "-fsanitize=address"}, {"name": "enable-all-smallstack", "configure": ["--enable-all", "--enable-smallstack"]}, - {"name": "enable-all", "configure": ["--enable-all"]}, + {"name": "enable-all", "configure": ["--enable-all"], + "cflags": "-Werror -Wdeclaration-after-statement -pedantic"}, {"name": "integration", "configure": ["--enable-openssh", "--enable-lighty", "--enable-stunnel", "--enable-opensslextra"]}, {"name": "dtls-suite", "configure": ["--enable-psk", "--enable-dtls", "--enable-dtls13", "--enable-dtls-mtu", "--enable-aesccm", "--enable-opensslextra"]}, {"name": "opensslextra", "configure": ["--enable-opensslextra"]}, {"name": "default"}, {"name": "cryptonly", "configure": ["--enable-cryptonly"]}, - {"name": "leantls-extra", "configure": ["--enable-leantls", "--enable-session-ticket", "--enable-sni", "--enable-opensslextra"]} + {"name": "leantls-extra", "configure": ["--enable-leantls", "--enable-session-ticket", "--enable-sni", "--enable-opensslextra"]}, + {"name": "all-Og", "configure": ["--enable-all"], "cflags": "-Werror -Wdeclaration-after-statement -Og", "check": false}, + {"name": "savesession", "configure": ["--enable-savesession"], "check": false} ] diff --git a/.github/scripts/parallel-make-check.py b/.github/scripts/parallel-make-check.py index 326378175ab..a1b13e279f3 100755 --- a/.github/scripts/parallel-make-check.py +++ b/.github/scripts/parallel-make-check.py @@ -14,7 +14,8 @@ # configure list of extra ./configure arguments # cc compiler passed to configure as CC=, overriding --cc # ("" leaves CC entirely to configure / the environment) -# cflags CFLAGS for make, overriding --cflags +# cflags CFLAGS for make, overriding --cflags (with --append-flags, +# appended to the CFLAGS configure chose instead) # ldflags LDFLAGS for make, overriding --ldflags # minutes expected duration, from the Minutes column of a previous # run's summary (default 1.0). Schedule weight only - configs @@ -92,6 +93,7 @@ import argparse import json import os +import re import shutil import signal import subprocess @@ -379,6 +381,18 @@ def warn(msg: str) -> None: else f"WARNING: {msg}") +def configured_flags(bdir: Path) -> dict[str, str]: + # The CFLAGS and LDFLAGS configure settled on, from the build dir's + # Makefile (automake writes them as plain "VAR = value" lines). + found = {"CFLAGS": "", "LDFLAGS": ""} + with open(bdir / "Makefile") as mf: + for line in mf: + m = re.match(r"(CFLAGS|LDFLAGS) = (.*)$", line) + if m: + found[m.group(1)] = m.group(2).strip() + return found + + def stale_estimate(cfg: Config, minutes: float) -> bool: # "minutes" is only a scheduling estimate (configs run longest-first; # --shard balances by it), never a pass/fail bound. Flag a finished @@ -401,8 +415,18 @@ def run_config(cfg: Config, opts: argparse.Namespace) -> tuple[str | None, configure = [str(SRCDIR / "configure")] + cfg.configure if cfg.cc: configure.append(f"CC={cfg.cc}") - flags = [f"CFLAGS={cfg.cflags}"] if cfg.cflags else [] - flags += [f"LDFLAGS={cfg.ldflags}"] if cfg.ldflags else [] + def flag_args() -> list[str]: + # Resolved per make command, not once up front: with --append-flags + # the configure-chosen values are only known after the configure + # step has written the build dir's Makefile. + cflags, ldflags = cfg.cflags, cfg.ldflags + if opts.append_flags: + chosen = configured_flags(bdir) + cflags = f"{chosen['CFLAGS']} {cflags}".strip() + ldflags = f"{chosen['LDFLAGS']} {ldflags}".strip() + flags = [f"CFLAGS={cflags}"] if cflags else [] + flags += [f"LDFLAGS={ldflags}"] if ldflags else [] + return flags # No -j here: wolfSSL's configure enables make's jobserver by default # (AX_AM_JOBSERVER adds AM_MAKEFLAGS += -j), and that explicit # -j on every automake sub-make overrides whatever the top-level make @@ -410,7 +434,6 @@ def run_config(cfg: Config, opts: argparse.Namespace) -> tuple[str | None, # hop. Measured across this pool, the jobserver default also utilizes # the CPUs better than a capped -j (configs' serial phases - configure, # link - get backfilled by other configs' compile jobs). - make = ["make"] + flags steps: list[tuple[str, list[str] | Callable[[], object]]] = [] if cfg.user_settings: # Staged before configure; --enable-usersettings builds pick it up @@ -420,14 +443,16 @@ def run_config(cfg: Config, opts: argparse.Namespace) -> tuple[str | None, bdir / "user_settings.h"))) steps += [(" ".join(cmd), cmd) for cmd in cfg.prepare] if cfg.build: - steps += [("configure", configure), ("make", make)] + steps += [("configure", configure), + ("make", lambda: ["make"] + flag_args())] if cfg.check: steps += [ # Prebuild the check programs without running any tests so # "make check" below is pure test execution. - ("make check TESTS=", make + ["check", "TESTS="]), + ("make check TESTS=", + lambda: ["make"] + flag_args() + ["check", "TESTS="]), ("private dirs", lambda: privatize_dirs(bdir, opts.private_dir)), - ("make check", ["make"] + flags + ["check"]), + ("make check", lambda: ["make"] + flag_args() + ["check"]), ] steps += [(" ".join(cmd), cmd) for cmd in cfg.run] # With "netns", each command runs in its own network namespace; --chdir @@ -459,13 +484,17 @@ def record_failure(step: str) -> str: failed = "aborted" break if callable(cmd): + # A callable either does the step itself or returns the + # argv list to run, built now that earlier steps have run. try: - cmd() + result = cmd() except Exception as e: # one config's bug, not the run's print(f"+ {step}: {e!r}", file=logf, flush=True) failed = record_failure(step) break - continue + if not isinstance(result, list): + continue + cmd = result cmd = netns + cmd print(f"+ {' '.join(cmd)}", file=logf, flush=True) # stdin=DEVNULL so a test that reads stdin sees EOF (as in CI) @@ -612,6 +641,13 @@ def main() -> int: "that do not set their own \"cc\"") p.add_argument("--cflags", default="", help="CFLAGS for configs that do not set their own") + p.add_argument("--append-flags", action=argparse.BooleanOptionalAction, + default=False, + help="append the CFLAGS/LDFLAGS given here or in a " + "config to the values configure chose, instead " + "of replacing them at make time: keeps the " + "configured warning set (wolfSSL's -Wall -Wextra " + "family) in force under -Werror") p.add_argument("--ldflags", default="", help="LDFLAGS for configs that do not set their own") p.add_argument("--private-dir", action="append", default=[], diff --git a/.github/workflows/smoke-test.yml b/.github/workflows/smoke-test.yml index f63b2fb3fe6..79553e4c825 100644 --- a/.github/workflows/smoke-test.yml +++ b/.github/workflows/smoke-test.yml @@ -52,7 +52,11 @@ jobs: smoke: # Only run from the wolfssl org to avoid burning forks' CI minutes. if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-24.04 + # ubuntu-22.04, not 24.04: in September 2026 jobs on the 24.04 label + # queued for a median of 13 minutes and up to 4.5 hours on busy + # afternoons, while 22.04 jobs started in about 3 minutes. The Jenkins + # PRB gate waits on this job, so its queue time is PRB latency. + runs-on: ubuntu-22.04 timeout-minutes: 60 env: CCACHE_MAXSIZE: 2G @@ -94,11 +98,12 @@ jobs: uses: ./.github/actions/install-apt-deps with: packages: autoconf automake libtool build-essential bubblewrap ccache - ghcr-debs-tag: ubuntu-24.04-minimal + ghcr-debs-tag: ubuntu-22.04-minimal # Ubuntu 24.04 can restrict unprivileged user namespaces via AppArmor, # which would stop the test scripts from re-execing under - # bwrap --unshare-net (their port-isolation mechanism). + # bwrap --unshare-net (their port-isolation mechanism). A no-op on + # 22.04 (the sysctl does not exist there); kept for a move back. - name: Allow unprivileged user namespaces (for bwrap) if: steps.merge_check.outputs.skip != 'true' run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 || true @@ -134,7 +139,17 @@ jobs: # errors). Every config builds with -Werror unless it sets its own # cflags: sanitize-asan replaces it with AddressSanitizer flags (UBSAN # excluded - current master has known left-shift UB in auto-generated - # SP math). --private-dir=certs gives every build dir its own certs/ + # SP math). --append-flags adds these to the CFLAGS configure chose + # rather than replacing them, so wolfSSL's own warning set (-Wall + # -Wextra -Wmaybe-uninitialized ...) stays in force under -Werror; a + # make-time CFLAGS= alone would silently drop it, and most of what + # the Jenkins PRB catches are exactly those warnings. + # -Wdeclaration-after-statement catches the C89 breaks that otherwise + # surface only in the MSVC and clang-tidy PRB jobs. enable-all adds + # -pedantic (PRB's medium-runtime list builds it that way), and the + # two build-only configs at the end, all-Og and savesession, are the + # PRB single-flag entries behind the September 2026 misses. + # --private-dir=certs gives every build dir its own certs/ # copy: crl-gen-openssl.test writes generated CRLs under certs/crl/, # which would race through the shared VPATH certs symlink. # @@ -149,7 +164,8 @@ jobs: - name: Build and make check all configs (parallel, out-of-tree) if: steps.merge_check.outputs.skip != 'true' run: | - .github/scripts/parallel-make-check.py ${{ github.event_name == 'schedule' && '--build-only' || '' }} --cflags=-Werror \ + .github/scripts/parallel-make-check.py ${{ github.event_name == 'schedule' && '--build-only' || '' }} \ + --append-flags "--cflags=-Werror -Wdeclaration-after-statement" \ --private-dir=certs .github/configs/smoke-test.json # Seed (master pushes + the weekday cron) writes the master-scoped