419 lines
28 KiB
C
419 lines
28 KiB
C
// Project build orchestrator. This file describes the Windows/MSVC build graph and keeps driver dependencies explicit.
|
|
|
|
#define NOB_IMPLEMENTATION
|
|
#include "nob.h"
|
|
|
|
// Compiler and linker flags stay in macros so they can be used in file-scope aggregate initializers.
|
|
// MSVC C rejects initializing a static object from another object, even when the source object is const.
|
|
// Drivers and user binaries do not inherit kernel include paths so private dependencies fail at compile time.
|
|
#define COMMON_CFLAGS_LITERAL "/nologo /W3 /WX /Od /GS- /Gs999999 /Gz /Gy /EHsc- /GR- /Oi- /Z7 /std:c17 /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_WARNINGS /Icode\\public /Icode\\common\\include"
|
|
#define KERNEL_CFLAGS_LITERAL COMMON_CFLAGS_LITERAL " /Icode\\kernel\\include"
|
|
#define DRIVER_CFLAGS_LITERAL COMMON_CFLAGS_LITERAL
|
|
#define USER_CFLAGS_LITERAL COMMON_CFLAGS_LITERAL
|
|
#define BOOT_CFLAGS_LITERAL KERNEL_CFLAGS_LITERAL
|
|
#define USER_HEAP_OBJS_LITERAL "obj\\runtime\\user_heap.obj obj\\runtime\\user_heap_exports.obj"
|
|
#define NATIVE_RUNTIME_OBJS_LITERAL "obj\\runtime\\native_exception.obj obj\\runtime\\native_start.obj"
|
|
#define NATIVE_EXE_LIBS_LITERAL "bin\\syscall.lib obj\\libc.obj " USER_HEAP_OBJS_LITERAL " " NATIVE_RUNTIME_OBJS_LITERAL
|
|
#define NATIVE_INIT_LIBS_LITERAL "bin\\syscall.lib obj\\libc.obj " USER_HEAP_OBJS_LITERAL " obj\\runtime\\native_exception.obj"
|
|
#define WIN32_EXE_LIBS_LITERAL "bin\\win32.lib bin\\syscall.lib obj\\libc.obj obj\\runtime\\native_start.obj"
|
|
#define POSIX_EXE_LIBS_LITERAL "bin\\posix.lib bin\\syscall.lib obj\\libc.obj obj\\runtime\\posix_start.obj obj\\runtime\\native_exception.obj"
|
|
#define NATIVE_EXE_ENTRY_LITERAL "/ENTRY:NtlNativeStart"
|
|
#define LWIP_CFLAGS_LITERAL DRIVER_CFLAGS_LITERAL " /Icode\\drivers\\net\\lwip\\include /Icode\\drivers\\net\\lwip\\third_party\\lwip\\src\\include /wd4005 /wd4100 /wd4103 /wd4127 /wd4244 /wd4267 /wd4706"
|
|
#define LFLAGS_LITERAL "/nologo /NODEFAULTLIB /DEBUG"
|
|
|
|
const char *CommonCflags = COMMON_CFLAGS_LITERAL;
|
|
const char *KernelCflags = KERNEL_CFLAGS_LITERAL;
|
|
const char *UserCflags = USER_CFLAGS_LITERAL;
|
|
const char *BootCflags = BOOT_CFLAGS_LITERAL;
|
|
const char *LwipCflags = LWIP_CFLAGS_LITERAL;
|
|
const char *LFLAGS = LFLAGS_LITERAL;
|
|
|
|
typedef struct Driver_Target {
|
|
const char *name;
|
|
const char *obj_dir;
|
|
const char *sources;
|
|
const char *cflags;
|
|
const char *libs;
|
|
} Driver_Target;
|
|
|
|
#define DRIVER_TARGET(name_, obj_dir_, sources_) { (name_), (obj_dir_), (sources_), DRIVER_CFLAGS_LITERAL, "" }
|
|
#define DRIVER_TARGET_LIBS(name_, obj_dir_, sources_, libs_) { (name_), (obj_dir_), (sources_), DRIVER_CFLAGS_LITERAL, (libs_) }
|
|
#define DRIVER_TARGET_FLAGS(name_, obj_dir_, sources_, cflags_) { (name_), (obj_dir_), (sources_), (cflags_), "" }
|
|
|
|
static const Driver_Target PCI_BUS_DRIVER =
|
|
DRIVER_TARGET_FLAGS("pci", "obj\\drivers\\pci", "code\\drivers\\bus\\pci\\pci.c", DRIVER_CFLAGS_LITERAL " /DPCI_SYS_BUILD");
|
|
|
|
static const Driver_Target STANDALONE_DRIVERS[] = {
|
|
DRIVER_TARGET("ps2", "obj\\drivers\\ps2", "code\\drivers\\input\\ps2\\ps2.c code\\drivers\\input\\ps2\\ps2_i8042.c"),
|
|
DRIVER_TARGET("serial", "obj\\drivers\\serial", "code\\drivers\\input\\serial\\serial.c"),
|
|
DRIVER_TARGET_LIBS("ata", "obj\\drivers\\ata", "code\\drivers\\storage\\ata\\ata.c", "bin\\pci.lib"),
|
|
DRIVER_TARGET_LIBS("ahci", "obj\\drivers\\ahci", "code\\drivers\\storage\\ahci\\ahci.c code\\drivers\\storage\\ahci\\ahci_port.c", "bin\\pci.lib"),
|
|
DRIVER_TARGET("fat32", "obj\\drivers\\fat32", "code\\drivers\\fs\\fat32\\fat32.c code\\drivers\\fs\\fat32\\fat32_mount.c"),
|
|
DRIVER_TARGET("ntfs", "obj\\drivers\\ntfs", "code\\drivers\\fs\\ntfs\\ntfs.c"),
|
|
DRIVER_TARGET_LIBS("vmwaresvga", "obj\\drivers\\vmwaresvga", "code\\drivers\\display\\vmwaresvga\\vmwaresvga.c", "bin\\pci.lib"),
|
|
DRIVER_TARGET_LIBS("usb", "obj\\drivers\\usb", "code\\drivers\\bus\\usb\\usb.c code\\drivers\\bus\\usb\\usb_bus.c code\\drivers\\bus\\usb\\usb_composite.c code\\drivers\\bus\\usb\\usb_core.c code\\drivers\\bus\\usb\\usb_xhci.c code\\drivers\\bus\\usb\\usb_hid.c code\\drivers\\bus\\usb\\usb_storage.c code\\drivers\\bus\\usb\\usb_hub.c", "bin\\pci.lib"),
|
|
DRIVER_TARGET_LIBS("rtl816x", "obj\\drivers\\rtl816x", "code\\drivers\\net\\rtl816x\\rtl816x.c", "bin\\pci.lib"),
|
|
DRIVER_TARGET_LIBS("rtl8139", "obj\\drivers\\rtl8139", "code\\drivers\\net\\rtl8139\\rtl8139.c", "bin\\pci.lib"),
|
|
};
|
|
|
|
// Creates layout.
|
|
void create_layout() {
|
|
const char *dirs[] = {
|
|
"obj", "bin", "obj\\boot", "obj\\kernel", "obj\\lwip", "obj\\hal",
|
|
"obj\\syscall", "obj\\runtime", "obj\\win32", "obj\\posix", "obj\\drivers", "obj\\init",
|
|
"obj\\shell_win32", "obj\\shell_posix", "obj\\shell_native",
|
|
"obj\\async_apc", "obj\\async_cancel", "obj\\apc_return_smoke", "obj\\edit", "obj\\httpget",
|
|
"obj\\tcpserve", "obj\\udp", "obj\\resolve", "obj\\ping", "obj\\doom", "obj\\video", "obj\\memtop",
|
|
"obj\\file_stat_smoke", "obj\\handle_dup_smoke", "obj\\named_queue_lifetime_smoke", "obj\\input_api_smoke", "obj\\input_model_smoke", "obj\\timer_smoke", "obj\\stats_abi_smoke", "obj\\realpath_smoke", "obj\\file_lock_smoke", "obj\\process_protection_smoke", "obj\\socket_addr_smoke", "obj\\syscall_contract_smoke", "obj\\would_block_smoke", "obj\\cwd_peb_smoke", "obj\\mmap_smoke", "obj\\pcache_smoke", "obj\\pcache_pressure", "obj\\dirty_writeback", "obj\\shared_mmap",
|
|
"obj\\pcache_invalidate", "obj\\pcache_mmap_read_reuse", "obj\\pcache_multithread",
|
|
"obj\\surface_smoke", "obj\\surface_invalid_rect", "obj\\surface_multithread_present", "obj\\net_irp_smoke", "obj\\module_load_smoke", "obj\\posix_module_smoke", "obj\\exception_dispatcher_smoke", "obj\\native_exception_runtime_smoke", "obj\\native_raise_exception_smoke", "obj\\exception_smoke", "obj\\win32_exception_smoke", "obj\\win32_seh_smoke"
|
|
};
|
|
for (size_t i = 0; i < NOB_ARRAY_LEN(dirs); i++) nob_mkdir_if_not_exists(dirs[i]);
|
|
nob_mkdir_if_not_exists(PCI_BUS_DRIVER.obj_dir);
|
|
for (size_t i = 0; i < NOB_ARRAY_LEN(STANDALONE_DRIVERS); i++) nob_mkdir_if_not_exists(STANDALONE_DRIVERS[i].obj_dir);
|
|
}
|
|
|
|
// Runs a shell command and waits for it to finish.
|
|
bool run_sync(const char *cmd_str) {
|
|
Nob_Cmd cmd = {0};
|
|
nob_cmd_append(&cmd, "cmd.exe", "/c", cmd_str);
|
|
bool ok = nob_cmd_run_sync(cmd);
|
|
nob_cmd_free(cmd);
|
|
return ok;
|
|
}
|
|
|
|
// Launches a shell command while the build graph continues.
|
|
Nob_Proc run_async(const char *cmd_str) {
|
|
Nob_Cmd cmd = {0};
|
|
nob_cmd_append(&cmd, "cmd.exe", "/c", cmd_str);
|
|
Nob_Proc proc = nob_cmd_run_async(cmd);
|
|
nob_cmd_free(cmd);
|
|
return proc;
|
|
}
|
|
|
|
// Deletes stale object files from a target directory before compiling into it.
|
|
// Link commands use directory wildcards, so removed translation units can otherwise
|
|
// survive as old .obj files and keep unresolved references alive.
|
|
bool clean_object_directory(const char *obj_dir) {
|
|
const char *cmd = nob_temp_sprintf("if exist %s\\*.obj del /q %s\\*.obj", obj_dir, obj_dir);
|
|
return run_sync(cmd);
|
|
}
|
|
|
|
// Cleans object directories that are linked through wildcards.
|
|
// The build is intentionally simple and does not maintain per-file dependency state,
|
|
// so stale objects are more dangerous than recompiling a few extra files.
|
|
bool clean_build_object_directories(void) {
|
|
const char *dirs[] = {
|
|
"obj\\boot", "obj\\kernel", "obj\\lwip", "obj\\hal",
|
|
"obj\\syscall", "obj\\runtime", "obj\\win32", "obj\\posix",
|
|
"obj\\init", "obj\\shell_win32", "obj\\shell_posix", "obj\\shell_native",
|
|
"obj\\async_apc", "obj\\async_cancel", "obj\\apc_return_smoke", "obj\\edit", "obj\\httpget",
|
|
"obj\\tcpserve", "obj\\udp", "obj\\resolve", "obj\\ping",
|
|
"obj\\doom", "obj\\video", "obj\\memtop", "obj\\file_stat_smoke", "obj\\handle_dup_smoke", "obj\\named_queue_lifetime_smoke", "obj\\input_api_smoke", "obj\\input_model_smoke", "obj\\timer_smoke", "obj\\stats_abi_smoke", "obj\\realpath_smoke", "obj\\file_lock_smoke", "obj\\process_protection_smoke", "obj\\socket_addr_smoke", "obj\\syscall_contract_smoke", "obj\\would_block_smoke", "obj\\cwd_peb_smoke", "obj\\mmap_smoke", "obj\\pcache_smoke", "obj\\pcache_pressure", "obj\\dirty_writeback", "obj\\shared_mmap",
|
|
"obj\\pcache_invalidate", "obj\\pcache_mmap_read_reuse", "obj\\pcache_multithread",
|
|
"obj\\surface_smoke", "obj\\surface_invalid_rect", "obj\\surface_multithread_present", "obj\\net_irp_smoke", "obj\\module_load_smoke", "obj\\posix_module_smoke", "obj\\exception_dispatcher_smoke", "obj\\native_exception_runtime_smoke", "obj\\native_raise_exception_smoke", "obj\\exception_smoke", "obj\\win32_exception_smoke", "obj\\win32_seh_smoke"
|
|
};
|
|
|
|
for (size_t i = 0; i < NOB_ARRAY_LEN(dirs); i++) {
|
|
if (!clean_object_directory(dirs[i])) return false;
|
|
}
|
|
|
|
if (!clean_object_directory(PCI_BUS_DRIVER.obj_dir)) return false;
|
|
for (size_t i = 0; i < NOB_ARRAY_LEN(STANDALONE_DRIVERS); i++) {
|
|
if (!clean_object_directory(STANDALONE_DRIVERS[i].obj_dir)) return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Creates an empty USB image the first time the build sees a missing usb.vhd.
|
|
// The image is intentionally left unmounted and unpopulated after formatting so
|
|
// callers can use it as removable FAT32 storage without the build overwriting it.
|
|
bool create_usb_vhd_if_missing(void) {
|
|
if (nob_file_exists("usb.vhd")) return true;
|
|
|
|
char vhd_path[MAX_PATH];
|
|
GetFullPathNameA("usb.vhd", MAX_PATH, vhd_path, NULL);
|
|
|
|
const char *diskpart_script = nob_temp_sprintf(
|
|
"create vdisk file=\"%s\" maximum=256 type=fixed\n"
|
|
"select vdisk file=\"%s\"\n"
|
|
"attach vdisk\n"
|
|
"convert gpt\n"
|
|
"create partition primary\n"
|
|
"format fs=ntfs quick\n"
|
|
"detach vdisk\n"
|
|
"exit\n",
|
|
vhd_path, vhd_path
|
|
);
|
|
|
|
nob_log(NOB_INFO, "usb.vhd missing, creating empty 256 MB FAT32 GPT image...");
|
|
nob_write_entire_file("usb_mkimage.txt", diskpart_script, strlen(diskpart_script));
|
|
bool ok = run_sync("diskpart /s usb_mkimage.txt");
|
|
remove("usb_mkimage.txt");
|
|
return ok;
|
|
}
|
|
|
|
// Runs the requested operation.
|
|
int main(int argc, char **argv) {
|
|
// The build tool rebuilds itself before doing any real work so the graph below matches the source.
|
|
NOB_GO_REBUILD_URSELF(argc, argv);
|
|
|
|
// The boot image must exist before the build can copy fresh binaries into it.
|
|
if (!nob_file_exists("disk.vhd")) {
|
|
nob_log(NOB_INFO, "disk.vhd missing, calling mkimage.bat...");
|
|
if (!run_sync("mkimage.bat")) return 1;
|
|
}
|
|
if (!create_usb_vhd_if_missing()) return 1;
|
|
create_layout();
|
|
if (!clean_build_object_directories()) return 1;
|
|
|
|
// Core images build sequentially because later images link against earlier import libraries.
|
|
nob_log(NOB_INFO, "--- Building Core Subsystems ---");
|
|
|
|
const char *core_tasks[] = {
|
|
"ml64 /nologo /c /Foobj\\kernel\\ke_switch.obj code\\kernel\\ke_switch.asm",
|
|
"ml64 /nologo /c /Foobj\\kernel\\ke_syscall_asm.obj code\\kernel\\ke_syscall.asm",
|
|
"ml64 /nologo /c /Foobj\\kernel\\ke_gdt_reload.obj code\\kernel\\ke_gdt_reload.asm",
|
|
"ml64 /nologo /c /Foobj\\syscall\\stubs.obj code\\user\\syscall\\syscall_stubs.asm",
|
|
"for %f in (code\\boot\\uefi\\*.asm) do ml64 /nologo /c /Fo\"obj\\boot\\%~nf.obj\" \"%f\"",
|
|
|
|
nob_temp_sprintf("cl %s /MP /c /Foobj\\ code\\common\\printf.c code\\common\\ini_parser.c", CommonCflags),
|
|
"cl /nologo /c /Foobj\\libc.obj code\\common\\libc.c",
|
|
nob_temp_sprintf("cl %s /c /Foobj\\runtime\\user_heap.obj code\\user\\runtime\\heap.c", UserCflags),
|
|
nob_temp_sprintf("cl %s /c /Foobj\\runtime\\user_heap_exports.obj code\\user\\runtime\\heap_exports.c", UserCflags),
|
|
nob_temp_sprintf("cl %s /c /Foobj\\runtime\\native_exception.obj code\\user\\runtime\\native_exception.c", UserCflags),
|
|
nob_temp_sprintf("cl %s /c /Foobj\\runtime\\native_start.obj code\\user\\runtime\\native_start.c", UserCflags),
|
|
nob_temp_sprintf("cl %s /c /Foobj\\runtime\\posix_start.obj code\\user\\runtime\\posix_start.c", UserCflags),
|
|
|
|
// Bootloader.
|
|
nob_temp_sprintf("cl %s /MP /c /Icode\\boot\\uefi\\include /Foobj\\boot\\ code\\boot\\uefi\\*.c && link %s /FORCE:MULTIPLE /SUBSYSTEM:EFI_APPLICATION /ENTRY:UefiMain /OUT:bin\\bootx64.efi obj\\libc.obj obj\\ini_parser.obj code\\boot\\uefi\\efilib.lib obj\\boot\\*.obj", BootCflags, LFLAGS),
|
|
|
|
// HAL.
|
|
nob_temp_sprintf("cl %s /MP /c /Foobj\\hal\\ code\\kernel\\hal\\*.c && link %s /DLL /OUT:bin\\hal.dll /ENTRY:HalInitialize /IGNORE:4216 obj\\printf.obj obj\\libc.obj obj\\hal\\*.obj", KernelCflags, LFLAGS),
|
|
|
|
// Kernel.
|
|
nob_temp_sprintf("cl %s /DKE_DISPLAY_BUILD /MP /c /Foobj\\kernel\\ code\\kernel\\*.c && link %s /SUBSYSTEM:NATIVE /ENTRY:KernelMain /OUT:bin\\kernel.exe bin\\hal.lib obj\\ini_parser.obj obj\\printf.obj obj\\libc.obj obj\\kernel\\*.obj", KernelCflags, LFLAGS),
|
|
|
|
// Subsystem DLLs.
|
|
"link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\syscall.dll obj\\syscall\\stubs.obj",
|
|
nob_temp_sprintf("cl %s /DUSER_HEAP_EXPORTS /DNTL_EXCEPTION_EXPORTS /MP /c /Foobj\\win32\\ code\\user\\runtime\\heap.c code\\user\\runtime\\heap_exports.c code\\user\\runtime\\native_exception.c code\\user\\personalities\\win32\\*.c && link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\win32.dll bin\\syscall.lib obj\\libc.obj obj\\win32\\*.obj", UserCflags),
|
|
nob_temp_sprintf("cl %s /DUSER_HEAP_EXPORTS /MP /c /Foobj\\posix\\ code\\user\\runtime\\heap.c code\\user\\runtime\\heap_exports.c code\\user\\personalities\\posix\\*.c && link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\posix.dll bin\\syscall.lib obj\\libc.obj obj\\posix\\*.obj", UserCflags)
|
|
};
|
|
|
|
for (size_t i = 0; i < NOB_ARRAY_LEN(core_tasks); i++) {
|
|
if (!run_sync(core_tasks[i])) return 1;
|
|
}
|
|
|
|
// PCI builds before PCI function drivers because it exports the bus-driver import library.
|
|
nob_log(NOB_INFO, "--- Building Bus Drivers ---");
|
|
const char *pci_cmd = nob_temp_sprintf(
|
|
"cl %s /MP /c /Fo%s\\ %s && link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\%s.sys /IMPLIB:bin\\%s.lib /ENTRY:DriverEntry bin\\hal.lib bin\\kernel.lib obj\\printf.obj obj\\libc.obj %s\\*.obj",
|
|
PCI_BUS_DRIVER.cflags, PCI_BUS_DRIVER.obj_dir, PCI_BUS_DRIVER.sources,
|
|
PCI_BUS_DRIVER.name, PCI_BUS_DRIVER.name, PCI_BUS_DRIVER.obj_dir
|
|
);
|
|
if (!run_sync(pci_cmd)) return 1;
|
|
|
|
// 4. Parallel Phase (Drivers and Applications).
|
|
nob_log(NOB_INFO, "--- Compiling Drivers and Apps in Parallel ---");
|
|
Nob_Procs procs = {0};
|
|
|
|
// Queue standalone drivers. Each driver is now a target with one or more
|
|
// translation units, but still links to one .sys image with DriverEntry.
|
|
for (size_t i = 0; i < NOB_ARRAY_LEN(STANDALONE_DRIVERS); i++) {
|
|
const Driver_Target *driver = &STANDALONE_DRIVERS[i];
|
|
const char *cmd = nob_temp_sprintf(
|
|
"cl %s /MP /c /Fo%s\\ %s && link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\%s.sys /ENTRY:DriverEntry bin\\hal.lib bin\\kernel.lib %s obj\\libc.obj %s\\*.obj",
|
|
driver->cflags, driver->obj_dir, driver->sources, driver->name,
|
|
driver->libs ? driver->libs : "", driver->obj_dir
|
|
);
|
|
nob_da_append(&procs, run_async(cmd));
|
|
}
|
|
|
|
// Parse lwIP Sources and Queue it.
|
|
Nob_String_Builder sb = {0}, lwip_files = {0};
|
|
if (nob_read_entire_file("code\\drivers\\net\\lwip\\lwip_sources.txt", &sb)) {
|
|
Nob_String_View sv = nob_sv_from_parts(sb.items, sb.count);
|
|
while (sv.count > 0) {
|
|
Nob_String_View line = nob_sv_trim(nob_sv_chop_by_delim(&sv, '\n'));
|
|
if (line.count > 0 && line.data[0] != '#') {
|
|
nob_sb_append_cstr(&lwip_files, "code\\");
|
|
for (size_t i = 0; i < line.count; i++) nob_sb_append_buf(&lwip_files, &(char){line.data[i] == '/' ? '\\' : line.data[i]}, 1);
|
|
nob_sb_append_cstr(&lwip_files, " ");
|
|
}
|
|
}
|
|
nob_sb_append_null(&lwip_files);
|
|
nob_da_append(&procs, run_async(nob_temp_sprintf("cl %s /MP /c /Foobj\\lwip\\ %s && link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\lwip.sys /ENTRY:DriverEntry bin\\hal.lib bin\\kernel.lib obj\\libc.obj obj\\lwip\\*.obj", LwipCflags, lwip_files.items)));
|
|
}
|
|
|
|
// Queue Subsystem Applications.
|
|
const char *apps[][4] = {
|
|
// Folder, Libs, Name, Optional Extra Link Args.
|
|
{"system\\init", NATIVE_INIT_LIBS_LITERAL, "init", "/ENTRY:_start"},
|
|
{"apps\\shell_win32", WIN32_EXE_LIBS_LITERAL, "shell_win32", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"apps\\shell_posix", POSIX_EXE_LIBS_LITERAL, "shell_posix", "/ENTRY:PosixStart"},
|
|
{"apps\\shell_native", NATIVE_EXE_LIBS_LITERAL, "shell_native", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\async_apc", NATIVE_EXE_LIBS_LITERAL, "async_apc", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\apc_return_smoke", NATIVE_EXE_LIBS_LITERAL, "apc_return_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\async_cancel", NATIVE_EXE_LIBS_LITERAL, "async_cancel", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\file_stat_smoke", NATIVE_EXE_LIBS_LITERAL, "file_stat_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\handle_dup_smoke", NATIVE_EXE_LIBS_LITERAL, "handle_dup_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\named_queue_lifetime_smoke", NATIVE_EXE_LIBS_LITERAL, "named_queue_lifetime_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\input_api_smoke", NATIVE_EXE_LIBS_LITERAL, "input_api_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\input_model_smoke", NATIVE_EXE_LIBS_LITERAL, "input_model_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\timer_smoke", NATIVE_EXE_LIBS_LITERAL, "timer_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\stats_abi_smoke", NATIVE_EXE_LIBS_LITERAL, "stats_abi_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\realpath_smoke", NATIVE_EXE_LIBS_LITERAL, "realpath_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\file_lock_smoke", NATIVE_EXE_LIBS_LITERAL, "file_lock_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\process_protection_smoke", NATIVE_EXE_LIBS_LITERAL, "process_protection_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\socket_addr_smoke", NATIVE_EXE_LIBS_LITERAL, "socket_addr_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\net_irp_smoke", NATIVE_EXE_LIBS_LITERAL, "net_irp_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\module_load_smoke", NATIVE_EXE_LIBS_LITERAL, "module_load_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\posix_module_smoke", POSIX_EXE_LIBS_LITERAL, "posix_module_smoke", "/ENTRY:PosixStart"},
|
|
{"tests\\exception_dispatcher_smoke", NATIVE_EXE_LIBS_LITERAL, "exception_dispatcher_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\native_exception_runtime_smoke", NATIVE_EXE_LIBS_LITERAL, "native_exception_runtime_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\native_raise_exception_smoke", NATIVE_EXE_LIBS_LITERAL, "native_raise_exception_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\exception_smoke", NATIVE_EXE_LIBS_LITERAL, "exception_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\win32_exception_smoke", WIN32_EXE_LIBS_LITERAL, "win32_exception_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\win32_seh_smoke", WIN32_EXE_LIBS_LITERAL, "win32_seh_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\syscall_contract_smoke", NATIVE_EXE_LIBS_LITERAL, "syscall_contract_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\would_block_smoke", NATIVE_EXE_LIBS_LITERAL, "would_block_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\cwd_peb_smoke", NATIVE_EXE_LIBS_LITERAL, "cwd_peb_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\mmap_smoke", NATIVE_EXE_LIBS_LITERAL, "mmap_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\pcache_smoke", NATIVE_EXE_LIBS_LITERAL, "pcache_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\pcache_pressure", NATIVE_EXE_LIBS_LITERAL, "pcache_pressure", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\dirty_writeback", NATIVE_EXE_LIBS_LITERAL, "dirty_writeback", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\shared_mmap", NATIVE_EXE_LIBS_LITERAL, "shared_mmap", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\pcache_invalidate", NATIVE_EXE_LIBS_LITERAL, "pcache_invalidate", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\pcache_mmap_read_reuse", NATIVE_EXE_LIBS_LITERAL, "pcache_mmap_read_reuse", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\pcache_multithread", NATIVE_EXE_LIBS_LITERAL, "pcache_multithread", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\surface_smoke", NATIVE_EXE_LIBS_LITERAL, "surface_smoke", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\surface_invalid_rect", NATIVE_EXE_LIBS_LITERAL, "surface_invalid_rect", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"tests\\surface_multithread_present", NATIVE_EXE_LIBS_LITERAL, "surface_multithread_present", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"apps\\edit", NATIVE_EXE_LIBS_LITERAL, "edit", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"apps\\httpget", NATIVE_EXE_LIBS_LITERAL, "httpget", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"apps\\tcpserve", NATIVE_EXE_LIBS_LITERAL, "tcpserve", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"apps\\udp", NATIVE_EXE_LIBS_LITERAL, "udp", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"apps\\resolve", NATIVE_EXE_LIBS_LITERAL, "resolve", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"apps\\ping", NATIVE_EXE_LIBS_LITERAL, "ping", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"apps\\doom", NATIVE_EXE_LIBS_LITERAL, "doom", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"apps\\video", "bin\\syscall.lib obj\\libc.obj " NATIVE_RUNTIME_OBJS_LITERAL " code\\user\\apps\\video\\bink2w64.lib", "video", NATIVE_EXE_ENTRY_LITERAL},
|
|
{"apps\\memtop", NATIVE_EXE_LIBS_LITERAL, "memtop", NATIVE_EXE_ENTRY_LITERAL}
|
|
};
|
|
|
|
for (size_t i = 0; i < NOB_ARRAY_LEN(apps); i++) {
|
|
const char *cmd = nob_temp_sprintf(
|
|
"cl %s /MP /c /Foobj\\%s\\ code\\user\\%s\\*.c && link %s /SUBSYSTEM:NATIVE %s /OUT:bin\\%s.exe /PDB:bin\\%s.pdb %s obj\\%s\\*.obj",
|
|
UserCflags, apps[i][2], apps[i][0], LFLAGS, apps[i][3], apps[i][2], apps[i][2], apps[i][1], apps[i][2]
|
|
);
|
|
nob_da_append(&procs, run_async(cmd));
|
|
}
|
|
|
|
// Wait for everything to link simultaneously.
|
|
if (!nob_procs_wait(procs)) {
|
|
nob_log(NOB_ERROR, "One or more parallel build jobs failed!");
|
|
return 1;
|
|
}
|
|
|
|
// 4. Mounting & Packing Image.
|
|
nob_log(NOB_INFO, "--- Mounting disk.vhd ---");
|
|
|
|
// Resolve the absolute path to disk.vhd for diskpart.
|
|
char vhd_path[MAX_PATH];
|
|
GetFullPathNameA("disk.vhd", MAX_PATH, vhd_path, NULL);
|
|
|
|
const char *diskpart_mnt = nob_temp_sprintf(
|
|
"select vdisk file=\"%s\"\nattach vdisk\n"
|
|
"select partition 1\nformat fs=fat32 quick\nassign letter=Z\n"
|
|
"select partition 2\nformat fs=fat32 quick\nassign letter=Y\nexit\n",
|
|
vhd_path
|
|
);
|
|
nob_write_entire_file("mnt.txt", diskpart_mnt, strlen(diskpart_mnt));
|
|
if (!run_sync("diskpart /s mnt.txt")) return 1;
|
|
|
|
nob_log(NOB_INFO, "--- Assembling ESP ---");
|
|
_mkdir("Z:\\apps"); _mkdir("Y:\\apps");
|
|
_mkdir("Z:\\system"); _mkdir("Z:\\drivers");
|
|
_mkdir("Z:\\EFI"); _mkdir("Z:\\EFI\\BOOT");
|
|
|
|
const char *copies[][2] = {
|
|
{"bin\\bootx64.efi", "Z:\\EFI\\BOOT\\bootx64.efi"}, {"bin\\kernel.exe", "Z:\\system\\colonel.exe"},
|
|
{"bin\\hal.dll", "Z:\\system\\hal.dll"}, {"bin\\syscall.dll", "Z:\\system\\syscall.dll"},
|
|
{"bin\\win32.dll", "Z:\\system\\win32.dll"}, {"bin\\posix.dll", "Z:\\system\\posix.dll"},
|
|
{"code\\settings.ini", "Z:\\system\\settings.ini"}, {"bin\\init.exe", "Z:\\system\\init.exe"},
|
|
|
|
{"bin\\pci.sys", "Z:\\drivers\\pci.sys"}, {"bin\\ps2.sys", "Z:\\drivers\\ps2.sys"},
|
|
{"bin\\serial.sys", "Z:\\drivers\\serial.sys"},
|
|
{"bin\\ata.sys", "Z:\\drivers\\ata.sys"}, {"bin\\ahci.sys", "Z:\\drivers\\ahci.sys"},
|
|
{"bin\\fat32.sys", "Z:\\drivers\\fat32.sys"}, {"bin\\ntfs.sys", "Z:\\drivers\\ntfs.sys"},
|
|
{"bin\\vmwaresvga.sys", "Z:\\drivers\\vmwaresvga.sys"},
|
|
{"bin\\lwip.sys", "Z:\\drivers\\lwip.sys"}, {"bin\\usb.sys", "Z:\\drivers\\usb.sys"},
|
|
{"bin\\rtl816x.sys", "Z:\\drivers\\rtl816x.sys"},
|
|
{"bin\\rtl8139.sys", "Z:\\drivers\\rtl8139.sys"}, {"code\\drivers\\drivers.ini", "Z:\\drivers\\drivers.ini"},
|
|
{"code\\boot.ini", "Z:\\boot.ini"},
|
|
|
|
{"bin\\shell_win32.exe", "Z:\\apps\\shell_win32.exe"}, {"bin\\shell_posix.exe", "Z:\\apps\\shell_posix.exe"},
|
|
{"bin\\shell_native.exe", "Z:\\apps\\shell_native.exe"}, {"bin\\edit.exe", "Z:\\apps\\edit.exe"},
|
|
{"bin\\httpget.exe", "Z:\\apps\\httpget.exe"}, {"bin\\tcpserve.exe", "Z:\\apps\\tcpserve.exe"},
|
|
{"bin\\udp.exe", "Z:\\apps\\udp.exe"}, {"bin\\resolve.exe", "Z:\\apps\\resolve.exe"},
|
|
{"bin\\ping.exe", "Z:\\apps\\ping.exe"}, {"bin\\doom.exe", "Z:\\apps\\doom.exe"},
|
|
{"bin\\video.exe", "Z:\\apps\\video.exe"}, {"bin\\memtop.exe", "Z:\\apps\\memtop.exe"},
|
|
|
|
{"bin\\async_apc.exe", "Y:\\apps\\async_apc.exe"}, {"bin\\async_cancel.exe", "Y:\\apps\\async_cancel.exe"},
|
|
{"bin\\apc_return_smoke.exe", "Y:\\apps\\apc_return_smoke.exe"},
|
|
{"bin\\file_stat_smoke.exe", "Y:\\apps\\file_stat_smoke.exe"},
|
|
{"bin\\handle_dup_smoke.exe", "Y:\\apps\\handle_dup_smoke.exe"},
|
|
{"bin\\named_queue_lifetime_smoke.exe", "Y:\\apps\\named_queue_lifetime_smoke.exe"},
|
|
{"bin\\input_api_smoke.exe", "Y:\\apps\\input_api_smoke.exe"},
|
|
{"bin\\input_model_smoke.exe", "Y:\\apps\\input_model_smoke.exe"},
|
|
{"bin\\timer_smoke.exe", "Y:\\apps\\timer_smoke.exe"},
|
|
{"bin\\stats_abi_smoke.exe", "Y:\\apps\\stats_abi_smoke.exe"},
|
|
{"bin\\realpath_smoke.exe", "Y:\\apps\\realpath_smoke.exe"},
|
|
{"bin\\file_lock_smoke.exe", "Y:\\apps\\file_lock_smoke.exe"},
|
|
{"bin\\process_protection_smoke.exe", "Y:\\apps\\process_protection_smoke.exe"},
|
|
{"bin\\socket_addr_smoke.exe", "Y:\\apps\\socket_addr_smoke.exe"},
|
|
{"bin\\net_irp_smoke.exe", "Y:\\apps\\net_irp_smoke.exe"},
|
|
{"bin\\module_load_smoke.exe", "Y:\\apps\\module_load_smoke.exe"},
|
|
{"bin\\posix_module_smoke.exe", "Y:\\apps\\posix_module_smoke.exe"},
|
|
{"bin\\exception_dispatcher_smoke.exe", "Y:\\apps\\exception_dispatcher_smoke.exe"},
|
|
{"bin\\native_exception_runtime_smoke.exe", "Y:\\apps\\native_exception_runtime_smoke.exe"},
|
|
{"bin\\native_raise_exception_smoke.exe", "Y:\\apps\\native_raise_exception_smoke.exe"},
|
|
{"bin\\exception_smoke.exe", "Y:\\apps\\exception_smoke.exe"},
|
|
{"bin\\win32_exception_smoke.exe", "Y:\\apps\\win32_exception_smoke.exe"},
|
|
{"bin\\win32_seh_smoke.exe", "Y:\\apps\\win32_seh_smoke.exe"},
|
|
{"bin\\syscall_contract_smoke.exe", "Y:\\apps\\syscall_contract_smoke.exe"},
|
|
{"bin\\would_block_smoke.exe", "Y:\\apps\\would_block_smoke.exe"},
|
|
{"bin\\cwd_peb_smoke.exe", "Y:\\apps\\cwd_peb_smoke.exe"},
|
|
{"bin\\mmap_smoke.exe", "Y:\\apps\\mmap_smoke.exe"}, {"bin\\pcache_smoke.exe", "Y:\\apps\\pcache_smoke.exe"},
|
|
{"bin\\pcache_pressure.exe", "Y:\\apps\\pcache_pressure.exe"},
|
|
{"bin\\dirty_writeback.exe", "Y:\\apps\\dirty_writeback.exe"},
|
|
{"bin\\shared_mmap.exe", "Y:\\apps\\shared_mmap.exe"},
|
|
{"bin\\pcache_invalidate.exe", "Y:\\apps\\pcache_invalidate.exe"},
|
|
{"bin\\pcache_mmap_read_reuse.exe", "Y:\\apps\\pcache_mmap_read_reuse.exe"},
|
|
{"bin\\pcache_multithread.exe", "Y:\\apps\\pcache_multithread.exe"},
|
|
{"bin\\surface_smoke.exe", "Y:\\apps\\surface_smoke.exe"},
|
|
{"bin\\surface_invalid_rect.exe", "Y:\\apps\\surface_invalid_rect.exe"},
|
|
{"bin\\surface_multithread_present.exe", "Y:\\apps\\surface_multithread_present.exe"}
|
|
};
|
|
|
|
for (size_t i = 0; i < NOB_ARRAY_LEN(copies); i++) nob_copy_file(copies[i][0], copies[i][1]);
|
|
|
|
if (nob_file_exists("code\\user\\apps\\video\\bink2w64.dll")) nob_copy_file("code\\user\\apps\\video\\bink2w64.dll", "Z:\\apps\\bink2w64.dll");
|
|
if (nob_file_exists("code\\user\\apps\\video\\video.bk2")) nob_copy_file("code\\user\\apps\\video\\video.bk2", "Z:\\apps\\video.bk2");
|
|
if (nob_file_exists("code\\user\\apps\\doom\\doom1.wad")) nob_copy_file("code\\user\\apps\\doom\\doom1.wad", "Z:\\apps\\doom1.wad");
|
|
|
|
nob_log(NOB_INFO, "--- Unmounting disk.vhd ---");
|
|
const char *diskpart_umnt = nob_temp_sprintf(
|
|
"select vdisk file=\"%s\"\ndetach vdisk\nexit\n",
|
|
vhd_path
|
|
);
|
|
nob_write_entire_file("umnt.txt", diskpart_umnt, strlen(diskpart_umnt));
|
|
run_sync("diskpart /s umnt.txt");
|
|
|
|
remove("mnt.txt");
|
|
remove("umnt.txt");
|
|
|
|
nob_log(NOB_INFO, "Build complete!");
|
|
return 0;
|
|
}
|