Skip to content

Integrate out-of-tree DKMS modules into the kernel at build time - #54

Open
Bjordis Collaku (bjordiscollaku) wants to merge 13 commits into
qcom/debian/latestfrom
feat/dkms-build-time-module-integration
Open

Integrate out-of-tree DKMS modules into the kernel at build time#54
Bjordis Collaku (bjordiscollaku) wants to merge 13 commits into
qcom/debian/latestfrom
feat/dkms-build-time-module-integration

Conversation

@bjordiscollaku

@bjordiscollaku Bjordis Collaku (bjordiscollaku) commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

This adds a build-time mechanism that compiles out-of-tree kernel modules from
their DKMS source packages and bundles them into the kernel package, in the same
run that builds the kernel. The device receives one self-contained kernel
package: the module is present and pinned to the exact kernel it was built
against, with no DKMS, compiler, or headers required on the target.

The mechanism is module-agnostic. It is implemented as a standalone, documented
tool (debian/scripts/bundle-dkms-modules.sh) that debian/rules invokes during
the build, and it is driven by a manifest, so onboarding any out-of-tree module
is a two-line change with no change to the build logic.

Design history and rationale: #44.

How it works, in order

flowchart TD
    P["module DKMS source package<br/>(from the distro apt source)"]
    K["1. Build kernel + headers<br/>in one packaging run"]
    H["2. Stage headers in the build tree"]
    R["3. debian/rules calls<br/>bundle-dkms-modules.sh"]
    RES["4. Resolve source + tokens<br/>via dpkg -L and dkms.conf"]
    D["5. dkms build against the<br/>staged headers (private tree)"]
    J{"6. Built a .ko?"}
    X["Fail the build<br/>with precise diagnostics"]
    S["7. Extract debug to -dbg,<br/>strip the shipped copy"]
    B["8. Bundle into the kernel image<br/>under lib/modules/KVER/extra"]
    O["9. On device: depmod indexes it,<br/>modprobe + autoload work"]

    P -. "Build-Depends" .-> RES
    K --> H --> R --> RES --> D --> J
    J -- "no" --> X
    J -- "yes" --> S --> B --> O
Loading
  1. The module's *-dkms package is installed via Build-Depends (build-time
    only; it never enters any binary package's runtime dependencies).
  2. The kernel and its headers are built and staged in the same run.
  3. debian/rules (override_dh_auto_install) invokes the bundling tool once the
    trees are staged.
  4. For each manifest module the tool resolves the source directory and the dkms
    name/version tokens from dpkg -L and the shipped dkms.conf.
  5. It runs dkms build against the staged headers in a private DKMS tree, so the
    module matches the exact kernel and the build stays rootless under fakeroot.
  6. It judges success by the produced artifact, not by exit codes, and fails the
    build with precise diagnostics if a listed module produces nothing.
  7. It extracts the module's debug into the -dbg package and strips the shipped
    copy, the same two-stage handling an in-tree module gets.
  8. It installs the module into the kernel image under lib/modules/<KVER>/extra/,
    guarding against duplicate and in-tree name collisions.
  9. On the device, the standard postinst depmod indexes extra/, so modprobe
    and autoload resolve the module.

The tool: debian/scripts/bundle-dkms-modules.sh

The bundling logic is a single standalone tool with a documented CLI, so
debian/rules stays a thin call, future changes (a new guard, signing,
compression) touch one file, and a developer can re-run just the bundling step
against already-staged trees.

Required:
  --kver KVER               kernel release (uname -r)
  --headers-dir DIR         absolute path to the staged kernel headers root
  --image-pkg-dir DIR       linux-image staging tree root
  --dbg-pkg-dir DIR         linux-image-dbg staging tree root
Optional:
  --modules-manifest FILE   default: debian/dkms-modules
  --arch ARCH               default: aarch64 (uname -m vocabulary for dkms)
  --objcopy PATH            default: aarch64-linux-gnu-objcopy, then objcopy
  -h, --help                full usage, prerequisites, and examples

The tool resolves each module authoritatively (no path globbing), judges
outcomes by artifacts, hard-fails when a declared module produces nothing, prints actionable diagnostics on failure
(the make.log tail for a build failure, or the dkms.conf gates evaluated
against the kernel config for a skip), and guards against name collisions.

CI path: debian/rules calls the tool

override_dh_auto_install invokes the tool with explicit, absolute paths after
the kernel, headers, and debug trees are staged:

$(CURDIR)/debian/scripts/bundle-dkms-modules.sh \
    --kver            "$$BASE" \
    --headers-dir     "$(CURDIR)/debian/linux-headers-$$BASE-qcom/usr/src/linux-headers-$$BASE" \
    --image-pkg-dir   "$(CURDIR)/$$PKG" \
    --dbg-pkg-dir     "$(CURDIR)/$$DBG_PKG" \
    --arch            "$(DKMS_ARCH)" \
    --objcopy         "$(OBJCOPY)" \
    --modules-manifest "$(CURDIR)/debian/dkms-modules"

dh_installmodules (called in override_dh_installdeb) wires the postinst
depmod that indexes extra/ on the device.

Developer path: run the tool standalone

A developer who has already staged the kernel trees can re-run just the bundling
step, without re-running the whole dpkg-buildpackage:

debian/scripts/bundle-dkms-modules.sh \
  --kver        <kernelrelease> \
  --headers-dir   /path/to/staged/linux-headers-<kernelrelease> \
  --image-pkg-dir /path/to/staged/linux-image-<kernelrelease>-qcom \
  --dbg-pkg-dir   /path/to/staged/linux-image-<kernelrelease>-qcom-dbg

--help documents the full CLI, prerequisites, and a host-arch note (the tool
builds with the host toolchain and is intended to run on a native arm64 host).

The manifest: debian/dkms-modules

A plain-text list of module names, one per line. Comments, blank lines, and CRLF
endings are tolerated. This is the single place that decides which modules are
built and bundled; the tool and debian/rules are untouched when it changes.

Adding a module is two lines:

  1. Append the module name to debian/dkms-modules.
  2. Add dkms and <name>-dkms (>= x.y.z) to Build-Depends in
    debian/control.in.

Module load policy

Blacklisting and load policy are orthogonal to this change. The bundled module is
installed under /lib/modules/<KVER>/extra/ and indexed by the standard depmod,
so to the loader it is an ordinary module: the usual controls apply by module name,
unchanged (a blacklist or install line in modprobe.d, or modprobe.blacklist=
or module_blacklist= on the kernel command line). The kernel package intentionally
ships no load policy of its own, because a blacklist is board and policy specific
while this package is shared across boards; that decision stays external to this
mechanism, at the image build stage.

Validation

CI (Ubuntu, resolute). Run
28193902324
(resolute, kernel 7.1.0-rc7-qcom-next-20260618). The Build kernel package
step builds and bundles the module from its *-dkms package:

[bundle-dkms]   Installed: .../lib/modules/.../extra/msm_kgsl.ko (stripped)
[bundle-dkms]   Debug:     .../linux-image-...-dbg/usr/lib/debug/lib/modules/.../extra/msm_kgsl.ko
[bundle-dkms] DKMS module bundling complete.

The packaged contents confirm the two-stage handling landed in both packages:

./lib/modules/.../extra/msm_kgsl.ko                  2,783,736 bytes  (kernel image, stripped)
./usr/lib/debug/lib/modules/.../extra/msm_kgsl.ko    1,271,360 bytes  (-dbg package)

All four packages (image, headers, dbg, dbgsym) built, and the
Upload .deb packages to S3 step now passes, so every step in the run is
green and the artifacts are published to
s3://.../pkg/temp/pkg-linux-qcom/28193902324-1/.

CI (Debian, trixie). Run
29125019996
(trixie, via Debusine). With kgsl-dkms now published to the Debusine workspace,
the Debian path satisfies the Build-Depends, the build runs to completion, and
msm_kgsl.ko is bundled into the linux-image exactly as on the Ubuntu path. All
Debusine build steps pass and the .debs publish to S3. Both distro families now
build and bundle the module end to end: Ubuntu (resolute, docker) and Debian
(trixie, Debusine).

Local (standalone tool, 18 of 18). The tool was exercised through its CLI
against shimmed leaf tools, so its real control flow, resolution, outcome
judgment, collision guards, and path layout all run:

Area Cases
Happy path module installed to extra/, debug written to the -dbg tree, strip ran on the shipped copy
Resolution failures package not installed, multiple dkms.conf, missing PACKAGE_NAME
Outcome diagnosis build failure prints the make.log tail; gated skip with config set, with config unset, and with no gates declared; compressed output reported
Collisions in-tree name clash, duplicate bundled basename, duplicate manifest entry
Manifest comment-only manifest skips cleanly, missing manifest fails closed, default path resolves correctly

Enablement status

