Skip to content

Added make prepare before Phase 1 make modules#27

Merged
dianlight merged 8 commits into
mainfrom
opencode/issue26-20260616220319
Jun 18, 2026
Merged

Added make prepare before Phase 1 make modules#27
dianlight merged 8 commits into
mainfrom
opencode/issue26-20260616220319

Conversation

@opencode-agent

Copy link
Copy Markdown
Contributor

Fix applied: Added an explicit make prepare step before make modules in Phase 1 (base module build) of the workflow.

Analysis of the failure (workflow run #148):

  • All RPi-based boards (rpi3_64, rpi4_64, rpi5_64, yellow) failed at the "Build base modules" step
  • All other non-RPi boards succeeded
  • The RPi kernel fork at 6.18.33 (commit 95b85bebbedc) has different build infrastructure from mainline 6.18.35 used by other boards
  • Phase 2 already had an explicit make prepare call for ZFS compatibility, but Phase 1 was missing it

The fix adds make prepare before make modules in .github/workflows/main_build.yml:436-441, ensuring the kernel source tree generates all required build artifacts (utsrelease.h, autoconf.h, architecture-specific headers, etc.) before module compilation. This follows the same pattern already established in Phase 2 for ZFS module building.

Closes #26

New%20session%20-%202026-06-16T22%3A03%3A18.514Z
opencode session  |  github run

Co-authored-by: dianlight <dianlight@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown

User opencode-agent[bot] does not have write permissions

github run

@dianlight

Copy link
Copy Markdown
Owner

/oc I have still an error for rpi. See run #150. You can also try yourself until all is ok

Key changes:
- Phase 1: Use MODULE_CROSS_COMPILE (Buildroot toolchain) for both
  make modules_prepare and make modules, instead of mixing system
  and Buildroot toolchains
- Phase 2 QUIC: Add make modules_prepare before make modules after
  source patching
- Phase 2 ZFS: Resolve MODULE_CROSS_COMPILE earlier and use
  consistently throughout the step
- All phases: Use modules_prepare (which generates module.lds)
  instead of bare prepare for module build preparation
@opencode-agent

Copy link
Copy Markdown
Contributor Author

Pushed commit 54464c5 to the PR branch. Here's what changed and why:

Root cause analysis: Only RPi boards (rpi3_64, rpi4_64, rpi5_64, yellow) fail in Phase 1 "Build base modules" — all other arm64 boards succeed. The RPi kernel fork at 6.18.33 (vs mainline 6.18.35) has a different prepare target that builds VDSO via cross-compilation. The previous fix ran make prepare with the system cross compiler (aarch64-linux-gnu-) while make modules used the Buildroot cross compiler (aarch64-buildroot-linux-gnu-). This toolchain mismatch caused the VDSO build to fail on the RPi fork.

Changes made (.github/workflows/main_build.yml):

  1. Phase 1make preparemake modules_prepare with MODULE_CROSS_COMPILE (Buildroot toolchain), same as make modules
  2. Phase 2 QUIC — Added make modules_prepare after source patching, before make modules
  3. Phase 2 ZFS — Moved MODULE_CROSS_COMPILE resolution before make prepare; use it consistently for prepare, olddefconfig, modules_prepare, and modules

New%20session%20-%202026-06-17T20%3A36%3A32.410Z
opencode session  |  github run

@github-actions

Copy link
Copy Markdown

User opencode-agent[bot] does not have write permissions

github run

@opencode-agent

Copy link
Copy Markdown
Contributor Author

User opencode-agent[bot] does not have write permissions

github run

@github-actions

Copy link
Copy Markdown

PR Review: #27

Changes Summary

Adds make modules_prepare before make modules in all 3 phases (base, QUIC, ZFS) and switches ZFS from CROSS_COMPILE to MODULE_CROSS_COMPILE (Buildroot toolchain) for prepare and olddefconfig.


Code Quality Issues

  1. DRY violationMODULE_CROSS_COMPILE resolution block (the case "${ARCH}" + [[ -x ... ]] fallback) is copy-pasted 3 times (Phase 1 at line ~475, QUIC at line ~561, ZFS at line ~611). Extract to a composite action or set it as a job-level env once.

  2. Minor inconsistency — Phase 1 base modules lack KBUILD_MODPOST_WARN=1 while QUIC and ZFS have it. Pre-existing, but worth noting since it could cause CI divergence.


Potential Bugs

  1. No || true on modules_prepare — with set -euo pipefail, a failure on any board/arch kills the step. modules_prepare can fail on kernels with unusual build setups. Consider graceful handling.

  2. modules_prepare after make prepare in ZFS is redundantmake prepare is a superset of modules_prepare. Not a bug, but unnecessary work. You could drop the second modules_prepare in the ZFS phase since prepare already ran. (Though it's harmless — it'll be a no-op.)


Suggestions

  1. De-duplicate toolchain resolution — add a setup step like:

    - name: Resolve Buildroot cross-compiler
      run: |
        case "${ARCH}" in
          arm64) echo "MODULE_CROSS_COMPILE=${OS_DIR}/output/host/bin/aarch64-buildroot-linux-gnu-" >> $GITHUB_ENV ;;
          x86)   echo "MODULE_CROSS_COMPILE=${OS_DIR}/output/host/bin/x86_64-buildroot-linux-gnu-" >> $GITHUB_ENV ;;
          *)     echo "MODULE_CROSS_COMPILE=${CROSS_COMPILE}" >> $GITHUB_ENV ;;
        esac
        [[ -x "${MODULE_CROSS_COMPILE}gcc" ]] || echo "MODULE_CROSS_COMPILE=${CROSS_COMPILE}" >> $GITHUB_ENV
  2. In ZFS, drop the second modules_preparemake prepare at line ~621 already generates all module build artifacts. The modules_prepare at line ~683 is a no-op after prepare.

  3. Consider make scripts instead of modules_preparemodules_prepare runs make scripts + generates Module.symvers. If you've already run make prepare, make scripts alone is sufficient and faster.


