#!/usr/bin/env bash usage() { cat << EOF Usage: $(basename "$0") [COMMAND] Commands: build Build the kernel (default) menuconfig Run menuconfig and save customizations repack Repack stock boot image with custom kernel download Download latest LineageOS boot image help Show this help message Examples: $(basename "$0") # Build the kernel $(basename "$0") build # Build the kernel $(basename "$0") menuconfig # Configure kernel interactively $(basename "$0") repack # Repack stock_boot.img with new kernel (auto-downloads if missing) $(basename "$0") download # Download latest LineageOS boot.img for dodge EOF exit 0 } set_basedir() { BASEDIR=$(realpath "$(dirname -- "$(realpath -- "${BASH_SOURCE[0]}")")/..") } ensure_repo_initialized() { if [ ! -d "$BASEDIR/.repo" ]; then echo ".dir missing, initializing..." pushd "$BASEDIR" > /dev/null repo init -u "$BASEDIR/meta" --git-lfs repo sync popd > /dev/null fi } download_magisk() { if [ ! -d "$BASEDIR/prebuilts/magisk" ]; then echo "Magisk binaries missing, downloading..." mkdir -p "$BASEDIR/prebuilts/magisk" pushd "$BASEDIR/prebuilts/magisk" > /dev/null wget "https://github.com/topjohnwu/Magisk/releases/download/v29.0/Magisk-v29.0.apk" || curl -OL "https://github.com/topjohnwu/Magisk/releases/download/v29.0/Magisk-v29.0.apk" unzip "Magisk-v29.0.apk" popd > /dev/null fi } setup_toolchain_vars() { GCCDIR="$BASEDIR/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9" GCCDIR32="$BASEDIR/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9" CLANGDIR="$BASEDIR/prebuilts/clang/host/linux-x86/clang-r547379" KERNELBUILDTOOLS="$BASEDIR/prebuilts/kernel-build-tools/linux-x86" MAKEOPTS=( O="$BASEDIR/work" ARCH=arm64 PATH="$CLANGDIR/bin:$GCCDIR/bin:$KERNELBUILDTOOLS/bin:$PATH" LD_LIBRARY_PATH="$CLANGDIR/lib" LLVM=1 CROSS_COMPILE="$GCCDIR/bin/aarch64-linux-android-" CROSS_COMPILE_ARM32="$GCCDIR32/bin/arm-linux-androideabi-" CLANG_TRIPLE=aarch64-linux-gnu- ) } prepare_kernel_source() { echo "Preparing source..." pushd "$BASEDIR/kernel/oneplus/sm8750" > /dev/null git reset --hard git clean -fd ln -s "${BASEDIR}/external/SukiSU-Ultra" "KernelSU" ln -s "${BASEDIR}/external/SukiSU-Ultra/kernel" "drivers/kernelsu" popd > /dev/null } add_sukisu() { pushd "$BASEDIR/kernel/oneplus/sm8750" > /dev/null MOD=false grep -q "kernelsu" "drivers/Makefile" || printf "\nobj-\$(CONFIG_KSU) += kernelsu/\n" >> "drivers/Makefile" || echo "[+] Modified Makefile." grep -q "source \"drivers/kernelsu/Kconfig\"" "drivers/Kconfig" || sed -i "/endmenu/i\source \"drivers/kernelsu/Kconfig\"" "drivers/Kconfig" && echo "[+] Modified Kconfig." popd > /dev/null } add_susfs() { pushd "$BASEDIR/kernel/oneplus/sm8750" > /dev/null cp "${BASEDIR}/external/susfs4ksu/kernel_patches/fs/"* "fs/" cp "${BASEDIR}/external/susfs4ksu/kernel_patches/include/linux/"* "include/linux/" patch --fuzz=3 -p1 < "${BASEDIR}/external/susfs4ksu/kernel_patches/50_add_susfs_in_gki-android15-6.6.patch" popd > /dev/null } configure_kernel() { pushd "$BASEDIR/kernel/oneplus/sm8750" > /dev/null mkdir -p "$BASEDIR/out" mkdir -p "$BASEDIR/work" make ${MAKEOPTS[@]} mrproper make ${MAKEOPTS[@]} gki_defconfig scripts/kconfig/merge_config.sh -m -O "$BASEDIR/work" \ "$BASEDIR/work/.config" \ arch/arm64/configs/vendor/sun_perf.config \ arch/arm64/configs/vendor/oplus/sun_perf.config if [ -e "${BASEDIR}/.config" ]; then echo "Adding custom configuration..." scripts/kconfig/merge_config.sh -m -O "${BASEDIR}/work" \ "${BASEDIR}/work/.config" \ "${BASEDIR}/.config" fi echo "CONFIG_DODGE_DTB=y" >> "$BASEDIR/work/.config" echo "CONFIG_OPLUS_DEVICE_DTBS=y" >> "$BASEDIR/work/.config" echo "CONFIG_COMPAT=y" >> "$BASEDIR/work/.config" echo "CONFIG_COMPAT_VDSO=y" >> "$BASEDIR/work/.config" make ${MAKEOPTS[@]} olddefconfig popd > /dev/null } build_kernel() { pushd "$BASEDIR/kernel/oneplus/sm8750" > /dev/null make ${MAKEOPTS[@]} \ KCFLAGS="-Wno-error=frame-larger-than=" \ -j$(nproc) 2>&1 | tee "$BASEDIR/work/build.log" popd > /dev/null } prepare_anykernel() { echo "Preparing AnyKernel3 package..." rm -rf "${BASEDIR}/work/AnyKernel3" mkdir -p "${BASEDIR}/work/AnyKernel3" cp -ra "${BASEDIR}/external/AnyKernel3/"* "${BASEDIR}/work/AnyKernel3/" cp "${BASEDIR}/meta/anykernel.sh" "${BASEDIR}/work/AnyKernel3/anykernel.sh" cp "${BASEDIR}/prebuilts/magisk/lib/arm64-v8a/libbusybox.so" "${BASEDIR}/work/AnyKernel3/tools/busybox" cp "${BASEDIR}/prebuilts/magisk/lib/arm64-v8a/libmagiskboot.so" "${BASEDIR}/work/AnyKernel3/tools/magiskboot" chmod +x "${BASEDIR}/work/AnyKernel3/tools/"* echo "Copying kernel Image..." cp "${BASEDIR}/work/arch/arm64/boot/Image" "${BASEDIR}/work/AnyKernel3/" } create_flashable_zip() { echo "Creating flashable zip..." KERNEL_VERSION=$(cat "${BASEDIR}/kernel/oneplus/sm8750/include/config/kernel.release" 2>/dev/null || echo "unknown") OUTPUT_ZIP="${BASEDIR}/out/LiteKernel-${KERNEL_VERSION}-$(date +%Y%m%d-%H%M%S).zip" pushd "${BASEDIR}/work/AnyKernel3" > /dev/null zip -r9 "${OUTPUT_ZIP}" * -x .git README.md .gitignore ./*.zip popd > /dev/null echo "Build complete!" echo "Flashable zip: ${OUTPUT_ZIP}" } run_menuconfig() { set_basedir setup_toolchain_vars mkdir -p "$BASEDIR/out" mkdir -p "$BASEDIR/work" pushd "$BASEDIR/kernel/oneplus/sm8750" > /dev/null echo "Generating base configuration..." make ${MAKEOPTS[@]} mrproper make ${MAKEOPTS[@]} gki_defconfig scripts/kconfig/merge_config.sh -m -O "$BASEDIR/work" \ "$BASEDIR/work/.config" \ arch/arm64/configs/vendor/sun_perf.config \ arch/arm64/configs/vendor/oplus/sun_perf.config make ${MAKEOPTS[@]} olddefconfig cp "$BASEDIR/work/.config" "$BASEDIR/work/.config.base" if [ -e "${BASEDIR}/.config" ]; then echo "Merging existing custom configuration..." scripts/kconfig/merge_config.sh -m -O "${BASEDIR}/work" \ "${BASEDIR}/work/.config" \ "${BASEDIR}/.config" make ${MAKEOPTS[@]} olddefconfig fi make ${MAKEOPTS[@]} menuconfig extract_custom_config popd > /dev/null } extract_custom_config() { echo "Extracting custom configuration differences..." if [ ! -f "$BASEDIR/work/.config.base" ]; then echo "Warning: No base config found for comparison" return fi > "$BASEDIR/.config" declare -A base_configs declare -A current_configs while IFS= read -r line; do if [[ "$line" =~ ^CONFIG_([^=]+)= ]]; then config_name="${BASH_REMATCH[1]}" base_configs["$config_name"]="$line" elif [[ "$line" =~ ^#\ (CONFIG_[^\ ]+)\ is\ not\ set ]]; then config_name="${BASH_REMATCH[1]#CONFIG_}" base_configs["$config_name"]="$line" fi done < "$BASEDIR/work/.config.base" while IFS= read -r line; do if [[ "$line" =~ ^CONFIG_([^=]+)= ]]; then config_name="${BASH_REMATCH[1]}" current_configs["$config_name"]="$line" elif [[ "$line" =~ ^#\ (CONFIG_[^\ ]+)\ is\ not\ set ]]; then config_name="${BASH_REMATCH[1]#CONFIG_}" current_configs["$config_name"]="$line" fi done < "$BASEDIR/work/.config" for config_name in "${!current_configs[@]}"; do if [[ "${base_configs[$config_name]}" != "${current_configs[$config_name]}" ]]; then echo "${current_configs[$config_name]}" >> "$BASEDIR/.config" fi done if [ -s "$BASEDIR/.config" ]; then sort -o "$BASEDIR/.config" "$BASEDIR/.config" echo "" echo "Custom configuration saved to: $BASEDIR/.config" echo "Changes from base configuration:" cat "$BASEDIR/.config" echo "" else echo "No configuration changes from base detected." rm -f "$BASEDIR/.config" fi } download_lineageos_boot() { set_basedir echo "Fetching latest LineageOS build information for dodge..." if ! command -v python3 &> /dev/null; then echo "Error: python3 is required but not found" return 1 fi BOOT_URL=$(curl -s "https://download.lineageos.org/api/v2/devices/dodge/builds" | python3 -c 'import sys,json;d=json.load(sys.stdin);boot=[f for f in d[0]["files"] if f["filename"]=="boot.img"][0];print(boot["url"])' 2>/dev/null) if [ -z "$BOOT_URL" ]; then echo "Error: Failed to fetch boot.img URL from LineageOS API" return 1 fi echo "Found boot.img URL: $BOOT_URL" echo "Downloading boot.img..." wget -O "${BASEDIR}/stock_boot.img" "$BOOT_URL" || curl -L -o "${BASEDIR}/stock_boot.img" "$BOOT_URL" if [ ! -f "${BASEDIR}/stock_boot.img" ]; then echo "Error: Failed to download boot.img" return 1 fi echo "Boot image saved to: ${BASEDIR}/stock_boot.img" } repack_boot_image() { set_basedir download_magisk if [ ! -f "${BASEDIR}/stock_boot.img" ]; then echo "stock_boot.img not found, attempting to download from LineageOS..." download_lineageos_boot || return 1 fi if [ ! -f "${BASEDIR}/work/arch/arm64/boot/Image" ]; then echo "Error: Kernel Image not found at ${BASEDIR}/work/arch/arm64/boot/Image" echo "Please build the kernel first using: $(basename "$0") build" return 1 fi MAGISKBOOT="${BASEDIR}/prebuilts/magisk/lib/x86_64/libmagiskboot.so" chmod +x "${MAGISKBOOT}" echo "Repacking boot image..." rm -rf "${BASEDIR}/out/repack" mkdir -p "${BASEDIR}/out/repack" pushd "${BASEDIR}/out/repack" > /dev/null ${MAGISKBOOT} unpack "${BASEDIR}/stock_boot.img" cp "${BASEDIR}/work/arch/arm64/boot/Image" kernel ${MAGISKBOOT} repack "${BASEDIR}/stock_boot.img" "${BASEDIR}/out/new_boot.img" popd > /dev/null echo "" echo "Boot image repacked successfully!" echo "Output: ${BASEDIR}/out/new_boot.img" } build() { set_basedir ensure_repo_initialized download_magisk setup_toolchain_vars prepare_kernel_source add_sukisu add_susfs configure_kernel build_kernel prepare_anykernel create_flashable_zip } main() { local command="${1:-build}" case "$command" in build) build ;; menuconfig) run_menuconfig ;; repack) repack_boot_image ;; download) download_lineageos_boot ;; help|--help|-h) usage ;; *) echo "Error: Unknown command '$command'" echo "" usage ;; esac } main "$@"