diff --git a/build.c b/build.c index 718b90fd..504be46f 100644 --- a/build.c +++ b/build.c @@ -18,8 +18,7 @@ typedef struct StepListNode StepListNode; struct StepListNode { String name; String cmd; - String link_file_path; - Bool silence_output_if_success; + Bool silence_if_success; StepListNode *next; StepListNode *prev; }; @@ -31,13 +30,12 @@ struct StepList { Size count; }; -void StepListAppend(Arena *arena, StepList *l, String name, String cmd, String link_file_path, Bool silence_output_if_success) +void StepListAppend(Arena *arena, StepList *l, String name, String cmd, Bool silence_if_success) { StepListNode *n = ArenaPush(arena, StepListNode); n->name = name; n->cmd = cmd; - n->link_file_path = link_file_path; - n->silence_output_if_success = silence_output_if_success; + n->silence_if_success = silence_if_success; DllPushBack(l->first, l->last, n); ++l->count; } @@ -163,78 +161,67 @@ void OnBuild(StringList cli_args) SH_PrintF(Lit("Building to \"%F\"\n"), FmtStr(out_bin_dir_path)); SH_Print(Lit("------------------------------\n\n")); - /* ========================== * - * Load hist file - * ========================== */ - - D_Hist hist = D_HistFromPath(&arena, hist_path); - /* ========================== * * Constants * ========================== */ - StepList compile_command_list = { 0 }; - + String dep_file_extension = Lit("d"); String obj_file_extension = Lit("obj"); - D_Tag executable = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/PowerPlay.exe"), FmtStr(out_bin_dir_path))); - D_Tag pdb = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/PowerPlay.pdb"), FmtStr(out_bin_dir_path))); + Bool should_embed_res_dir = !arg_developer; + Bool should_embed_in_rc = !!arg_msvc; - /* Pch tags */ - D_Tag pch_header = D_FileTagFromPath(&arena, Lit("src/common.h")); - D_Tag pch_c_src_gen_output = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/common.c"), FmtStr(out_obj_dir_path))); - D_Tag pch_c_src_gen_obj_output = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/common.c.obj"), FmtStr(out_obj_dir_path))); - D_Tag pch_c_output = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/common.c.pch"), FmtStr(out_obj_dir_path))); - D_Tag pch_cpp_output = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/common.cpp.pch"), FmtStr(out_obj_dir_path))); - D_Tag pch_cpp_src_gen_output = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/common.cpp"), FmtStr(out_obj_dir_path))); - D_Tag pch_cpp_src_gen_obj_output = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/common.cpp.obj"), FmtStr(out_obj_dir_path))); - /* Dependency order: common.h -> common.c (generated for msvc) -> common.c.obj -> common.c.pch -> PowerPlay.exe */ - D_AddDependency(pch_c_src_gen_output, pch_header); - D_AddDependency(pch_c_src_gen_obj_output, pch_c_src_gen_output); - D_AddDependency(pch_c_output, pch_c_src_gen_obj_output); - D_AddDependency(executable, pch_c_output); - /* Dependency order: common.h -> common.cpp (generated for msvc) -> common.cpp.obj -> common.cpp.pch -> PowerPlay.exe*/ - D_AddDependency(pch_cpp_src_gen_output, pch_header); - D_AddDependency(pch_cpp_src_gen_obj_output, pch_cpp_src_gen_output); - D_AddDependency(pch_cpp_output, pch_cpp_src_gen_obj_output); - D_AddDependency(executable, pch_cpp_output); + D_Tag executable_file = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/PowerPlay.exe"), FmtStr(out_bin_dir_path))); + D_Tag res_dir = D_DirTagFromPath(&arena, Lit("res")); + D_Tag shaders_dir = D_DirTagFromPath(&arena, Lit("src/shaders")); + D_Tag icon_file = D_FileTagFromPath(&arena, Lit("icon.ico")); + + D_Tag inc_src_file = D_FileTagFromPath(&arena, Lit("src/inc.c")); + D_Tag rc_res_file = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/rc.res"), FmtStr(out_obj_dir_path))); + +#if 0 + D_Tag pch_header_file = D_FileTagFromPath(&arena, Lit("src/common.h")); + D_Tag pch_c_src_gen_file = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/common.c"), FmtStr(out_obj_dir_path))); + D_Tag pch_cpp_src_gen_file = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/common.cpp"), FmtStr(out_obj_dir_path))); + D_Tag pch_c_src_gen_obj_file = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/common.c.obj"), FmtStr(out_obj_dir_path))); + D_Tag pch_cpp_src_gen_obj_file = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/common.cpp.obj"), FmtStr(out_obj_dir_path))); + D_Tag pch_c_file = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/common.c.pch"), FmtStr(out_obj_dir_path))); + D_Tag pch_cpp_file = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/common.cpp.pch"), FmtStr(out_obj_dir_path))); +#endif /* ========================== * * Determine compiler args * ========================== */ - String final_c_compile_args_fmt = { 0 }; - String final_cpp_compile_args_fmt = { 0 }; - String final_pch_c_compile_args_fmt = { 0 }; - String final_pch_cpp_compile_args_fmt = { 0 }; - String final_link_args_fmt = { 0 }; + StringList c_compile_args = { 0 }; + StringList cpp_compile_args = { 0 }; + StringList pch_c_compile_args = { 0 }; + StringList pch_cpp_compile_args = { 0 }; + StringList compile_and_link_args = { 0 }; + StringList compile_args = { 0 }; + StringList compile_warnings = { 0 }; + + StringList link_warnings = { 0 }; + StringList link_args = { 0 }; + + StringList rc_compile_args = { 0 }; { - StringList compile_warnings = { 0 }; - StringList compile_and_link_args = { 0 }; - StringList compile_args = { 0 }; - - StringList c_compile_args = { 0 }; - StringList cpp_compile_args = { 0 }; - StringList pch_c_compile_args = { 0 }; - StringList pch_cpp_compile_args = { 0 }; - - StringList link_warnings = { 0 }; - StringList link_args = { 0 }; - if (arg_msvc) { /* Msvc */ StringListAppend(&arena, &c_compile_args, Lit("cl.exe /nologo /c \"%F\" /Fo\"%F\"")); StringListAppend(&arena, &cpp_compile_args, Lit("cl.exe /nologo /c \"%F\" /Fo\"%F\"")); StringListAppend(&arena, &pch_c_compile_args, Lit("cl.exe /nologo /c /Yc\"%F\" \"%F\"")); StringListAppend(&arena, &pch_cpp_compile_args, Lit("cl.exe /nologo /c /Yc\"%F\" \"%F\"")); + StringListAppend(&arena, &rc_compile_args, Lit("rc /fo\"%F\" \"%F\"")); - StringListAppend(&arena, &c_compile_args, StringF(&arena, Lit("/Yu\"%F\" /FI\"%F\" /Fp\"%F\""), FmtStr(pch_header.full_path), FmtStr(pch_header.full_path), FmtStr(pch_c_output.full_path))); - StringListAppend(&arena, &cpp_compile_args, StringF(&arena, Lit("/Yu\"%F\" /FI\"%F\" /Fp\"%F\""), FmtStr(pch_header.full_path), FmtStr(pch_header.full_path), FmtStr(pch_cpp_output.full_path))); - StringListAppend(&arena, &pch_c_compile_args, StringF(&arena, Lit("/FI\"%F\" /Fp\"%F\" /Fo\"%F\""), FmtStr(pch_header.full_path), FmtStr(pch_c_output.full_path), FmtStr(pch_c_src_gen_obj_output.full_path))); - StringListAppend(&arena, &pch_cpp_compile_args, StringF(&arena, Lit("/FI\"%F\" /Fp\"%F\" /Fo\"%F\""), FmtStr(pch_header.full_path), FmtStr(pch_cpp_output.full_path), FmtStr(pch_cpp_src_gen_obj_output.full_path))); +#if 0 + StringListAppend(&arena, &c_compile_args, StringF(&arena, Lit("/Yu\"%F\" /FI\"%F\" /Fp\"%F\""), FmtStr(pch_header_file.full_path), FmtStr(pch_header_file.full_path), FmtStr(pch_c_file.full_path))); + StringListAppend(&arena, &cpp_compile_args, StringF(&arena, Lit("/Yu\"%F\" /FI\"%F\" /Fp\"%F\""), FmtStr(pch_header_file.full_path), FmtStr(pch_header_file.full_path), FmtStr(pch_cpp_file.full_path))); + StringListAppend(&arena, &pch_c_compile_args, StringF(&arena, Lit("/FI\"%F\" /Fp\"%F\" /Fo\"%F\""), FmtStr(pch_header_file.full_path), FmtStr(pch_c_file.full_path), FmtStr(pch_c_src_gen_obj_file.full_path))); + StringListAppend(&arena, &pch_cpp_compile_args, StringF(&arena, Lit("/FI\"%F\" /Fp\"%F\" /Fo\"%F\""), FmtStr(pch_header_file.full_path), FmtStr(pch_cpp_file.full_path), FmtStr(pch_cpp_src_gen_obj_file.full_path))); +#endif - StringListAppend(&arena, &link_args, Lit("link.exe /nologo %F")); - StringListAppend(&arena, &link_args, StringF(&arena, Lit("/OUT:\"%F\" /PDB:\"%F\" /DEBUG:FULL /OPT:REF /OPT:ICF"), FmtStr(executable.full_path), FmtStr(pdb.full_path))); + StringListAppend(&arena, &link_args, Lit("link.exe /nologo %F /OUT:\"%F\" /DEBUG:FULL /OPT:REF /OPT:ICF")); String warnings = Lit("/WX /Wall " "/options:strict " @@ -245,16 +232,20 @@ void OnBuild(StringList cli_args) StringListAppend(&arena, &compile_args, StringF(&arena, Lit("/Fd\"%F\\\""), FmtStr(out_bin_dir_path))); } else { /* Clang */ - StringListAppend(&arena, &c_compile_args, Lit("clang -xc -std=c99 -c %F -o %F")); - StringListAppend(&arena, &cpp_compile_args, Lit("clang -xc++ -std=c++20 -c %F -o %F")); - StringListAppend(&arena, &pch_c_compile_args, Lit("clang -xc-header -std=c99 -c %F -o %F")); - StringListAppend(&arena, &pch_cpp_compile_args, Lit("clang -xc++-header -std=c++20 -c %F -o %F")); + StringListAppend(&arena, &c_compile_args, Lit("clang -xc -std=c99 -c %F -o %F -MD")); + StringListAppend(&arena, &cpp_compile_args, Lit("clang -xc++ -std=c++20 -c %F -o %F -MD")); + StringListAppend(&arena, &pch_c_compile_args, Lit("clang -xc-header -std=c99 -c %F -o %F -MD")); + StringListAppend(&arena, &pch_cpp_compile_args, Lit("clang -xc++-header -std=c++20 -c %F -o %F -MD")); + StringListAppend(&arena, &rc_compile_args, Lit("llvm-rc /fo\"%F\" \"%F\"")); + +#if 0 + StringListAppend(&arena, &c_compile_args, StringF(&arena, Lit("-include-pch %F"), FmtStr(pch_c_file.full_path))); + StringListAppend(&arena, &cpp_compile_args, StringF(&arena, Lit("-include-pch %F"), FmtStr(pch_cpp_file.full_path))); +#endif - StringListAppend(&arena, &c_compile_args, StringF(&arena, Lit("-include-pch %F"), FmtStr(pch_c_output.full_path))); - StringListAppend(&arena, &cpp_compile_args, StringF(&arena, Lit("-include-pch %F"), FmtStr(pch_cpp_output.full_path))); StringListAppend(&arena, &link_args, Lit("clang %F")); - StringListAppend(&arena, &link_args, StringF(&arena, Lit("-o \"%F\""), FmtStr(executable.full_path))); + StringListAppend(&arena, &link_args, StringF(&arena, Lit("-o \"%F\""), FmtStr(executable_file.full_path))); StringListAppend(&arena, &compile_and_link_args, @@ -391,262 +382,295 @@ void OnBuild(StringList cli_args) StringListAppend(&arena, &compile_args, StringF(&arena, Lit("-DINCBIN_DIR_RAW=\"%F\""), FmtStr(incbin_dir))); } +#if 0 final_c_compile_args_fmt = StringFromStringLists(&arena, Lit(" "), c_compile_args, compile_warnings, compile_and_link_args, compile_args); final_cpp_compile_args_fmt = StringFromStringLists(&arena, Lit(" "), cpp_compile_args, compile_warnings, compile_and_link_args, compile_args); final_pch_c_compile_args_fmt = StringFromStringLists(&arena, Lit(" "), pch_c_compile_args, compile_warnings, compile_and_link_args, compile_args); final_pch_cpp_compile_args_fmt = StringFromStringLists(&arena, Lit(" "), pch_cpp_compile_args, compile_warnings, compile_and_link_args, compile_args); + final_rc_compile_args_fmt = StringFromStringLists(&arena, Lit(" "), rc_compile_args); final_link_args_fmt = StringFromStringLists(&arena, Lit(" "), link_args, link_warnings, compile_and_link_args); +#endif } /* ========================== * - * Generate embeddable tar files + * Read hist file * ========================== */ - Bool embed_in_rc = !!arg_msvc; - - D_Tag res_dir = D_DirTagFromPath(&arena, Lit("res")); - D_Tag shaders_dir = D_DirTagFromPath(&arena, Lit("src/shaders")); - - D_Tag inc_file = D_FileTagFromPath(&arena, Lit("src/inc.c")); - RcIncludeList rc_includes = { 0 }; - - /* Generate shaders tar */ - D_Tag shaders_tar = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/shaders.tar"), FmtStr(out_inc_dir_path))); - D_AddDependency(shaders_tar, shaders_dir); - if (embed_in_rc) { - RcIncludeListAppend(&arena, &rc_includes, shaders_tar, Lit("RCDATA")); - } else { - D_AddDependency(inc_file, shaders_tar); - } - if (D_IsDirty(shaders_tar, &hist)) { - String tar_cmd = StringF(&arena, Lit("cd %F && tar cvf %F ."), FmtStr(shaders_dir.full_path), FmtStr(shaders_tar.full_path)); - String step_name = StringF(&arena, Lit("%F -> %F"), FmtStr(D_GetName(shaders_dir)), FmtStr(D_GetName(shaders_tar))); - StepListAppend(&arena, &compile_command_list, step_name, tar_cmd, (String) { 0 }, true); - } - - /* Generate res tar */ - if (!arg_developer) { - D_Tag res_tar = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/res.tar"), FmtStr(out_inc_dir_path))); - D_AddDependency(res_tar, res_dir); - if (embed_in_rc) { - RcIncludeListAppend(&arena, &rc_includes, res_tar, Lit("RCDATA")); - } else { - D_AddDependency(inc_file, res_tar); - } - if (D_IsDirty(res_tar, &hist)) { - String tar_cmd = StringF(&arena, Lit("cd %F && tar cvf %F ."), FmtStr(res_dir.full_path), FmtStr(res_tar.full_path)); - String step_name = StringF(&arena, Lit("%F -> %F"), FmtStr(D_GetName(res_dir)), FmtStr(D_GetName(res_tar))); - StepListAppend(&arena, &compile_command_list, step_name, tar_cmd, (String) { 0 }, true); - } - } + D_Hist hist = D_HistFromPath(&arena, hist_path); /* ========================== * - * RC file (windows) + * Assemble input files * ========================== */ + D_TagList tar_input_dirs = { 0 }; + D_Tag rc_input_file = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/rc.rc"), FmtStr(out_inc_dir_path)));; + D_Tag pch_header_file = D_FileTagFromPath(&arena, Lit("src/common.h")); + 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_Tag rc_file = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/rc.rc"), FmtStr(out_inc_dir_path)));; + D_AddDependency(rc_input_file, icon_file); + 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_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_dir)), FmtStr(Lit("RCDATA")), FmtStr(D_GetName(shaders_dir)))); + if (should_embed_res_dir) { + D_AppendWrite(rc_input_file, StringF(&arena, Lit("%F %F DISCARDABLE %F\n"), FmtStr(D_GetName(res_dir)), FmtStr(Lit("RCDATA")), FmtStr(D_GetName(res_dir)))); + } + } + } + } - /* Add icon file to rc list */ - { - D_Tag icon_file = D_FileTagFromPath(&arena, Lit("icon.ico")); - RcIncludeListAppend(&arena, &rc_includes, icon_file, Lit("ICON")); + /* Append 'src' dir c & cpp files */ + { + D_Tag src_dir = D_DirTagFromPath(&arena, Lit("src")); + 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 file = n->tag; + String path = file.full_path; + String name = D_GetName(file); + String extension = StringPathExtension(name); + Bool is_dir = file.is_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 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_FileTagFromPath(&arena, dep_file_path); + } + D_AddDependency(file, dep_file); + + { + String dep_file_data = D_ReadAll(&arena, dep_file); + StringList patterns = { 0 }; + StringListAppend(&arena, &patterns, Lit("\r\n")); + StringListAppend(&arena, &patterns, Lit("\n")); + StringList lines = StringSplit(&arena, dep_file_data, patterns); + for (StringListNode *dn = lines.first; dn; dn = dn->next) { + String line = dn->string; + line = StringReplace(&arena, line, Lit("\\ "), Lit(" ")); + if (StringEndsWith(line, Lit(" \\"))) { + line.len -= 2; + } + if (StringBeginsWith(line, Lit(" "))) { + line.len -= 2; + line.text += 2; + } + if (!StringEndsWith(line, Lit(":"))) { + D_Tag tag = D_FileTagFromPath(&arena, line); + if (!D_TagEqual(tag, file)) { + D_AddDependency(file, tag); + } + } + } + } + } + } + } + + /* ========================== * + * Assemble build steps + * ========================== */ + + 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_FileTagFromPath(&arena, StringF(&arena, Lit("%F/%F.tar"), FmtStr(out_inc_dir_path), FmtStr(D_GetName(input_dir)))); + 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); } - /* Add rc dependencies */ - for (RcIncludeListNode *rin = rc_includes.first; rin; rin = rin->next) { - D_AddDependency(rc_file, rin->tag); + 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); } + } - D_Tag rc_res_file = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/rc.res"), FmtStr(out_obj_dir_path))); - D_AddDependency(rc_res_file, rc_file); - D_AddDependency(executable, rc_res_file); + /* Build rc file */ + { + 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)) { - /* Generate rc file */ - D_ClearWrite(rc_file, Lit("")); - for (RcIncludeListNode *rin = rc_includes.first; rin; rin = rin->next) { - String name = D_GetName(rin->tag); - String line = StringF(&arena, Lit("%F %F DISCARDABLE %F\n"), FmtStr(name), FmtStr(rin->rc_type), FmtStr(name)); - D_AppendWrite(rc_file, line); - } - - /* Append rc -> res compile command */ - String rc_compile_cmd = { 0 }; - if (arg_msvc) { - rc_compile_cmd = StringF(&arena, Lit("rc /fo\"%F\" \"%F\""), FmtStr(rc_res_file.full_path), FmtStr(rc_file.full_path)); - } else { - rc_compile_cmd = StringF(&arena, Lit("llvm-rc /fo\"%F\" \"%F\""), FmtStr(rc_res_file.full_path), FmtStr(rc_file.full_path)); - } - String step_name = StringF(&arena, Lit("%F -> %F"), FmtStr(D_GetName(rc_file)), FmtStr(D_GetName(rc_res_file))); - StepListAppend(&arena, &compile_command_list, step_name, rc_compile_cmd, rc_res_file.full_path, true); + 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 */ + { + String pch_c_compile_args_fmt = StringFromStringLists(&arena, Lit(" "), pch_c_compile_args, compile_warnings, compile_and_link_args, compile_args); + String pch_cpp_compile_args_fmt = StringFromStringLists(&arena, Lit(" "), pch_cpp_compile_args, compile_warnings, compile_and_link_args, compile_args); - /* ========================== * - * PCH compile commands - * ========================== */ + D_Tag pch_c_file = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/%F.c_pch"), FmtStr(out_obj_dir_path), FmtStr(D_GetName(pch_header_file)))); + D_Tag pch_cpp_file = D_FileTagFromPath(&arena, StringF(&arena, Lit("%F/%F.cpp_pch"), FmtStr(out_obj_dir_path), FmtStr(D_GetName(pch_header_file)))); + D_AddDependency(pch_c_file, pch_header_file); + D_AddDependency(pch_cpp_file, pch_header_file); - if (arg_msvc) { - { - if (D_IsDirty(pch_c_output, &hist)) { - D_ClearWrite(pch_c_src_gen_output, Lit("")); - String comp_cmd = StringF(&arena, final_pch_c_compile_args_fmt, FmtStr(pch_header.full_path), FmtStr(pch_c_src_gen_output.full_path)); - String link_file = pch_c_src_gen_obj_output.full_path; - String step_name = StringF(&arena, Lit("%F -> %F"), FmtStr(D_GetName(pch_header)), FmtStr(D_GetName(pch_c_output))); - StepListAppend(&arena, &compile_command_list, step_name, comp_cmd, link_file, true); - } - } - { - if (D_IsDirty(pch_cpp_src_gen_output, &hist)) { - D_ClearWrite(pch_cpp_src_gen_output, Lit("")); - String comp_cmd = StringF(&arena, final_pch_cpp_compile_args_fmt, FmtStr(pch_header.full_path), FmtStr(pch_cpp_src_gen_output.full_path)); - String link_file = pch_cpp_src_gen_obj_output.full_path; - String step_name = StringF(&arena, Lit("%F -> %F"), FmtStr(D_GetName(pch_header)), FmtStr(D_GetName(pch_cpp_src_gen_output))); - StepListAppend(&arena, &compile_command_list, step_name, comp_cmd, link_file, true); - } - } - } else { - { - if (D_IsDirty(pch_c_output, &hist)) { - String comp_cmd = StringF(&arena, final_pch_c_compile_args_fmt, FmtStr(pch_header.full_path), FmtStr(pch_c_output.full_path)); - String step_name = StringF(&arena, Lit("%F -> %F"), FmtStr(D_GetName(pch_header)), FmtStr(D_GetName(pch_c_output))); - StepListAppend(&arena, &compile_command_list, step_name, comp_cmd, (String) { 0 }, true); - } - } - { - if (D_IsDirty(pch_cpp_output, &hist)) { - String comp_cmd = StringF(&arena, final_pch_cpp_compile_args_fmt, FmtStr(pch_header.full_path), FmtStr(pch_cpp_output.full_path)); - String step_name = StringF(&arena, Lit("%F -> %F"), FmtStr(D_GetName(pch_header)), FmtStr(D_GetName(pch_cpp_output))); - StepListAppend(&arena, &compile_command_list, step_name, comp_cmd, (String) { 0 }, true); - } - } - } - - /* ========================== * - * Add src file compile commands - * ========================== */ - - D_Tag src_dir = D_DirTagFromPath(&arena, Lit("src")); - D_TagList src_files = D_GetDirContents(&arena, src_dir); - - for (D_TagListNode *n = src_files.first; n; n = n->next) { - D_Tag file = n->tag; - - Bool ignore = !!file.is_dir; - if (ignore) continue; - - String name = D_GetName(file); - String extension = D_GetExtension(file); - Bool is_c = StringEqual(extension, Lit("c")); - Bool is_cpp = !is_c && StringEqual(extension, Lit("cpp")); - - ignore = !(is_c || is_cpp); - if (ignore) continue; - - /* Determine platform specific source files */ - { - if (StringBeginsWith(name, Lit("sys_")) || - StringBeginsWith(name, Lit("renderer_")) || - StringBeginsWith(name, Lit("playback_")) || - StringBeginsWith(name, Lit("mp3_")) || - StringBeginsWith(name, Lit("ttf_"))) { - ignore = true; - 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"))); - } - } - - } - if (ignore) continue; - - D_Tag obj_file; - { - String obj_file_path = { 0 }; - String name_no_extension = StringPathNoExtension(name); - 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_FileTagFromPath(&arena, obj_file_path); - } - D_AddDependency(obj_file, file); - D_AddDependency(executable, obj_file); - - String comp_cmd = { 0 }; - if (D_IsDirty(obj_file, &hist)) { - String comp_cmd_fmt = is_c ? final_c_compile_args_fmt : final_cpp_compile_args_fmt; - 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, &compile_command_list, step_name, comp_cmd, obj_file.full_path, true); - } - - /* ========================== * - * Compile / link - * ========================== */ - - if (D_IsDirty(executable, &hist)) { - Bool success = true; - StringList link_files = { 0 }; - - /* Compile */ - Size comp_i = 0; - Size comp_count = compile_command_list.count; - for (StepListNode *n = compile_command_list.first; n; n = n->next) { - ++comp_i; - String comp_cmd = n->cmd; - if (comp_cmd.len > 0 ) { - SH_PrintF(Lit("[%F/%F] %F\n"), FmtI64(comp_i), FmtI64(comp_count), FmtStr(n->name)); - //SH_PrintF(Lit("%F\n"), FmtStr(comp_cmd)); - SH_CommandResult result = SH_RunCommandCaptureOutput(&arena, comp_cmd, true); - if (!n->silence_output_if_success || result.error != 0) { - SH_PrintF(Lit("%F\n"), FmtStr(result.output)); - } - if (result.error != 0) { - Assert(false); - success = false; - break; - } - } - String link_file_path = n->link_file_path; - if (link_file_path.len > 0) { - StringListAppend(&arena, &link_files, link_file_path); - } - } - - /* Link */ - if (success) { - String link_files_str = { 0 }; + if (arg_msvc) { +#if 0 + StringListAppend(&arena, &c_compile_args, StringF(&arena, Lit("/Yu\"%F\" /FI\"%F\" /Fp\"%F\""), FmtStr(pch_header_file.full_path), FmtStr(pch_header_file.full_path), FmtStr(pch_c_file.full_path))); + StringListAppend(&arena, &cpp_compile_args, StringF(&arena, Lit("/Yu\"%F\" /FI\"%F\" /Fp\"%F\""), FmtStr(pch_header_file.full_path), FmtStr(pch_header_file.full_path), FmtStr(pch_cpp_file.full_path))); + StringListAppend(&arena, &pch_c_compile_args, StringF(&arena, Lit("/FI\"%F\" /Fp\"%F\" /Fo\"%F\""), FmtStr(pch_header_file.full_path), FmtStr(pch_c_file.full_path), FmtStr(pch_c_src_gen_obj_file.full_path))); + StringListAppend(&arena, &pch_cpp_compile_args, StringF(&arena, Lit("/FI\"%F\" /Fp\"%F\" /Fo\"%F\""), FmtStr(pch_header_file.full_path), FmtStr(pch_cpp_file.full_path), FmtStr(pch_cpp_src_gen_obj_file.full_path))); +#endif + } else { + StringListAppend(&arena, &c_compile_args, StringF(&arena, Lit("-include-pch %F"), FmtStr(pch_c_file.full_path))); + StringListAppend(&arena, &cpp_compile_args, StringF(&arena, Lit("-include-pch %F"), FmtStr(pch_cpp_file.full_path))); + /* C */ { - StringList link_files_quoted_list = { 0 }; - for (StringListNode *n = link_files.first; n; n = n->next) { - String path = StringF(&arena, Lit("\"%F\""), FmtStr(n->string)); - StringListAppend(&arena, &link_files_quoted_list, path); + if (D_IsDirty(pch_c_file, &hist)) { + 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); } - link_files_str = StringFromStringList(&arena, Lit(" "), link_files_quoted_list); + } + /* Cpp */ + { + if (D_IsDirty(pch_cpp_file, &hist)) { + 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); + } + } + } + } + + /* Build 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_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_FileTagFromPath(&arena, obj_file_path); + } + D_AddDependency(obj_file, 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); } - String link_cmd = StringF(&arena, final_link_args_fmt, FmtStr(link_files_str)); - //SH_PrintF(Lit("[Link] %F\n"), FmtStr(link_cmd)); - SH_Print(Lit("Linking...\n")); - SH_CommandResult result = SH_RunCommandCaptureOutput(&arena, link_cmd, false); - if (result.error != 0) { - Assert(false); - success = false; + D_TagListAppend(&arena, &link_files, obj_file); + } + } + + /* Link */ + { + String link_files_str = { 0 }; + { + StringList link_files_quoted_list = { 0 }; + for (D_TagListNode *n = link_files.first; n; n = n->next) { + D_Tag file = n->tag; + String path = StringF(&arena, Lit("\"%F\""), FmtStr(file.full_path)); + StringListAppend(&arena, &link_files_quoted_list, path); + D_AddDependency(executable_file, file); } - //D_SetDirty(executable); + link_files_str = StringFromStringList(&arena, Lit(" "), link_files_quoted_list); + } + + if (link_files_str.len > 0) { + String link_args_fmt = StringFromStringLists(&arena, Lit(" "), link_args, link_warnings, compile_and_link_args); + String cmd = StringF(&arena, link_args_fmt, FmtStr(link_files_str)); + StepListAppend(&arena, &build_steps, Lit("Linking"), cmd, true); + } + } + + /* ========================== * + * Execute build steps + * + * TODO: Parallelize + * ========================== */ + + { + Bool success = true; + if (D_IsDirty(executable_file, &hist)) { + Size step_i = 0; + Size step_count = build_steps.count; + for (StepListNode *n = build_steps.first; n; n = n->next) { + ++step_i; + String cmd = n->cmd; + if (cmd.len > 0) { + SH_PrintF(Lit("[%F/%F] %F\n"), FmtI64(step_i), FmtI64(step_count), FmtStr(n->name)); + //SH_PrintF(Lit("%F\n"), FmtStr(cmd)); + SH_CommandResult result = SH_RunCommandCaptureOutput(&arena, cmd, true); + if (!n->silence_if_success || result.error != 0) { + SH_PrintF(Lit("%F\n"), FmtStr(result.output)); + } + if (result.error != 0) { + Assert(false); + success = false; + break; + } + } + } + } else { + SH_Print(Lit("Nothing to build")); } if (!success) { Error(Lit("Build failed")); OS_Exit(1); } - } else { - /* Nothing to build */ - SH_Print(Lit("Nothing to build")); } /* ========================== *