Verdict

The changes are correct and address the root cause (cross-compiler mismatch on RPi's 6.18.33 fork). The core fix — using the Buildroot MODULE_CROSS_COMPILE consistently for all make targets — is sound. The additions of modules_prepare are correct in spirit (Phase 1 and QUIC) though slightly redundant in ZFS.

Approved with suggestions above for follow-up cleanup.

New%20session%20-%202026-06-18T13%3A22%3A38.521Z
opencode session  |  github run

@github-actions

Copy link
Copy Markdown

🛠️ [QUALITY] DRY violation — Cross-compiler resolution block copy-pasted 3 times

The MODULE_CROSS_COMPILE resolution logic (OS_DIR=... + case "${ARCH}" + [[ -x ... ]] fallback) is duplicated verbatim at:

  • Phase 1 (line 474-484)
  • Phase 2 QUIC (line 561-567)
  • Phase 2 ZFS (line 611-617)

If the path, architecture list, or fallback logic changes, all three must be updated in lockstep. Extract this into a job-level step or a composite action once, and export MODULE_CROSS_COMPILE to $GITHUB_ENV.

# Add as a dedicated step before the first build step
- name: Resolve Buildroot cross-compiler
  run: |
    OS_DIR="${GITHUB_WORKSPACE}/operating-system"
    case "${ARCH}" in
      arm64) MCC="${OS_DIR}/output/host/bin/aarch64-buildroot-linux-gnu-" ;;
      x86)   MCC="${OS_DIR}/output/host/bin/x86_64-buildroot-linux-gnu-" ;;
      *)     MCC="${CROSS_COMPILE}" ;;
    esac
    [[ -x "${MCC}gcc" ]] || MCC="${CROSS_COMPILE}"
    echo "MODULE_CROSS_COMPILE=${MCC}" >> "$GITHUB_ENV"

Then remove the three inline blocks and reference ${{ env.MODULE_CROSS_COMPILE }} or $MODULE_CROSS_COMPILE directly.


🛠️ [QUALITY] modules_prepare after prepare in ZFS phase is a no-op

At line 620-625 you run make prepare, which is a superset of modules_prepare (it generates all the same headers + basic kernel build artifacts). The modules_prepare at line 683-688 does nothing after prepare — the kernel build system detects it's already done and returns immediately. While harmless, it adds ~4 seconds of unnecessary output and could confuse future readers. Either drop it (since prepare already ran), or drop the earlier prepare if only module artifacts are needed.


