Files
Simple-Kernel/nob.c
T
2026-08-28 10:35:45 +03:00

284 lines
8.2 KiB
C

#define NOB_IMPLEMENTATION
#include "nob.h"
#include <stdbool.h>
#define BUILD_FOLDER "build/"
#define SRC_FOLDER "src/"
bool render_clangd_config(void) {
Nob_String_Builder tmpl = {0};
if (!nob_read_entire_file(".clangd.template", &tmpl))
return false;
nob_sb_append_null(&tmpl);
const char *include_path = getenv("x86_64_ELF_GCC_INCLUDE");
if (include_path == NULL) {
nob_log(NOB_ERROR, "x86_64_ELF_GCC_INCLUDE not set");
nob_sb_free(tmpl);
return false;
}
const char *needle = "${env:X86_64_ELF_GCC_INCLUDE}";
Nob_String_Builder out = {0};
const char *cursor = tmpl.items;
const char *found;
while ((found = strstr(cursor, needle)) != NULL) {
nob_sb_append_buf(&out, cursor, found - cursor);
nob_sb_append_cstr(&out, include_path);
cursor = found + strlen(needle);
}
nob_sb_append_cstr(&out, cursor);
bool ok = nob_write_entire_file(".clangd", out.items, out.count);
nob_sb_free(tmpl);
nob_sb_free(out);
return ok;
}
bool build_assembly(Nob_Cmd *cmd) {
const char *output = BUILD_FOLDER "boot.o";
const char *input = SRC_FOLDER "boot.s";
int rebuild = nob_needs_rebuild1(output, input);
if (!rebuild)
return true;
nob_cmd_append(cmd, "x86_64-elf-as", "-o", BUILD_FOLDER "boot.o", SRC_FOLDER "boot.s");
if (!nob_cmd_run(cmd))
return false;
return true;
}
bool build_c(Nob_Cmd *cmd) {
const char *inputFiles[] = {SRC_FOLDER "kernel.c", SRC_FOLDER "serial.h"};
const char *output = BUILD_FOLDER "kernel.o";
int rebuild = nob_needs_rebuild(output, inputFiles, NOB_ARRAY_LEN(inputFiles));
if (!rebuild)
return true;
nob_cmd_append(cmd,
"x86_64-elf-gcc",
"-std=gnu99",
"-ffreestanding",
"-mcmodel=large",
"-mno-red-zone",
"-mno-mmx",
"-mno-sse",
"-mno-sse2",
"-Wall",
"-Wextra",
"-O2",
"-o", BUILD_FOLDER "kernel.o",
"-c", SRC_FOLDER "kernel.c");
if (!nob_cmd_run(cmd))
return false;
return true;
}
bool link_everything(Nob_Cmd *cmd) {
const char *output = BUILD_FOLDER "kernel";
const char *input[] = {SRC_FOLDER "linker.ld", BUILD_FOLDER "kernel.o", BUILD_FOLDER "boot.o"};
int rebuild = nob_needs_rebuild(output, input, NOB_ARRAY_LEN(input));
if (!rebuild)
return true;
const char *objectFiles[] = {BUILD_FOLDER "kernel.o", BUILD_FOLDER "boot.o"};
nob_cmd_append(cmd,
"x86_64-elf-gcc",
"-T", SRC_FOLDER "linker.ld",
"-o", BUILD_FOLDER "kernel",
"-ffreestanding",
"-O2",
"-nostdlib");
// Add objectFiles as input
for (size_t i = 0; i < NOB_ARRAY_LEN(objectFiles); i++) {
nob_cmd_append(cmd, objectFiles[i]);
}
nob_cmd_append(cmd, "-lgcc");
if (!nob_cmd_run(cmd))
return false;
return true;
}
bool check_kernel(Nob_Cmd *cmd) {
nob_cmd_append(cmd, "grub-file", "--is-x86-multiboot", BUILD_FOLDER "kernel");
if (!nob_cmd_run(cmd))
return false;
return true;
}
bool clean_dir(const char *dir_path) {
Nob_File_Paths children = {0};
if (!nob_read_entire_dir(dir_path, &children))
return false;
bool ok = true;
for (size_t i = 0; i < children.count; ++i) {
const char *name = children.items[i];
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
continue;
const char *full_path = nob_temp_sprintf("%s/%s", dir_path, name);
if (!nob_delete_file(full_path)) {
clean_dir(full_path);
nob_delete_file(full_path);
}
}
nob_da_free(children);
return ok;
}
bool build_bootable_image(Nob_Cmd *cmd) {
// NOTE: this does not rebuild on change of limine bins
const char *output = BUILD_FOLDER "kernel.iso";
const char *input[] = {BUILD_FOLDER "kernel", SRC_FOLDER "limine.conf"};
int rebuild = nob_needs_rebuild(output, input, NOB_ARRAY_LEN(input));
if (!rebuild)
return true;
if (!nob_mkdir_if_not_exists(BUILD_FOLDER "isodir"))
return false;
if (!nob_mkdir_if_not_exists(BUILD_FOLDER "isodir/boot"))
return false;
if (!nob_mkdir_if_not_exists(BUILD_FOLDER "isodir/boot/limine"))
return false;
if (!nob_mkdir_if_not_exists(BUILD_FOLDER "isodir/EFI"))
return false;
if (!nob_mkdir_if_not_exists(BUILD_FOLDER "isodir/EFI/BOOT"))
return false;
if (!nob_mkdir_if_not_exists(BUILD_FOLDER "limine"))
return false;
if (!nob_file_exists(BUILD_FOLDER "limine/limine.c")) {
nob_cmd_append(cmd, "git", "clone", "https://github.com/limine-bootloader/limine.git", "--branch=v11.x-binary", "--depth=1", BUILD_FOLDER "limine");
if (!nob_cmd_run(cmd))
return false;
}
nob_cmd_append(cmd, "make", "-C", BUILD_FOLDER "limine");
if (!nob_cmd_run(cmd))
return false;
nob_cmd_append(cmd, "cp",
BUILD_FOLDER "limine/limine-bios.sys",
BUILD_FOLDER "limine/limine-bios-cd.bin",
BUILD_FOLDER "limine/limine-uefi-cd.bin",
BUILD_FOLDER "isodir/boot/limine/");
if (!nob_cmd_run(cmd))
return false;
nob_cmd_append(cmd, "cp",
BUILD_FOLDER "limine/BOOTIA32.EFI",
BUILD_FOLDER "limine/BOOTX64.EFI",
BUILD_FOLDER "isodir/EFI/BOOT/");
if (!nob_cmd_run(cmd))
return false;
nob_cmd_append(cmd, "cp", SRC_FOLDER "limine.conf", BUILD_FOLDER "isodir/boot/limine/limine.conf");
if (!nob_cmd_run(cmd))
return false;
nob_cmd_append(cmd, "cp", BUILD_FOLDER "kernel", BUILD_FOLDER "isodir/boot/");
if (!nob_cmd_run(cmd))
return false;
nob_cmd_append(cmd, "xorriso", "-as", "mkisofs",
"-b", "boot/limine/limine-bios-cd.bin",
"-no-emul-boot", "-boot-load-size", "4", "-boot-info-table",
"--efi-boot", "boot/limine/limine-uefi-cd.bin",
"-efi-boot-part", "--efi-boot-image", "--protective-msdos-label",
BUILD_FOLDER "isodir", "-o", BUILD_FOLDER "kernel.iso");
if (!nob_cmd_run(cmd))
return false;
nob_cmd_append(cmd, BUILD_FOLDER "limine/limine", "bios-install", BUILD_FOLDER "kernel.iso");
if (!nob_cmd_run(cmd))
return false;
return true;
}
bool runQemu(Nob_Cmd *cmd) {
nob_cmd_append(cmd, "qemu-system-x86_64", "-cdrom", BUILD_FOLDER "kernel.iso", "-serial", "stdio");
if (!nob_cmd_run(cmd))
return false;
return true;
}
int main(int argc, char **argv) {
NOB_GO_REBUILD_URSELF(argc, argv);
const char *program_name = shift(argv, argc);
bool clean = false;
bool run = false; // starts qemu
bool build = false;
while (argc > 0) {
const char *arg = shift(argv, argc);
if (strcmp(arg, "clean") == 0)
clean = true;
if (strcmp(arg, "run") == 0)
run = true;
if (strcmp(arg, "build") == 0)
build = true;
}
if (clean) {
const char *dir_path = BUILD_FOLDER;
Nob_Dir_Entry dir = {0};
if (!nob_dir_entry_open(dir_path, &dir)) {
nob_log(NOB_INFO, "No build directory to clean. Skipping...");
} else {
if (!clean_dir(BUILD_FOLDER))
return 1;
nob_delete_file(BUILD_FOLDER);
}
}
if (build) {
if (!nob_mkdir_if_not_exists(BUILD_FOLDER))
return 1;
Nob_Cmd cmd = {0};
if (!render_clangd_config())
return 1;
if (!build_assembly(&cmd))
return 1;
if (!build_c(&cmd))
return 1;
if (!link_everything(&cmd))
return 1;
if (!check_kernel(&cmd))
return 1;
if (!build_bootable_image(&cmd))
return 1;
}
if (run) {
Nob_Cmd cmd = {0};
if (!runQemu(&cmd))
return 1;
}
if (!clean && !build && !run) {
nob_log(NOB_INFO, "Usage: %s (build || clean || run)", program_name);
return 1;
}
return 0;
}