#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 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(&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 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 common_link_flags = {}; Dqn_FArray32 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 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 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 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 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 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 raylib_obj_files = {}; { RecordScopeTime("%.*s Raylib ", DQN_STR_FMT(compiler_label)); Dqn_FArray32 base_files = Dqn_FArray_InitCArray({ 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 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 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 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 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 feely_pona_backend_include_dirs = Dqn_FArray_InitCArray({ 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 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 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 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; }