diff --git a/README.md b/README.md index 9346dde..ac57987 100644 --- a/README.md +++ b/README.md @@ -440,7 +440,7 @@ this fixed order: |------|--------|-------------| | 1 | `make defconfig` | ARM64 base defconfig from kernel source | | 2 | `debian/rules` | Disable `CONFIG_LOCALVERSION_AUTO` (prevents git hash in `uname -r`) | -| 3 | Unified fragment pipeline | `arch/arm64/configs/qcom.config` (if present), then `debian/config/*.config` (sorted) | +| 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` | @@ -449,12 +449,17 @@ this fixed order: All config fragments are processed through a single unified pipeline: 1. Collect fragments in order: - - `arch/arm64/configs/qcom.config` first (kernel-source fragment, present in `qcom-next`) + - `arch/arm64/configs/prune.config` first (kernel-source fragment) + - then `arch/arm64/configs/qcom.config` (kernel-source fragment, present in + `qcom-next`), so it wins over anything `prune.config` turned off - then `debian/config/*.config` in sorted filename order -2. Append all collected fragments to `.config` +2. Merge all collected fragments into `.config` in one + `scripts/kconfig/merge_config.sh -m -r` invocation — later fragments override + earlier ones, and every override is reported 3. Run `make olddefconfig` once to resolve all conflicts and fill in dependencies -`qcom.config` and `debian/config/*.config` use exactly the same mechanism. +`prune.config`, `qcom.config` and `debian/config/*.config` use exactly the same +mechanism. ### `debian/config/` — always-applied fragments @@ -499,18 +504,26 @@ verbatim so drift is a plain diff; only the SPDX header is added locally. | `usb-can.config` | slcan, gs_usb, peak_usb | USB CAN adapter demos/testing | **In-tree fragments.** `--kernel-config` carries fragments applied *in addition* -to the set above. Today that means fragments shipped by the kernel source under -`arch/arm64/configs/`, referenced with an `intree:` prefix rather than copied -into this repository so they stay versioned with the kernel they target: +to the set above. Today that means fragments shipped by the kernel source, +referenced with an `intree:` prefix rather than copied into this repository so +they stay versioned with the kernel they target: ``` ---kernel-config intree:qcom_debug +--kernel-config intree:arch/arm64/configs/qcom_debug.config,intree:kernel/configs/debug.config ``` -`intree:` resolves to `arch/arm64/configs/.config`. A bare name is -still accepted for compatibility but is redundant, since that fragment is -already applied. An in-tree fragment sharing a filename with a packaging -fragment is rejected rather than silently overwriting it. +`intree:` names a file relative to the kernel source root, so any +directory in the tree can be used, not just `arch/arm64/configs/`. The path must +end in `.config`, and an absolute path or one containing `..` is rejected. The +fragment is copied into `debian/config/` under its basename, so two entries +resolving to the same filename — whether two in-tree paths +(`arch/arm64/configs/hardening.config` and `kernel/configs/hardening.config`) or +an in-tree path and a packaging fragment — are rejected rather than one silently +overwriting the other. + +A bare name (no `intree:` prefix) is still accepted for compatibility but is +redundant, since every fragment in `debian/config-available/` is already +applied. **Activating via `build-kernel.sh`:** diff --git a/build-kernel.sh b/build-kernel.sh index 70d9b8f..8fd946a 100755 --- a/build-kernel.sh +++ b/build-kernel.sh @@ -53,8 +53,8 @@ OPTIONS: --profiles PROFILES DEB_BUILD_PROFILES (e.g. debug) --kernel-config LIST Extra config fragments, beyond debian/config-available/ which is always applied in full. An "intree:" prefix - resolves to arch/arm64/configs/.config in the - kernel source (e.g. intree:qcom_debug) + names a path relative to the kernel source root + (e.g. intree:arch/arm64/configs/qcom_debug.config) Paths: -k, --kernel-dir DIR Kernel source directory (default: $KERNEL_DIR) diff --git a/debian/rules b/debian/rules index 7d98654..6b4ab45 100755 --- a/debian/rules +++ b/debian/rules @@ -168,14 +168,16 @@ override_dh_auto_configure: # 1. ARM64 base defconfig # 2. Disable CONFIG_LOCALVERSION_AUTO (must happen before any merges) # 3. Config fragments applied in a single unified pipeline: - # a. arch/arm64/configs/qcom.config (kernel-source, always applied if present) - # b. arch/arm64/configs/prune.config (kernel-source, always applied if present) + # a. arch/arm64/configs/prune.config (kernel-source, always applied if present) + # b. arch/arm64/configs/qcom.config (kernel-source, always applied if present) # c. debian/config/*.config (packaging fragments) # Populated by prepare-source.sh: every fragment in # debian/config-available/, plus any intree: fragments named in # --kernel-config. Applied in LC_ALL=C filename order so the # result does not depend on the builder's locale. - # All fragments: append to .config + make olddefconfig. + # All fragments are merged in one scripts/kconfig/merge_config.sh -m -r + # 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 # --------------------------------------------------------------------------- @@ -198,18 +200,18 @@ override_dh_auto_configure: # Step 3: Unified config fragment pipeline. @CONFIG_FILE="$(if $(BUILD_OBJ),$(BUILD_OBJ)/).config"; \ FRAGMENTS=""; \ - if [ -f arch/arm64/configs/qcom.config ]; then \ - echo "Found kernel-source fragment: arch/arm64/configs/qcom.config"; \ - FRAGMENTS="arch/arm64/configs/qcom.config"; \ - else \ - echo "Note: arch/arm64/configs/qcom.config not found (not a qcom-next tree?)"; \ - fi; \ if [ -f arch/arm64/configs/prune.config ]; then \ echo "Found kernel-source fragment: arch/arm64/configs/prune.config"; \ - FRAGMENTS="$$FRAGMENTS arch/arm64/configs/prune.config"; \ + FRAGMENTS="arch/arm64/configs/prune.config"; \ else \ echo "Note: arch/arm64/configs/prune.config not found (skipping)"; \ fi; \ + if [ -f arch/arm64/configs/qcom.config ]; then \ + echo "Found kernel-source fragment: arch/arm64/configs/qcom.config"; \ + FRAGMENTS="$$FRAGMENTS arch/arm64/configs/qcom.config"; \ + else \ + echo "Note: arch/arm64/configs/qcom.config not found (not a qcom-next tree?)"; \ + fi; \ if [ -d debian/config ] && ls debian/config/*.config >/dev/null 2>&1; then \ for f in $$(ls debian/config/*.config | LC_ALL=C sort); do \ echo "Found packaging fragment: $$f"; \ @@ -219,10 +221,14 @@ override_dh_auto_configure: echo "Note: no packaging fragments in debian/config/ (none activated via --kernel-config)"; \ fi; \ if [ -n "$$FRAGMENTS" ]; then \ - for frag in $$FRAGMENTS; do \ - echo "Applying config fragment: $$frag"; \ - cat "$$frag" >> "$$CONFIG_FILE"; \ - done; \ + [ -x scripts/kconfig/merge_config.sh ] || { \ + echo "ERROR: scripts/kconfig/merge_config.sh not found or not executable"; \ + exit 1; \ + }; \ + echo "Merging config fragments into $$CONFIG_FILE:$$FRAGMENTS"; \ + ARCH=$(ARCH) scripts/kconfig/merge_config.sh -m -r \ + $(if $(BUILD_OBJ),-O $(BUILD_OBJ)) \ + "$$CONFIG_FILE" $$FRAGMENTS; \ echo "Running olddefconfig to resolve all fragment conflicts..."; \ $(MAKE) $(KBUILD_O_ARG) ARCH=$(ARCH) olddefconfig; \ else \ diff --git a/prepare-source.sh b/prepare-source.sh index 6908768..886e6d8 100755 --- a/prepare-source.sh +++ b/prepare-source.sh @@ -65,11 +65,13 @@ OPTIONS: --kernel-config LIST Comma-separated fragments to apply in addition to debian/config-available/, every entry of which is applied to every build regardless of this option. - An "intree:" prefix resolves to - arch/arm64/configs/.config in the kernel - source, for fragments that ship with the kernel - and are versioned with it - (e.g. intree:qcom_debug). + An "intree:" prefix names a path relative to the + kernel source root, for fragments that ship with + the kernel and are versioned with it + (e.g. intree:arch/arm64/configs/qcom_debug.config + or intree:kernel/configs/debug.config). The path + must end in .config; absolute paths and ".." are + rejected. A bare name is accepted for compatibility but is redundant, since that fragment is already applied. Entries are processed in LC_ALL=C sorted order. @@ -208,7 +210,6 @@ log_info "Copied $ACTUAL_DEBIAN_DIR -> $SOURCE_DIR/debian" # has already been applied. ACTIVE_DIR="$SOURCE_DIR/debian/config" AVAIL_DIR="$SOURCE_DIR/debian/config-available" -INTREE_DIR="$SOURCE_DIR/arch/arm64/configs" mkdir -p "$ACTIVE_DIR" log_step "Applying all packaging fragments from debian/config-available/" @@ -233,22 +234,45 @@ if [[ -n "$KERNEL_CONFIG" ]]; then if [[ "$cfg" == intree:* ]]; then # In-tree fragment, shipped by the kernel source rather than by this # repository. Referenced instead of vendored so it stays versioned - # with the kernel it targets. - frag="${cfg#intree:}" - frag="${frag%.config}.config" - src="$INTREE_DIR/$frag" + # with the kernel it targets. The entry spells the whole path + # relative to the kernel source root, so fragments outside + # arch/arm64/configs/ are reachable too (kernel/configs/debug.config). + path="${cfg#intree:}" + case "$path" in + "" | /* | ".." | "../"* | *"/../"* | *"/..") + log_error "Invalid in-tree fragment: ${cfg}" + log_error "Expected a path relative to the kernel source root, e.g. intree:arch/arm64/configs/qcom_debug.config" + exit 1 + ;; + esac + # debian/rules globs debian/config/*.config, so a fragment named + # anything else would be copied in and then silently ignored. + [[ "$path" == *.config ]] || { + log_error "In-tree fragment must name a .config file: $cfg" + log_error "Spell the whole path, e.g. intree:arch/arm64/configs/qcom_debug.config" + exit 1 + } + src="$SOURCE_DIR/$path" + frag="$(basename "$path")" + dir="$(dirname "$path")" [[ -f "$src" ]] || { - log_error "In-tree fragment not found: arch/arm64/configs/$frag" - log_error "Available: $(ls "$INTREE_DIR"/*.config 2>/dev/null | xargs -n1 basename | tr '\n' ' ')" + log_error "In-tree fragment not found: $path" + log_error "Paths are relative to the kernel source root ($SOURCE_DIR)." + avail="$(ls "$SOURCE_DIR/$dir"/*.config 2>/dev/null | xargs -n1 basename | tr '\n' ' ')" + [[ -n "$avail" ]] && log_error "Available in $dir/: $avail" exit 1 } + # The fragment keeps only its basename in debian/config/, so two + # in-tree paths can collide with each other as well as with a + # packaging fragment (kernel/configs/hardening.config and + # arch/arm64/configs/hardening.config both exist). [[ -e "$ACTIVE_DIR/$frag" ]] && { log_error "Fragment name collision in debian/config/: $frag" - log_error "An in-tree fragment must not share a filename with a packaging fragment." + log_error "An in-tree fragment must not share a filename with an already applied fragment." exit 1 } cp "$src" "$ACTIVE_DIR/$frag" - log_info " Applied: $frag (from arch/arm64/configs)" + log_info " Applied: $frag (from $dir)" else frag="${cfg%.config}.config" [[ -f "$AVAIL_DIR/$frag" ]] || {