feely_pona/feely_pona_build.cpp

613 lines
32 KiB
C++

#define DQN_IMPLEMENTATION
#include "External/tely/External/dqn/dqn.h"
#define DQN_CPP_BUILD_IMPLEMENTATION
#include "External/tely/External/dqn/dqn_cppbuild.h"
struct BuildTime
{
Dqn_Str8 name;
uint64_t timestamps[2];
};
enum Compiler
{
Compiler_MSVC,
Compiler_GCC,
Compiler_EMCC,
Compiler_Count,
};
#define PRINT_HELP Dqn_Print_StdLnF(Dqn_PrintStd_Out, "USAGE: feely_pona_build [--help|--dry-run|--web|--fast-dev-build|--msvc|--gcc]")
int main(int argc, char const **argv)
{
// NOTE: Preamble ==============================================================================
Dqn_Library_Init(Dqn_LibraryOnInit_Nil);
Dqn_FArray32<BuildTime> build_timings = {};
BuildTime *global_build_timings = Dqn_FArray_Make(&build_timings, Dqn_ZeroMem_Yes);
global_build_timings->name = DQN_STR8("Dqn_CPPBuild Summary (Total)");
global_build_timings->timestamps[0] = Dqn_OS_PerfCounterNow();
#if 0
RebuildProgramIfRequired(argc, argv);
#else
Dqn_Print_StdLnF(Dqn_PrintStd_Out, "-- Dqn_CPPBuild v0");
#endif
bool build_using_compiler[Compiler_Count] = {};
// NOTE: Parse arguments =======================================================================
bool dry_run = false;
bool fast_dev_build = false;
for (Dqn_isize arg_index = 1; arg_index < argc; arg_index++) {
Dqn_Str8 arg = Dqn_Str8_InitCStr8(argv[arg_index]);
if (arg == DQN_STR8("--help")) {
PRINT_HELP;
return 0;
} else if (arg == DQN_STR8("--dry-run")) {
dry_run = true;
} else if (arg == DQN_STR8("--fast-dev-build")) {
fast_dev_build = true;
} else if (arg == DQN_STR8("--gcc")) {
build_using_compiler[Compiler_GCC] = true;
} else if (arg == DQN_STR8("--msvc")) {
build_using_compiler[Compiler_MSVC] = true;
} else if (arg == DQN_STR8("--web")) {
build_using_compiler[Compiler_EMCC] = true;
} else {
PRINT_HELP;
return 0;
}
}
// NOTE: Add a default compiler target if none were specified
{
size_t total_compiler_targets = 0;
for (bool is_set : build_using_compiler)
total_compiler_targets += DQN_CAST(size_t)is_set;
if (total_compiler_targets == 0) {
#if defined(DQN_OS_WIN32)
build_using_compiler[Compiler_MSVC] = true;
#else
compiler_targets[Compiler_GCC] = true;
#endif
}
}
// NOTE: Setup build ===========================================================================
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
Dqn_Str8 const exe_dir = Dqn_OS_EXEDir(scratch.arena);
Dqn_Str8 const code_dir = exe_dir;
Dqn_Str8 const build_dir = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/Build", DQN_STR_FMT(exe_dir));
Dqn_Str8 const tely_dir = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/External/tely", DQN_STR_FMT(exe_dir));
#define RecordScopeTime(...) \
BuildTime *build_time_ = Dqn_FArray_Make<BuildTime>(&build_timings, Dqn_ZeroMem_Yes); \
build_time_->name = Dqn_Str8_InitF(scratch.allocator, ##__VA_ARGS__); \
build_time_->timestamps[0] = Dqn_OS_PerfCounterNow(); \
DQN_DEFER { build_time_->timestamps[1] = Dqn_OS_PerfCounterNow(); }
bool assets_copied = false;
for (Dqn_usize compiler_index = 0; compiler_index < Compiler_Count; compiler_index++) {
if (!build_using_compiler[compiler_index])
continue;
Compiler compiler = DQN_CAST(Compiler) compiler_index;
Dqn_Str8 obj_file_extension = compiler == Compiler_MSVC ? DQN_STR8("obj") : DQN_STR8("o");
Dqn_Str8 compiler_label = {};
switch (compiler) {
case Compiler_MSVC: compiler_label = DQN_STR8("msvc"); break;
case Compiler_GCC: compiler_label = DQN_STR8("gcc"); break;
case Compiler_EMCC: compiler_label = DQN_STR8("emcc"); break;
case Compiler_Count: break;
}
// NOTE: Compile flags =========================================================================
Dqn_FArray32<Dqn_Str8> common_compile_flags_no_warnings = {};
if (compiler == Compiler_MSVC) {
Dqn_FArray_AddCArrayAssert(&common_compile_flags_no_warnings, {
DQN_STR8("cl"),
DQN_STR8("-Z7"),
DQN_STR8("-MT"),
DQN_STR8("-EHsc"),
DQN_STR8("-nologo"),
});
} else if (compiler == Compiler_GCC) {
Dqn_FArray_AddCArrayAssert(&common_compile_flags_no_warnings, {
DQN_STR8("g++"),
DQN_STR8("-g"),
});
} else {
DQN_ASSERT(compiler == Compiler_EMCC);
#if defined(DQN_OS_WIN32)
Dqn_FArray_AddCArrayAssert(&common_compile_flags_no_warnings, {
DQN_STR8("cmd"),
DQN_STR8("/c"),
DQN_STR8("emcc.bat"),
});
#else
Dqn_FArray_AddCArrayAssert(&common_compile_flags_no_warnings, {
DQN_STR8("emcc"),
DQN_STR8("-Os"), // Optimise for size
});
#endif
}
Dqn_FArray32<Dqn_Str8> common_link_flags = {};
Dqn_FArray32<Dqn_Str8> common_compile_flags = common_compile_flags_no_warnings;
Dqn_FArray_AddCArrayAssert(&common_compile_flags_no_warnings, {DQN_STR8("-w")});
if (compiler == Compiler_MSVC) {
Dqn_FArray_AddCArrayAssert(&common_compile_flags, {DQN_STR8("-W4")});
Dqn_FArray_AddCArrayAssert(&common_link_flags, {
DQN_STR8("-link"),
DQN_STR8("-incremental:no"),
});
} else {
Dqn_FArray_AddCArrayAssert(&common_compile_flags, {
DQN_STR8("-Wall"),
});
Dqn_FArray_AddCArrayAssert(&common_link_flags, {
DQN_STR8("-lm"),
});
}
// NOTE: Link flags ============================================================================
// NOTE: Build context =========================================================================
Dqn_CPPBuildContext common_build_context = {};
common_build_context.build_dir = build_dir;
common_build_context.flags_style = compiler == Compiler_MSVC ? Dqn_CPPBuildFlagsStyle_MSVC : Dqn_CPPBuildFlagsStyle_GCC;
// NOTE: Build program =========================================================================
// NOTE: Copy assets ===========================================================================
if (!assets_copied) {
RecordScopeTime("Copy assets");
assets_copied = true;
Dqn_FArray32<Dqn_Str8> cmd_array = {};
#if defined(DQN_OS_WIN32)
Dqn_FArray_AddCArray(&cmd_array, {
DQN_STR8("robocopy"),
DQN_STR8("/MIR"), // Mirror
DQN_STR8("/NJH"), // No job header
DQN_STR8("/NJS"), // No job summary
DQN_STR8("/NDL"),
DQN_STR8("/NP"), // No progress
});
#else
cmd_array = Dqn_FArray_AddCArray(&cmd_array, {
DQN_STR8("cp"),
DQN_STR8("--recursive"),
DQN_STR8("--force"),
});
#endif
DQN_MSVC_WARNING_PUSH
DQN_MSVC_WARNING_DISABLE(6063)
DQN_MSVC_WARNING_DISABLE(6064)
// TODO(doyle): The stringify macro in AddCArrayAssert triggers MSVC's code '-analyze'
// flag because it forwards the '%.*s' into Dqn_Log_TypeFCallSite which takes in a
// format string.
//
// warning C6064: Missing integer argument to 'Dqn_Log_TypeFCallSite' that corresponds to conversion specifier '1'.
// warning C6063: Missing string argument to 'Dqn_Log_TypeFCallSite' that corresponds to conversion specifier '2'.
// warning C6064: Missing integer argument to 'Dqn_Log_TypeFCallSite' that corresponds to conversion specifier '3'.
// warning C6063: Missing string argument to 'Dqn_Log_TypeFCallSite' that corresponds to conversion specifier '4'.
// NOTE: Copy the fonts
{
Dqn_FArray32<Dqn_Str8> font_cmd_array = cmd_array;
Dqn_FArray_AddCArrayAssert(&font_cmd_array, {
Dqn_FsPath_ConvertF(scratch.arena, "%.*s/Data/Fonts", DQN_STR_FMT(exe_dir)), // Source
Dqn_FsPath_ConvertF(scratch.arena, "%.*s/Data/Fonts", DQN_STR_FMT(build_dir)), // Dest
});
Dqn_Slice<Dqn_Str8> cmd_slice = Dqn_FArray_Slice(&font_cmd_array);
Dqn_Print_StdLnF(Dqn_PrintStd_Out, "[BUILD] Executing '%s'", Dqn_Slice_Str8RenderSpaceSeparated(scratch.arena, cmd_slice).data);
if (!dry_run)
Dqn_OS_Exec(cmd_slice, /*working_dir*/ {});
}
// NOTE: Copy the audio
{
Dqn_FArray32<Dqn_Str8> audio_cmd_array = cmd_array;
Dqn_FArray_AddCArrayAssert(&audio_cmd_array, {
Dqn_FsPath_ConvertF(scratch.arena, "%.*s/Data/Audio", DQN_STR_FMT(exe_dir)), // Source
Dqn_FsPath_ConvertF(scratch.arena, "%.*s/Data/Audio", DQN_STR_FMT(build_dir)), // Dest
});
Dqn_Slice<Dqn_Str8> cmd_slice = Dqn_FArray_Slice(&audio_cmd_array);
Dqn_Print_StdLnF(Dqn_PrintStd_Out, "[BUILD] Executing '%s'", Dqn_Slice_Str8RenderSpaceSeparated(scratch.arena, cmd_slice).data);
if (!dry_run)
Dqn_OS_Exec(cmd_slice, /*working_dir*/ {});
}
// NOTE: Copy the texture atlas
{
Dqn_Str8 atlas_dest_dir = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/Data/Textures", DQN_STR_FMT(build_dir));
Dqn_Fs_MakeDir(atlas_dest_dir);
Dqn_Str8 atlas_txt_src = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/Data/Textures/atlas.txt", DQN_STR_FMT(exe_dir));
Dqn_Str8 atlas_txt_dest = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/Data/Textures/atlas.txt", DQN_STR_FMT(build_dir));
Dqn_Str8 atlas_png_src = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/Data/Textures/atlas.png", DQN_STR_FMT(exe_dir));
Dqn_Str8 atlas_png_dest = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/Data/Textures/atlas.png", DQN_STR_FMT(build_dir));
if (!Dqn_Fs_Copy(atlas_txt_src, atlas_txt_dest, true /*overwrite*/)) {
Dqn_Print_StdLnF(Dqn_PrintStd_Out, "[BUILD] Failed to copy file from '%.*s' to '%.*s'", DQN_STR_FMT(atlas_txt_src), DQN_STR_FMT(atlas_txt_dest));
return -1;
}
if (!Dqn_Fs_Copy(atlas_png_src, atlas_png_dest, true /*overwrite*/)) {
Dqn_Print_StdLnF(Dqn_PrintStd_Out, "[BUILD] Failed to copy file from '%.*s' to '%.*s'", DQN_STR_FMT(atlas_png_src), DQN_STR_FMT(atlas_png_dest));
return -1;
}
}
DQN_MSVC_WARNING_POP
}
// NOTE: Raylib ============================================================================
Dqn_Str8 raylib_dir = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/External/raylib", DQN_STR_FMT(tely_dir));
Dqn_FArray32<Dqn_Str8> raylib_obj_files = {};
{
RecordScopeTime("%.*s Raylib ", DQN_STR_FMT(compiler_label));
Dqn_FArray32<Dqn_Str8> base_files = Dqn_FArray_InitCArray<Dqn_Str8, 32>({
Dqn_FsPath_ConvertF(scratch.arena, "%.*s/rcore.c", DQN_STR_FMT(raylib_dir)),
Dqn_FsPath_ConvertF(scratch.arena, "%.*s/utils.c", DQN_STR_FMT(raylib_dir)),
Dqn_FsPath_ConvertF(scratch.arena, "%.*s/raudio.c", DQN_STR_FMT(raylib_dir)),
Dqn_FsPath_ConvertF(scratch.arena, "%.*s/rmodels.c", DQN_STR_FMT(raylib_dir)),
Dqn_FsPath_ConvertF(scratch.arena, "%.*s/rtext.c", DQN_STR_FMT(raylib_dir)),
Dqn_FsPath_ConvertF(scratch.arena, "%.*s/rtextures.c", DQN_STR_FMT(raylib_dir)),
Dqn_FsPath_ConvertF(scratch.arena, "%.*s/rshapes.c", DQN_STR_FMT(raylib_dir)),
});
if (compiler != Compiler_EMCC) {
Dqn_FArray_AddCArrayAssert(&base_files, {
Dqn_FsPath_ConvertF(scratch.arena, "%.*s/rglfw.c", DQN_STR_FMT(raylib_dir))
});
}
Dqn_FArray32<Dqn_Str8> compile_flags = common_compile_flags_no_warnings;
Dqn_FArray_AddCArrayAssert(&compile_flags, {DQN_STR8("-c")});
if (compiler == Compiler_EMCC) {
Dqn_FArray_AddCArrayAssert(&compile_flags, {
DQN_STR8("-Os"),
DQN_STR8("-D"), DQN_STR8("PLATFORM_WEB"),
DQN_STR8("-D"), DQN_STR8("GRAPHICS_API_OPENGL_ES2"),
});
} else {
if (compiler == Compiler_GCC) {
DQN_ASSERT(compile_flags.data[0] == DQN_STR8("g++"));
compile_flags.data[0] = DQN_STR8("gcc");
}
Dqn_FArray_AddCArrayAssert(&compile_flags, {
DQN_STR8("-D"), DQN_STR8("PLATFORM_DESKTOP"),
});
}
Dqn_CPPBuildContext build_context = common_build_context;
build_context.compile_flags = Dqn_FArray_Slice(&compile_flags);
build_context.include_dirs = Dqn_Slice_InitCArray(scratch.arena, {
Dqn_FsPath_ConvertF(scratch.arena, "%.*s", DQN_STR_FMT(raylib_dir)),
Dqn_FsPath_ConvertF(scratch.arena, "%.*s/external/glfw/include", DQN_STR_FMT(raylib_dir)),
Dqn_FsPath_ConvertF(scratch.arena, "%.*s/glfw/deps/mingw", DQN_STR_FMT(raylib_dir)),
});
for (Dqn_Str8 base_file : base_files) {
Dqn_Str8 file_stem = Dqn_Str8_FileNameNoExtension(base_file);
Dqn_CPPBuildCompileFile build_file = {};
build_file.input_file_path = base_file;
build_file.output_file_path = Dqn_Str8_InitF(scratch.allocator, "%.*s_%.*s.%.*s", DQN_STR_FMT(compiler_label), DQN_STR_FMT(file_stem), DQN_STR_FMT(obj_file_extension));
Dqn_FArray_AddAssert(&raylib_obj_files, build_file.output_file_path);
build_context.compile_files = Dqn_Slice_Init(&build_file, 1);
Dqn_Str8 cmd = Dqn_CPPBuild_ToCommandLineStr8(build_context, Dqn_CPPBuildMode_AlwaysRebuild, scratch.arena);
Dqn_Print_StdLnF(Dqn_PrintStd_Out, "[BUILD] Executing '%.*s'", DQN_STR_FMT(cmd));
if (!dry_run)
Dqn_CPPBuild_ExecOrAbort(build_context, Dqn_CPPBuildMode_CacheBuild);
}
}
// NOTE: Sokol =============================================================================
Dqn_Str8 sokol_dir = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/External/sokol", DQN_STR_FMT(tely_dir));
Dqn_FArray32<Dqn_Str8> sokol_obj_files = {};
{
RecordScopeTime("%.*s Sokol", DQN_STR_FMT(compiler_label));
Dqn_CPPBuildCompileFile build_file = {};
build_file.input_file_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/External/sokol/sokol_audio.c", DQN_STR_FMT(tely_dir));
build_file.output_file_path = Dqn_Str8_InitF(scratch.allocator, "%.*s_sokol.%.*s", DQN_STR_FMT(compiler_label), DQN_STR_FMT(obj_file_extension));
Dqn_FArray32<Dqn_Str8> compile_flags = common_compile_flags_no_warnings;
Dqn_FArray_AddCArrayAssert(&compile_flags, {
DQN_STR8("-c"),
});
if (compiler == Compiler_EMCC)
Dqn_FArray_AddCArrayAssert(&compile_flags, {DQN_STR8("-Os")});
Dqn_CPPBuildContext build_context = common_build_context;
build_context.compile_flags = Dqn_FArray_Slice(&compile_flags);
build_context.compile_files = Dqn_Slice_Init(&build_file, 1);
Dqn_FArray_AddAssert(&sokol_obj_files, build_file.output_file_path);
Dqn_Str8 cmd = Dqn_CPPBuild_ToCommandLineStr8(build_context, Dqn_CPPBuildMode_AlwaysRebuild, scratch.arena);
Dqn_Print_StdLnF(Dqn_PrintStd_Out, "[BUILD] Executing '%.*s'", DQN_STR_FMT(cmd));
if (!dry_run)
Dqn_CPPBuild_ExecOrAbort(build_context, Dqn_CPPBuildMode_CacheBuild);
}
// NOTE: Feely Pona Sprite Packer ==============================================================
if (compiler == Compiler_MSVC) {
RecordScopeTime("Sprite Packer");
Dqn_CPPBuildContext build_context = common_build_context;
Dqn_CPPBuildCompileFile build_file = {};
build_file.input_file_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/feely_pona_sprite_packer.cpp", DQN_STR_FMT(code_dir));
build_file.output_file_path = Dqn_Str8_InitF(scratch.allocator, "%.*s_feely_pona_sprite_packer.%.*s", DQN_STR_FMT(compiler_label), DQN_STR_FMT(obj_file_extension));
if (compiler == Compiler_MSVC) {
build_file.prefix_flags = Dqn_Slice_InitCArray(scratch.arena, {DQN_STR8("/Tp")});
} else {
build_file.prefix_flags = Dqn_Slice_InitCArray(scratch.arena, {DQN_STR8("-xc++")});
build_file.suffix_flags = Dqn_Slice_InitCArray(scratch.arena, {DQN_STR8("-xnone")});
}
build_context.compile_flags = Dqn_FArray_Slice(&common_compile_flags);
build_context.link_flags = Dqn_FArray_Slice(&common_link_flags);
build_context.build_dir = build_dir;
Dqn_Str8 cmd = Dqn_CPPBuild_ToCommandLineStr8(build_context, Dqn_CPPBuildMode_AlwaysRebuild, scratch.arena);
Dqn_Print_StdLnF(Dqn_PrintStd_Out, "[BUILD] Executing '%.*s'", DQN_STR_FMT(cmd));
if (!dry_run)
Dqn_CPPBuild_ExecOrAbort(build_context, Dqn_CPPBuildMode_CacheBuild);
}
// NOTE: Feely Pona Link Flags =============================================================
Dqn_FArray32<Dqn_Str8> feely_pona_raylib_backend_link_flags = {};
{
Dqn_FArray_AddArrayAssert(&feely_pona_raylib_backend_link_flags, sokol_obj_files.data, sokol_obj_files.size);
Dqn_FArray_AddArrayAssert(&feely_pona_raylib_backend_link_flags, raylib_obj_files.data, raylib_obj_files.size);
if (compiler == Compiler_MSVC) {
Dqn_FArray_AddCArrayAssert(&feely_pona_raylib_backend_link_flags, {
DQN_STR8("gdi32.lib"), // raylib
DQN_STR8("opengl32.lib"), // raylib
DQN_STR8("winmm.lib"), // raylib
DQN_STR8("user32.lib"),
DQN_STR8("shell32.lib"),
});
} else if (compiler == Compiler_GCC) {
Dqn_FArray_AddCArrayAssert(&feely_pona_raylib_backend_link_flags, {
DQN_STR8("-lpthread"),
});
#if defined(DQN_OS_UNIX)
Dqn_FArray_AddCArrayAssert(&csight_raylib_backend_link_flags, {
DQN_STR8("-ldl"),
DQN_STR8("-lasound"),
});
#else
Dqn_FArray_AddCArrayAssert(&feely_pona_raylib_backend_link_flags, {
DQN_STR8("-lgdi32"), // raylib
DQN_STR8("-lopengl32"), // raylib
DQN_STR8("-lwinmm"), // raylib
DQN_STR8("-lole32"), // sokol audio
DQN_STR8("-lbcrypt"), // dqn
DQN_STR8("-lwininet"), // dqn
DQN_STR8("-ldbghelp"), // dqn
});
#endif
}
}
Dqn_FArray32<Dqn_Str8> feely_pona_backend_include_dirs = Dqn_FArray_InitCArray<Dqn_Str8, 32>({
sokol_dir,
raylib_dir,
});
// NOTE: Feely Pona No DLL =================================================================
if (!fast_dev_build || compiler == Compiler_EMCC) {
RecordScopeTime("%.*s Feely Pona", DQN_STR_FMT(compiler_label));
Dqn_CPPBuildCompileFile build_file = {};
build_file.input_file_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/feely_pona_unity.cpp", DQN_STR_FMT(code_dir));
if (compiler == Compiler_EMCC)
build_file.output_file_path = Dqn_FsPath_ConvertF(scratch.arena, "Terry_Cherry.html");
else
build_file.output_file_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s_terry_cherry", DQN_STR_FMT(compiler_label));
Dqn_FArray32<Dqn_Str8> compile_flags = common_compile_flags;
Dqn_FArray_AddCArrayAssert(&compile_flags, {
DQN_STR8("-D"), DQN_STR8("TELY_WITH_PLATFORM"),
DQN_STR8("-D"), DQN_STR8("FEELY_PONA_IMPLEMENTATION"),
});
if (compiler == Compiler_EMCC) {
// NOTE: Write Feely Pona version into Emscripten HTML Shell
Dqn_Str8 html_shell_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/feely_pona_emscripten_shell.html", DQN_STR_FMT(build_dir));
{
Dqn_Str8 html_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/feely_pona_emscripten_shell.html", DQN_STR_FMT(code_dir));
Dqn_Str8 html_buffer = Dqn_Fs_Read(html_path, scratch.allocator);
if (!DQN_CHECKF(html_buffer.size,
"Failed to read Emscripten HTML shell file. The file at\n\n '%.*s'\n\ndoes not exist or is not readable",
DQN_STR_FMT(html_path)))
return -1;
Dqn_Str8 version_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/feely_pona_version.txt", DQN_STR_FMT(code_dir));
Dqn_Str8 version_buffer = Dqn_Fs_Read(version_path, scratch.allocator);
Dqn_Str8SplitAllocResult version_parts = Dqn_Str8_SplitAlloc(scratch.allocator, version_buffer, DQN_STR8("\n"));
if (!DQN_CHECKF(version_parts.size == 3,
"Version file '%.*s' must have 3 lines containing, date, commit hash and number of commits. The buffer we tried extracting information from was\n\n%.*s\n\n",
DQN_STR_FMT(version_path),
DQN_STR_FMT(version_buffer))) {
return -1;
}
Dqn_Str8 date = Dqn_Str8_TrimWhitespaceAround(version_parts.data[0]);
Dqn_Str8 commit_hash = Dqn_Str8_TrimWhitespaceAround(version_parts.data[1]);
Dqn_Str8 commit_count = Dqn_Str8_TrimWhitespaceAround(version_parts.data[2]);
Dqn_Str8 version_text = Dqn_Str8_InitF(scratch.allocator,
"%.*s edition rev. %.*s-%.*s",
DQN_STR_FMT(date),
DQN_STR_FMT(commit_count),
DQN_STR_FMT(commit_hash));
Dqn_Str8 html_buffer_processed = Dqn_Str8_Replace(html_buffer,
DQN_STR8("@version@"),
version_text,
0 /*start_index*/,
scratch.allocator);
if (!DQN_CHECKF(Dqn_Fs_Write(html_shell_path,
html_buffer_processed),
"Failed to write Emscripten HTML shell with the project version inserted into it. We were unable to write to the target location\n\n '%.*s'\n",
DQN_STR_FMT(html_shell_path)))
return -1;
}
Dqn_FArray_AddCArrayAssert(&compile_flags, {
DQN_STR8("-Wall"),
DQN_STR8("-s"), DQN_STR8("USE_GLFW=3"),
DQN_STR8("-s"), DQN_STR8("TOTAL_MEMORY=512MB"),
DQN_STR8("-s"), DQN_STR8("TOTAL_STACK=32MB"),
DQN_STR8("-s"), DQN_STR8("ALLOW_MEMORY_GROWTH"),
DQN_STR8("--shell-file"), html_shell_path,
DQN_STR8("--preload-file"), DQN_STR8("Data"),
DQN_STR8("-msimd128"),
DQN_STR8("-msse2"),
});
bool debug_build = false;
if (debug_build) {
Dqn_FArray_AddCArrayAssert(&compile_flags, {
DQN_STR8("-s"), DQN_STR8("ASSERTIONS=2"),
DQN_STR8("-s"), DQN_STR8("SAFE_HEAP=0"),
DQN_STR8("-s"), DQN_STR8("STACK_OVERFLOW_CHECK=2"),
DQN_STR8("--profiling-funcs"), // Expose function names in stack trace
DQN_STR8("-g") // Debug symbols
});
} else {
Dqn_FArray_AddCArrayAssert(&compile_flags, {
DQN_STR8("-Os"),
});
}
}
Dqn_CPPBuildContext build_context = common_build_context;
build_context.compile_files = Dqn_Slice_Init(&build_file, 1);
build_context.include_dirs = Dqn_FArray_Slice(&feely_pona_backend_include_dirs);
build_context.compile_flags = Dqn_FArray_Slice(&compile_flags);
build_context.link_flags = Dqn_FArray_Slice(&feely_pona_raylib_backend_link_flags);
Dqn_Str8 cmd = Dqn_CPPBuild_ToCommandLineStr8(build_context, Dqn_CPPBuildMode_AlwaysRebuild, scratch.arena);
Dqn_Print_StdLnF(Dqn_PrintStd_Out, "[BUILD] Executing '%.*s'", DQN_STR_FMT(cmd));
if (!dry_run)
Dqn_CPPBuild_ExecOrAbort(build_context, Dqn_CPPBuildMode_AlwaysRebuild);
// NOTE: Copy generated files for web target to directory
if (compiler == Compiler_EMCC) {
Dqn_Str8 folder_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/Terry_Cherry", DQN_STR_FMT(build_dir));
if (!Dqn_Fs_DirExists(folder_path)) {
if (!Dqn_Fs_MakeDir(folder_path)) {
Dqn_Print_StdLnF(Dqn_PrintStd_Out, "Failed to make directory '%.*s'", DQN_STR_FMT(folder_path));
return -1;
}
}
Dqn_Str8 const generated_file_extension[] = {
DQN_STR8("data"),
DQN_STR8("html"),
DQN_STR8("js"),
DQN_STR8("wasm"),
};
for (Dqn_Str8 file_ext : generated_file_extension) {
Dqn_Str8 src_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/Terry_Cherry.%.*s", DQN_STR_FMT(build_dir), DQN_STR_FMT(file_ext));
Dqn_Str8 dest_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/Terry_Cherry.%.*s", DQN_STR_FMT(folder_path), DQN_STR_FMT(file_ext));
Dqn_Print_StdLnF(Dqn_PrintStd_Out, "[BUILD] Moving '%.*s' to '%.*s'\n", DQN_STR_FMT(src_path), DQN_STR_FMT(dest_path));
if (!dry_run && !Dqn_Fs_Move(src_path, dest_path, true /*overwrite*/)) {
Dqn_Print_StdLnF(Dqn_PrintStd_Out, "Failed to copy file from '%.*s' to '%.*s'", DQN_STR_FMT(src_path), DQN_STR_FMT(dest_path));
return -1;
}
}
}
}
// NOTE: Feely Pona Dev DLL ================================================================
if (compiler == Compiler_MSVC) {
RecordScopeTime("%.*s Feely Pona Dev DLL", DQN_STR_FMT(compiler_label));
Dqn_CPPBuildCompileFile build_file = {};
build_file.input_file_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/feely_pona_unity.h", DQN_STR_FMT(code_dir));
build_file.output_file_path = Dqn_FsPath_ConvertF(scratch.arena, "terry_cherry_dev_dll", DQN_STR_FMT(compiler_label));
build_file.prefix_flags = Dqn_Slice_InitCArray(scratch.arena, {DQN_STR8("/Tp")});
Dqn_FArray32<Dqn_Str8> compile_flags = common_compile_flags;
Dqn_FArray_AddAssert(&compile_flags, DQN_STR8("-LD"));
Dqn_FArray_AddAssert(&compile_flags, DQN_STR8("-D FEELY_PONA_IMPLEMENTATION"));
if (!fast_dev_build)
Dqn_FArray_AddAssert(&compile_flags, DQN_STR8("-analyze"));
Dqn_CPPBuildContext build_context = common_build_context;
build_context.compile_files = Dqn_Slice_Init(&build_file, 1);
build_context.compile_flags = Dqn_FArray_Slice(&compile_flags);
Dqn_Str8 cmd = Dqn_CPPBuild_ToCommandLineStr8(build_context, Dqn_CPPBuildMode_AlwaysRebuild, scratch.arena);
Dqn_Print_StdLnF(Dqn_PrintStd_Out, "[BUILD] Executing '%.*s'", DQN_STR_FMT(cmd));
if (!dry_run)
Dqn_CPPBuild_ExecOrAbort(build_context, Dqn_CPPBuildMode_AlwaysRebuild);
}
// NOTE: Feely Pona Dev ====================================================================
if (compiler == Compiler_MSVC) {
RecordScopeTime("%.*s Feely Pona Dev", DQN_STR_FMT(compiler_label));
Dqn_CPPBuildCompileFile build_file = {};
build_file.input_file_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/feely_pona_unity.h", DQN_STR_FMT(code_dir));
build_file.output_file_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s_terry_cherry_dev", DQN_STR_FMT(compiler_label));
build_file.prefix_flags = Dqn_Slice_InitCArray(scratch.arena, {DQN_STR8("/Tp")});
Dqn_FArray32<Dqn_Str8> compile_flags = common_compile_flags;
Dqn_FArray_AddCArrayAssert(&compile_flags, {
DQN_STR8("-D"), DQN_STR8("TELY_WITH_PLATFORM"),
DQN_STR8("-D"), DQN_STR8("TELY_WITH_PLATFORM_DLL"),
});
Dqn_CPPBuildContext build_context = common_build_context;
build_context.compile_files = Dqn_Slice_Init(&build_file, 1);
build_context.compile_flags = Dqn_FArray_Slice(&compile_flags);
build_context.link_flags = Dqn_FArray_Slice(&feely_pona_raylib_backend_link_flags);
build_context.include_dirs = Dqn_FArray_Slice(&feely_pona_backend_include_dirs);
Dqn_Str8 cmd = Dqn_CPPBuild_ToCommandLineStr8(build_context, Dqn_CPPBuildMode_AlwaysRebuild, scratch.arena);
Dqn_Print_StdLnF(Dqn_PrintStd_Out, "[BUILD] Executing '%.*s'", DQN_STR_FMT(cmd));
if (!dry_run) {
Dqn_Str8 exe_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s_feely_pona_dev.exe", DQN_STR_FMT(build_dir), DQN_STR_FMT(compiler_label));
bool exe_is_locked = false;
if (Dqn_Fs_Exists(exe_path)) {
Dqn_FsFile exe_file = Dqn_Fs_OpenFile(exe_path, Dqn_FsFileOpen_OpenIfExist, Dqn_FsFileAccess_Read | Dqn_FsFileAccess_Write);
exe_is_locked = exe_file.error_size;
Dqn_Fs_CloseFile(&exe_file);
}
if (!exe_is_locked) {
Dqn_CPPBuild_ExecOrAbort(build_context, Dqn_CPPBuildMode_AlwaysRebuild);
}
}
}
}
global_build_timings->timestamps[1] = Dqn_OS_PerfCounterNow();
Dqn_usize longest_name = 0;
for (BuildTime build_time : build_timings)
longest_name = DQN_MAX(longest_name, build_time.name.size + 1);
for (Dqn_usize build_index = 0; build_index < build_timings.size; build_index++) {
BuildTime build_time = build_timings.data[build_index];
Dqn_Print_StdF(Dqn_PrintStd_Out, "%.*s:", DQN_STR_FMT(build_time.name));
if (build_time.name.size < longest_name)
Dqn_Print_StdF(Dqn_PrintStd_Out, "%*s", DQN_CAST(int)(longest_name - build_time.name.size), "");
Dqn_Print_StdLnF(Dqn_PrintStd_Out, "%.2fms", Dqn_OS_PerfCounterMs(build_time.timestamps[0], build_time.timestamps[1]));
}
return 0;
}