2023-10-24 13:11:48 +00:00
|
|
|
#if !defined(DQN_CPP_BUILD_H)
|
|
|
|
#define DQN_CPP_BUILD_H
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// $$$$$$\ $$$$$$$\ $$$$$$$\ $$$$$$$\ $$\ $$\ $$$$$$\ $$\ $$$$$$$\
|
|
|
|
// $$ __$$\ $$ __$$\ $$ __$$\ $$ __$$\ $$ | $$ |\_$$ _|$$ | $$ __$$\
|
|
|
|
// $$ / \__|$$ | $$ |$$ | $$ | $$ | $$ |$$ | $$ | $$ | $$ | $$ | $$ |
|
|
|
|
// $$ | $$$$$$$ |$$$$$$$ | $$$$$$$\ |$$ | $$ | $$ | $$ | $$ | $$ |
|
|
|
|
// $$ | $$ ____/ $$ ____/ $$ __$$\ $$ | $$ | $$ | $$ | $$ | $$ |
|
|
|
|
// $$ | $$\ $$ | $$ | $$ | $$ |$$ | $$ | $$ | $$ | $$ | $$ |
|
|
|
|
// \$$$$$$ |$$ | $$ | $$$$$$$ |\$$$$$$ |$$$$$$\ $$$$$$$$\ $$$$$$$ |
|
|
|
|
// \______/ \__| \__| \_______/ \______/ \______|\________|\_______/
|
|
|
|
//
|
|
|
|
// dqn_cppbuild.h -- Helper functions to make build scripts in C++
|
|
|
|
//
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2024-02-25 13:15:09 +00:00
|
|
|
#if !defined(DQN_H)
|
|
|
|
#error 'dqn.h' must be included before 'dqn_cppbuild.h'
|
|
|
|
#endif
|
2024-01-31 12:49:23 +00:00
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
struct Dqn_CPPBuildCompileFile
|
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
Dqn_Slice<Dqn_Str8> prefix_flags;
|
|
|
|
Dqn_Slice<Dqn_Str8> suffix_flags;
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_Str8 input_file_path;
|
|
|
|
Dqn_Str8 output_file_path;
|
|
|
|
};
|
|
|
|
|
|
|
|
Dqn_Str8 const DQN_CPP_BUILD_OBJ_SUFFIX_OBJ = DQN_STR8(".obj");
|
|
|
|
Dqn_Str8 const DQN_CPP_BUILD_OBJ_SUFFIX_O = DQN_STR8(".o");
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
enum Dqn_CPPBuildFlagsStyle
|
|
|
|
{
|
|
|
|
Dqn_CPPBuildFlagsStyle_MSVC,
|
|
|
|
Dqn_CPPBuildFlagsStyle_GCC,
|
|
|
|
Dqn_CPPBuildFlagsStyle_CLANG,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum Dqn_CPPBuildAppendCompilerToCommand
|
2023-10-24 13:11:48 +00:00
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
Dqn_CPPBuildAppendCompilerToCommand_No,
|
|
|
|
Dqn_CPPBuildAppendCompilerToCommand_Yes,
|
2023-10-24 13:11:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct Dqn_CPPBuildContext
|
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
// Dictates the type of compiler flags the functions may append to the
|
|
|
|
// build command line
|
|
|
|
Dqn_CPPBuildFlagsStyle flags_style;
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_Str8 compile_file_obj_suffix;
|
|
|
|
Dqn_Slice<Dqn_CPPBuildCompileFile> compile_files;
|
|
|
|
Dqn_Slice<Dqn_Str8> compile_flags;
|
|
|
|
Dqn_Slice<Dqn_Str8> include_dirs;
|
|
|
|
Dqn_Slice<Dqn_Str8> link_flags;
|
|
|
|
Dqn_Str8 build_dir;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum Dqn_CPPBuildStatus
|
|
|
|
{
|
|
|
|
Dqn_CPPBuildStatus_Ok,
|
|
|
|
Dqn_CPPBuildStatus_BuildDirectoryFailedToBeMade,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Dqn_CPPBuildAsyncResult
|
|
|
|
{
|
|
|
|
Dqn_CPPBuildStatus status;
|
|
|
|
Dqn_OSExecAsyncHandle async_handle;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum Dqn_CPPBuildMode
|
|
|
|
{
|
|
|
|
Dqn_CPPBuildMode_AlwaysRebuild,
|
|
|
|
Dqn_CPPBuildMode_CacheBuild,
|
|
|
|
};
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
DQN_API Dqn_Slice<Dqn_Str8> Dqn_CPPBuild_ToCommandLine (Dqn_CPPBuildContext build_context, Dqn_CPPBuildMode mode, Dqn_Arena *arena);
|
|
|
|
DQN_API Dqn_Str8 Dqn_CPPBuild_ToCommandLineStr8(Dqn_CPPBuildContext build_context, Dqn_CPPBuildMode mode, Dqn_Arena *arena);
|
|
|
|
DQN_API Dqn_CPPBuildAsyncResult Dqn_CPPBuild_Async (Dqn_CPPBuildContext build_context, Dqn_CPPBuildMode mode);
|
|
|
|
DQN_API void Dqn_CPPBuild_ExecOrAbort (Dqn_CPPBuildContext build_context, Dqn_CPPBuildMode mode);
|
2023-10-24 13:11:48 +00:00
|
|
|
#endif // DQN_CPP_BUILD_H
|
|
|
|
|
|
|
|
#if defined(DQN_CPP_BUILD_IMPLEMENTATION)
|
2024-01-31 12:49:23 +00:00
|
|
|
DQN_API Dqn_Slice<Dqn_Str8> Dqn_CPPBuild_ToCommandLine(Dqn_CPPBuildContext build_context, Dqn_CPPBuildMode mode, Dqn_Arena *arena)
|
2023-10-24 13:11:48 +00:00
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
// NOTE: Check if object files are newer than the source files /////////////////////////////////
|
|
|
|
Dqn_Scratch scratch = Dqn_Scratch_Get(arena);
|
|
|
|
Dqn_Slice<Dqn_Str8> result = {};
|
2023-10-24 13:11:48 +00:00
|
|
|
|
|
|
|
Dqn_Slice<Dqn_CPPBuildCompileFile> dirtied_compile_files = build_context.compile_files;
|
|
|
|
if (mode == Dqn_CPPBuildMode_CacheBuild) {
|
|
|
|
dirtied_compile_files = Dqn_Slice_Alloc<Dqn_CPPBuildCompileFile>(scratch.arena, build_context.compile_files.size, Dqn_ZeroMem_Yes);
|
|
|
|
dirtied_compile_files.size = 0;
|
|
|
|
|
|
|
|
DQN_FOR_UINDEX (index, build_context.compile_files.size) {
|
|
|
|
Dqn_CPPBuildCompileFile file = build_context.compile_files.data[index];
|
|
|
|
|
|
|
|
Dqn_Str8 obj_file_name = {};
|
|
|
|
if (file.output_file_path.size) {
|
|
|
|
obj_file_name = file.output_file_path;
|
|
|
|
} else {
|
|
|
|
// NOTE: Determine the object file suffix
|
|
|
|
Dqn_Str8 compile_file_obj_suffix = build_context.compile_file_obj_suffix;
|
|
|
|
if (compile_file_obj_suffix.size == 0)
|
|
|
|
compile_file_obj_suffix = DQN_CPP_BUILD_OBJ_SUFFIX_OBJ;
|
|
|
|
|
|
|
|
// NOTE: Create the object file path
|
|
|
|
Dqn_Str8 file_stem = Dqn_Str8_FileNameNoExtension(file.input_file_path);
|
2024-01-31 12:49:23 +00:00
|
|
|
obj_file_name = Dqn_Str8_InitF(scratch.arena, "%.*s%.*s", DQN_STR_FMT(file_stem), DQN_STR_FMT(compile_file_obj_suffix));
|
2023-10-24 13:11:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Dqn_Str8 obj_file_path = obj_file_name;
|
|
|
|
if (build_context.build_dir.size)
|
2024-01-31 12:49:23 +00:00
|
|
|
obj_file_path = Dqn_OS_PathConvertF(scratch.arena, "%.*s/%.*s", DQN_STR_FMT(build_context.build_dir), DQN_STR_FMT(obj_file_name));
|
2023-10-24 13:11:48 +00:00
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
Dqn_OSPathInfo file_info = Dqn_OS_PathInfo(file.input_file_path);
|
|
|
|
Dqn_OSPathInfo obj_file_info = Dqn_OS_PathInfo(obj_file_path);
|
2023-10-24 13:11:48 +00:00
|
|
|
if (obj_file_info.last_write_time_in_s >= file_info.last_write_time_in_s)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
dirtied_compile_files.data[dirtied_compile_files.size++] = file;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dirtied_compile_files.size <= 0)
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
// NOTE: Build the command line invocation /////////////////////////////////////////////////////
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_Str8Builder builder = {};
|
2024-01-31 12:49:23 +00:00
|
|
|
builder.arena = scratch.arena;
|
|
|
|
Dqn_Str8Builder_AppendRefArray(&builder, build_context.compile_flags);
|
2023-10-24 13:11:48 +00:00
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
DQN_FOR_UINDEX(index, build_context.include_dirs.size) {
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_Str8 include_dir = build_context.include_dirs.data[index];
|
2024-01-31 12:49:23 +00:00
|
|
|
Dqn_Str8Builder_AppendRef(&builder, DQN_STR8("-I"));
|
|
|
|
Dqn_Str8Builder_AppendRef(&builder, include_dir);
|
2023-10-24 13:11:48 +00:00
|
|
|
}
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
DQN_FOR_UINDEX(index, dirtied_compile_files.size) {
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_CPPBuildCompileFile file = dirtied_compile_files.data[index];
|
2024-01-31 12:49:23 +00:00
|
|
|
if (Dqn_Str8_HasData(file.output_file_path)) {
|
|
|
|
switch (build_context.flags_style) {
|
|
|
|
case Dqn_CPPBuildFlagsStyle_MSVC: {
|
|
|
|
Dqn_Str8Builder_AppendF(&builder, "-Fo%.*s", DQN_STR_FMT(file.output_file_path));
|
2023-10-24 13:11:48 +00:00
|
|
|
} break;
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
case Dqn_CPPBuildFlagsStyle_GCC: /*FALLTHRU*/
|
|
|
|
case Dqn_CPPBuildFlagsStyle_CLANG: {
|
|
|
|
Dqn_Str8Builder_AppendF (&builder, "-o");
|
|
|
|
Dqn_Str8Builder_AppendRef(&builder, file.output_file_path);
|
2023-10-24 13:11:48 +00:00
|
|
|
} break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
// TODO(doyle): Check if the file exists, error if it doesn't
|
2023-10-24 13:11:48 +00:00
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
Dqn_Str8Builder_AppendRefArray(&builder, file.prefix_flags);
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_Str8Builder_AppendRef(&builder, file.input_file_path);
|
2024-01-31 12:49:23 +00:00
|
|
|
Dqn_Str8Builder_AppendRefArray(&builder, file.suffix_flags);
|
2023-10-24 13:11:48 +00:00
|
|
|
}
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
Dqn_Str8Builder_AppendRefArray(&builder, build_context.link_flags);
|
|
|
|
result = Dqn_Str8Builder_BuildSlice(&builder, arena);
|
2023-10-24 13:11:48 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
DQN_API Dqn_Str8 Dqn_CPPBuild_ToCommandLineStr8(Dqn_CPPBuildContext build_context, Dqn_CPPBuildMode mode, Dqn_Arena *arena)
|
|
|
|
{
|
|
|
|
Dqn_Slice<Dqn_Str8> cmd_line = Dqn_CPPBuild_ToCommandLine(build_context, mode, arena);
|
|
|
|
Dqn_Str8 result = Dqn_Slice_Str8Render(arena, cmd_line, DQN_STR8(" ") /*separator*/);
|
|
|
|
return result;
|
|
|
|
}
|
2023-10-24 13:11:48 +00:00
|
|
|
|
2024-03-25 02:14:05 +00:00
|
|
|
DQN_API Dqn_CPPBuildAsyncResult Dqn_CPPBuild_Async(Dqn_CPPBuildContext build_context, Dqn_CPPBuildMode mode, Dqn_ErrorSink *error)
|
2023-10-24 13:11:48 +00:00
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
|
|
|
Dqn_Slice<Dqn_Str8> cmd_line = Dqn_CPPBuild_ToCommandLine(build_context, mode, scratch.arena);
|
|
|
|
Dqn_CPPBuildAsyncResult result = {};
|
|
|
|
if (!cmd_line.size)
|
2023-10-24 13:11:48 +00:00
|
|
|
return result;
|
|
|
|
|
2024-02-11 07:23:13 +00:00
|
|
|
if (!Dqn_OS_MakeDir(build_context.build_dir)) {
|
2023-10-24 13:11:48 +00:00
|
|
|
result.status = Dqn_CPPBuildStatus_BuildDirectoryFailedToBeMade;
|
2024-03-25 02:14:05 +00:00
|
|
|
Dqn_ErrorSink_MakeF(error, result.status, "Failed to make build directory '%.*s'", DQN_STR_FMT(build_context.build_dir));
|
2023-10-24 13:11:48 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-03-25 02:14:05 +00:00
|
|
|
result.async_handle = Dqn_OS_ExecAsync(cmd_line, build_context.build_dir, Dqn_OSExecFlag_Nil, error);
|
2023-10-24 13:11:48 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dqn_CPPBuild_ExecOrAbort(Dqn_CPPBuildContext build_context, Dqn_CPPBuildMode mode)
|
|
|
|
{
|
2024-02-11 07:23:13 +00:00
|
|
|
if (!Dqn_OS_MakeDir(build_context.build_dir)) {
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_Log_ErrorF("Failed to make build dir '%.*s'", DQN_STR_FMT(build_context.build_dir));
|
|
|
|
exit(-1);
|
|
|
|
}
|
2024-01-31 12:49:23 +00:00
|
|
|
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
|
|
|
Dqn_Slice<Dqn_Str8> cmd_line = Dqn_CPPBuild_ToCommandLine(build_context, mode, scratch.arena);
|
2024-03-25 02:14:05 +00:00
|
|
|
Dqn_OS_ExecOrAbort(cmd_line, build_context.build_dir, Dqn_OSExecFlag_Nil, scratch.arena);
|
2023-10-24 13:11:48 +00:00
|
|
|
}
|
|
|
|
#endif // DQN_CPP_BUILD_IMPLEMENTATION
|