#!/bin/bash

declare -a CROSS_OPTS=()
declare -a DFF=()
declare -a MAKE_OPTS=()
CC_IS_SET=0
CROSS_DESTDIR="../build/arch"
DESTDIR="../build/bu"
DESTDIR_CLANG="../build/bu_clang"
DUMP_MAKE=0

while getopts "a:A:d:f:cC:mMwW" OPT; do
	case "$OPT" in
		a) DESTDIR="$OPTARG" ;;
		A) CROSS_DESTDIR="$OPTARG" ;;
		c) MAKE_OPTS+=('C=1')
		   CROSS_OPTS+=('-c')
		   ;;
		C) MAKE_OPTS+=("CC=$OPTARG")
		   CC_IS_SET=1
		   ;;
		d) readarray -t DFF < <(git diff --name-only "$OPTARG"|sed -n 's@\.c$@.o@ p')
		   test "${#DFF[@]}" -eq 0 && exit 1
		   ;;
		f) readarray -t DFF < "$OPTARG"
		   test "${#DFF[@]}" -eq 0 && exit 1
		   ;;
		m) DUMP_MAKE=1 ;;
		w) MAKE_OPTS+=("W=1") ;;
		W) MAKE_OPTS+=("W=12") ;;
		*) exit 1 ;;
	esac
done

if [ "${#DFF[@]}" -ne 0 ]; then
	echo Files: "${DFF[@]}"
	set -- "${DFF[@]}"
else
	shift $(($OPTIND-1))
fi