🚨 [CRITICAL] set -euo pipefail without fallback on modules_prepare

All three modules_prepare invocations (lines 487, 570, 684) run under set -euo pipefail. If modules_prepare fails on an exotic kernel fork (e.g., an RPi variant with incomplete Kbuild), it will abort the entire step, including for other architectures in a matrix that would have succeeded. Consider adding || true with a diagnostic, or wrapping it:

echo "[INFO] Running 'make modules_prepare' ..."
make -C "${LINUX_SRC}" \
  ARCH="${ARCH}" \
  CROSS_COMPILE="${MODULE_CROSS_COMPILE}" \
  modules_prepare \
  2>&1 | tail -60 || echo "[WARN] modules_prepare exited non-zero, continuing"

This is the pattern already implied by | tail -XX (pipe absorbs non-zero exit) — but since set -o pipefail is active, a make failure still propagates.


💡 [NITPICK] Minor: extra blank line inconsistency between Phase 1 and Phase 2

Phase 1 has a blank line before the echo "[INFO] Building..." comment (line 493), but the QUIC phase does not (line 576 directly follows 2>&1 | tail -60). Add a blank line before line 576 for visual consistency with the other two phases.


Summary: The core fix (using MODULE_CROSS_COMPILE with Buildroot toolchain for all make targets in ZFS, and adding modules_prepare to Phase 1 and QUIC) is correct and targets the root cause. The main improvement is de-duplicating the toolchain resolution, which is a safety issue for future maintenance.

New%20session%20-%202026-06-18T13%3A33%3A33.861Z
opencode session  |  github run

dianlight and others added 2 commits June 18, 2026 16:10
Why this change was needed:
The previous dedup step removed rp1-cfe/ and patched the parent Makefile,
but left the parent Kconfig untouched. olddefconfig parses Kconfig files
before any compilation starts, so it died with "can't open file
rp1-cfe/Kconfig" on all three RPi boards (rpi3_64, rpi4_64, rpi5_64).

What changed:
Added sed -i '/rp1-cfe/d' on the parent Kconfig alongside the existing
Makefile patch, and updated the log message accordingly.

Problem solved:
All RPi board builds no longer fail with "can't open file" during
olddefconfig when both rp1-cfe/ and rp1_cfe/ co-exist in the kernel tree.

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Here is my review of the PR changes across the three phases in .github/workflows/main_build.yml.


🛠️ [QUALITY] DRY violation — Cross-compiler resolution block copy-pasted 3 times

The MODULE_CROSS_COMPILE resolution logic (OS_DIR=... + case "${ARCH}" + [[ -x ... ]] fallback) is duplicated verbatim at:

  • Phase 1 (lines 514–523)
  • Phase 2 QUIC (lines 600–606)
  • Phase 2 ZFS (lines 649–656)

If the path, arch list, or fallback logic ever changes, all three must be updated in lockstep. Extract once into a dedicated step and export to $GITHUB_ENV:

      # ─────────────────────────────────────────────────────────────────────
      # Resolve Buildroot cross-compiler once for all build phases
      # ─────────────────────────────────────────────────────────────────────
      - name: Resolve Buildroot cross-compiler
        if: steps.precheck.outputs.should_build == 'true'
        env:
          ARCH: ${{ steps.arch.outputs.ARCH }}
          CROSS_COMPILE: ${{ steps.arch.outputs.CROSS_COMPILE }}
        run: |
          OS_DIR="${GITHUB_WORKSPACE}/operating-system"
          case "${ARCH}" in
            arm64) MCC="${OS_DIR}/output/host/bin/aarch64-buildroot-linux-gnu-" ;;
            x86)   MCC="${OS_DIR}/output/host/bin/x86_64-buildroot-linux-gnu-" ;;
            *)     MCC="${CROSS_COMPILE}" ;;
          esac
          [[ -x "${MCC}gcc" ]] || MCC="${CROSS_COMPILE}"
          echo "MODULE_CROSS_COMPILE=${MCC}" >> "$GITHUB_ENV"

Then remove the three inline resolution blocks and replace them with a plain echo "[INFO] Module build CROSS_COMPILE=${MODULE_CROSS_COMPILE}" (the env var is already available from the job environment).


