diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 68a6ddf..343fd8e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -46,6 +46,11 @@ on: required: false default: false type: boolean + modules: + description: "Also build and archive lib/modules as modules-.tar.gz (when CONFIG_MODULES=y)." + required: false + default: false + type: boolean uimage_args: description: "mkimage/uImage flags passed to build.ts on arm64 (empty = skip uImage). Defaults reproduce the previous hardcoded values; override any --uimage-* flag here." required: false @@ -92,6 +97,7 @@ jobs: INPUT_CONFIG: ${{ github.event.inputs.config }} INPUT_DEFCONFIG: ${{ github.event.inputs.defconfig }} INPUT_INITRD: ${{ github.event.inputs.initrd }} + INPUT_MODULES: ${{ github.event.inputs.modules }} INPUT_UIMAGE_ARGS: ${{ github.event.inputs.uimage_args }} run: | REPO="${INPUT_REPO}" @@ -101,6 +107,7 @@ jobs: echo "MERGE_CONFIG=${INPUT_CONFIG}" >> "$GITHUB_ENV" echo "DEFCONFIG=${INPUT_DEFCONFIG}" >> "$GITHUB_ENV" echo "GEN_INITRD=${INPUT_INITRD}" >> "$GITHUB_ENV" + echo "GEN_MODULES=${INPUT_MODULES}" >> "$GITHUB_ENV" echo "UIMAGE_ARGS=${INPUT_UIMAGE_ARGS}" >> "$GITHUB_ENV" if [[ -n "$REPO" ]]; then @@ -144,6 +151,9 @@ jobs: if [[ "$GEN_INITRD" == "true" ]]; then EXTRA_ARGS+=(--initrd) fi + if [[ "$GEN_MODULES" == "true" ]]; then + EXTRA_ARGS+=(--modules) + fi # uImage generation is arm64-only; word-split the flag string. if [[ "$CPU_ARCH" == "aarch64" && -n "$UIMAGE_ARGS" ]]; then EXTRA_ARGS+=($UIMAGE_ARGS) @@ -192,3 +202,13 @@ jobs: path: | linux-stable/initrd.img-* linux-stable/uInitrd + + - name: Upload modules + if: github.event_name == 'workflow_dispatch' && env.GEN_MODULES == 'true' + uses: actions/upload-artifact@v4 + with: + name: modules-${{ env.VERSION }}.${{ env.CPU_ARCH }} + if-no-files-found: warn + path: | + linux-stable/modules-*.tar.gz + linux-stable/modules-*.tar.gz.sha256 diff --git a/build.ts b/build.ts index 603ad9e..9c458da 100755 --- a/build.ts +++ b/build.ts @@ -77,6 +77,9 @@ const rawArgs = Deno.args; // (e.g. .config or config-6.6.98-sun60iw2). // --initrd also generate an initrd (initrd.img) and, on arm64, // a U-Boot uInitrd alongside the kernel. +// --modules build the loadable modules and archive the staged +// lib/modules/ tree as modules-.tar.gz +// (no-op when the config has no CONFIG_MODULES=y). // --defconfig build a board/BSP kernel: run `make ` (e.g. // sun60iw2_defconfig) as the base config so the board's // essentials WIN, then layer our default config as a @@ -98,6 +101,7 @@ let versionLabel: string | undefined; let mergeConfigInput: string | undefined; let defconfigInput: string | undefined; let genInitrd = false; +let genModules = false; let genUimage = false; let uimageArch = "arm"; let uimageOs = "linux"; @@ -145,6 +149,8 @@ for (let i = 0; i < rawArgs.length; i++) { defconfigInput = takeValue("--defconfig"); } else if (arg === "--initrd") { genInitrd = true; + } else if (arg === "--modules") { + genModules = true; } else if (arg === "--uimage") { genUimage = true; } else if (arg === "--uimage-arch" || arg.startsWith("--uimage-arch=")) { @@ -610,4 +616,48 @@ if (!hasModules) { } } +// Optionally archive the loadable modules (lib/modules/) for the +// board rootfs. Modules aren't part of vmlinux/Image, so ship them separately. +if (genModules) { + const configText = await Deno.readTextFile(".config"); + const hasModules = configText.includes("CONFIG_MODULES=y"); + + if (!hasModules) { + console.log( + chalk.yellow("--modules requested but CONFIG_MODULES is not enabled; skipping.") + ); + } else { + console.log(chalk.magenta("Archiving lib/modules...")); + + const krel = await capture(["make", "-s", "kernelrelease"]); + + // Build + stage into modules-out/ (idempotent — a no-op if --initrd + // already staged them). Staged (not system) install needs no sudo. + await run(["make", "modules", `-j${nproc}`]); + await run(["make", "modules_install", `INSTALL_MOD_PATH=${cwd}/modules-out`]); + + // Archive the lib/modules/ subtree. The build/source symlinks in + // it point back into the tree; --dereference would pull the whole kernel + // tree in, so drop them instead. + const MODULES_TGZ = `modules-${krel}.tar.gz`; + await run([ + "tar", + "--exclude=build", + "--exclude=source", + "-czf", + MODULES_TGZ, + "-C", + "modules-out", + "lib/modules", + ]); + + const modSum = await capture(["sha256sum", MODULES_TGZ]); + await Deno.writeTextFile(`${MODULES_TGZ}.sha256`, `${modSum}\n`); + + console.log( + chalk.green(`modules archived: ${chalk.cyan(`${cwd}/${MODULES_TGZ}`)}`) + ); + } +} + Deno.exit(0);