// Bootstrap: cl /nologo nob.c // After that, just run: nob.exe #define NOB_IMPLEMENTATION #include "nob.h" #define BUILD_DIR "build" #define IMGUI_LIB BUILD_DIR "/imgui.lib" static const char *src_files[] = { "src/main.cpp", "src/platform/platform_win32.cpp", "src/renderer/renderer_dx12.cpp", }; static const char *imgui_files[] = { "vendor/imgui/imgui.cpp", "vendor/imgui/imgui_draw.cpp", "vendor/imgui/imgui_tables.cpp", "vendor/imgui/imgui_widgets.cpp", "vendor/imgui/imgui_demo.cpp", "vendor/imgui/backends/imgui_impl_win32.cpp", "vendor/imgui/backends/imgui_impl_dx12.cpp", }; static const char *link_libs[] = { "d3d12.lib", "dxgi.lib", "d3dcompiler.lib", "user32.lib", "gdi32.lib", "shell32.lib", "ole32.lib", "dwmapi.lib", }; static bool build_imgui_lib(void) { int need = nob_needs_rebuild(IMGUI_LIB, imgui_files, NOB_ARRAY_LEN(imgui_files)); if (need < 0) return false; if (!need) { nob_log(NOB_INFO, "%s is up to date", IMGUI_LIB); return true; } nob_log(NOB_INFO, "Building %s...", IMGUI_LIB); // Compile each imgui source to .obj Nob_Cmd cmd = {0}; nob_cmd_append(&cmd, "cl.exe"); nob_cmd_append(&cmd, "/nologo", "/std:c++17", "/EHsc", "/W3", "/c"); nob_cmd_append(&cmd, "/Ivendor/imgui", "/Ivendor/imgui/backends"); #ifdef _DEBUG nob_cmd_append(&cmd, "/Zi", "/Od", "/D_DEBUG"); #else nob_cmd_append(&cmd, "/O2", "/DNDEBUG"); #endif nob_cmd_append(&cmd, nob_temp_sprintf("/Fo:%s/", BUILD_DIR)); nob_cmd_append(&cmd, nob_temp_sprintf("/Fd:%s/", BUILD_DIR)); for (size_t i = 0; i < NOB_ARRAY_LEN(imgui_files); i++) nob_cmd_append(&cmd, imgui_files[i]); if (!nob_cmd_run(&cmd)) return false; // Archive .obj files into a .lib cmd.count = 0; nob_cmd_append(&cmd, "lib.exe", "/nologo"); nob_cmd_append(&cmd, nob_temp_sprintf("/OUT:%s", IMGUI_LIB)); for (size_t i = 0; i < NOB_ARRAY_LEN(imgui_files); i++) { const char *base = nob_temp_sprintf("%s", imgui_files[i]); const char *slash = strrchr(base, '/'); const char *name = slash ? slash + 1 : base; size_t len = strlen(name); char *obj = nob_temp_sprintf("%s/%.*s.obj", BUILD_DIR, (int)(len - 4), name); nob_cmd_append(&cmd, obj); } if (!nob_cmd_run(&cmd)) return false; // Clean up imgui .obj files for (size_t i = 0; i < NOB_ARRAY_LEN(imgui_files); i++) { const char *slash = strrchr(imgui_files[i], '/'); const char *name = slash ? slash + 1 : imgui_files[i]; size_t len = strlen(name); nob_delete_file(nob_temp_sprintf("%s/%.*s.obj", BUILD_DIR, (int)(len - 4), name)); } return true; } int main(int argc, char **argv) { NOB_GO_REBUILD_URSELF(argc, argv); if (!nob_mkdir_if_not_exists(BUILD_DIR)) return 1; // Build vendor libs (unless already built) if (!build_imgui_lib()) return 1; // Compile and link Nob_Cmd cmd = {0}; nob_cmd_append(&cmd, "cl.exe"); nob_cmd_append(&cmd, "/nologo", "/std:c++17", "/EHsc", "/W3"); nob_cmd_append(&cmd, "/Isrc", "/Ivendor/imgui", "/Ivendor/imgui/backends"); #ifdef _DEBUG nob_cmd_append(&cmd, "/Zi", "/Od", "/D_DEBUG"); #else nob_cmd_append(&cmd, "/Zi", "/O2", "/DNDEBUG"); #endif nob_cmd_append(&cmd, nob_temp_sprintf("/Fe:%s/autosample.exe", BUILD_DIR)); nob_cmd_append(&cmd, nob_temp_sprintf("/Fo:%s/", BUILD_DIR)); nob_cmd_append(&cmd, nob_temp_sprintf("/Fd:%s/autosample.pdb", BUILD_DIR)); for (size_t i = 0; i < NOB_ARRAY_LEN(src_files); i++) nob_cmd_append(&cmd, src_files[i]); nob_cmd_append(&cmd, "/link"); nob_cmd_append(&cmd, "/SUBSYSTEM:CONSOLE"); nob_cmd_append(&cmd, nob_temp_sprintf("/PDB:%s/autosample.pdb", BUILD_DIR)); nob_cmd_append(&cmd, "/DEBUG"); nob_cmd_append(&cmd, IMGUI_LIB); for (size_t i = 0; i < NOB_ARRAY_LEN(link_libs); i++) nob_cmd_append(&cmd, link_libs[i]); if (!nob_cmd_run(&cmd)) return 1; // Clean up .obj files for (size_t i = 0; i < NOB_ARRAY_LEN(src_files); i++) { const char *slash = strrchr(src_files[i], '/'); const char *name = slash ? slash + 1 : src_files[i]; size_t len = strlen(name); nob_delete_file(nob_temp_sprintf("%s/%.*s.obj", BUILD_DIR, (int)(len - 4), name)); } nob_log(NOB_INFO, "Build complete: %s/autosample.exe", BUILD_DIR); return 0; }