From 922677bb7f35877328384c1b1cb9520d30ba48c0 Mon Sep 17 00:00:00 2001 From: Christopher Obbard Date: Fri, 28 Aug 2026 12:29:48 +0100 Subject: [PATCH 1/8] packaging: drop unused debug build profile There is no longer any need to apply a separate configuration when building the package with the debug build profile. Remove all mention of it from the repository, along with the README sections and examples describing them. --profiles is kept as a generic DEB_BUILD_PROFILES pass-through; only the debug-specific example goes. Signed-off-by: Christopher Obbard --- README.md | 17 ----------------- build-kernel.sh | 3 +-- debian/rules | 11 ----------- prepare-source.sh | 20 -------------------- 4 files changed, 1 insertion(+), 50 deletions(-) diff --git a/README.md b/README.md index ac57987..f400f00 100644 --- a/README.md +++ b/README.md @@ -217,9 +217,6 @@ clone → prepare → build. Run it from the repo root. # Build with explicit LOCALVERSION ./build-kernel.sh --tag qcom-next-7.2-rc7-20260826 --localversion qcom-next-20260826 -# Build debug variant -./build-kernel.sh --latest-tag --localversion debug --profiles debug - # Use local kernel source (skip clone) ./build-kernel.sh --local-source /path/to/kernel-source --localversion qcom-next-20260826 @@ -442,7 +439,6 @@ this fixed order: | 2 | `debian/rules` | Disable `CONFIG_LOCALVERSION_AUTO` (prevents git hash in `uname -r`) | | 3 | Unified fragment pipeline | `arch/arm64/configs/prune.config`, then `arch/arm64/configs/qcom.config` (both if present), then `debian/config/*.config` (sorted) | | 4 | `debian/rules` | Re-check `CONFIG_LOCALVERSION_AUTO` (merges may re-enable it) | -| 5 | `arch/arm64/configs/debug.config` | Debug options — only when `DEB_BUILD_PROFILES=debug` | ### Unified config fragment pipeline (step 3) @@ -562,18 +558,6 @@ EOF Commit it to `config-available/`. It will not affect any build until explicitly activated via `--enable-configs my-feature` or a manual copy to `config/`. -### Debug build (step 5) - -```bash -# Via build-kernel.sh -./build-kernel.sh --latest-tag --profiles debug - -# Via dpkg-buildpackage directly -DEB_BUILD_PROFILES=debug dpkg-buildpackage -us -uc -b -``` - -Merges `arch/arm64/configs/debug.config` from the kernel source if present. - --- ## Configuration knobs @@ -585,7 +569,6 @@ Merges `arch/arm64/configs/debug.config` from the kernel source if present. | Always-on config | Add `*.config` to `debian/config/` | Applied on every build | | Optional config | `--enable-configs name` or copy from `debian/config-available/` | Activated per build | | Out-of-tree build dir | `O=` or `KBUILD_OUTPUT=` | Reads artifacts from objdir | -| Debug build | `DEB_BUILD_PROFILES=debug` or `--profiles debug` | Merges `arch/arm64/configs/debug.config` | | Parallel jobs | `DEB_BUILD_OPTIONS=parallel=N` | Controls `make -jN` | --- diff --git a/build-kernel.sh b/build-kernel.sh index 8fd946a..f762e08 100755 --- a/build-kernel.sh +++ b/build-kernel.sh @@ -50,7 +50,7 @@ OPTIONS: (default: $DEFAULT_DISTRO) --build-mode MODE docker|native|sbuild (default: $DEFAULT_BUILD_MODE) --docker-build PATH Path to docker_deb_build.py (docker mode) - --profiles PROFILES DEB_BUILD_PROFILES (e.g. debug) + --profiles PROFILES DEB_BUILD_PROFILES (default: none) --kernel-config LIST Extra config fragments, beyond debian/config-available/ which is always applied in full. An "intree:" prefix names a path relative to the kernel source root @@ -76,7 +76,6 @@ EXAMPLES: $0 --local-source /path/to/kernel --build-mode native $0 --local-source /path/to/kernel --kver-extra -mybuild $0 --latest-tag --kernel-config docker,systemd-boot - $0 --latest-tag --profiles debug DISTRIBUTIONS: noble Ubuntu 24.04 LTS diff --git a/debian/rules b/debian/rules index 6b4ab45..8f40251 100755 --- a/debian/rules +++ b/debian/rules @@ -179,7 +179,6 @@ override_dh_auto_configure: # invocation (later fragments win, overrides are reported), followed by # make olddefconfig to resolve the resulting dependencies. # 4. Re-check CONFIG_LOCALVERSION_AUTO (merges may re-enable it) - # 5. arch/arm64/configs/debug.config — only when DEB_BUILD_PROFILES=debug # --------------------------------------------------------------------------- # Step 1: Base defconfig @@ -243,16 +242,6 @@ override_dh_auto_configure: echo "# CONFIG_LOCALVERSION_AUTO is not set" >> "$$CONFIG_FILE"; \ fi - # Step 5: Merge debug.config if debug build profile is active. - @if echo "$(DEB_BUILD_PROFILES)" | grep -qw "debug"; then \ - if [ -f arch/arm64/configs/debug.config ]; then \ - echo "Debug profile active: merging arch/arm64/configs/debug.config..."; \ - $(MAKE) $(KBUILD_O_ARG) ARCH=$(ARCH) debug.config; \ - else \ - echo "Warning: debug profile requested but arch/arm64/configs/debug.config not found"; \ - fi; \ - fi - override_dh_auto_build: # Read LOCALVERSION from debian/localversion (written by 'prepare' target). # This avoids the fragile back-derivation from the source package name that diff --git a/prepare-source.sh b/prepare-source.sh index 886e6d8..6d38e27 100755 --- a/prepare-source.sh +++ b/prepare-source.sh @@ -76,11 +76,6 @@ OPTIONS: redundant, since that fragment is already applied. Entries are processed in LC_ALL=C sorted order. - Debug: - --debug Enable debug build: copies arch/arm64/configs/debug.config - from the kernel source into debian/config/ so it is - applied as a config fragment during the build. - Paths: --debian-dir DIR Path to the debian/ packaging directory (default: $DEBIAN_DIR) @@ -113,7 +108,6 @@ SRCPKG="$DEFAULT_SRCPKG" BINPKG="$DEFAULT_BINPKG" DEBIAN_REVISION="$DEFAULT_DEBIAN_REVISION" KERNEL_CONFIG="" -DEBUG=false while [[ $# -gt 0 ]]; do case $1 in @@ -126,7 +120,6 @@ while [[ $# -gt 0 ]]; do --debian-revision) DEBIAN_REVISION="$2"; shift 2 ;; --kernel-config) KERNEL_CONFIG="$2"; shift 2 ;; --debian-dir) DEBIAN_DIR="$2"; shift 2 ;; - --debug) DEBUG=true; shift ;; -h|--help) usage ;; *) log_error "Unknown option: $1"; exit 1 ;; esac @@ -178,7 +171,6 @@ log_info " Debian revision: $DEBIAN_REVISION" [[ -n "$LOCALVERSION" ]] && log_info " LOCALVERSION: $LOCALVERSION" [[ -n "$KVER_EXTRA" ]] && log_info " KVER_EXTRA: $KVER_EXTRA" [[ -n "$KERNEL_CONFIG" ]] && log_info " Kernel config: $KERNEL_CONFIG" -[[ "$DEBUG" == true ]] && log_info " Debug build: yes" echo # ── Inject debian/ ─────────────────────────────────────────────────────────── @@ -285,18 +277,6 @@ if [[ -n "$KERNEL_CONFIG" ]]; then done < <(printf '%s\n' "${CFG_LIST[@]}" | tr -d ' ' | LC_ALL=C sort) fi -# ── Debug config fragment ───────────────────────────────────────────────────── -if [[ "$DEBUG" == true ]]; then - DEBUG_CONFIG="$SOURCE_DIR/kernel/configs/debug.config" - if [[ -f "$DEBUG_CONFIG" ]]; then - mkdir -p "$SOURCE_DIR/debian/config" - cp "$DEBUG_CONFIG" "$SOURCE_DIR/debian/config/debug.config" - log_info "Copied kernel/configs/debug.config into debian/config/" - else - log_warn "kernel/configs/debug.config not found — debug config will not be applied" - fi -fi - # ── Prepare: generate control, changelog, localversion, pkgversion ─────────── log_step "Running debian/rules prepare..." PREPARE_ARGS="DISTRO=$DISTRO SRCPKG=$SRCPKG BINPKG=$BINPKG DEBIAN_REVISION=$DEBIAN_REVISION" From 59bdf0d9e5fc2fa30d9833ba6c9ef378685573d7 Mon Sep 17 00:00:00 2001 From: Christopher Obbard Date: Fri, 28 Aug 2026 12:34:19 +0100 Subject: [PATCH 2/8] d/rules: keep dh_strip and dh_dwz away from the shipped debug symbols dh_strip does not exempt /usr/lib/debug/; its only debug-path exclusions are .../debug/.build-id/ directories and debug/*.so. The vmlinux staged into linux-image--dbg is an ordinary ELF executable so dh_strip stripped it, removing the DWARF and the symbol table. Nothing was saved first: the package name already ends in -dbg, so dh_strip's automatic dbgsym extraction is skipped. The result was a -dbg package useless for crash, kdump and systemtap. dh_dwz, which runs immediately before, would also run dwz over that same multi-gigabyte vmlinux. Exclude by path rather than by package name. -X is a substring match against the full path, so it covers everything the -dbg package ships and needs no lookup of the kernel release to build the package name. Signed-off-by: Christopher Obbard --- debian/rules | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/debian/rules b/debian/rules index 8f40251..d6a632e 100755 --- a/debian/rules +++ b/debian/rules @@ -412,6 +412,14 @@ override_dh_auto_install: --objcopy "$(OBJCOPY)" \ --modules-manifest "$(CURDIR)/debian/dkms-modules" +# Ignore files shipped in debug package. +override_dh_dwz: + dh_dwz -X/usr/lib/debug/ + +# Ignore files shipped in debug package. +override_dh_strip: + dh_strip -X/usr/lib/debug/ + # Skip automatic dh_installmodules — called manually in override_dh_installdeb. override_dh_installmodules: @echo "Skipping automatic dh_installmodules (called manually in override_dh_installdeb)" From 17404214f88f2523709431032716bd6ab954712d Mon Sep 17 00:00:00 2001 From: Christopher Obbard Date: Fri, 28 Aug 2026 20:24:03 +0100 Subject: [PATCH 3/8] d/rules: stop dh_strip generating automatic -dbgsym packages Debug symbols for this source package are shipped by the declared linux-image--dbg package. The -dbgsym package debhelper generated alongside it duplicated that role for the headers tree without being declared or documented in debian/control.in. Drop it from the documented outputs at the same time: a build now publishes five binary packages per variant, all declared in debian/control.in. Signed-off-by: Christopher Obbard --- README.md | 8 ++++---- debian/rules | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f400f00..cf6b04a 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,6 @@ Packages follow the standard Debian/Ubuntu kernel naming convention: | `linux-image-` | Kernel image, modules, DTBs | `linux-image-7.2.0-qcom-next-20260826` | | `linux-headers-` | Headers for out-of-tree modules | `linux-headers-7.2.0-qcom-next-20260826` | | `linux-image--dbg` | Debug symbols | `linux-image-7.2.0-qcom-next-20260826-dbg` | -| `linux-headers--dbgsym` | Headers debug symbols, generated automatically by debhelper | `linux-headers-7.2.0-qcom-next-20260826-dbgsym` | | `` | Image metapackage tracking the newest kernel image | `linux-image-qcom-next` | | `` | Headers metapackage tracking the newest headers | `linux-headers-qcom-next` | @@ -28,9 +27,10 @@ build matrix (`binpkg` / derived headers name). They stay constant across snapshots and depend on the newest versioned package, so installing `linux-image-qcom-next` follows the latest build of that variant. -`debian/control.in` declares five of these; the `-dbgsym` package is produced by -debhelper rather than declared, so a build publishes six binary packages per -variant. +`debian/control.in` declares all five, so a build publishes five binary packages +per variant. `dh_strip` is run with `--no-automatic-dbgsym`, so debhelper +generates no additional `-dbgsym` package: debug symbols are shipped only by the +declared `linux-image--dbg`. **`-qcom`** is a static flavour suffix appended by the packaging, identifying Qualcomm-packaged kernels independently of the branch name. diff --git a/debian/rules b/debian/rules index d6a632e..58f152a 100755 --- a/debian/rules +++ b/debian/rules @@ -417,8 +417,9 @@ override_dh_dwz: dh_dwz -X/usr/lib/debug/ # Ignore files shipped in debug package. +# Don't build "-dbgsym" packages. override_dh_strip: - dh_strip -X/usr/lib/debug/ + dh_strip -X/usr/lib/debug/ --no-automatic-dbgsym # Skip automatic dh_installmodules — called manually in override_dh_installdeb. override_dh_installmodules: From bef6b98077c6244c8a55bd59ab87efc78fcae31e Mon Sep 17 00:00:00 2001 From: Christopher Obbard Date: Fri, 28 Aug 2026 14:08:50 +0100 Subject: [PATCH 4/8] d/rules: mirror the kernel/ path level in the module debug tree modules.order lists build-tree-relative paths, but modules_install puts in-tree modules under $MODLIB/kernel/. The debug files were written without that level, so the debug tree did not mirror the module tree. Signed-off-by: Christopher Obbard --- debian/rules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/rules b/debian/rules index 58f152a..ae2768c 100755 --- a/debian/rules +++ b/debian/rules @@ -375,7 +375,7 @@ override_dh_auto_install: src_mod="$$mod"; \ [ -n "$$OBJ_DIR" ] && src_mod="$$OBJ_DIR/$$mod"; \ [ -f "$$src_mod" ] || continue; \ - dbg="$$DBG_PKG/usr/lib/debug/lib/modules/$$BASE/$$mod"; \ + dbg="$$DBG_PKG/usr/lib/debug/lib/modules/$$BASE/kernel/$$mod"; \ mkdir -p "$${dbg%/*}"; \ $(OBJCOPY) --only-keep-debug "$$src_mod" "$$dbg" 2>/dev/null || \ cp -a "$$src_mod" "$$dbg"; \ From 25c9454a77bf42dfa90a8f6ddd161a7c6da123c3 Mon Sep 17 00:00:00 2001 From: Christopher Obbard Date: Fri, 28 Aug 2026 13:32:49 +0100 Subject: [PATCH 5/8] bundle-dkms-modules: don't strip modules after build The DKMS modules in linux-image--dbg carried no debug information. The extraction itself was fine: dkms had already stripped the module before bundle-dkms-modules.sh ever saw it. dkms strips by default. read_conf resolves an unset STRIP[index] to ${strip[0]:-yes} and build_module then runs: strip -g "$built_module" which is --strip-debug: the same operation as Stage 3 here, but applied before Stage 2 has extracted anything. objcopy --only-keep-debug therefore copied out an ELF with no .debug_* sections, and the shipped module had no debug information to lose either. Pass --directive 'STRIP=no' to dkms build to stop stripping the modules after building. Signed-off-by: Christopher Obbard --- debian/scripts/bundle-dkms-modules.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/debian/scripts/bundle-dkms-modules.sh b/debian/scripts/bundle-dkms-modules.sh index c2649f0..d6aeca1 100755 --- a/debian/scripts/bundle-dkms-modules.sh +++ b/debian/scripts/bundle-dkms-modules.sh @@ -350,12 +350,15 @@ for name in $DKMS_MODULES; do # Capture exit code separately: dkms exit-code conventions vary across # versions (a BUILD_EXCLUSIVE skip can exit 0). Outcome is judged by # artifact presence, not exit code. + # + # --directive STRIP=no stops dkms from stripping the module. dkms_rc=0 dkms build "$PKG_NAME/$PKG_VER" \ --kernelsourcedir "$HEADERS_DIR" \ --dkmstree "$DKMS_TREE" \ -k "$KVER" \ --arch "$DKMS_ARCH" \ + --directive "STRIP=no" \ || dkms_rc=$? # ── Judge outcome by artifacts ──────────────────────────────────────────── From 961cabbb9d6f3637be025cb54c78268fa7ac5a06 Mon Sep 17 00:00:00 2001 From: Christopher Obbard Date: Fri, 28 Aug 2026 20:24:19 +0100 Subject: [PATCH 6/8] bundle-dkms-modules: fail if a module contains no debug information objcopy --only-keep-debug succeeds whether or not the module it reads carries DWARF, so a module built without debug information yields a debug file with no symbols and the -dbg package ships it. Assert that the extracted file has a .debug_info section, and fail if it does not. Match against readelf's captured output rather than piping it into `grep -q`. grep -q exits at the first match, readelf dies of SIGPIPE on its next write, and under this script's `set -o pipefail` the pipeline reports that failure instead of grep's success - firing the assertion on a file that does carry DWARF. Whether readelf gets far enough to be killed depends on stdio flush timing against grep's startup, so the pipeline form would fail only sometimes, which is worse than failing always. Read readelf's stderr into the same variable rather than discarding it, so a readelf that cannot read the file reports why instead of being indistinguishable from a file with no DWARF, and print the section list when the assertion fires: that is the evidence needed to tell "built without debug information" from "something stripped it". Report a failing objcopy the same way. Falling back to a full copy keeps the -dbg package usable when extraction fails, but it is a degradation and should not happen silently. Signed-off-by: Christopher Obbard --- debian/scripts/bundle-dkms-modules.sh | 37 +++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/debian/scripts/bundle-dkms-modules.sh b/debian/scripts/bundle-dkms-modules.sh index d6aeca1..7c1d9ad 100755 --- a/debian/scripts/bundle-dkms-modules.sh +++ b/debian/scripts/bundle-dkms-modules.sh @@ -447,9 +447,42 @@ for name in $DKMS_MODULES; do install -D -m 644 "$ko" "$dest" # Stage 2: extract debug symbols before stripping (non-destructive read) + # Falling back to a full copy keeps the -dbg package usable when objcopy + # cannot extract, but that is a degradation, not a normal outcome: + # report what objcopy said instead of discarding it. mkdir -p "${dbg%/*}" - "$OBJCOPY" --only-keep-debug "$dest" "$dbg" 2>/dev/null \ - || cp -a "$dest" "$dbg" + if ! objcopy_err="$("$OBJCOPY" --only-keep-debug "$dest" "$dbg" 2>&1)"; then + log_warn "objcopy --only-keep-debug failed for $b; copying the module instead" + printf '%s\n' "$objcopy_err" | sed 's/^/ | /' >&2 + cp -a "$dest" "$dbg" + fi + + # Stage 2b: the extraction above succeeds even when there is nothing to + # extract, so assert the result actually carries DWARF. + # + # Capture readelf's output rather than piping it into `grep -q`: grep -q + # exits at the first match, readelf dies of SIGPIPE on its next write, + # and under `set -o pipefail` the pipeline reports that failure — firing + # this assertion on a file that does carry DWARF. Whether readelf gets + # far enough to be killed depends on stdio flush timing, so the pipeline + # form fails only sometimes, which is worse than failing always. + if ! dbg_sections="$(readelf -SW "$dbg" 2>&1)"; then + log_error "readelf failed on the extracted debug file for $b" + log_error " debug: $dbg" + printf '%s\n' "$dbg_sections" | sed 's/^/ | /' >&2 + exit 1 + fi + if ! grep -q '\.debug_info' <<< "$dbg_sections"; then + log_error "No DWARF in the extracted debug file for $b" + log_error " module: $ko" + log_error " debug: $dbg" + log_error "The -dbg package would ship a debug file with no symbols." + log_error "Check that the module was compiled with debug information" + log_error "and that nothing stripped it before this script ran." + log_error "Sections in the extracted debug file:" + printf '%s\n' "$dbg_sections" | sed 's/^/ | /' >&2 + exit 1 + fi # Stage 3: strip the shipped copy in place strip --strip-debug "$dest" From 88e62b8e5f06a4ed8c7d498b3e47f16716e0d8fb Mon Sep 17 00:00:00 2001 From: Christopher Obbard Date: Fri, 28 Aug 2026 13:35:59 +0100 Subject: [PATCH 7/8] bundle-dkms-modules: report the build host's dkms configuration dkms hardcodes where it reads configuration from: /etc/dkms/framework.conf and /etc/dkms/framework.conf.d/*.conf in read_framework_conf and the /etc/dkms/*.conf overrides in read_conf. Neither set can be redirected by an option or an environment variable, so a build cannot opt out of whatever the host ships; it can only be explicit about it. Most of the exposure is already closed. framework.conf accepts a fixed variable list; it is sourced before the command line is parsed, so --dkmstree and --kernelsourcedir win over it; and --directive is applied after every conf file. What remains is tmp_location, parallel_jobs, the compress_*_opts and post_transaction, the last being an arbitrary command dkms will run. Print whatever config is present, once for the framework configuration and again per module for the overrides that apply to it, so a surprising host setting appears in the build log instead of acting silently. Deliberately not fatal: a build host is allowed to have dkms configured; this is diagnostic rather than a policy. Signed-off-by: Christopher Obbard --- debian/scripts/bundle-dkms-modules.sh | 45 +++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/debian/scripts/bundle-dkms-modules.sh b/debian/scripts/bundle-dkms-modules.sh index 7c1d9ad..1c43e1a 100755 --- a/debian/scripts/bundle-dkms-modules.sh +++ b/debian/scripts/bundle-dkms-modules.sh @@ -279,6 +279,38 @@ log_info " objcopy: $OBJCOPY" log_info " modules: $DKMS_MODULES" echo +# --------------------------------------------------------------------------- +# Report any dkms configuration present on the build host. +# +# dkms hardcodes the paths it reads configuration from: /etc/dkms/framework.conf +# and /etc/dkms/framework.conf.d/*.conf in read_framework_conf, and the +# /etc/dkms/*.conf overrides in read_conf. None of them can be +# redirected by an option or an environment variable, so a build cannot opt out +# of whatever the host happens to ship; it can only be explicit about it. +# +# Most of the exposure is already closed: framework.conf accepts a fixed +# variable list, it is sourced before the command line is parsed so --dkmstree +# and --kernelsourcedir are higher priority and the --directive passed to dkms +# build is applied after every conf file. What remains is tmp_location, +# parallel_jobs, the compress_*_opts, and post_transaction, the last being an +# arbitrary command dkms will run. +# +# Print whatever is there so a surprising host setting shows up in the build +# log rather than acting silently. This is deliberately not fatal: a build host +# is allowed to have dkms configured. +# --------------------------------------------------------------------------- +_dkms_host_conf=0 +for _conf in /etc/dkms/framework.conf /etc/dkms/framework.conf.d/*.conf; do + [[ -e "$_conf" ]] || continue + _dkms_host_conf=1 + log_warn "Host dkms configuration in effect: $_conf" + grep -vE '^[[:space:]]*(#|$)' "$_conf" | sed 's/^/ | /' || true +done +if [[ "$_dkms_host_conf" -eq 0 ]]; then + log_info "No host dkms framework configuration found." +fi +echo + # --------------------------------------------------------------------------- # Private DKMS tree — redirects artifacts away from /var/lib/dkms/ (root-owned, # not writable under fakeroot / non-root dpkg-buildpackage). @@ -346,6 +378,19 @@ for name in $DKMS_MODULES; do log_info " kernelsourcedir: $HEADERS_DIR" log_info " dkmstree: $DKMS_TREE" + # ── Report per-module dkms.conf overrides on the build host ────────────── + # read_conf sources these after the vendor dkms.conf, so they can change how + # this module is built. The --directive below still wins over them, but + # anything they set that we do not pin takes effect silently otherwise. + for _conf in "/etc/dkms/$PKG_NAME.conf" \ + "/etc/dkms/$PKG_NAME-$PKG_VER.conf" \ + "/etc/dkms/$PKG_NAME-$PKG_VER-$KVER.conf" \ + "/etc/dkms/$PKG_NAME--$KVER.conf"; do + [[ -e "$_conf" ]] || continue + log_warn "Host override for $PKG_NAME in effect: $_conf" + grep -vE '^[[:space:]]*(#|$)' "$_conf" | sed 's/^/ | /' || true + done + # ── Run dkms build ──────────────────────────────────────────────────────── # Capture exit code separately: dkms exit-code conventions vary across # versions (a BUILD_EXCLUSIVE skip can exit 0). Outcome is judged by From 0841cf3e358f47bd2920c8dfc42de17173326afd Mon Sep 17 00:00:00 2001 From: Christopher Obbard Date: Fri, 28 Aug 2026 20:10:14 +0100 Subject: [PATCH 8/8] bundle-dkms-modules: always print the dkms build log make.log was printed only when the build failed, and then only its last 300 lines. A module that builds is not necessarily a module built correctly: the debug information check exists precisely because the result can be wrong while dkms reports success, and when it fires the compiler command lines are the first thing wanted. They were gone by then - the private dkms tree is deleted on EXIT, so nothing survives the build to look at. Print make.log for every module, before the outcome is judged, so it is in the log whether the build succeeded or not. debian/rules exports KBUILD_VERBOSE, so the full compiler command lines are there. A failed build still hard-fails, and the BUILD_EXCLUSIVE gate analysis for the "dkms attempted no build" case is unchanged; the failure path now refers to the log above rather than printing a tail of it a second time. Signed-off-by: Christopher Obbard --- debian/scripts/bundle-dkms-modules.sh | 33 +++++++++++++++++++-------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/debian/scripts/bundle-dkms-modules.sh b/debian/scripts/bundle-dkms-modules.sh index 1c43e1a..5773d0b 100755 --- a/debian/scripts/bundle-dkms-modules.sh +++ b/debian/scripts/bundle-dkms-modules.sh @@ -16,10 +16,12 @@ set -euo pipefail # 2. Reads PACKAGE_NAME / PACKAGE_VERSION from the package's dkms.conf. # 3. Builds the module with `dkms build` against the staged kernel headers, # using a private --dkmstree (mktemp) to avoid writing to /var/lib/dkms/. -# 4. Judges the outcome by artifact presence, not dkms exit code. -# On failure: prints make.log tail (build failure) or BUILD_EXCLUSIVE gate -# analysis (skip), then hard-fails — a manifest entry is a presence contract. -# 5. For each produced .ko: +# 4. Prints the dkms make.log for every module, built or not: the private +# dkms tree is deleted on exit, so this is the only record left in CI. +# 5. Judges the outcome by artifact presence, not dkms exit code. +# On failure: adds BUILD_EXCLUSIVE gate analysis when dkms attempted no +# build, then hard-fails — a manifest entry is a presence contract. +# 6. For each produced .ko: # - Collision-checks against already-bundled modules and in-tree modules. # - Installs to /lib/modules//extra/.ko # - Extracts debug symbols to /usr/lib/debug/lib/modules//extra/.ko @@ -406,21 +408,32 @@ for name in $DKMS_MODULES; do --directive "STRIP=no" \ || dkms_rc=$? + # ── Report the build log ────────────────────────────────────────────────── + # dkms writes make.log inside the private dkms tree, which is deleted on + # EXIT, so this is the only surviving record of the build in CI. + # + # Print it whether or not the build succeeded. A module that builds can + # still be compiled with the wrong flags, and the compiler command lines + # are the only place that is visible — debian/rules exports KBUILD_VERBOSE, + # so they are all here. + mklog="$(find "$DKMS_TREE/$PKG_NAME/$PKG_VER" -name make.log 2>/dev/null \ + | head -1 || true)" + if [[ -n "$mklog" ]]; then + log_step "dkms build log for $PKG_NAME/$PKG_VER ($mklog):" + sed 's/^/ | /' "$mklog" + echo + fi + # ── Judge outcome by artifacts ──────────────────────────────────────────── # A .ko under //// means success. # dkms's make.log separates the two failure modes: # - make.log present → build was attempted and failed # - no make.log → dkms attempted no build (BUILD_EXCLUSIVE gate) - # The log is printed inline because the private dkms tree is deleted on - # EXIT, so it is the only surviving record in CI. kos="$(find "$DKMS_TREE/$PKG_NAME/$PKG_VER/$KVER" -name '*.ko' 2>/dev/null || true)" if [[ "$dkms_rc" -ne 0 || -z "$kos" ]]; then - mklog="$(find "$DKMS_TREE/$PKG_NAME/$PKG_VER" -name make.log 2>/dev/null \ - | head -1 || true)" if [[ -n "$mklog" ]]; then - log_error "dkms build failed for $PKG_NAME/$PKG_VER on kernel $KVER (dkms exit $dkms_rc); make.log tail:" - tail -n 300 "$mklog" | sed 's/^/ | /' >&2 + log_error "dkms build failed for $PKG_NAME/$PKG_VER on kernel $KVER (dkms exit $dkms_rc); see the build log above." else log_error "$PKG_NAME/$PKG_VER produced no module for kernel $KVER; dkms attempted no build (dkms exit $dkms_rc)." gates="$(grep -E '^[[:space:]]*BUILD_EXCLUSIVE' "$conf" 2>/dev/null || true)"