🛠️ [QUALITY] modules_prepare after prepare in ZFS phase is a superset no-op

At line 659–664 you run make prepare, which is a superset of modules_prepare (it generates all the same headers, autoconf.h, utsrelease.h, plus arch-specific build artifacts). The second modules_prepare at lines 722–727 does nothing — the kernel build system detects everything is up to date and returns immediately. Drop it (it is ~4 seconds of unnecessary noise per ZFS build):


          make -C "${LINUX_SRC}" \
            ARCH="${ARCH}" \
            CROSS_COMPILE="${MODULE_CROSS_COMPILE}" \
            olddefconfig \
            2>&1 | tail -30

          echo "[INFO] Building ZFS kernel modules ..."
          make -C "${LINUX_SRC}" \
            ARCH="${ARCH}" \
            KBUILD_MODPOST_WARN=1 \
            CROSS_COMPILE="${MODULE_CROSS_COMPILE}" \
            modules \
            2>&1 | tail -100

          echo "[INFO] ZFS module built successfully."

(Alternatively, keep modules_prepare and drop the earlier prepare if ZFS configure only needs module-level headers. The PR description says ZFS configure needs utsrelease.h from make prepare, so keep prepare and drop modules_prepare.)


🚨 [CRITICAL] set -euo pipefail with no fallback on modules_prepare

All three modules_prepare invocations (lines 525–530, 608–613, 722–727) run under set -euo pipefail. If modules_prepare fails on an exotic kernel fork (e.g., a future RPi variant with incomplete Kbuild), it aborts the entire step for that board. The | tail -60 does not absorb failure because set -o pipefail propagates the make exit code.

Add a diagnostic fallback to continue when modules_prepare fails (the modules build will fail independently with a clearer error if headers are genuinely missing):

          echo "[INFO] Running 'make modules_prepare' for kernel module build ..."
          make -C "${LINUX_SRC}" \
            ARCH="${ARCH}" \
            CROSS_COMPILE="${MODULE_CROSS_COMPILE}" \
            modules_prepare \
            2>&1 | tail -60 || echo "[WARN] modules_prepare exited non-zero, continuing"

Apply the same pattern to the QUIC (line 608–613) and ZFS (line 722–727) phases.


💡 [NITPICK] Inconsistent fallback style for [[ -x ... ]] check

Phase 1 (lines 520–522) uses an if block, while QUIC (line 606) and ZFS (line 656) use || short-circuit. They are functionally identical but look different. Standardize on the shorter || form (or if form) across all three for consistency.


💡 [NITPICK] Missing blank line before QUIC echo

Phase 1 (line 525) and ZFS (line 659) have a blank line before the echo "[INFO] Running ...", but QUIC (line 608) does not. Add one for visual consistency:


          echo "[INFO] Running 'make modules_prepare' for QUIC module build ..."

Summary: The core fix — using the Buildroot MODULE_CROSS_COMPILE consistently for all make targets across all three phases — is correct and directly addresses the RPi toolchain mismatch. The three suggestions above are non-blocking refinements (DRY extraction, removing the redundant modules_prepare in ZFS, and hardening modules_prepare against set -e failures).

New%20session%20-%202026-06-18T14%3A25%3A44.503Z
opencode session  |  github run

dianlight and others added 2 commits June 18, 2026 16:27
Why this change was needed:
The heredoc pattern used to capture github.event.pull_request.body placed
a ${{ }} expression and the PR_BODY_EOF delimiter at column 0 inside the
run: | block. YAML block scalars terminate at any line with lower
indentation than the block content, so the parser saw those lines as
outside the scalar and raised a syntax error on line 81.

What changed:
PR_BODY is now declared in the step's env: map as
  PR_BODY: ${{ github.event.pull_request.body }}
and the run: script reads it directly from the environment variable.
The heredoc and its delimiters are gone entirely.

Problem solved:
The workflow file is valid YAML again. GitHub Actions safely handles
multi-line PR body values (newlines, special chars) through env vars
without any YAML quoting issues.

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Here is my review of the PR changes across .github/workflows/main_build.yml.


🛠️ [QUALITY] Cross-compiler resolution block copy-pasted 3 times