declare -A DRV_ARCH=(
	arch/alpha/kernel/setup.o alpha
	arch/alpha/kernel/srmcons.o alpha
	arch/arm/mach-exynos/suspend.o arm
	arch/arm/mach-sa1100/assabet.o arm_sa1100
	arch/arm/mach-sa1100/collie.o arm_sa1100
	arch/arm/mach-sa1100/h3xxx.o arm_sa1100
	arch/arm64/kvm/arch_timer.o arm64
	arch/loongarch/kernel/sysrq.o loongarch
	arch/mips/kernel/sysrq.o mips
	arch/m68k/amiga/config.o m68k
	arch/m68k/apollo/config.o m68k
	arch/m68k/atari/config.o m68k
	arch/m68k/emu/nfcon.o m68k
	arch/m68k/mac/config.o m68k
	arch/m68k/q40/config.o m68k
	arch/parisc/kernel/pdc_cons.o parisc
	arch/powerpc/kernel/legacy_serial.o powerpc
	arch/powerpc/kvm/book3s_hv.o powerpc
	arch/powerpc/kvm/book3s_xive.o powerpc
	arch/powerpc/platforms/cell/axon_msi.o powerpc
	arch/powerpc/platforms/cell/interrupt.o powerpc
	arch/powerpc/platforms/cell/spider-pic.o powerpc
	arch/powerpc/platforms/powermac/setup.o powerpc
	arch/powerpc/platforms/powermac/smp.o powerpc
	arch/powerpc/platforms/powernv/opal.o powerpc
	arch/powerpc/platforms/powernv/pci-ioda.o powerpc
	arch/powerpc/platforms/pseries/hvconsole.o powerpc
	arch/powerpc/platforms/pseries/msi.o powerpc
	arch/powerpc/platforms/52xx/media5200.o powerpc_mpc5200
	arch/powerpc/sysdev/cpm2_pic.o powerpc_tqm8560
	arch/powerpc/sysdev/i8259.o powerpc
	arch/powerpc/sysdev/mpic.o powerpc
	arch/powerpc/xmon/xmon.o powerpc
	arch/sparc/kernel/process_64.o sparc
	arch/um/drivers/chan_kern.o um
	arch/um/drivers/chan_user.o um
	arch/um/drivers/line.o um
	arch/um/drivers/null.o um
	arch/um/drivers/ssl.o um
	arch/um/drivers/stdio_console.o um
	arch/um/drivers/virt-pci.o um
	arch/xtensa/platforms/iss/console.o xtensa
	drivers/acpi/irq.o loongarch
	drivers/edac/amd8111_edac.o powerpc
	drivers/edac/armada_xp_edac.o arm
	drivers/edac/mpc85xx_edac.o powerpc
	drivers/edac/thunderx_edac.o arm64
	drivers/gpio/gpio-sa1100.o arm_sa1100
	drivers/irqchip/irq-apple-aic.o arm64
	drivers/irqchip/irq-armada-370-xp.o arm
	drivers/irqchip/irq-dw-apb-ictl.o arm64
	drivers/irqchip/irq-econet-en751221.o mips
	drivers/irqchip/irq-gic.o arm64
	drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.o arm64
	drivers/irqchip/irq-gic-v3-its.o arm64
	drivers/irqchip/irq-gic-v3-mbi.o arm64
	drivers/irqchip/irq-gic-v3.o arm64
	drivers/irqchip/irq-ixp4xx.o arm
	drivers/irqchip/irq-i8259.o mips
	drivers/irqchip/irq-loongarch-avec.o loongarch
	drivers/irqchip/irq-loongarch-cpu.o loongarch
	drivers/irqchip/irq-loongson-eiointc.o loongarch
	drivers/irqchip/irq-loongson-htvec.o loongarch
	drivers/irqchip/irq-loongson-liointc.o loongarch
	drivers/irqchip/irq-loongson-pch-lpc.o loongarch
	drivers/irqchip/irq-loongson-pch-msi.o loongarch
	drivers/irqchip/irq-loongson-pch-pic.o loongarch
	drivers/irqchip/irq-ls-scfg-msi.o arm64
	drivers/irqchip/irq-mips-cpu.o mips
	drivers/irqchip/irq-mips-gic.o mips_m32r
	drivers/irqchip/irq-partition-percpu.o arm64
	drivers/irqchip/irq-riscv-aplic-direct.o riscv
	drivers/irqchip/irq-riscv-imsic-platform.o riscv
	drivers/irqchip/irq-riscv-intc.o riscv
	drivers/irqchip/irq-sa11x0.o arm_sa1100
	drivers/irqchip/irq-sifive-plic.o riscv
	drivers/irqchip/irq-ti-sci-inta.o arm64
	drivers/irqchip/irq-xtensa-pic.o xtensa
	drivers/net/dsa/microchip/ksz_ptp.o riscv
	drivers/parisc/superio.o parisc
	drivers/pci/controller/pcie-apple.o arm
	drivers/pci/controller/pcie-apple.o riscv
	drivers/pci/controller/pcie-iproc-msi.o arm
	drivers/remoteproc/pru_rproc.o arm64
	drivers/soc/tegra/pmc.o arm64
	drivers/s390/char/con3215.o s390
	drivers/s390/char/con3270.o s390
	drivers/s390/char/sclp_rw.o s390
	drivers/s390/char/sclp_tty.o s390
	drivers/s390/char/sclp_vt220.o s390
	drivers/s390/char/tty3270.o s390
	drivers/tty/amiserial.o m68k
	drivers/tty/ehv_bytechan.o powerpc
	drivers/tty/hvc/hvc_dcc.o arm64
	drivers/tty/hvc/hvc_iucv.o s390
	drivers/tty/hvc/hvc_riscv_sbi.o riscv
	drivers/tty/hvc/hvc_rtas.o powerpc
	drivers/tty/hvc/hvcs.o powerpc
	drivers/tty/hvc/hvc_udbg.o powerpc
	drivers/tty/hvc/hvc_vio.o powerpc
	drivers/tty/hvc/hvsi_lib.o powerpc
	drivers/tty/hvc/hvsi.o powerpc
	drivers/tty/serial/amba-pl010.o arm64
	drivers/tty/serial/amba-pl011.o arm64
	drivers/tty/serial/apbuart.o sparc
	drivers/tty/serial/ar933x_uart.o mips
	drivers/tty/serial/cpm_uart.o powerpc_tqm8560
	drivers/tty/serial/dz.o mips_decstation
	drivers/tty/serial/earlycon-arm-semihost.o arm64
	drivers/tty/serial/earlycon-riscv-sbi.o riscv
	drivers/tty/serial/ip22zilog.o mips
	drivers/tty/serial/mcf.o m68k_coldfire
	drivers/tty/serial/mpc52xx_uart.o powerpc_mpc5200
	drivers/tty/serial/mux.o parisc
	drivers/tty/serial/pic32_uart.o mips
	drivers/tty/serial/pmac_zilog.o powerpc
	drivers/tty/serial/pxa.o arm_pxa
	drivers/tty/serial/sa1100.o arm_sa1100
	drivers/tty/serial/sb1250-duart.o mips_sb1250
	drivers/tty/serial/serial_txx9.o mips_rbtx49xx
	drivers/tty/serial/sunhv.o sparc
	drivers/tty/serial/sunsab.o sparc
	drivers/tty/serial/sunsu.o sparc
	drivers/tty/serial/sunzilog.o sparc
	drivers/tty/serial/vr41xx_siu.o mips_e55
	drivers/tty/serial/zs.o mips_decstation
	drivers/tty/serial/21285.o arm_footbridge
	drivers/tty/serial/8250/8250_acorn.o arm_rpc
	drivers/tty/serial/8250/8250_aspeed_vuart.o arm64
	drivers/tty/serial/8250/8250_hp300.o m68k
	drivers/tty/serial/8250/8250_parisc.o parisc
	drivers/tty/vcc.o sparc
	drivers/video/console/newport_con.o mips
	drivers/video/console/sticon.o parisc

	drivers/edac/octeon_edac-l2c.o mips_special # OCTEON
	drivers/edac/octeon_edac-pc.o mips_special # OCTEON
	drivers/tty/mips_ejtag_fdc.o mips_special # MIPS_EJTAG_FDC_TTY -> MIPS_CDMM -> CPU_MIPSR2 || CPU_MIPSR5
	drivers/usb/misc/sisusbvga/sisusb_con.o broken # BROKEN
	sound/soc/ti/ams-delta.o arm_special # SND_SOC_OMAP_AMS_DELTA -> MACH_AMS_DELTA -> OMAP1

	arch/arc/kernel/intc-arcv2.o SPECIAL # CONFIG_ISA_ARCV2
	arch/arc/kernel/intc-compact.o SPECIAL # CONFIG_ISA_ARCOMPACT
	arch/arc/kernel/mcip.o SPECIAL # CONFIG_ARC_MCIP
	arch/arm/common/sa1111.o SPECIAL # CONFIG_SA1111
	arch/arm/mach-imx/avic.o SPECIAL # CONFIG_MXC_AVIC
	arch/arm/mach-imx/tzic.o SPECIAL # CONFIG_MXC_TZIC
	arch/mips/alchemy/common/platform.o SPECIAL # CONFIG_MIPS_ALCHEMY
	arch/mips/ath25/ar2315.o SPECIAL # CONFIG_SOC_AR2315
	arch/mips/ath25/ar5312.o SPECIAL # CONFIG_SOC_AR5312
	arch/mips/ath25/devices.o SPECIAL # CONFIG_ATH25
	arch/mips/pci/pci-ar2315.o SPECIAL # CONFIG_PCI_AR2315
	arch/mips/pci/pci-rt3883.o SPECIAL # CONFIG_SOC_RT3883
	arch/mips/pci/pci-xtalk-bridge.o SPECIAL # CONFIG_PCI_XTALK_BRIDGE
	arch/mips/ralink/irq.o SPECIAL # CONFIG_IRQ_INTC
	arch/mips/rb532/serial.o SPECIAL # CONFIG_MIKROTIK_RB532
	arch/mips/txx9/generic/setup.o SPECIAL # CONFIG_MACH_TX49XX
	arch/powerpc/platforms/embedded6xx/flipper-pic.o SPECIAL # CONFIG_GAMECUBE_COMMON
	arch/powerpc/platforms/embedded6xx/hlwd-pic.o SPECIAL # CONFIG_WII
	arch/powerpc/platforms/512x/mpc5121_ads_cpld.o SPECIAL # CONFIG_MPC5121_ADS
	arch/powerpc/platforms/8xx/cpm1-ic.o SPECIAL # CONFIG_CPM1
	arch/powerpc/platforms/85xx/socrates_fpga_pic.o SPECIAL # CONFIG_SOCRATES
	arch/powerpc/sysdev/ehv_pic.o SPECIAL # CONFIG_PPC_EPAPR_HV_PIC
	arch/powerpc/sysdev/ge/ge_pic.o SPECIAL # CONFIG_GE_FPGA
	arch/powerpc/sysdev/ipic.o SPECIAL # CONFIG_IPIC
	arch/powerpc/sysdev/tsi108_pci.o SPECIAL # CONFIG_TSI108_BRIDGE
	arch/x86/platform/ce4100/ce4100.o SPECIAL # CONFIG_X86_INTEL_CE
	drivers/irqchip/irq-aspeed-vic.o SPECIAL # CONFIG_ARCH_ASPEED
	drivers/irqchip/irq-ath79-misc.o SPECIAL # CONFIG_ATH79
	drivers/irqchip/irq-bcm2835.o SPECIAL # CONFIG_ARCH_BCM2835
	drivers/irqchip/irq-bcm2836.o SPECIAL # CONFIG_ARCH_BCM2835
	drivers/irqchip/irq-bcm6345-l1.o SPECIAL # CONFIG_BCM6345_L1_IRQ
	drivers/irqchip/irq-clps711x.o SPECIAL # CONFIG_CLPS711X_IRQCHIP
	drivers/irqchip/irq-csky-mpintc.o SPECIAL # CONFIG_CSKY_MPINTC
	drivers/irqchip/irq-davinci-cp-intc.o SPECIAL # CONFIG_DAVINCI_CP_INTC
	drivers/irqchip/irq-digicolor.o SPECIAL # CONFIG_ARCH_DIGICOLOR
	drivers/irqchip/irq-ftintc010.o SPECIAL # CONFIG_FARADAY_FTINTC010
	drivers/irqchip/irq-hip04.o SPECIAL # CONFIG_ARCH_HIP04
	drivers/irqchip/irq-imgpdc.o SPECIAL # CONFIG_IMGPDC_IRQ
	drivers/irqchip/irq-lpc32xx.o SPECIAL # CONFIG_ARCH_LPC32XX
	drivers/irqchip/irq-ls1x.o SPECIAL # CONFIG_LS1X_IRQ
	drivers/irqchip/irq-mmp.o SPECIAL # CONFIG_ARCH_MMP
	drivers/irqchip/irq-mxs.o SPECIAL # CONFIG_IRQ_MXS
	drivers/irqchip/irq-nvic.o SPECIAL # CONFIG_ARM_NVIC
	drivers/irqchip/irq-omap-intc.o SPECIAL # CONFIG_OMAP_IRQCHIP
	drivers/irqchip/irq-orion.o SPECIAL # CONFIG_ORION_IRQCHIP
	drivers/irqchip/irq-or1k-pic.o SPECIAL # CONFIG_OR1K_PIC
	drivers/irqchip/irq-pic32-evic.o SPECIAL # CONFIG_PIC32_EVIC
	drivers/irqchip/irq-rda-intc.o SPECIAL # CONFIG_RDA_INTC
	drivers/irqchip/irq-realtek-rtl.o SPECIAL # CONFIG_MACH_REALTEK_RTL
	drivers/irqchip/irq-sun4i.o SPECIAL # CONFIG_SUN4I_INTC
	drivers/irqchip/irq-tb10x.o SPECIAL # CONFIG_TB10X_IRQC
	drivers/irqchip/irq-versatile-fpga.o SPECIAL # CONFIG_VERSATILE_FPGA_IRQ
	drivers/irqchip/irq-vic.o SPECIAL # CONFIG_ARM_VIC
	drivers/irqchip/irq-vt8500.o SPECIAL # CONFIG_ARCH_VT8500
	drivers/irqchip/irq-wpcm450-aic.o SPECIAL # CONFIG_WPCM450_AIC
	drivers/irqchip/irq-xtensa-mx.o SPECIAL # CONFIG_XTENSA_MX
	drivers/irqchip/irq-zevio.o SPECIAL # CONFIG_ARCH_NSPIRE
	drivers/mfd/ab8500-core.o SPECIAL # CONFIG_AB8500_CORE
	drivers/mfd/db8500-prcmu.o SPECIAL # CONFIG_MFD_DB8500_PRCMU
	drivers/mfd/ioc3.o SPECIAL # CONFIG_SGI_MFD_IOC3
	drivers/pci/controller/pci-mvebu.o SPECIAL # CONFIG_PCI_MVEBU
	drivers/thermal/qcom/lmh.o SPECIAL # CONFIG_QCOM_LMH

	arch/arm/mach-omap1/board-ams-delta.o NO_CONFIG
	arch/arm/mach-omap1/irq.o NO_CONFIG
	arch/arm/mach-omap2/omap-wakeupgen.o NO_CONFIG
	arch/arm/mach-pxa/irq.o NO_CONFIG
	arch/arm/plat-orion/gpio.o NO_CONFIG
	arch/mips/cavium-octeon/octeon-irq.o NO_CONFIG
	arch/mips/lantiq/irq.o NO_CONFIG
	arch/mips/sgi-ip27/ip27-irq.o NO_CONFIG
	arch/mips/sgi-ip30/ip30-irq.o NO_CONFIG
	arch/nios2/kernel/irq.o NO_CONFIG
	arch/powerpc/platforms/44x/uic.o NO_CONFIG
	arch/powerpc/platforms/52xx/mpc52xx_gpt.o NO_CONFIG
	arch/powerpc/platforms/52xx/mpc52xx_pic.o NO_CONFIG
	arch/powerpc/platforms/8xx/pic.o NO_CONFIG
	arch/powerpc/platforms/amigaone/setup.o NO_CONFIG
	arch/powerpc/platforms/chrp/setup.o NO_CONFIG
	arch/powerpc/platforms/pasemi/setup.o NO_CONFIG
	arch/powerpc/platforms/powermac/pic.o NO_CONFIG
	arch/powerpc/platforms/powernv/opal-irqchip.o NO_CONFIG
	arch/powerpc/platforms/ps3/interrupt.o NO_CONFIG
	arch/powerpc/sysdev/fsl_msi.o NO_CONFIG
	arch/powerpc/sysdev/xics/xics-common.o NO_CONFIG
	arch/powerpc/sysdev/xive/common.o NO_CONFIG
	arch/sh/boards/mach-se/7343/irq.o NO_CONFIG
	arch/sh/boards/mach-se/7722/irq.o NO_CONFIG
	arch/sh/boards/mach-x3proto/gpio.o NO_CONFIG
	arch/sh/kernel/cpu/sh3/serial-sh770x.o NO_CONFIG
	arch/sh/kernel/cpu/sh3/serial-sh7710.o NO_CONFIG
	arch/sh/kernel/cpu/sh3/serial-sh7720.o NO_CONFIG
	arch/sh/kernel/cpu/sh4a/serial-sh7722.o NO_CONFIG
	drivers/gpu/drm/msm/msm_mdss.o NO_CONFIG
)

