WORKING_DIR?=$(shell pwd) EXTERNAL_DIR?=$(WORKING_DIR)/external BUILD_DIR?=$(WORKING_DIR)/build LINUX_DIR?=$(EXTERNAL_DIR)/linux LINUX_REPO?=https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git BUSYBOX_DIR?=$(EXTERNAL_DIR)/busybox BUSYBOX_REPO?=https://git.busybox.net/busybox INITRAMFS_INIT?=initramfs_init ROOTFS_DIR?=$(BUILD_DIR)/rootfs INITRAMFS_DIR?=$(BUILD_DIR)/initramfs LIMINE_REPO?=https://github.com/limine-bootloader/limine.git LIMINE_BRANCH?=v8.x-binary ISO_ROOT?=$(BUILD_DIR)/iso_root LIMINE_DIR?=$(EXTERNAL_DIR)/limine ISO_PATH?=$(BUILD_DIR)/yerba-linux.iso .PHONY: all kernel initramfs rootfs iso run clean all: iso $(EXTERNAL_DIR): @mkdir -p $(EXTERNAL_DIR) $(BUILD_DIR): @mkdir -p $(BUILD_DIR) $(LINUX_DIR): $(EXTERNAL_DIR) @if [ -d $(LINUX_DIR) ]; then \ echo "[yerba] Linux kernel already cloned, skipping..."; \ else \ echo "[yerba] cloning Linux kernel..."; \ git clone --depth 1 $(LINUX_REPO) $(LINUX_DIR); \ fi kernel: $(LINUX_DIR) $(BUILD_DIR) @if [ -f $(BUILD_DIR)/bzImage ]; then \ echo "[yerba] bzImage already exists, skipping kernel build..."; \ else \ echo "[yerba] building kernel (default defconfig)..."; \ rm -f $(LINUX_DIR)/.config; \ cp $(WORKING_DIR)/linux_config $(LINUX_DIR)/.config; \ $(MAKE) -C $(LINUX_DIR) -j$(shell nproc) bzImage; \ cp $(LINUX_DIR)/arch/x86/boot/bzImage $(BUILD_DIR)/bzImage; \ fi initramfs: busybox kernel | $(BUILD_DIR) @if [ -f $(BUILD_DIR)/initramfs.cpio.gz ]; then \ echo "[yerba] initramfs already created, skipping..."; \ else \ echo "[yerba] creating initramfs..."; \ rm -rf $(INITRAMFS_DIR); \ mkdir -p $(INITRAMFS_DIR)/bin; \ mkdir -p $(INITRAMFS_DIR)/sbin; \ mkdir -p $(INITRAMFS_DIR)/etc; \ mkdir -p $(INITRAMFS_DIR)/proc; \ mkdir -p $(INITRAMFS_DIR)/sys; \ mkdir -p $(INITRAMFS_DIR)/dev; \ cp -a $(BUSYBOX_DIR)/_install/. $(INITRAMFS_DIR)/; \ cp $(WORKING_DIR)/initramfs_init $(INITRAMFS_DIR)/init; \ chmod +x $(INITRAMFS_DIR)/init; \ cd $(INITRAMFS_DIR) && find . | cpio -o -H newc | gzip > $(BUILD_DIR)/initramfs.cpio.gz; \ fi $(ROOTFS_DIR): $(BUILD_DIR) mkdir -p $(ROOTFS_DIR) rootfs: $(ROOTFS_DIR) kernel initramfs busybox @if [ -f $(BUILD_DIR)/rootfs.squashfs ]; then \ echo "[yerba] rootfs squashfs image already exists, skipping..."; \ else \ rm -rf $(ROOTFS_DIR); \ mkdir -p $(ROOTFS_DIR); \ echo "[yerba] creating rootfs..."; \ mkdir -p $(ROOTFS_DIR)/bin; \ mkdir -p $(ROOTFS_DIR)/sbin; \ mkdir -p $(ROOTFS_DIR)/etc; \ mkdir -p $(ROOTFS_DIR)/proc; \ mkdir -p $(ROOTFS_DIR)/sys; \ mkdir -p $(ROOTFS_DIR)/dev; \ mkdir -p $(ROOTFS_DIR)/home; \ mkdir -p $(ROOTFS_DIR)/var; \ mkdir -p $(ROOTFS_DIR)/usr; \ mkdir -p $(ROOTFS_DIR)/root; \ mkdir -p $(ROOTFS_DIR)/mnt; \ mkdir -p $(ROOTFS_DIR)/tmp; \ cp -a $(BUSYBOX_DIR)/_install/. $(ROOTFS_DIR)/; \ ln -sf sbin/init $(ROOTFS_DIR)/init; \ echo "proc /proc proc defaults 0 0" > $(ROOTFS_DIR)/etc/fstab; \ echo "sysfs /sys sysfs defaults 0 0" >> $(ROOTFS_DIR)/etc/fstab; \ echo "devtmpfs /dev devtmpfs defaults 0 0" >> $(ROOTFS_DIR)/etc/fstab; \ echo "::sysinit:/bin/mount -a" > $(ROOTFS_DIR)/etc/inittab; \ echo "::askfirst:/bin/sh" >> $(ROOTFS_DIR)/etc/inittab; \ echo "::ctrlaltdel:/sbin/reboot" >> $(ROOTFS_DIR)/etc/inittab; \ echo "[yerba] creating squashfs image..."; \ mksquashfs $(ROOTFS_DIR) $(BUILD_DIR)/rootfs.squashfs -comp zstd -noappend; \ fi $(BUSYBOX_DIR): $(EXTERNAL_DIR) @if [ -d $(BUSYBOX_DIR) ]; then \ echo "[yerba] BusyBox already cloned, skipping..."; \ else \ echo "[yerba] cloning BusyBox..."; \ git clone --depth 1 $(BUSYBOX_REPO) $(BUSYBOX_DIR); \ fi busybox: $(BUSYBOX_DIR) $(BUILD_DIR) @if [ -d $(BUSYBOX_DIR)/_install ]; then \ echo "[yerba] BusyBox already built, skipping..."; \ else \ echo "[yerba] building BusyBox..."; \ rm -f $(BUSYBOX_DIR)/.config; \ cp $(WORKING_DIR)/busybox_config $(BUSYBOX_DIR)/.config; \ $(MAKE) -C $(BUSYBOX_DIR) -j$(shell nproc); \ $(MAKE) -C $(BUSYBOX_DIR) CONFIG_PREFIX=$(BUSYBOX_DIR)/_install install; \ fi $(LIMINE_DIR): $(EXTERNAL_DIR) @if [ -d $(LIMINE_DIR) ]; then \ echo "[yerba] Limine already cloned, skipping..."; \ else \ echo "[yerba] cloning Limine..."; \ git clone --depth 1 --branch=$(LIMINE_BRANCH) $(LIMINE_REPO) $(LIMINE_DIR); \ fi iso: kernel initramfs busybox rootfs $(LIMINE_DIR) @if [ -f $(ISO_PATH) ]; then \ echo "[yerba] iso already created, skipping..."; \ else \ echo "[yerba] building Limine..."; \ $(MAKE) -C $(LIMINE_DIR); \ echo "[yerba] bootstrapping Limine and creating ISO..."; \ mkdir -p $(ISO_ROOT)/boot/limine; \ mkdir -p $(ISO_ROOT)/EFI/BOOT; \ mkdir -p $(ISO_ROOT)/yerba; \ cp $(BUILD_DIR)/bzImage $(ISO_ROOT)/boot/; \ cp $(BUILD_DIR)/initramfs.cpio.gz $(ISO_ROOT)/boot/; \ cp $(WORKING_DIR)/limine.conf $(ISO_ROOT)/boot/limine; \ cp $(LIMINE_DIR)/limine-bios.sys $(LIMINE_DIR)/limine-bios-cd.bin $(LIMINE_DIR)/limine-uefi-cd.bin $(ISO_ROOT)/boot/limine; \ cp $(LIMINE_DIR)/BOOTX64.EFI $(ISO_ROOT)/EFI/BOOT/; \ cp $(LIMINE_DIR)/BOOTIA32.EFI $(ISO_ROOT)/EFI/BOOT/; \ cp $(BUILD_DIR)/rootfs.squashfs $(ISO_ROOT)/yerba/; \ xorriso -as mkisofs -R -r -J -b boot/limine/limine-bios-cd.bin -no-emul-boot -boot-load-size 4 -boot-info-table -hfsplus -apm-block-size 2048 --efi-boot boot/limine/limine-uefi-cd.bin -efi-boot-part --efi-boot-image --protective-msdos-label $(ISO_ROOT) -o $(ISO_PATH); \ $(LIMINE_DIR)/limine bios-install $(ISO_PATH); \ fi clean: rm -rf $(EXTERNAL_DIR) $(BUILD_DIR) run: iso @echo "[yerba] booting in QEMU..." qemu-system-x86_64 -cdrom $(ISO_PATH) -m 2G -cpu host -enable-kvm -vga std setup: $(LINUX_DIR) $(LIMINE_DIR) $(BUSYBOX_DIR) @echo "[yerba] all repos fetched"