This PR delivers the mechanism in full, with a reference module (kgsl) wired
in and validated end to end on both distro families (the two runs above).

A module can only be built on a family whose apt source publishes its *-dkms
package. For the reference module this is now satisfied on both: the source is
on Qualcomm Artifactory (the Ubuntu path) and, as of the rebuild in
qualcomm-linux/pkg-kgsl#62, on the Debusine workspace (the Debian path). Both
nightly families (trixie via Debusine, resolute via docker) build and bundle it
green, so the reference module stays wired in at merge.

The per-family principle still applies to future modules: turn a module on for
a family (a manifest line plus a Build-Depends entry) only once that family's
apt source carries the module source. Happy to sequence this whichever way the
maintainers prefer.

Requirements (R1 to R7)
# Requirement
R1 One kernel package: kernel image plus every required out-of-tree module, built in the same run. No DKMS on the device.
R2 The kernel build declares a Build-Depends on the DKMS source packages. DKMS is a build-time tool, not a runtime mechanism.
R3 DKMS packages must not appear in Depends, Recommends, or Suggests of any binary package.
R4 Each module is compiled from source against the exact kernel produced in the same run. No cached artifact.
R5 A change to a DKMS package requires a kernel rebuild. Multiple changes can be batched into one rebuild.
R6 Each module's own CI stays independent and validates its own *-dkms package. The kernel CI only consumes it.
R7 The bundled module is handled like an in-tree module: stripped in the shipped package, debug symbols in the -dbg package.
Design decisions
Decision Rationale
Build-time DKMS, not on-device Single self-contained package, no toolchain or headers on the target, module pinned to the exact kernel (R1, R4).
DKMS as a build dependency only The module is baked in, so nothing is resolved at install time and the runtime dependency graph stays clean (R3).
A standalone, documented tool The logic lives in one file with a CLI, so debian/rules is a thin call, future changes touch one place, and the step is independently re-runnable.
Build against this run's staged headers The module is compiled against the headers produced earlier in the same run, so it matches and loads against this kernel (R4).
Manifest driven Which modules to build is separated from how to build them; a new module is two lines with no logic change.
Fail on a missing module If a manifest module produces no artifact, the build fails rather than silently shipping without it. Never inferred from the module's own gates, so a misconfigured gate cannot silently drop a declared module.
Judge outcomes by artifacts, not exit codes DKMS exit-code conventions vary across versions (a skip can exit 0). Success is a built module; failure diagnosis comes from the make.log and the dkms.conf gates.
Resolve identity from dpkg and dkms.conf dpkg -L names the one dkms.conf the package ships; its PACKAGE_NAME/PACKAGE_VERSION are the tokens dkms keys on. No path globbing.
Private DKMS tree plus source symlink Lets the build run rootless under fakeroot, away from the root-owned /var/lib/dkms.
In-tree-equivalent debug handling Debug to the -dbg package via objcopy --only-keep-debug, then strip the shipped copy via strip --strip-debug.
Commits (13)
Bring-up
  declare the DKMS build-time dependency
  build the out-of-tree module and bundle it into the image
  drive the bundled modules from a manifest
  fail the build when a module yields no artifact
  pass dkms the uname -m architecture
  strip bundled modules and capture their debug
  resolve modules via dpkg and dkms.conf
  diagnose dkms build outcomes precisely
  guard against module name collisions when bundling
  extract bundling into debian/scripts/bundle-dkms-modules.sh

Post-extraction hardening
  fix a recipe syntax error in override_dh_auto_install
  fail closed when the manifest is missing
  harden the CLI and document the host-arch requirement

Not in this PR

  • On-target validation: installing the package on a device and confirming the
    module loads and functions (modprobe, autoload). Hardware validation, owned by
    the device team.

Notes

  • Target branch: qcom/debian/latest.
  • All commits are DCO signed off and single authored.

kgsl-dkms provides the KGSL GPU driver source and DKMS configuration.
Listing it as a Build-Depends makes dpkg-buildpackage install it into
the build environment before any debian/rules target runs, giving the
DKMS build step in override_dh_auto_install access to the source tree
at /usr/src/kgsl-<version>/.

dkms is the build-time tool that compiles the module. Neither package
appears in the binary package Depends/Recommends/Suggests — they are
consumed during the build and never reach the target device.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
…nux-image

Build the module from its installed -dkms source with `dkms build`, against
the kernel headers staged earlier in the same dpkg-buildpackage run, and
install the resulting .ko into linux-image under /lib/modules/<KVER>/extra/.

