diff --git a/build.c b/build.c index fddca9cb..b73d723c 100644 --- a/build.c +++ b/build.c @@ -1,5 +1,18 @@ #include "buildit.h" +typedef struct WorkerSharedState WorkerSharedState; + +/* ========================== * + * Globals + * ========================== */ + +Bool force_rebuild = false; + +Arena arena = { 0 }; +D_Store store = { 0 }; +D_Hist hist = { 0 }; +WorkerSharedState *worker_shared = { 0 }; + /* ========================== * * Util * ========================== */ @@ -11,9 +24,6 @@ void Error(String msg) Bool IsDirty(D_Tag tag) { - extern Bool force_rebuild; - extern D_Store store; - extern D_Hist hist; Bool res = force_rebuild ? true : D_IsDirty(&store, &hist, tag); if (!res) { if (tag.kind == D_TagKind_File || tag.kind == D_TagKind_Dir) { @@ -133,7 +143,6 @@ struct WorkerSharedState { Worker *first_worker; I64 worker_count; }; -extern WorkerSharedState worker_shared; typedef struct Worker Worker; struct Worker { @@ -155,22 +164,22 @@ OS_ThreadEntryPointFuncDef(WorkerEntryPoint, arg) OS_SetThreadName(Lit("Builder worker")); #endif - while (!worker_shared.shutdown) { - OS_MutexLockW(&worker_shared.mutex); + while (!worker_shared->shutdown) { + OS_MutexLockW(&worker_shared->mutex); { - if (!worker_shared.shutdown && !worker_shared.first_step_list) { - OS_ConditionVariableWaitW(&worker_shared.cv, &worker_shared.mutex); + if (!worker_shared->shutdown && !worker_shared->first_step_list) { + OS_ConditionVariableWaitW(&worker_shared->cv, &worker_shared->mutex); } - if (!worker_shared.shutdown && worker_shared.first_step_list) { - StepList *sl = worker_shared.first_step_list; + if (!worker_shared->shutdown && worker_shared->first_step_list) { + StepList *sl = worker_shared->first_step_list; Step *s = DequeueNextStep(sl); if (s) { - OS_MutexUnlockW(&worker_shared.mutex); + OS_MutexUnlockW(&worker_shared->mutex); { s->func(s); } - OS_MutexLockW(&worker_shared.mutex); + OS_MutexLockW(&worker_shared->mutex); } else { /* Wait for all steps in old step list to finish, then pop the list */ for (Step *check_step = sl->first; check_step; check_step = check_step->next) { @@ -182,50 +191,50 @@ OS_ThreadEntryPointFuncDef(WorkerEntryPoint, arg) } OS_MutexUnlockW(&check_step->res_mutex); } - SllQueuePop(worker_shared.first_step_list, worker_shared.last_step_list); + SllQueuePop(worker_shared->first_step_list, worker_shared->last_step_list); } } } - OS_MutexUnlockW(&worker_shared.mutex); + OS_MutexUnlockW(&worker_shared->mutex); } } void StartWorkers(I64 count) { - OS_MutexLockW(&worker_shared.mutex); + OS_MutexLockW(&worker_shared->mutex); { for (I64 i = 0; i < count; ++i) { - Worker *w = ArenaPush(&worker_shared.arena, Worker); - w->thread = OS_ThreadAlloc(&WorkerEntryPoint, (void *)worker_shared.worker_count); - SllStackPush(worker_shared.first_worker, w); - ++worker_shared.worker_count; + Worker *w = ArenaPush(&worker_shared->arena, Worker); + w->thread = OS_ThreadAlloc(&WorkerEntryPoint, (void *)worker_shared->worker_count); + SllStackPush(worker_shared->first_worker, w); + ++worker_shared->worker_count; } } - OS_MutexUnlockW(&worker_shared.mutex); + OS_MutexUnlockW(&worker_shared->mutex); } void ShutdownWorkers(void) { - OS_MutexLockW(&worker_shared.mutex); + OS_MutexLockW(&worker_shared->mutex); { - worker_shared.shutdown = true; - OS_ConditionVariableBroadcast(&worker_shared.cv); + worker_shared->shutdown = true; + OS_ConditionVariableBroadcast(&worker_shared->cv); } - OS_MutexUnlockW(&worker_shared.mutex); + OS_MutexUnlockW(&worker_shared->mutex); - for (Worker *w = worker_shared.first_worker; w; w = w->next) { + for (Worker *w = worker_shared->first_worker; w; w = w->next) { OS_ThreadWaitRelease(&w->thread); } } void AddStepListToWorkQueue(StepList *sl) { - OS_MutexLockW(&worker_shared.mutex); + OS_MutexLockW(&worker_shared->mutex); { - SllQueuePush(worker_shared.first_step_list, worker_shared.last_step_list, sl); - OS_ConditionVariableBroadcast(&worker_shared.cv); + SllQueuePush(worker_shared->first_step_list, worker_shared->last_step_list, sl); + OS_ConditionVariableBroadcast(&worker_shared->cv); } - OS_MutexUnlockW(&worker_shared.mutex); + OS_MutexUnlockW(&worker_shared->mutex); } /* ========================== * @@ -237,6 +246,14 @@ struct BuildStepSimpleCommandArg { String cmd; }; +typedef struct BuildStepMsvcCompileCommandArg BuildStepMsvcCompileCommandArg; +struct BuildStepMsvcCompileCommandArg { + String cmd; + D_Tag depfile_dependent; + D_Tag output_depfile; + D_TagList depfile_force_includes; +}; + void BuildStepSimpleCommand(Step *s) { TempArena scratch = ScratchBeginNoConflict(); @@ -263,21 +280,37 @@ void BuildStepSimpleCommand(Step *s) ScratchEnd(scratch); } -void BuildStepCompileRc(Step *s) +void BuildStepMsvcCompileCommand(Step *s) { + TempArena scratch = ScratchBeginNoConflict(); + + BuildStepMsvcCompileCommandArg *arg = s->arg; + SH_CommandResult result = SH_RunCommandCaptureOutput(scratch.arena, arg->cmd, true); + + if (!result.error && !D_IsNil(arg->depfile_dependent) && !D_IsNil(arg->output_depfile)) { + String depfile_data = B_DepfileTextFromMsvcOutput(scratch.arena, arg->depfile_dependent, arg->depfile_force_includes, result.output); + D_ClearWrite(arg->output_depfile, depfile_data); + } + + OS_MutexLockW(&s->res_mutex); + { + if (result.output.len > 0) { + OS_MutexLockW(&s->sl->mutex); + { + s->res_output.text = ArenaPushArrayNoZero(&s->sl->arena, Byte, result.output.len); + } + OS_MutexUnlockW(&s->sl->mutex); + s->res_output.len = result.output.len; + MemoryCopy(s->res_output.text, result.output.text, result.output.len); + } + s->res_status = result.error ? StepStatus_Failure : StepStatus_Success; + OS_ConditionVariableBroadcast(&s->res_cv); + } + OS_MutexUnlockW(&s->res_mutex); + + ScratchEnd(scratch); } -/* ========================== * - * Globals - * ========================== */ - -Arena arena = { 0 }; -D_Store store = { 0 }; -D_Hist hist = { 0 }; -WorkerSharedState worker_shared = { 0 }; - -Bool force_rebuild = false; - /* ========================== * * Build * ========================== */ @@ -288,13 +321,14 @@ void OnBuild(StringList cli_args) arena = ArenaAlloc(Gigabyte(64)); store = D_StoreAlloc(); + worker_shared = ArenaPush(&arena, WorkerSharedState); /* ========================== * * Setup workers * ========================== */ - worker_shared.mutex = OS_MutexAlloc(); - worker_shared.arena = ArenaAlloc(Gigabyte(64)); + worker_shared->mutex = OS_MutexAlloc(); + worker_shared->arena = ArenaAlloc(Gigabyte(64)); I64 worker_count = OS_GetProcessorCount(); StartWorkers(worker_count); @@ -412,22 +446,19 @@ void OnBuild(StringList cli_args) 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\" /FS")); - StringListAppend(&arena, &cpp_compile_args, Lit("cl.exe /nologo /c \"%F\" /Fo\"%F\" /FS")); - StringListAppend(&arena, &pch_c_compile_args, Lit("cl.exe /nologo /c /Yc\"%F\" \"%F\" /FS")); - StringListAppend(&arena, &pch_cpp_compile_args, Lit("cl.exe /nologo /c /Yc\"%F\" \"%F\" /FS")); + StringListAppend(&arena, &c_compile_args, Lit("cl.exe /nologo /c \"%F\" /Fo\"%F\" /FS /showIncludes")); + StringListAppend(&arena, &cpp_compile_args, Lit("cl.exe /nologo /c \"%F\" /Fo\"%F\" /FS /showIncludes")); + StringListAppend(&arena, &pch_c_compile_args, Lit("cl.exe /nologo /c /Yc\"%F\" \"%F\" /FS /showIncludes")); + StringListAppend(&arena, &pch_cpp_compile_args, Lit("cl.exe /nologo /c /Yc\"%F\" \"%F\" /FS /showIncludes")); StringListAppend(&arena, &rc_compile_args, Lit("rc /fo\"%F\" \"%F\"")); StringListAppend(&arena, &link_args, Lit("link.exe /nologo %F /OUT:\"%F\" /DEBUG:FULL /OPT:REF /OPT:ICF")); @@ -708,9 +739,9 @@ void OnBuild(StringList cli_args) * Build step: Compile pch files * ========================== */ + D_TagList depfile_force_includes = { 0 }; { 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); @@ -727,6 +758,8 @@ void OnBuild(StringList cli_args) D_AddDependency(&store, pch_cpp_file, dep_file); if (arg_msvc) { + D_TagListAppend(&arena, &depfile_force_includes, pch_header_file); + D_Tag pch_c_src_gen_file = D_TagFromPath(&arena, StringF(&arena, Lit("%F/common.c"), FmtStr(out_obj_dir_path)), D_TagKind_File); D_Tag pch_c_src_gen_obj_file = D_TagFromPath(&arena, StringF(&arena, Lit("%F/common.c.obj"), FmtStr(out_obj_dir_path)), D_TagKind_File); D_Tag pch_cpp_src_gen_file = D_TagFromPath(&arena, StringF(&arena, Lit("%F/common.cpp"), FmtStr(out_obj_dir_path)), D_TagKind_File); @@ -773,18 +806,22 @@ void OnBuild(StringList cli_args) /* C */ if (IsDirty(pch_c_file)) { - BuildStepSimpleCommandArg *bs_arg = ArenaPush(&arena, BuildStepSimpleCommandArg); - bs_arg->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))); - AddStep(&rc_and_pch_build_steps, step_name, &BuildStepSimpleCommand, bs_arg); + BuildStepMsvcCompileCommandArg *bs_arg = ArenaPush(&arena, BuildStepMsvcCompileCommandArg); + bs_arg->cmd = StringF(&arena, pch_c_compile_args_fmt, FmtStr(pch_header_file.full_path), FmtStr(pch_c_file.full_path)); + bs_arg->depfile_dependent = pch_header_file; + bs_arg->output_depfile = dep_file; + AddStep(&comp_build_steps, step_name, &BuildStepMsvcCompileCommand, bs_arg); } /* Cpp */ if (IsDirty(pch_cpp_file)) { - BuildStepSimpleCommandArg *bs_arg = ArenaPush(&arena, BuildStepSimpleCommandArg); - bs_arg->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))); - AddStep(&rc_and_pch_build_steps, step_name, &BuildStepSimpleCommand, bs_arg); + BuildStepMsvcCompileCommandArg *bs_arg = ArenaPush(&arena, BuildStepMsvcCompileCommandArg); + bs_arg->cmd = StringF(&arena, pch_cpp_compile_args_fmt, FmtStr(pch_header_file.full_path), FmtStr(pch_cpp_file.full_path)); + bs_arg->depfile_dependent = pch_header_file; + bs_arg->output_depfile = dep_file; + AddStep(&comp_build_steps, step_name, &BuildStepMsvcCompileCommand, bs_arg); } } } @@ -861,10 +898,19 @@ void OnBuild(StringList cli_args) if (IsDirty(obj_file)) { String comp_cmd_fmt = is_c ? c_compile_args_fmt : cpp_compile_args_fmt; - BuildStepSimpleCommandArg *bs_arg = ArenaPush(&arena, BuildStepSimpleCommandArg); - bs_arg->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))); - AddStep(&comp_build_steps, step_name, &BuildStepSimpleCommand, bs_arg); + if (arg_msvc) { + BuildStepMsvcCompileCommandArg *bs_arg = ArenaPush(&arena, BuildStepMsvcCompileCommandArg); + bs_arg->cmd = StringF(&arena, comp_cmd_fmt, FmtStr(file.full_path), FmtStr(obj_file.full_path)); + bs_arg->depfile_dependent = obj_file; + bs_arg->output_depfile = dep_file; + bs_arg->depfile_force_includes = depfile_force_includes; + AddStep(&comp_build_steps, step_name, &BuildStepMsvcCompileCommand, bs_arg); + } else { + BuildStepSimpleCommandArg *bs_arg = ArenaPush(&arena, BuildStepSimpleCommandArg); + bs_arg->cmd = StringF(&arena, comp_cmd_fmt, FmtStr(file.full_path), FmtStr(obj_file.full_path)); + AddStep(&comp_build_steps, step_name, &BuildStepSimpleCommand, bs_arg); + } } D_TagListAppend(&arena, &link_files, obj_file);