function echo_red() {
	tput setaf 9
	echo "$@"
	tput sgr0
}

declare -a UNHANDLED
declare -a BU
declare -A ARCHS

for FILE; do
	ARCH="${DRV_ARCH[$FILE]}"
	if [ -n "$ARCH" ]; then
		if [ "$ARCH" != 'NO_CONFIG' -a "$ARCH" != 'SPECIAL' ]; then
			declare -n ref="$ARCH"
			ref+=($FILE)
			ARCHS[$ARCH]=1
		fi
	else
		BU+=($FILE)
	fi
done

for ARCH in "${!ARCHS[@]}"; do
	if [ -z "$CROSS_DESTDIR" ]; then
		echo_red "no -A specified" >&2
		exit 1
	fi

	declare -n ref="$ARCH"
	echo
	echo_red "=== BUILDING for $ARCH ==="
	echo Files: "${ref[@]}"
	if [ -d "$CROSS_DESTDIR/$ARCH" ]; then
		FILTERED_MAKE=`mktemp --tmpdir Makefile.XXXXXXXXXX`
		cat >"$FILTERED_MAKE" <<EOF
SOURCE=$PWD
BUILD=$PWD/$CROSS_DESTDIR/$ARCH
DRVS=${ref[@]}
EOF
cat >>"$FILTERED_MAKE" <<'EOF'
VPATH=$(SOURCE)
MAKEFLAGS += --no-builtin-rules
CMD=$(foreach drv,$(DRVS),$(BUILD)/$(dir $(drv)).$(notdir $(drv)).cmd)

