diff --git a/build.c b/build.c index a26828a1..e54cc8e5 100644 --- a/build.c +++ b/build.c @@ -1,6 +1,13 @@ #define Rtc 1 #include "buildit.h" +/* ========================== * + * Globals + * ========================== */ + +D_Hist hist = { 0 }; +Bool force_rebuild = false; + /* ========================== * * Util * ========================== */ @@ -10,6 +17,11 @@ void Error(String msg) SH_PrintF(Lit("ERROR: %F\n"), FmtStr(msg)); } +Bool IsDirty(D_Tag tag) +{ + return force_rebuild ? true : D_IsDirty(tag, &hist); +} + /* ========================== * * Step * ========================== */ @@ -128,6 +140,7 @@ void OnBuild(StringList cli_args) } String hist_path = OS_GetAbsPath(&arena, StringF(&arena, Lit("%F/.dephist"), FmtStr(arg_outdir))); + String build_hash_path = OS_GetAbsPath(&arena, StringF(&arena, Lit("%F/.pp_build_hash"), FmtStr(arg_outdir))); String out_dep_dir_path = OS_GetAbsPath(&arena, StringF(&arena, Lit("%F/dep/"), FmtStr(arg_outdir))); String out_obj_dir_path = OS_GetAbsPath(&arena, StringF(&arena, Lit("%F/obj/"), FmtStr(arg_outdir))); String out_inc_dir_path = OS_GetAbsPath(&arena, StringF(&arena, Lit("%F/inc/"), FmtStr(arg_outdir))); @@ -273,7 +286,7 @@ void OnBuild(StringList cli_args) } else { /* Enable UBSan */ StringListAppend(&arena, &compile_and_link_args, Lit("-fsanitize=undefined -fsanitize-trap=all")); - //StringListAppend(&compile_and_link_args, "-fsanitize=undefined"); + //StringListAppend(&arena, &compile_and_link_args, Lit("-fsanitize=undefined")); } } @@ -363,128 +376,125 @@ void OnBuild(StringList cli_args) } /* ========================== * - * Read hist file + * Generate root dependencies * ========================== */ - D_Hist hist = D_HistFromPath(&arena, hist_path); - - /* ========================== * - * Assemble input files - * ========================== */ - - D_TagList tar_input_dirs = { 0 }; - D_Tag rc_input_file = D_TagFromPath(&arena, StringF(&arena, Lit("%F/rc.rc"), FmtStr(out_inc_dir_path)), D_TagKind_File); - D_Tag pch_header_file = D_TagFromPath(&arena, Lit("src/common.h"), D_TagKind_File); - D_TagList src_input_files = { 0 }; - - /* Append tar input dirs */ - D_TagListAppend(&arena, &tar_input_dirs, shaders_dir); - if (should_embed_res_dir) { - D_TagListAppend(&arena, &tar_input_dirs, res_dir); - } - - /* Generate & append rc input file */ - if (PlatformWindows) { - D_AddDependency(rc_input_file, icon_file); - /* TODO: Depend on tar files rather than dir (more correct) */ - if (should_embed_in_rc) { - D_AddDependency(rc_input_file, shaders_dir); - if (should_embed_res_dir) { - D_AddDependency(rc_input_file, res_dir); - } - } - if (D_IsDirty(rc_input_file, &hist)) { - D_Tag shaders_tar_file = D_TagFromPath(&arena, StringF(&arena, Lit("%F/%F.tar"), FmtStr(out_inc_dir_path), FmtStr(D_GetName(shaders_dir))), D_TagKind_File); - D_ClearWrite(rc_input_file, Lit("")); - D_AppendWrite(rc_input_file, StringF(&arena, Lit("%F %F DISCARDABLE %F\n"), FmtStr(D_GetName(icon_file)), FmtStr(Lit("ICON")), FmtStr(D_GetName(icon_file)))); - if (should_embed_in_rc) { - D_AppendWrite(rc_input_file, StringF(&arena, Lit("%F %F DISCARDABLE %F\n"), FmtStr(D_GetName(shaders_tar_file)), FmtStr(Lit("RCDATA")), FmtStr(D_GetName(shaders_tar_file)))); - if (should_embed_res_dir) { - D_Tag res_tar_file = D_TagFromPath(&arena, StringF(&arena, Lit("%F/%F.tar"), FmtStr(out_inc_dir_path), FmtStr(D_GetName(res_dir))), D_TagKind_File); - D_AppendWrite(rc_input_file, StringF(&arena, Lit("%F %F DISCARDABLE %F\n"), FmtStr(D_GetName(res_tar_file)), FmtStr(Lit("RCDATA")), FmtStr(D_GetName(res_tar_file)))); - } - } - } - } - - /* Append 'src' dir c & cpp files */ { - D_Tag src_dir = D_TagFromPath(&arena, Lit("src"), D_TagKind_Dir); - D_TagList src_dir_files = D_GetDirContents(&arena, src_dir); - for (D_TagListNode *n = src_dir_files.first; n; n = n->next) { - Bool ignore = true; + D_Tag build_hash_file = D_TagFromPath(&arena, build_hash_path, D_TagKind_File); - D_Tag file = n->tag; - String path = file.full_path; - String name = D_GetName(file); - String extension = StringPathExtension(name); - Bool is_dir = file.kind == D_TagKind_Dir; - Bool is_c = !is_dir && StringEqual(extension, Lit("c")); - Bool is_cpp = !is_dir && !is_c && StringEqual(extension, Lit("cpp")); - if (is_c || is_cpp) { - if (StringBeginsWith(name, Lit("sys_")) || - StringBeginsWith(name, Lit("renderer_")) || - StringBeginsWith(name, Lit("playback_")) || - StringBeginsWith(name, Lit("mp3_")) || - StringBeginsWith(name, Lit("ttf_"))) { - if (PlatformWindows) { - ignore = !(StringEqual(name, Lit("sys_win32.c")) || - StringEqual(name, Lit("renderer_d3d11.c")) || - StringEqual(name, Lit("playback_wasapi.c")) || - StringEqual(name, Lit("mp3_mmf.c")) || - StringEqual(name, Lit("ttf_dwrite.cpp"))); - } - } else { - ignore = false; - } - } + U64 build_hash = D_HashString64Basis; + { + String args_str = StringFromStringList(&arena, Lit(" "), cli_args); + String compile_time_str = Lit(__DATE__ __TIME__); + build_hash = D_HashString64(build_hash, args_str); + build_hash = D_HashString64(build_hash, compile_time_str); + } - if (!ignore) { - D_TagListAppend(&arena, &src_input_files, file); + U64 old_build_hash = 0; + { + String build_hash_file_data = D_ReadAll(&arena, build_hash_file); + if (build_hash_file_data.len >= 8) { + MemoryCopy((Byte *)&old_build_hash, build_hash_file_data.text, 8); } } + + if (build_hash != old_build_hash) { + SH_Print(Lit("Builder exe or build args have changed, rebuilding all.\n")); + force_rebuild = true; + String data = StringFromStruct(&build_hash); + D_ClearWrite(build_hash_file, data); + } } + /* ========================== * - * Assemble build steps + * Build * ========================== */ + hist = D_HistFromPath(&arena, hist_path); + StepList build_steps = { 0 }; D_TagList link_files = { 0 }; - /* Build tar files */ - for (D_TagListNode *n = tar_input_dirs.first; n; n = n->next) { - D_Tag input_dir = n->tag; - D_Tag tar_file = D_TagFromPath(&arena, StringF(&arena, Lit("%F/%F.tar"), FmtStr(out_inc_dir_path), FmtStr(D_GetName(input_dir))), D_TagKind_File); - D_AddDependency(tar_file, input_dir); - if (should_embed_in_rc) { - D_AddDependency(rc_res_file, tar_file); - } else { - D_AddDependency(inc_src_file, tar_file); - } - if (D_IsDirty(tar_file, &hist)) { - String cmd = StringF(&arena, Lit("cd %F && tar cvf %F ."), FmtStr(input_dir.full_path), FmtStr(tar_file.full_path)); - String step_name = StringF(&arena, Lit("%F -> %F"), FmtStr(D_GetName(input_dir)), FmtStr(D_GetName(tar_file))); - StepListAppend(&arena, &build_steps, step_name, cmd, true); - } - } + /* ========================== * + * Build step: Tar archives + * ========================== */ - /* Build rc file */ - if (PlatformWindows) { - String rc_compile_args_fmt = StringFromStringLists(&arena, Lit(" "), rc_compile_args); - D_AddDependency(rc_res_file, rc_input_file); - - if (D_IsDirty(rc_res_file, &hist)) { - String cmd = StringF(&arena, rc_compile_args_fmt, FmtStr(rc_res_file.full_path), FmtStr(rc_input_file.full_path)); - String step_name = StringF(&arena, Lit("%F -> %F"), FmtStr(D_GetName(rc_input_file)), FmtStr(D_GetName(rc_res_file))); - StepListAppend(&arena, &build_steps, step_name, cmd, true); - } - - D_TagListAppend(&arena, &link_files, rc_res_file); - } - - /* Build pch */ { + D_TagList tar_input_dirs = { 0 }; + { + D_TagListAppend(&arena, &tar_input_dirs, shaders_dir); + if (should_embed_res_dir) { + D_TagListAppend(&arena, &tar_input_dirs, res_dir); + } + } + + for (D_TagListNode *n = tar_input_dirs.first; n; n = n->next) { + D_Tag input_dir = n->tag; + D_Tag tar_file = D_TagFromPath(&arena, StringF(&arena, Lit("%F/%F.tar"), FmtStr(out_inc_dir_path), FmtStr(D_GetName(input_dir))), D_TagKind_File); + D_AddDependency(tar_file, input_dir); + if (should_embed_in_rc) { + D_AddDependency(rc_res_file, tar_file); + } else { + D_AddDependency(inc_src_file, tar_file); + } + if (IsDirty(tar_file)) { + String cmd = StringF(&arena, Lit("cd %F && tar cvf %F ."), FmtStr(input_dir.full_path), FmtStr(tar_file.full_path)); + String step_name = StringF(&arena, Lit("%F -> %F"), FmtStr(D_GetName(input_dir)), FmtStr(D_GetName(tar_file))); + StepListAppend(&arena, &build_steps, step_name, cmd, true); + } + } + } + + /* ========================== * + * Build step: Compile RC files + * ========================== */ + + if (PlatformWindows) { + D_Tag rc_input_file = D_TagFromPath(&arena, StringF(&arena, Lit("%F/rc.rc"), FmtStr(out_inc_dir_path)), D_TagKind_File); + { + D_Tag shaders_tar_file = D_TagFromPath(&arena, StringF(&arena, Lit("%F/%F.tar"), FmtStr(out_inc_dir_path), FmtStr(D_GetName(shaders_dir))), D_TagKind_File); + D_Tag res_tar_file = D_TagFromPath(&arena, StringF(&arena, Lit("%F/%F.tar"), FmtStr(out_inc_dir_path), FmtStr(D_GetName(res_dir))), D_TagKind_File); + D_AddDependency(rc_input_file, icon_file); + if (should_embed_in_rc) { + D_AddDependency(rc_input_file, shaders_tar_file); + if (should_embed_res_dir) { + D_AddDependency(rc_input_file, res_tar_file); + } + } + if (IsDirty(rc_input_file)) { + D_ClearWrite(rc_input_file, Lit("")); + D_AppendWrite(rc_input_file, StringF(&arena, Lit("%F %F DISCARDABLE %F\n"), FmtStr(D_GetName(icon_file)), FmtStr(Lit("ICON")), FmtStr(D_GetName(icon_file)))); + if (should_embed_in_rc) { + D_AppendWrite(rc_input_file, StringF(&arena, Lit("%F %F DISCARDABLE %F\n"), FmtStr(D_GetName(shaders_tar_file)), FmtStr(Lit("RCDATA")), FmtStr(D_GetName(shaders_tar_file)))); + if (should_embed_res_dir) { + D_AppendWrite(rc_input_file, StringF(&arena, Lit("%F %F DISCARDABLE %F\n"), FmtStr(D_GetName(res_tar_file)), FmtStr(Lit("RCDATA")), FmtStr(D_GetName(res_tar_file)))); + } + } + } + } + + { + String rc_compile_args_fmt = StringFromStringLists(&arena, Lit(" "), rc_compile_args); + D_AddDependency(rc_res_file, rc_input_file); + + if (IsDirty(rc_res_file)) { + String cmd = StringF(&arena, rc_compile_args_fmt, FmtStr(rc_res_file.full_path), FmtStr(rc_input_file.full_path)); + String step_name = StringF(&arena, Lit("%F -> %F"), FmtStr(D_GetName(rc_input_file)), FmtStr(D_GetName(rc_res_file))); + StepListAppend(&arena, &build_steps, step_name, cmd, true); + } + + D_TagListAppend(&arena, &link_files, rc_res_file); + } + } + + /* ========================== * + * Build step: Compile pch files + * ========================== */ + + { + D_Tag pch_header_file = D_TagFromPath(&arena, Lit("src/common.h"), D_TagKind_File); + D_Tag dep_file; { String name = D_GetName(pch_header_file); @@ -520,7 +530,7 @@ void OnBuild(StringList cli_args) /* C */ D_AddDependency(pch_c_src_gen_obj_file, pch_c_src_gen_file); D_AddDependency(pch_c_file, pch_c_src_gen_obj_file); - if (D_IsDirty(pch_c_file, &hist)) { + if (IsDirty(pch_c_file)) { D_ClearWrite(pch_c_src_gen_file, Lit("")); String cmd = StringF(&arena, pch_c_compile_args_fmt, FmtStr(pch_header_file.full_path), FmtStr(pch_c_src_gen_file.full_path)); String step_name = StringF(&arena, Lit("%F -> %F"), FmtStr(D_GetName(pch_header_file)), FmtStr(D_GetName(pch_c_file))); @@ -530,7 +540,7 @@ void OnBuild(StringList cli_args) /* Cpp */ D_AddDependency(pch_cpp_src_gen_obj_file, pch_cpp_src_gen_file); D_AddDependency(pch_cpp_file, pch_cpp_src_gen_obj_file); - if (D_IsDirty(pch_cpp_file, &hist)) { + if (IsDirty(pch_cpp_file)) { D_ClearWrite(pch_cpp_src_gen_file, Lit("")); String cmd = StringF(&arena, pch_cpp_compile_args_fmt, FmtStr(pch_header_file.full_path), FmtStr(pch_cpp_src_gen_file.full_path)); String step_name = StringF(&arena, Lit("%F -> %F"), FmtStr(D_GetName(pch_header_file)), FmtStr(D_GetName(pch_cpp_file))); @@ -544,14 +554,14 @@ void OnBuild(StringList cli_args) String pch_cpp_compile_args_fmt = StringFromStringLists(&arena, Lit(" "), pch_cpp_compile_args, compile_warnings, compile_and_link_args, compile_args); /* C */ - if (D_IsDirty(pch_c_file, &hist)) { + if (IsDirty(pch_c_file)) { String comp_cmd = StringF(&arena, pch_c_compile_args_fmt, FmtStr(pch_header_file.full_path), FmtStr(pch_c_file.full_path)); String step_name = StringF(&arena, Lit("%F -> %F"), FmtStr(D_GetName(pch_header_file)), FmtStr(D_GetName(pch_c_file))); StepListAppend(&arena, &build_steps, step_name, comp_cmd, true); } /* Cpp */ - if (D_IsDirty(pch_cpp_file, &hist)) { + if (IsDirty(pch_cpp_file)) { String comp_cmd = StringF(&arena, pch_cpp_compile_args_fmt, FmtStr(pch_header_file.full_path), FmtStr(pch_cpp_file.full_path)); String step_name = StringF(&arena, Lit("%F -> %F"), FmtStr(D_GetName(pch_header_file)), FmtStr(D_GetName(pch_cpp_file))); StepListAppend(&arena, &build_steps, step_name, comp_cmd, true); @@ -559,46 +569,93 @@ void OnBuild(StringList cli_args) } } - /* Build src files */ + /* ========================== * + * Build step: Compile src files + * ========================== */ + { - String c_compile_args_fmt = StringFromStringLists(&arena, Lit(" "), c_compile_args, compile_warnings, compile_and_link_args, compile_args); - String cpp_compile_args_fmt = StringFromStringLists(&arena, Lit(" "), cpp_compile_args, compile_warnings, compile_and_link_args, compile_args); - for (D_TagListNode *n = src_input_files.first; n; n = n->next) { - D_Tag file = n->tag; - String path = file.full_path; - String name = D_GetName(file); - String extension = StringPathExtension(name); - Bool is_c = StringEqual(extension, Lit("c")); - Bool is_cpp = !is_c && StringEqual(extension, Lit("cpp")); + D_TagList src_input_files = { 0 }; + { + D_Tag src_dir = D_TagFromPath(&arena, Lit("src"), D_TagKind_Dir); + D_TagList src_dir_files = D_GetDirContents(&arena, src_dir); + for (D_TagListNode *n = src_dir_files.first; n; n = n->next) { + Bool ignore = true; - D_Tag dep_file; - { - String name_no_extension = StringPathNoExtension(name); - String dep_file_path = StringF(&arena, Lit("%F/%F.%F"), FmtStr(out_obj_dir_path), FmtStr(name_no_extension), FmtStr(dep_file_extension)); - dep_file = D_TagFromPath(&arena, dep_file_path, D_TagKind_DepFile); + D_Tag file = n->tag; + String path = file.full_path; + String name = D_GetName(file); + String extension = StringPathExtension(name); + Bool is_dir = file.kind == D_TagKind_Dir; + Bool is_c = !is_dir && StringEqual(extension, Lit("c")); + Bool is_cpp = !is_dir && !is_c && StringEqual(extension, Lit("cpp")); + if (is_c || is_cpp) { + if (StringBeginsWith(name, Lit("sys_")) || + StringBeginsWith(name, Lit("renderer_")) || + StringBeginsWith(name, Lit("playback_")) || + StringBeginsWith(name, Lit("mp3_")) || + StringBeginsWith(name, Lit("ttf_"))) { + if (PlatformWindows) { + ignore = !(StringEqual(name, Lit("sys_win32.c")) || + StringEqual(name, Lit("renderer_d3d11.c")) || + StringEqual(name, Lit("playback_wasapi.c")) || + StringEqual(name, Lit("mp3_mmf.c")) || + StringEqual(name, Lit("ttf_dwrite.cpp"))); + } + } else { + ignore = false; + } + } + + if (!ignore) { + D_TagListAppend(&arena, &src_input_files, file); + } } + } - D_Tag obj_file; - { - String name_no_extension = StringPathNoExtension(name); - String obj_file_path = StringF(&arena, Lit("%F/%F.%F"), FmtStr(out_obj_dir_path), FmtStr(name_no_extension), FmtStr(obj_file_extension)); - obj_file = D_TagFromPath(&arena, obj_file_path, D_TagKind_File); + { + String c_compile_args_fmt = StringFromStringLists(&arena, Lit(" "), c_compile_args, compile_warnings, compile_and_link_args, compile_args); + String cpp_compile_args_fmt = StringFromStringLists(&arena, Lit(" "), cpp_compile_args, compile_warnings, compile_and_link_args, compile_args); + for (D_TagListNode *n = src_input_files.first; n; n = n->next) { + D_Tag file = n->tag; + String path = file.full_path; + String name = D_GetName(file); + String extension = StringPathExtension(name); + Bool is_c = StringEqual(extension, Lit("c")); + Bool is_cpp = !is_c && StringEqual(extension, Lit("cpp")); + + D_Tag dep_file; + { + String name_no_extension = StringPathNoExtension(name); + String dep_file_path = StringF(&arena, Lit("%F/%F.%F"), FmtStr(out_obj_dir_path), FmtStr(name_no_extension), FmtStr(dep_file_extension)); + dep_file = D_TagFromPath(&arena, dep_file_path, D_TagKind_DepFile); + } + + D_Tag obj_file; + { + String name_no_extension = StringPathNoExtension(name); + String obj_file_path = StringF(&arena, Lit("%F/%F.%F"), FmtStr(out_obj_dir_path), FmtStr(name_no_extension), FmtStr(obj_file_extension)); + obj_file = D_TagFromPath(&arena, obj_file_path, D_TagKind_File); + } + D_AddDependency(obj_file, file); + D_AddDependency(obj_file, dep_file); + + if (IsDirty(obj_file)) { + String comp_cmd_fmt = is_c ? c_compile_args_fmt : cpp_compile_args_fmt; + String comp_cmd = StringF(&arena, comp_cmd_fmt, FmtStr(file.full_path), FmtStr(obj_file.full_path)); + String step_name = StringF(&arena, Lit("%F -> %F"), FmtStr(name), FmtStr(D_GetName(obj_file))); + StepListAppend(&arena, &build_steps, step_name, comp_cmd, true); + } + + D_TagListAppend(&arena, &link_files, obj_file); } - D_AddDependency(obj_file, file); - D_AddDependency(obj_file, dep_file); - - if (D_IsDirty(obj_file, &hist)) { - String comp_cmd_fmt = is_c ? c_compile_args_fmt : cpp_compile_args_fmt; - String comp_cmd = StringF(&arena, comp_cmd_fmt, FmtStr(file.full_path), FmtStr(obj_file.full_path)); - String step_name = StringF(&arena, Lit("%F -> %F"), FmtStr(name), FmtStr(D_GetName(obj_file))); - StepListAppend(&arena, &build_steps, step_name, comp_cmd, true); - } - - D_TagListAppend(&arena, &link_files, obj_file); } } - /* Link */ + + /* ========================== * + * Build step: Link + * ========================== */ + { String link_files_str = { 0 }; { @@ -626,7 +683,7 @@ void OnBuild(StringList cli_args) { Bool success = true; - if (D_IsDirty(executable_file, &hist)) { + if (IsDirty(executable_file)) { Size step_i = 0; Size step_count = build_steps.count; for (StepListNode *n = build_steps.first; n; n = n->next) {