711 lines
31 KiB
C
711 lines
31 KiB
C
#define Rtc 1
|
|
#include "buildit.h"
|
|
|
|
/* ========================== *
|
|
* Util
|
|
* ========================== */
|
|
|
|
void Error(String msg)
|
|
{
|
|
SH_PrintF(Lit("ERROR: %F\n"), FmtStr(msg));
|
|
}
|
|
|
|
/* ========================== *
|
|
* Step
|
|
* ========================== */
|
|
|
|
typedef struct StepListNode StepListNode;
|
|
struct StepListNode {
|
|
String name;
|
|
String cmd;
|
|
Bool silence_if_success;
|
|
StepListNode *next;
|
|
StepListNode *prev;
|
|
};
|
|
|
|
typedef struct StepList StepList;
|
|
struct StepList {
|
|
StepListNode *first;
|
|
StepListNode *last;
|
|
Size count;
|
|
};
|
|
|
|
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->silence_if_success = silence_if_success;
|
|
DllPushBack(l->first, l->last, n);
|
|
++l->count;
|
|
}
|
|
|
|
/* ========================== *
|
|
* Rc include
|
|
* ========================== */
|
|
|
|
typedef struct RcIncludeListNode RcIncludeListNode;
|
|
struct RcIncludeListNode {
|
|
D_Tag tag;
|
|
String rc_type;
|
|
RcIncludeListNode *next;
|
|
RcIncludeListNode *prev;
|
|
};
|
|
|
|
typedef struct RcIncludeList RcIncludeList;
|
|
struct RcIncludeList {
|
|
RcIncludeListNode *first;
|
|
RcIncludeListNode *last;
|
|
Size count;
|
|
};
|
|
|
|
void RcIncludeListAppend(Arena *arena, RcIncludeList *l, D_Tag tag, String rc_type)
|
|
{
|
|
RcIncludeListNode *n = ArenaPush(arena, RcIncludeListNode);
|
|
n->tag = tag;
|
|
n->rc_type = rc_type;
|
|
DllPushBack(l->first, l->last, n);
|
|
++l->count;
|
|
}
|
|
|
|
/* ========================== *
|
|
* Depfile
|
|
*
|
|
* TODO: Migrate this to buildit
|
|
* ========================== */
|
|
|
|
void AddDependenciesFromDepFile(Arena *arena, D_Tag file, D_Tag dep_file)
|
|
{
|
|
TempArena scratch = ScratchBegin(arena);
|
|
|
|
D_AddDependency(file, dep_file);
|
|
{
|
|
String dep_file_data = D_ReadAll(scratch.arena, dep_file);
|
|
StringList patterns = { 0 };
|
|
StringListAppend(scratch.arena, &patterns, Lit("\r\n"));
|
|
StringListAppend(scratch.arena, &patterns, Lit("\n"));
|
|
StringList lines = StringSplit(scratch.arena, dep_file_data, patterns);
|
|
for (StringListNode *dn = lines.first; dn; dn = dn->next) {
|
|
String line = dn->string;
|
|
line = StringReplace(scratch.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(scratch.arena, line);
|
|
if (!D_TagEqual(tag, file)) {
|
|
String line_copy = StringCopy(arena, line);
|
|
D_Tag tag_copy = D_FileTagFromPath(arena, line_copy);
|
|
D_AddDependency(file, tag_copy);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ScratchEnd(scratch);
|
|
}
|
|
|
|
/* ========================== *
|
|
* Build
|
|
* ========================== */
|
|
|
|
void OnBuild(StringList cli_args)
|
|
{
|
|
Arena arena = ArenaAlloc(Gigabyte(64));
|
|
|
|
OS_TimeStamp start = OS_GetTimeStamp();
|
|
|
|
/* ========================== *
|
|
* Read args
|
|
* ========================== */
|
|
|
|
String arg_outdir = Lit("build");
|
|
Bool arg_msvc = false;
|
|
Bool arg_rtc = false;
|
|
Bool arg_asan = false;
|
|
Bool arg_crtlib = false;
|
|
Bool arg_debinfo = false;
|
|
Bool arg_developer = false;
|
|
Bool arg_profiling = false;
|
|
Bool arg_unoptimized = false;
|
|
|
|
{
|
|
typedef enum ArgState {
|
|
ArgState_None,
|
|
ArgState_OutputDir
|
|
} ArgState;
|
|
|
|
ArgState arg_state = ArgState_None;
|
|
for (StringListNode *n = cli_args.first; n; n = n->next) {
|
|
String arg = n->string;
|
|
if (n != cli_args.first) {
|
|
switch (arg_state) {
|
|
case ArgState_OutputDir:
|
|
{
|
|
arg_outdir = arg;
|
|
arg_state = ArgState_None;
|
|
} break;
|
|
|
|
default:
|
|
{
|
|
if (StringEqual(arg, Lit("-O"))) arg_state = ArgState_OutputDir;
|
|
if (StringEqual(arg, Lit("-clang"))) arg_msvc = false;
|
|
if (StringEqual(arg, Lit("-msvc"))) arg_msvc = true;
|
|
if (StringEqual(arg, Lit("-rtc"))) arg_rtc = true;
|
|
if (StringEqual(arg, Lit("-asan"))) arg_asan = true;
|
|
if (StringEqual(arg, Lit("-crtlib"))) arg_crtlib = true;
|
|
if (StringEqual(arg, Lit("-debinfo"))) arg_debinfo = true;
|
|
if (StringEqual(arg, Lit("-developer"))) arg_developer = true;
|
|
if (StringEqual(arg, Lit("-profiling"))) arg_profiling = true;
|
|
if (StringEqual(arg, Lit("-unoptimized"))) arg_unoptimized = true;
|
|
} break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
String hist_path = OS_GetAbsPath(&arena, StringF(&arena, Lit("%F/.dephist"), 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)));
|
|
String out_bin_dir_path = OS_GetAbsPath(&arena, StringF(&arena, Lit("%F/bin/"), FmtStr(arg_outdir)));
|
|
|
|
if (!OS_DirExists(out_obj_dir_path)) {
|
|
OS_CreateDirAtAbsPath(out_obj_dir_path);
|
|
}
|
|
if (!OS_DirExists(out_inc_dir_path)) {
|
|
OS_CreateDirAtAbsPath(out_inc_dir_path);
|
|
}
|
|
if (!OS_DirExists(out_bin_dir_path)) {
|
|
OS_CreateDirAtAbsPath(out_bin_dir_path);
|
|
}
|
|
|
|
SH_Print(Lit("------------------------------\n"));
|
|
{
|
|
String compiler = { 0 };
|
|
String compiler_loc = { 0 };
|
|
SH_CommandResult where_res = { 0 };
|
|
if (arg_msvc) {
|
|
compiler = Lit("Msvc");
|
|
where_res = SH_RunCommandCaptureOutput(&arena, Lit("where cl.exe"), true);
|
|
} else {
|
|
compiler = Lit("Clang");
|
|
where_res = SH_RunCommandCaptureOutput(&arena, Lit("where clang.exe"), true);
|
|
}
|
|
compiler_loc = where_res.error ? Lit("Not found") : StringReplace(&arena, where_res.output, Lit("\n"), Lit(""));
|
|
SH_PrintF(Lit("Compiler: %F (%F)\n"), FmtStr(compiler), FmtStr(compiler_loc));
|
|
}
|
|
if (arg_asan) SH_Print(Lit("Asan Enabled\n"));
|
|
if (arg_profiling) SH_Print(Lit("Profiling\n"));
|
|
if (arg_developer) SH_Print(Lit("Developer build enabled\n"));
|
|
SH_PrintF(Lit("Building to \"%F\"\n"), FmtStr(out_bin_dir_path));
|
|
SH_Print(Lit("------------------------------\n\n"));
|
|
|
|
/* ========================== *
|
|
* Constants
|
|
* ========================== */
|
|
|
|
String dep_file_extension = Lit("d");
|
|
String obj_file_extension = Lit("obj");
|
|
Bool should_embed_res_dir = !arg_developer;
|
|
Bool should_embed_in_rc = !!arg_msvc;
|
|
|
|
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
|
|
* ========================== */
|
|
|
|
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 };
|
|
{
|
|
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\""));
|
|
|
|
#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 /OUT:\"%F\" /DEBUG:FULL /OPT:REF /OPT:ICF"));
|
|
|
|
String warnings = Lit("/WX /Wall "
|
|
"/options:strict "
|
|
"/wd4820 /wd4201 /wd5220 /wd4514 /wd4244 /wd5045 /wd4242 /wd4061 /wd4189 /wd4723 /wd5246");
|
|
StringListAppend(&arena, &compile_warnings, warnings);
|
|
StringListAppend(&arena, &link_warnings, Lit("/WX"));
|
|
|
|
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, &rc_compile_args, Lit("llvm-rc /fo\"%F\" \"%F\""));
|
|
|
|
StringListAppend(&arena, &c_compile_args, StringF(&arena, Lit("-MD -MF \"%F\""), FmtStr(out_dep_dir_path)));
|
|
StringListAppend(&arena, &cpp_compile_args, StringF(&arena, Lit("-MD -MF \"%F\""), FmtStr(out_dep_dir_path)));
|
|
StringListAppend(&arena, &pch_c_compile_args, StringF(&arena, Lit("-MD -MF \"%F\""), FmtStr(out_dep_dir_path)));
|
|
StringListAppend(&arena, &pch_cpp_compile_args, StringF(&arena, Lit("-MD -MF \"%F\""), FmtStr(out_dep_dir_path)));
|
|
|
|
|
|
StringListAppend(&arena, &link_args, Lit("clang %F"));
|
|
StringListAppend(&arena, &link_args, StringF(&arena, Lit("-o \"%F\""), FmtStr(executable_file.full_path)));
|
|
|
|
StringListAppend(&arena,
|
|
&compile_and_link_args,
|
|
Lit("-fuse-ld=lld-link "
|
|
"-fno-strict-aliasing "
|
|
"-fno-finite-loops "
|
|
"-fwrapv "
|
|
"-msse4.1 "
|
|
"-msse4.2 "));
|
|
|
|
String warnings = Lit("-Weverything -Werror "
|
|
"-Wframe-larger-than=65536 "
|
|
"-Wno-unused-macros -Wno-gnu-zero-variadic-macro-arguments -Wno-documentation "
|
|
"-Wno-old-style-cast -Wno-conversion -Wno-sign-conversion "
|
|
"-Wno-declaration-after-statement -Wno-extra-semi -Wno-extra-semi-stmt "
|
|
"-Wno-bad-function-cast -Wno-class-varargs -Wno-unreachable-code-break "
|
|
"-Wno-cast-align -Wno-float-equal -Wno-zero-as-null-pointer-constant "
|
|
"-Wno-cast-qual -Wno-missing-noreturn -Wno-missing-field-initializers "
|
|
"-Wno-missing-braces -Wno-initializer-overrides "
|
|
"-Wno-c99-extensions -Wno-c++98-compat-pedantic -Wno-c++98-compat "
|
|
"-Wno-switch-enum -Wno-switch-default "
|
|
"-Wno-reserved-identifier -Wno-reserved-macro-identifier "
|
|
"-Wno-unsafe-buffer-usage -Wno-writable-strings "
|
|
""
|
|
"-Wno-c11-extensions -Wno-gnu-anonymous-struct -Wno-nested-anon-types "
|
|
""
|
|
"-Wno-double-promotion");
|
|
/* -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-parameter */
|
|
|
|
StringListAppend(&arena, &compile_warnings, warnings);
|
|
StringListAppend(&arena, &link_warnings, warnings);
|
|
}
|
|
|
|
/* RTC */
|
|
if (arg_rtc) {
|
|
if (!arg_crtlib) {
|
|
Error(Lit("CRTLIB (C runtime library) Must be enabled when compiling with RTC (runtime checks)"));
|
|
OS_Exit(1);
|
|
}
|
|
StringListAppend(&arena, &compile_args, Lit("-DRTC=1"));
|
|
if (arg_msvc) {
|
|
if (!arg_asan) {
|
|
/* Enable /RTC option (not compatible with ASAN) */
|
|
StringListAppend(&arena, &compile_and_link_args, Lit("/RTCcsu"));
|
|
}
|
|
} else {
|
|
/* Enable UBSan */
|
|
StringListAppend(&arena, &compile_and_link_args, Lit("-fsanitize=undefined -fsanitize-trap=all"));
|
|
//StringListAppend(&compile_and_link_args, "-fsanitize=undefined");
|
|
}
|
|
}
|
|
|
|
/* CRTLIB */
|
|
if (arg_crtlib) {
|
|
StringListAppend(&arena, &compile_args, Lit("-DCRTLIB=1"));
|
|
} else {
|
|
if (arg_msvc) {
|
|
/* TODO */
|
|
Error(Lit("TODO\n"));
|
|
OS_Exit(1);
|
|
} else {
|
|
StringListAppend(&arena, &compile_and_link_args, Lit("-mno-stack-arg-probe -fno-builtin -nostdlib"));
|
|
}
|
|
}
|
|
|
|
/* Optimization */
|
|
if (arg_unoptimized) {
|
|
StringListAppend(&arena, &compile_args, Lit("-DUNOPTIMIZED=1"));
|
|
if (arg_msvc) {
|
|
StringListAppend(&arena, &compile_args, Lit("/Od"));
|
|
} else {
|
|
StringListAppend(&arena, &compile_and_link_args, Lit("-O0"));
|
|
}
|
|
} else {
|
|
if (arg_msvc) {
|
|
StringListAppend(&arena, &compile_args, Lit("/O2"));
|
|
StringListAppend(&arena, &link_args, Lit("/LTCG"));
|
|
} else {
|
|
StringListAppend(&arena, &compile_and_link_args, Lit("-O3 -flto"));
|
|
}
|
|
}
|
|
|
|
/* Debug info */
|
|
if (arg_debinfo) {
|
|
StringListAppend(&arena, &compile_args, Lit("-DDEBINFO=1"));
|
|
if (arg_msvc) {
|
|
StringListAppend(&arena, &compile_args, Lit("/JMC /Zi"));
|
|
} else {
|
|
StringListAppend(&arena, &compile_and_link_args, Lit("-g"));
|
|
}
|
|
}
|
|
|
|
/* Address sanitizer */
|
|
if (arg_asan) {
|
|
if (!arg_crtlib) {
|
|
Error(Lit("CRTLIB (C runtime library) Must be enabled when compiling with asan enabled"));
|
|
OS_Exit(1);
|
|
}
|
|
StringListAppend(&arena, &compile_args, Lit("-DASAN=1"));
|
|
if (arg_msvc) {
|
|
StringListAppend(&arena, &compile_args, Lit("/fsanitize=address"));
|
|
} else {
|
|
StringListAppend(&arena, &compile_and_link_args, Lit("-fsanitize=address -shared-libasan"));
|
|
}
|
|
}
|
|
|
|
/* Developer mode */
|
|
if (arg_developer) {
|
|
StringListAppend(&arena, &compile_args, Lit("-DDEVELOPER=1"));
|
|
}
|
|
|
|
/* Profiling */
|
|
if (arg_profiling) {
|
|
if (!arg_crtlib) {
|
|
Error(Lit("CRTLIB (C runtime library) Must be enabled when compiling with profiling enabled"));
|
|
OS_Exit(1);
|
|
}
|
|
if (arg_msvc) {
|
|
Error(Lit("MSVC not supported with profiling enabled (Profiling relies on Clang attributes)"));
|
|
OS_Exit(1);
|
|
}
|
|
StringListAppend(&arena, &compile_args, Lit("-DPROFILING=1"));
|
|
/* Tracy flags */
|
|
StringListAppend(&arena, &compile_args, Lit("-DTRACY_ENABLE=1"));
|
|
StringListAppend(&arena, &compile_args, Lit("-DTRACY_CALLSTACK=5"));
|
|
StringListAppend(&arena, &compile_args, Lit("-DTRACY_NO_SAMPLING -DTRACY_NO_SYSTEM_TRACING -DTRACY_NO_CALLSTACK"));
|
|
/* Disable compile_warnings when compiling tracy client */
|
|
compile_warnings = (StringList) { 0 };
|
|
link_warnings = (StringList) { 0 };
|
|
}
|
|
|
|
if (!arg_msvc) {
|
|
String incbin_dir = StringReplace(&arena, out_inc_dir_path, Lit("\\"), Lit("/"));
|
|
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
|
|
}
|
|
|
|
/* ========================== *
|
|
* Read hist file
|
|
* ========================== */
|
|
|
|
D_Hist hist = D_HistFromPath(&arena, hist_path);
|
|
|
|
/* ========================== *
|
|
* 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_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))));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
AddDependenciesFromDepFile(&arena, file, dep_file);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ========================== *
|
|
* 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);
|
|
}
|
|
|
|
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 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)) {
|
|
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);
|
|
|
|
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 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 */
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
/* 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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
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("No work to do\n"));
|
|
}
|
|
if (!success) {
|
|
Error(Lit("Build failed\n"));
|
|
OS_Exit(1);
|
|
}
|
|
}
|
|
|
|
/* ========================== *
|
|
* Write hist file
|
|
* ========================== */
|
|
|
|
D_WriteStateToHistFile(hist_path);
|
|
|
|
OS_TimeStamp end = OS_GetTimeStamp();
|
|
F64 seconds = OS_SecondsFromTimeStamp(end - start);
|
|
SH_PrintF(Lit("Finished in %F seconds\n"), FmtF64P(seconds, 5));
|
|
|
|
#if 0
|
|
#if Rtc
|
|
getchar();
|
|
#endif
|
|
#endif
|
|
}
|