all: $(DRVS)

%.o: %.c
	@echo $@

-include $(CMD)
EOF
		declare -a FILTERED_MAKE_CMD=(make -s -C "$CROSS_DESTDIR/$ARCH" -f "$FILTERED_MAKE")
		if [ "$DUMP_MAKE" -eq 1 ]; then
			echo "=== Makefile DUMP ==="
			cat "$FILTERED_MAKE"
			echo "=== Makefile run ==="
			"${FILTERED_MAKE_CMD[@]}" -d
			echo "=== Makefile DUMP END ==="
		fi
		readarray -t FILTERED < <("${FILTERED_MAKE_CMD[@]}")
		rm -f "$FILTERED_MAKE"
	else
		declare -a FILTERED=("${ref[@]}")
	fi
	if [ "${#FILTERED[@]}" -ne 0 ]; then
		kernel-build-arch -a "$ARCH" -D "$CROSS_DESTDIR" "${CROSS_OPTS[@]}" "${FILTERED[@]}"
		RETVAL=$?
		if [ $RETVAL -eq 200 ]; then
			UNHANDLED+=("${ref[@]}")
		elif [ $RETVAL -ne 0 ]; then
		       exit 1
		fi
	fi
	echo "=== done $ARCH ==="
	echo
done

if [ "${#BU[@]}" -ne 0 ]; then
	if [ -z "$DESTDIR" ]; then
		echo_red "no -a specified" >&2
		exit 1
	fi

	JOBS=$((`grep -c ^processor /proc/cpuinfo`+1))
	echo_red "=== BUILDING ==="
	echo Files: "${BU[@]}"
	set -x
	make O="$DESTDIR" -k "-j$JOBS" "${MAKE_OPTS[@]}" "${BU[@]}"
	RETVAL=$?
	set +x
	if [ $RETVAL -eq 0 -a $CC_IS_SET -eq 0 ]; then
		set -x
		make O="$DESTDIR_CLANG" CC='clang' -k "-j$JOBS" "${MAKE_OPTS[@]}" "${BU[@]}"
		set +x
	fi
	echo "=== done ==="
fi

if [ "${#UNHANDLED[@]}" -ne 0 ]; then
	echo
	echo_red "=== UNHANDLED files ==="
	( IFS=$'\n'; echo "${UNHANDLED[*]}" )
fi
