msvc depfile support
This commit is contained in:
parent
1d43fee5a1
commit
59c2d06ffa
166
build.c
166
build.c
@ -1,5 +1,18 @@
|
|||||||
#include "buildit.h"
|
#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
|
* Util
|
||||||
* ========================== */
|
* ========================== */
|
||||||
@ -11,9 +24,6 @@ void Error(String msg)
|
|||||||
|
|
||||||
Bool IsDirty(D_Tag tag)
|
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);
|
Bool res = force_rebuild ? true : D_IsDirty(&store, &hist, tag);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
if (tag.kind == D_TagKind_File || tag.kind == D_TagKind_Dir) {
|
if (tag.kind == D_TagKind_File || tag.kind == D_TagKind_Dir) {
|
||||||
@ -133,7 +143,6 @@ struct WorkerSharedState {
|
|||||||
Worker *first_worker;
|
Worker *first_worker;
|
||||||
I64 worker_count;
|
I64 worker_count;
|
||||||
};
|
};
|
||||||
extern WorkerSharedState worker_shared;
|
|
||||||
|
|
||||||
typedef struct Worker Worker;
|
typedef struct Worker Worker;
|
||||||
struct Worker {
|
struct Worker {
|
||||||
@ -155,22 +164,22 @@ OS_ThreadEntryPointFuncDef(WorkerEntryPoint, arg)
|
|||||||
OS_SetThreadName(Lit("Builder worker"));
|
OS_SetThreadName(Lit("Builder worker"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (!worker_shared.shutdown) {
|
while (!worker_shared->shutdown) {
|
||||||
OS_MutexLockW(&worker_shared.mutex);
|
OS_MutexLockW(&worker_shared->mutex);
|
||||||
{
|
{
|
||||||
if (!worker_shared.shutdown && !worker_shared.first_step_list) {
|
if (!worker_shared->shutdown && !worker_shared->first_step_list) {
|
||||||
OS_ConditionVariableWaitW(&worker_shared.cv, &worker_shared.mutex);
|
OS_ConditionVariableWaitW(&worker_shared->cv, &worker_shared->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!worker_shared.shutdown && worker_shared.first_step_list) {
|
if (!worker_shared->shutdown && worker_shared->first_step_list) {
|
||||||
StepList *sl = worker_shared.first_step_list;
|
StepList *sl = worker_shared->first_step_list;
|
||||||
Step *s = DequeueNextStep(sl);
|
Step *s = DequeueNextStep(sl);
|
||||||
if (s) {
|
if (s) {
|
||||||
OS_MutexUnlockW(&worker_shared.mutex);
|
OS_MutexUnlockW(&worker_shared->mutex);
|
||||||
{
|
{
|
||||||
s->func(s);
|
s->func(s);
|
||||||
}
|
}
|
||||||
OS_MutexLockW(&worker_shared.mutex);
|
OS_MutexLockW(&worker_shared->mutex);
|
||||||
} else {
|
} else {
|
||||||
/* Wait for all steps in old step list to finish, then pop the list */
|
/* 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) {
|
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);
|
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)
|
void StartWorkers(I64 count)
|
||||||
{
|
{
|
||||||
OS_MutexLockW(&worker_shared.mutex);
|
OS_MutexLockW(&worker_shared->mutex);
|
||||||
{
|
{
|
||||||
for (I64 i = 0; i < count; ++i) {
|
for (I64 i = 0; i < count; ++i) {
|
||||||
Worker *w = ArenaPush(&worker_shared.arena, Worker);
|
Worker *w = ArenaPush(&worker_shared->arena, Worker);
|
||||||
w->thread = OS_ThreadAlloc(&WorkerEntryPoint, (void *)worker_shared.worker_count);
|
w->thread = OS_ThreadAlloc(&WorkerEntryPoint, (void *)worker_shared->worker_count);
|
||||||
SllStackPush(worker_shared.first_worker, w);
|
SllStackPush(worker_shared->first_worker, w);
|
||||||
++worker_shared.worker_count;
|
++worker_shared->worker_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OS_MutexUnlockW(&worker_shared.mutex);
|
OS_MutexUnlockW(&worker_shared->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShutdownWorkers(void)
|
void ShutdownWorkers(void)
|
||||||
{
|
{
|
||||||
OS_MutexLockW(&worker_shared.mutex);
|
OS_MutexLockW(&worker_shared->mutex);
|
||||||
{
|
{
|
||||||
worker_shared.shutdown = true;
|
worker_shared->shutdown = true;
|
||||||
OS_ConditionVariableBroadcast(&worker_shared.cv);
|
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);
|
OS_ThreadWaitRelease(&w->thread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddStepListToWorkQueue(StepList *sl)
|
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);
|
SllQueuePush(worker_shared->first_step_list, worker_shared->last_step_list, sl);
|
||||||
OS_ConditionVariableBroadcast(&worker_shared.cv);
|
OS_ConditionVariableBroadcast(&worker_shared->cv);
|
||||||
}
|
}
|
||||||
OS_MutexUnlockW(&worker_shared.mutex);
|
OS_MutexUnlockW(&worker_shared->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -237,6 +246,14 @@ struct BuildStepSimpleCommandArg {
|
|||||||
String cmd;
|
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)
|
void BuildStepSimpleCommand(Step *s)
|
||||||
{
|
{
|
||||||
TempArena scratch = ScratchBeginNoConflict();
|
TempArena scratch = ScratchBeginNoConflict();
|
||||||
@ -263,21 +280,37 @@ void BuildStepSimpleCommand(Step *s)
|
|||||||
ScratchEnd(scratch);
|
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
|
* Build
|
||||||
* ========================== */
|
* ========================== */
|
||||||
@ -288,13 +321,14 @@ void OnBuild(StringList cli_args)
|
|||||||
|
|
||||||
arena = ArenaAlloc(Gigabyte(64));
|
arena = ArenaAlloc(Gigabyte(64));
|
||||||
store = D_StoreAlloc();
|
store = D_StoreAlloc();
|
||||||
|
worker_shared = ArenaPush(&arena, WorkerSharedState);
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Setup workers
|
* Setup workers
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
worker_shared.mutex = OS_MutexAlloc();
|
worker_shared->mutex = OS_MutexAlloc();
|
||||||
worker_shared.arena = ArenaAlloc(Gigabyte(64));
|
worker_shared->arena = ArenaAlloc(Gigabyte(64));
|
||||||
|
|
||||||
I64 worker_count = OS_GetProcessorCount();
|
I64 worker_count = OS_GetProcessorCount();
|
||||||
StartWorkers(worker_count);
|
StartWorkers(worker_count);
|
||||||
@ -412,22 +446,19 @@ void OnBuild(StringList cli_args)
|
|||||||
StringList cpp_compile_args = { 0 };
|
StringList cpp_compile_args = { 0 };
|
||||||
StringList pch_c_compile_args = { 0 };
|
StringList pch_c_compile_args = { 0 };
|
||||||
StringList pch_cpp_compile_args = { 0 };
|
StringList pch_cpp_compile_args = { 0 };
|
||||||
|
|
||||||
StringList compile_and_link_args = { 0 };
|
StringList compile_and_link_args = { 0 };
|
||||||
StringList compile_args = { 0 };
|
StringList compile_args = { 0 };
|
||||||
StringList compile_warnings = { 0 };
|
StringList compile_warnings = { 0 };
|
||||||
|
|
||||||
StringList link_warnings = { 0 };
|
StringList link_warnings = { 0 };
|
||||||
StringList link_args = { 0 };
|
StringList link_args = { 0 };
|
||||||
|
|
||||||
StringList rc_compile_args = { 0 };
|
StringList rc_compile_args = { 0 };
|
||||||
{
|
{
|
||||||
if (arg_msvc) {
|
if (arg_msvc) {
|
||||||
/* Msvc */
|
/* Msvc */
|
||||||
StringListAppend(&arena, &c_compile_args, Lit("cl.exe /nologo /c \"%F\" /Fo\"%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"));
|
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"));
|
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"));
|
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, &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"));
|
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
|
* 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 pch_header_file = D_TagFromPath(&arena, Lit("src/common.h"), D_TagKind_File);
|
||||||
|
|
||||||
D_Tag dep_file;
|
D_Tag dep_file;
|
||||||
{
|
{
|
||||||
String name = D_GetName(pch_header_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);
|
D_AddDependency(&store, pch_cpp_file, dep_file);
|
||||||
|
|
||||||
if (arg_msvc) {
|
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_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_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);
|
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 */
|
/* C */
|
||||||
if (IsDirty(pch_c_file)) {
|
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)));
|
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 */
|
/* Cpp */
|
||||||
if (IsDirty(pch_cpp_file)) {
|
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)));
|
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)) {
|
if (IsDirty(obj_file)) {
|
||||||
String comp_cmd_fmt = is_c ? c_compile_args_fmt : cpp_compile_args_fmt;
|
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)));
|
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);
|
D_TagListAppend(&arena, &link_files, obj_file);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user