The MODULE_CROSS_COMPILE resolution logic is duplicated verbatim at:

  • Phase 1 (lines 514–523)
  • Phase 2 QUIC (lines 601–607)
  • Phase 2 ZFS (lines 650–657)

If the path, arch list, or fallback logic changes, all three must be updated in lockstep. Extract this once into a dedicated step before Phase 1 and export to $GITHUB_ENV. Then replace the three inline blocks with a simple echo that references the already-set env var.

      # ─────────────────────────────────────────────────────────────────────
      # Resolve Buildroot cross-compiler (shared by all build phases)
      # ─────────────────────────────────────────────────────────────────────
      - name: Resolve Buildroot cross-compiler
        if: steps.precheck.outputs.should_build == 'true'
        env:
          ARCH: ${{ steps.arch.outputs.ARCH }}
          CROSS_COMPILE: ${{ steps.arch.outputs.CROSS_COMPILE }}
        run: |
          OS_DIR="${GITHUB_WORKSPACE}/operating-system"
          case "${ARCH}" in
            arm64) MCC="${OS_DIR}/output/host/bin/aarch64-buildroot-linux-gnu-" ;;
            x86)   MCC="${OS_DIR}/output/host/bin/x86_64-buildroot-linux-gnu-" ;;
            *)     MCC="${CROSS_COMPILE}" ;;
          esac
          [[ -x "${MCC}gcc" ]] || MCC="${CROSS_COMPILE}"
          echo "MODULE_CROSS_COMPILE=${MCC}" >> "$GITHUB_ENV"
          echo "[INFO] Module build CROSS_COMPILE=${MCC}"

      # ─────────────────────────────────────────────────────────────────────
      # Phase 1: Build base modules (no kernel source patching required)
      # ─────────────────────────────────────────────────────────────────────
      - name: Build base modules (xfs, nfsd, nfs)
        if: steps.precheck.outputs.should_build == 'true'
        env:
          ARCH: ${{ steps.arch.outputs.ARCH }}
          CROSS_COMPILE: ${{ steps.arch.outputs.CROSS_COMPILE }}
        run: |
          set -euo pipefail
          # ... (same logic up to olddefconfig) ...

          echo "[INFO] Module build CROSS_COMPILE=${MODULE_CROSS_COMPILE}"

          echo "[INFO] Running 'make modules_prepare' for kernel module build ..."
          make -C "${LINUX_SRC}" \
            ARCH="${ARCH}" \
            CROSS_COMPILE="${MODULE_CROSS_COMPILE}" \
            modules_prepare \
            2>&1 | tail -60
          # ... rest of Phase 1 ...

Then remove the three inline resolution blocks (lines 514–523, 601–607, 650–657) and replace them with just echo "[INFO] Module build CROSS_COMPILE=${MODULE_CROSS_COMPILE}".


💡 [NITPICK] Inconsistent fallback style for toolchain check

Phase 1 (lines 521–523) uses an if block, while QUIC (line 607) and ZFS (line 657) use || short-circuit. Functionally identical but inconsistent when reading across phases. Standardize on the terser || form:

          [[ -x "${MODULE_CROSS_COMPILE}gcc" ]] || MODULE_CROSS_COMPILE="${CROSS_COMPILE}"

Apply to lines 521–523 in Phase 1.


💡 [NITPICK] Missing blank line before QUIC modules_prepare echo

Phase 1 (line 526) and ZFS (line 723) have a blank line before the echo "[INFO] Running 'make modules_prepare'...", but the QUIC section (line 609) does not.


          echo "[INFO] Running 'make modules_prepare' for QUIC module build ..."

Insert a blank line before line 609 for visual consistency.


Summary: The core fix — consistently using the Buildroot MODULE_CROSS_COMPILE across all make targets in all three phases — is correct and directly addresses the RPi toolchain mismatch that caused the VDSO build failure. The three items above are non-blocking follow-up refinements.

New%20session%20-%202026-06-18T14%3A30%3A28.247Z
opencode session  |  github run

@dianlight dianlight merged commit 484932e into main Jun 18, 2026
9 checks passed
@dianlight dianlight deleted the opencode/issue26-20260616220319 branch June 18, 2026 18:52
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.

RPi kernel issue on 18-rc

1 participant