Use a private --dkmstree (mktemp) with a hand-created source symlink so the
build runs rootless under fakeroot without writing to the root-owned
/var/lib/dkms, and pass an absolute --kernelsourcedir via $(CURDIR) because
dkms invokes make from inside the module source directory.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
Add debian/dkms-modules, a plain-text list of modules to build and bundle,
and read it in debian/rules so the build loops over every listed module
instead of a single hardcoded block. Adding a module is then a one-line
manifest entry plus its Build-Depends, with no debian/rules change.

Comments (# to end of line), blank lines, and CR line endings are
stripped when the manifest is read, so an annotated or CRLF-edited
manifest cannot leak stray tokens into the module list.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
dkms build can complete without producing a module, for example when a
BUILD_EXCLUSIVE_* directive in the module's dkms.conf does not match
the target kernel, and the bundling loop would previously just bundle
nothing. A manifest entry is a presence contract: capture the built
.ko list and hard-fail when it is empty, instead of silently shipping
linux-image without a declared module.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
dkms --arch and dkms.conf BUILD_EXCLUSIVE_ARCH speak uname -m
vocabulary (aarch64), while the build passed a hardcoded kbuild-style
token (arm64). The mismatch is latent today only because kgsl declares
no BUILD_EXCLUSIVE_ARCH gate; a module that does would be wrongly
gated off by the arm64 token. Introduce DKMS_ARCH (aarch64) alongside
the kbuild ARCH variable and pass that instead.

Only the architecture label inside the private dkms tree changes; the
built .ko is found recursively under the kernel directory, so the
produced packages are identical.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
The DKMS-built .ko was installed into linux-image with `install -m 644`
and never stripped. dh_strip skips /lib/modules, and the module never
flows through `make modules_install`, which strips in-tree modules via
INSTALL_MOD_STRIP=1. So an unstripped ~2.8 MB module shipped on every
device, with its debug symbols baked in rather than separated out.

Give each bundled .ko the same two-stage treatment in-tree modules get:
capture its debug into the -dbg package's parallel debug tree with
objcopy --only-keep-debug (matching the in-tree modules.order loop), then
strip the shipped copy in place with strip --strip-debug. That is the
exact tool and flag modules_install INSTALL_MOD_STRIP=1 uses on in-tree
modules (the kernel's STRIP --strip-debug, plain strip on native arm64).

--strip-debug is required for kernel modules (a full strip drops the
symtab and relocations needed to load), and the strip must follow the
debug capture. Loadability is unaffected (depmod/modinfo data preserved).

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
Replace the dpkg-query version parse (cut -d- mishandles epochs and
hyphenated upstream versions) with resolution through the package
manager: dpkg -L <name>-dkms names the one /usr/src/<dir>/dkms.conf
the package ships (dh_dkms layout), so the source tree is found
without guessing and a look-alike directory from another package, for
example a future kgsl-extras-dkms next to kgsl-dkms, can never be
picked up. The dkms name/version tokens are then read from dkms.conf
(PACKAGE_NAME/PACKAGE_VERSION), which is what dkms itself keys its
tree layout and build on, so the manifest entry only needs to match
the package name, not the module's internal naming.

Guards fail the build when the package is missing, ships zero or
several dkms.conf files, lacks the name/version fields, or when two
manifest entries resolve to the same dkms module.

No change to the produced packages: for kgsl the resolved source dir,
tokens, and build call are identical.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
A missing module can be a failed build or a skipped one, and dkms
exit-code conventions are not a reliable discriminator (a
BUILD_EXCLUSIVE skip can exit 0, and conventions vary across dkms
versions). Worse, on a real compile failure dkms points at its
make.log inside the private dkms tree, which lives in an ephemeral
build environment: the actual compile error never reached the CI log.

Capture the dkms exit code and judge the outcome by artifacts:

  - a .ko under <tree>/<name>/<ver>/<kernel>/ means success;
  - otherwise, make.log present means a build was attempted and
    failed: print its tail inline (the only surviving record in CI),
    together with the exit code;
  - no make.log means dkms attempted no build: print the
    BUILD_EXCLUSIVE gates declared in the module's dkms.conf, evaluate
    each BUILD_EXCLUSIVE_CONFIG against the staged kernel config, and
    print the kernel release and dkms arch being built, so the
    unsatisfied gate is visible without reproducing the build;
  - call out compressed module output explicitly if that is what the
    build produced, since only plain .ko is bundled.

The build still hard-fails in every no-module case (a manifest entry
is a presence contract). The private dkms tree is now removed via an
EXIT trap, so failure paths no longer leak it.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
Two manifest entries emitting a .ko with the same basename would
silently overwrite each other in extra/, and a bundled module sharing
its name with an in-tree module would ship two copies of the same
module name in one package, leaving precedence on the target to
depmod search order. Fail the build loudly in both cases; neither is
a configuration this package should ship.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
…les.sh

Move the entire out-of-tree DKMS module integration block out of
override_dh_auto_install in debian/rules and into a dedicated, standalone
tool: debian/scripts/bundle-dkms-modules.sh.

Motivation
----------
The DKMS block in debian/rules had grown to ~120 lines of dense shell
embedded in Make recipe syntax. Keeping it there made debian/rules harder
to read, and any future DKMS-related change (new module type, signing,
compression support) required editing the build rules file directly.
Extracting the logic into a named tool with a documented CLI achieves three
goals simultaneously:

  1. Cleanliness — debian/rules is reduced to a single 7-line invocation
     with explicit, named parameters; the build rules file describes *what*
     happens, not *how* DKMS modules are built.

  2. Modularity — all DKMS logic lives in one place. Future changes
     (additional guards, new dkms.conf fields, signing hooks) touch only
     bundle-dkms-modules.sh, never debian/rules.

  3. Developer ergonomics — the script is independently invocable. A
     developer who has already staged the kernel trees can re-run just the
     DKMS bundling step without re-executing the full dpkg-buildpackage,
     passing the required paths explicitly via a documented CLI.

What the script does (unchanged from the original rules block)
--------------------------------------------------------------
For each module listed in debian/dkms-modules:

  - Resolves the installed -dkms package via 'dpkg -L' (authoritative;
    no /usr/src/ globbing; a look-alike from another package cannot be
    picked up).
  - Reads PACKAGE_NAME / PACKAGE_VERSION from the package's dkms.conf
    (the authority on the tokens that drive the dkms tree layout).
  - Builds with 'dkms build' against the staged kernel headers, using a
    private --dkmstree (mktemp -d) to avoid writing to the root-owned
    /var/lib/dkms/ under fakeroot.
  - Judges the outcome by .ko artifact presence, not dkms exit code
    (conventions vary across dkms versions; a BUILD_EXCLUSIVE skip can
    exit 0). On failure: prints make.log tail (compile error) or
    BUILD_EXCLUSIVE gate analysis with per-CONFIG_* kernel config
    evaluation (skip), then hard-fails — a manifest entry is a presence
    contract.
  - For each produced .ko: collision-checks against already-bundled
    modules (duplicate basename) and in-tree modules (depmod precedence
    ambiguity); installs to lib/modules/<kver>/extra/; extracts debug
    symbols via 'objcopy --only-keep-debug' into the -dbg staging tree;
    strips the shipped copy with 'strip --strip-debug' (not full strip:
    kernel modules require their symtab and relocations to be loadable
    by the module loader).

One intentional improvement over the original rules block: the .ko
install loop is rewritten from 'printf | while' (pipe subshell) to
'while < <(process substitution)', so 'exit 1' inside the collision
guards terminates the script directly rather than only the subshell.
Under 'set -e -o pipefail' both forms propagate failure, but the process
substitution form is unambiguous and does not rely on pipefail semantics.

CLI design
----------
Required parameters (must be passed explicitly; no defaults derivable
without Make context):

  --kver KVER               Kernel release string (uname -r)
  --headers-dir DIR         Absolute path to staged kernel headers root
                            (MUST be absolute: dkms cd's into the module
                            source dir before invoking make)
  --image-pkg-dir DIR       linux-image staging tree root
  --dbg-pkg-dir DIR         linux-image-dbg staging tree root

Optional parameters (have safe defaults matching the rules context):

  --modules-manifest FILE   Default: debian/dkms-modules (relative to
                            the script's own location)
  --arch ARCH               Default: aarch64 (uname -m vocabulary for
                            dkms --arch and BUILD_EXCLUSIVE_ARCH gates)
  --objcopy PATH            Default: aarch64-linux-gnu-objcopy -> objcopy
  -h, --help                Full usage with prerequisites and examples

debian/rules changes
--------------------
  - Add DKMS_ARCH ?= aarch64 Make variable (passed to script via --arch;
    kept in rules so it remains overridable at dpkg-buildpackage time via
    the standard Make variable override mechanism).
  - Replace the ~120-line DKMS shell block with a 7-line script
    invocation. All paths are passed as absolute via $(CURDIR) to satisfy
    the --headers-dir absoluteness requirement and to make the invocation
    self-documenting.
  - Remove the DKMS_MODULES Make variable (manifest is now read at
    runtime by the script; no Make-time evaluation needed).

New files
---------
  debian/scripts/bundle-dkms-modules.sh   standalone DKMS bundling tool
  debian/dkms-modules                     module manifest (kgsl)

Modified files
--------------
  debian/rules        DKMS_ARCH var + single script invocation
  debian/control.in   kgsl-dkms (>= 1.0.2), dkms in Build-Depends
  README.md           repo structure, file table, new DKMS bundling section

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
The DKMS extraction (14a1f96) left a stray "; \" line between the
vmlinux block's closing "fi; \" and the bundle-dkms-modules.sh
invocation. Under .ONESHELL (SHELL=/bin/bash, .SHELLFLAGS=-e -o
pipefail -c) the whole recipe is one spliced `bash -c`, so the
backslash-continuations collapse the region to "...fi; ; <script>",
an empty command between two ";" separators. bash rejects it with
"syntax error near unexpected token ';'", and the recipe aborts at
parse time before the DKMS script (or anything after the vmlinux
block) ever runs.

This is an unconditional build break: CI run 28134406848 failed at
"debian/rules:211: override_dh_auto_install" with exactly this error
after a full 12-minute kernel compile, and the .deb was never built.

Remove the stray separator; the preceding "fi; \" already terminates
the if-statement. Verified with a make .ONESHELL reproduction (errors
before, parses and reaches the script after) and bash -n on the
recipe.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
The manifest is a presence contract, but a missing or misdirected
--modules-manifest produced an empty module list, which the script
treated as "no modules" and exited 0 — silently shipping a kernel
without its declared out-of-tree modules. That is exactly the failure
the contract exists to prevent.

Check the manifest exists before parsing and hard-fail if it does not;
only an existing-but-empty (or comment-only) manifest is a legitimate
skip. This also removes the now-dead post-parse existence check and
drops the cd error-suppression in the path-to-absolute resolution
(the file is confirmed present first, so the cd cannot fail and a
mangled path can no longer slip through).

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
…uirement

For the standalone developer path the CLI was too permissive:

  - An unknown/misspelled option fell into usage(), which exits 0, so a
    typo'd flag looked like success. Report it on stderr and exit 1.
  - A value-taking flag given as the last argument tripped `set -u` with
    a raw "$2: unbound variable". Guard each with require_val so it fails
    with a clear "<flag> requires a value" message.

Also document two prerequisites that were implicit: module resolution
needs a Debian-family host with a dpkg database, and the script does not
cross-compile (dkms uses the host toolchain), so it must run on a native
arm64 host for the produced .ko to match the target kernel. --arch only
sets the dkms BUILD_EXCLUSIVE_ARCH label, not the compiler.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
@bjordiscollaku
Bjordis Collaku (bjordiscollaku) force-pushed the feat/dkms-build-time-module-integration branch from 1d842df to 916da65 Compare June 25, 2026 18:49
Bjordis Collaku (bjordiscollaku) added a commit that referenced this pull request Jul 8, 2026
The Debian Debusine build path now needs kgsl-dkms as a build dependency
(via PR #54 against qcom/debian/latest). The package is published in the
qli Debusine workspace, so the build step must expose qli as an extra
build-dependency source when invoking debusine-action/lib/build.

Set EXTRA_BUILD_DEP_WORKSPACES=qli in Build in Debusine and pass
DEBUSINE_USER, which lib/build currently requires to apply its
extra_repositories compatibility workaround.
Bjordis Collaku (bjordiscollaku) added a commit that referenced this pull request Jul 8, 2026
The Debian Debusine build path now needs kgsl-dkms as a build dependency
(via PR #54 against qcom/debian/latest). The package is published in the
qli Debusine workspace, so the build step must expose qli as an extra
build-dependency source when invoking debusine-action/lib/build.

Set EXTRA_BUILD_DEP_WORKSPACES=qli in Build in Debusine and pass
DEBUSINE_USER, which lib/build currently requires to apply its
extra_repositories compatibility workaround.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
@bjordiscollaku
Bjordis Collaku (bjordiscollaku) force-pushed the feat/dkms-build-time-module-integration branch from 9917688 to 916da65 Compare July 11, 2026 00:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant