Yocto Kernel Configuration - Part 4: Advanced Management and Automation

This is the final part of our Yocto kernel configuration series. In this article, we’ll cover advanced techniques for automating configuration management, validation, and troubleshooting.

Overview

In this part, you’ll learn how to:

  • Automate patch generation with scripts
  • Validate configurations automatically
  • Create testing workflows for multiple machines
  • Troubleshoot common issues effectively
  • Set up CI/CD integration for configuration changes

Prerequisites

Before starting this part, make sure you’ve completed:

  • Part 1: Getting Started with Devshell
  • Part 2: Machine-Specific defconfig and bbappend
  • Part 3: Git Patches and Version Control
  • You understand shell scripting basics

Automated Patch Generation

Script 1: Automated Configuration Patch Generator

#!/bin/bash
# save as: generate-config-patch.sh
 
set -e
 
SCRIPT_NAME=$(basename "$0")
KERNEL_DIR="$1"
CONFIG_NAME="$2"
PATCH_DIR="$3"
 
usage() {
    echo "Usage: $SCRIPT_NAME <kernel_dir> <config_name> <patch_dir>"
    echo "Example: $SCRIPT_NAME ~/linux-variscite-work tof-camera ~/patches"
    echo ""
    echo "This script will:"
    echo "1. Set up cross-compilation environment"
    echo "2. Run menuconfig for interactive configuration"
    echo "3. Generate defconfig and create git patch"
    echo "4. Validate patch format and application"
    exit 1
}
 
if [ $# -ne 3 ]; then
    usage
fi
 
if [ ! -d "$KERNEL_DIR" ]; then
    echo "Error: Kernel directory '$KERNEL_DIR' does not exist"
    exit 1
fi
 
cd "$KERNEL_DIR"
 
# Set up environment
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
 
echo "=== Automated Kernel Configuration Patch Generator ==="
echo "Kernel directory: $KERNEL_DIR"
echo "Configuration name: $CONFIG_NAME"
echo "Patch output directory: $PATCH_DIR"
echo ""
 
# Ensure git is initialized
if [ ! -d ".git" ]; then
    echo "Initializing git repository..."
    git init
    git add .
    git commit -m "Initial kernel source"
fi
 
# Start with base configuration
echo "Loading base configuration..."
make imx8mp_var_defconfig
make olddefconfig
 
echo "Starting interactive configuration..."
echo "Configure your kernel options and save when done."
read -p "Press Enter to continue to menuconfig..."
make menuconfig
 
# Generate defconfig and patch
echo "Generating defconfig..."
make savedefconfig
cp defconfig arch/arm64/configs/imx8mp_var_defconfig
 
# Create git commit
git add arch/arm64/configs/imx8mp_var_defconfig
git commit -m "arm64: defconfig: Enable $CONFIG_NAME support
 
Automatically generated configuration patch for $CONFIG_NAME
 
Signed-off-by: $(git config user.name) <$(git config user.email)>"
 
# Generate patch
mkdir -p "$PATCH_DIR"
git format-patch -1 HEAD --output-directory="$PATCH_DIR"
 
# Validate patch
PATCH_FILE=$(ls "$PATCH_DIR"/*.patch | tail -1)
echo "Validating patch: $PATCH_FILE"
git apply --check "$PATCH_FILE"
 
echo "✅ Patch generated successfully: $PATCH_FILE"
echo "✅ Patch validation passed"

Script 2: Configuration Validation Script

#!/bin/bash
# save as: validate-config-patch.sh
 
PATCH_FILE="$1"
KERNEL_DIR="$2"
 
usage() {
    echo "Usage: $0 <patch_file> <kernel_dir>"
    echo "Example: $0 patches/0001-*.patch ~/linux-variscite-work"
    exit 1
}
 
if [ $# -ne 2 ]; then
    usage
fi
 
if [ ! -f "$PATCH_FILE" ]; then
    echo "Error: Patch file '$PATCH_FILE' not found"
    exit 1
fi
 
if [ ! -d "$KERNEL_DIR" ]; then
    echo "Error: Kernel directory '$KERNEL_DIR' not found"
    exit 1
fi
 
cd "$KERNEL_DIR"
 
echo "=== Configuration Patch Validator ==="
echo "Patch file: $PATCH_FILE"
echo "Kernel directory: $KERNEL_DIR"
echo ""
 
# Test patch application
echo "Testing patch application..."
git apply --check "$PATCH_FILE"
if [ $? -eq 0 ]; then
    echo "✅ Patch applies cleanly"
else
    echo "❌ Patch application failed"
    exit 1
fi
 
# Apply patch temporarily
echo "Applying patch temporarily..."
git stash push -m "Backup before patch test"
git apply "$PATCH_FILE"
 
# Test configuration build
echo "Testing configuration build..."
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
make olddefconfig
 
if [ $? -eq 0 ]; then
    echo "✅ Configuration builds successfully"
else
    echo "❌ Configuration build failed"
    git stash pop
    exit 1
fi
 
# Restore original state
git stash pop
 
echo "✅ Patch validation successful"

Multi-Machine Testing Automation

Script 3: Multi-Machine Build Tester

#!/bin/bash
# save as: test-multi-machine.sh
 
YOCTO_BUILD_DIR="$1"
shift
MACHINES=("$@")
 
usage() {
    echo "Usage: $0 <yocto_build_dir> <machine1> [machine2] [machine3]..."
    echo "Example: $0 ~/yocto-build imx8mp-var-som-dev imx8mp-var-som-prod"
    exit 1
}
 
if [ $# -lt 2 ]; then
    usage
fi
 
if [ ! -d "$YOCTO_BUILD_DIR" ]; then
    echo "Error: Yocto build directory '$YOCTO_BUILD_DIR' not found"
    exit 1
fi
 
cd "$YOCTO_BUILD_DIR"
source oe-init-build-env
 
echo "=== Multi-Machine Kernel Configuration Tester ==="
echo "Build directory: $YOCTO_BUILD_DIR"
echo "Machines to test: ${MACHINES[*]}"
echo ""
 
RESULTS=()
 
for machine in "${MACHINES[@]}"; do
    echo "========================================="
    echo "Testing machine: $machine"
    echo "========================================="
    
    # Set machine
    export MACHINE=$machine
    
    # Clean and build
    echo "Cleaning previous build..."
    bitbake -c cleansstate linux-variscite
    
    echo "Building kernel for $machine..."
    START_TIME=$(date +%s)
    
    if bitbake linux-variscite; then
        END_TIME=$(date +%s)
        DURATION=$((END_TIME - START_TIME))
        echo "✅ $machine: Build successful (${DURATION}s)"
        RESULTS+=("✅ $machine: SUCCESS (${DURATION}s)")
        
        # Verify configuration
        echo "Verifying configuration..."
        bitbake -c devshell linux-variscite << 'EOF'
grep -E "CONFIG_VIDEO_MLX7502X|CONFIG_MXC_MIPI_CSI" .config
exit
EOF
        
    else
        END_TIME=$(date +%s)
        DURATION=$((END_TIME - START_TIME))
        echo "❌ $machine: Build failed (${DURATION}s)"
        RESULTS+=("❌ $machine: FAILED (${DURATION}s)")
    fi
    
    echo ""
done
 
echo "========================================="
echo "SUMMARY"
echo "========================================="
for result in "${RESULTS[@]}"; do
    echo "$result"
done

Configuration Validation Workflows

Script 4: Comprehensive Configuration Validator

#!/bin/bash
# save as: validate-kernel-config.sh
 
CONFIG_FILE="$1"
EXPECTED_OPTIONS="$2"
 
usage() {
    echo "Usage: $0 <config_file> <expected_options_file>"
    echo ""
    echo "expected_options_file format:"
    echo "CONFIG_VIDEO_MLX7502X=m"
    echo "CONFIG_MXC_MIPI_CSI=m"
    echo "# CONFIG_DEBUG_KERNEL is not set"
    exit 1
}
 
if [ $# -ne 2 ]; then
    usage
fi
 
if [ ! -f "$CONFIG_FILE" ]; then
    echo "Error: Config file '$CONFIG_FILE' not found"
    exit 1
fi
 
if [ ! -f "$EXPECTED_OPTIONS" ]; then
    echo "Error: Expected options file '$EXPECTED_OPTIONS' not found"
    exit 1
fi
 
echo "=== Kernel Configuration Validator ==="
echo "Config file: $CONFIG_FILE"
echo "Expected options: $EXPECTED_OPTIONS"
echo ""
 
FAILED_CHECKS=0
TOTAL_CHECKS=0
 
while IFS= read -r expected_line; do
    # Skip empty lines and comments
    [[ -z "$expected_line" || "$expected_line" =~ ^#.*$ ]] && continue
    
    TOTAL_CHECKS=$((TOTAL_CHECKS + 1))
    
    if grep -Fxq "$expected_line" "$CONFIG_FILE"; then
        echo "✅ Found: $expected_line"
    else
        echo "❌ Missing: $expected_line"
        FAILED_CHECKS=$((FAILED_CHECKS + 1))
    fi
done < "$EXPECTED_OPTIONS"
 
echo ""
echo "========================================="
echo "VALIDATION SUMMARY"
echo "========================================="
echo "Total checks: $TOTAL_CHECKS"
echo "Passed: $((TOTAL_CHECKS - FAILED_CHECKS))"
echo "Failed: $FAILED_CHECKS"
 
if [ $FAILED_CHECKS -eq 0 ]; then
    echo "✅ All configuration checks passed!"
    exit 0
else
    echo "❌ Configuration validation failed!"
    exit 1
fi

Advanced Troubleshooting Techniques

Common Issues and Automated Solutions

#!/bin/bash
# save as: troubleshoot-kernel-config.sh
 
ISSUE_TYPE="$1"
KERNEL_DIR="$2"
 
usage() {
    echo "Usage: $0 <issue_type> <kernel_dir>"
    echo ""
    echo "Issue types:"
    echo "  missing-deps    - Check for missing dependencies"
    echo "  config-conflict - Check for configuration conflicts"
    echo "  build-failure   - Analyze build failure logs"
    echo "  patch-reject    - Analyze patch rejection issues"
    exit 1
}
 
if [ $# -ne 2 ]; then
    usage
fi
 
cd "$KERNEL_DIR"
 
case "$ISSUE_TYPE" in
    "missing-deps")
        echo "=== Checking for Missing Dependencies ==="
        export ARCH=arm64
        export CROSS_COMPILE=aarch64-linux-gnu-
        
        # Check cross-compiler
        if ! command -v aarch64-linux-gnu-gcc &> /dev/null; then
            echo "❌ Cross-compiler not found: aarch64-linux-gnu-gcc"
            echo "Install with: sudo apt-get install gcc-aarch64-linux-gnu"
        else
            echo "✅ Cross-compiler found"
        fi
        
        # Check required tools
        TOOLS=("bc" "flex" "bison" "libssl-dev" "libncurses5-dev")
        for tool in "${TOOLS[@]}"; do
            if dpkg -l | grep -q "$tool"; then
                echo "✅ $tool installed"
            else
                echo "❌ $tool missing - install with: sudo apt-get install $tool"
            fi
        done
        ;;
        
    "config-conflict")
        echo "=== Checking for Configuration Conflicts ==="
        make olddefconfig 2>&1 | grep -E "(warning|error|conflict)" || echo "✅ No conflicts found"
        ;;
        
    "build-failure")
        echo "=== Analyzing Build Failure ==="
        if [ -f ".config" ]; then
            echo "Checking problematic configurations..."
            grep -E "CONFIG_.*=m" .config | head -10
            echo ""
            echo "Try building with these options as built-in (=y) instead of modules (=m)"
        else
            echo "❌ No .config file found"
        fi
        ;;
        
    "patch-reject")
        echo "=== Analyzing Patch Rejection ==="
        echo "Common patch issues:"
        echo "1. Line ending differences (DOS vs Unix)"
        echo "2. Whitespace differences"
        echo "3. Context changes in source files"
        echo ""
        echo "Solutions:"
        echo "- Run: dos2unix patch-file.patch"
        echo "- Check: git apply --whitespace=fix patch-file.patch"
        echo "- Regenerate patch from current source"
        ;;
        
    *)
        echo "Unknown issue type: $ISSUE_TYPE"
        usage
        ;;
esac

CI/CD Integration

GitHub Actions Workflow

# save as: .github/workflows/kernel-config-test.yml
name: Kernel Configuration Test
 
on:
  push:
    paths:
      - 'recipes-kernel/linux/linux-variscite/**'
  pull_request:
    paths:
      - 'recipes-kernel/linux/linux-variscite/**'
 
jobs:
  validate-patches:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Install dependencies
      run: |
        sudo apt-get update
        sudo apt-get install -y gcc-aarch64-linux-gnu bc flex bison libssl-dev libncurses5-dev
    
    - name: Set up kernel source
      run: |
        # Download and set up linux-variscite source
        # This would be specific to your setup
        
    - name: Validate patches
      run: |
        for patch in recipes-kernel/linux/linux-variscite/*.patch; do
          echo "Validating $patch"
          ./scripts/validate-config-patch.sh "$patch" linux-variscite-work/
        done
    
    - name: Test multi-machine builds
      run: |
        # Set up Yocto environment and test builds
        ./scripts/test-multi-machine.sh build/ imx8mp-var-som-dev imx8mp-var-som-prod

Best Practices Summary

1. Automation Workflow

# Complete automation workflow:
# 1. Generate patches
./generate-config-patch.sh ~/linux-variscite-work tof-camera ~/patches
 
# 2. Validate patches
./validate-config-patch.sh ~/patches/0001-*.patch ~/linux-variscite-work
 
# 3. Test multi-machine builds
./test-multi-machine.sh ~/yocto-build imx8mp-var-som-dev imx8mp-var-som-prod
 
# 4. Validate final configuration
./validate-kernel-config.sh .config expected-tof-options.txt

2. Directory Structure

# Recommended project structure:
project/
├── scripts/
   ├── generate-config-patch.sh
   ├── validate-config-patch.sh
   ├── test-multi-machine.sh
   └── troubleshoot-kernel-config.sh
├── patches/
   ├── 0001-arm64-defconfig-Enable-media-framework.patch
   └── 0002-arm64-defconfig-Enable-ToF-sensor.patch
├── configs/
   ├── expected-dev-options.txt
   └── expected-prod-options.txt
└── meta-layer/
    └── recipes-kernel/linux/linux-variscite/
        ├── defconfig-dev
        ├── defconfig-prod
        └── linux-variscite_%.bbappend

3. Testing Strategy

# Multi-level testing approach:
# Level 1: Patch validation
for patch in patches/*.patch; do
    ./validate-config-patch.sh "$patch" linux-variscite-work/
done
 
# Level 2: Configuration validation
./validate-kernel-config.sh .config configs/expected-options.txt
 
# Level 3: Multi-machine builds
./test-multi-machine.sh build/ machine1 machine2 machine3
 
# Level 4: Runtime testing (manual)
# Boot test images and verify ToF camera functionality

Quick Reference

Essential Scripts Usage

# Generate new configuration patch
./generate-config-patch.sh <kernel_dir> <config_name> <patch_dir>
 
# Validate existing patch
./validate-config-patch.sh <patch_file> <kernel_dir>
 
# Test multiple machines
./test-multi-machine.sh <yocto_build_dir> <machine1> [machine2] ...
 
# Troubleshoot issues
./troubleshoot-kernel-config.sh <issue_type> <kernel_dir>
 
# Validate configuration
./validate-kernel-config.sh <config_file> <expected_options_file>

Common Issue Types

# Troubleshooting commands:
./troubleshoot-kernel-config.sh missing-deps <kernel_dir>
./troubleshoot-kernel-config.sh config-conflict <kernel_dir>
./troubleshoot-kernel-config.sh build-failure <kernel_dir>
./troubleshoot-kernel-config.sh patch-reject <kernel_dir>

Series Conclusion

This completes our comprehensive 4-part series on Yocto kernel configuration management:

  • Part 1: Basic devshell operations and configuration workflow
  • Part 2: Machine-specific defconfig files and bbappend management
  • Part 3: Professional git patches and version control
  • Part 4: Advanced automation and troubleshooting

With these tools and techniques, you now have a complete, professional workflow for managing kernel configurations in Yocto projects. The automation scripts provided will save you time and ensure consistency across your development and production builds.

Key Takeaways

Automate repetitive tasks with scripts ✅ Validate configurations before deployment ✅ Test multiple machines systematically ✅ Troubleshoot issues efficiently ✅ Integrate with CI/CD for continuous validation

This approach scales from simple single-machine projects to complex multi-machine production environments, ensuring your kernel configuration management remains maintainable and professional.