improve determinism test speed

This commit is contained in:
Nikita Smith
2026-04-23 17:18:24 -07:00
parent 467e09178e
commit 7ed5977d20
4 changed files with 71 additions and 52 deletions
+6 -6
View File
@@ -2044,7 +2044,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
} }
PE_FinalizedExports finalized_exports = pe_finalize_export_list(scratch.arena, resolved_exports); PE_FinalizedExports finalized_exports = pe_finalize_export_list(scratch.arena, resolved_exports);
String8 edata_obj = pe_make_edata_obj(arena->v[0], str8_skip_last_slash(config->image_name), COFF_TimeStamp_Max, config->machine, finalized_exports); String8 edata_obj = pe_make_edata_obj(arena->v[0], lnk_get_image_name(config), COFF_TimeStamp_Max, config->machine, finalized_exports);
lnk_inputer_push_obj_linkgen(inputer, 0, str8_lit("* Exports *"), edata_obj); lnk_inputer_push_obj_linkgen(inputer, 0, str8_lit("* Exports *"), edata_obj);
ProfEnd(); ProfEnd();
@@ -2119,7 +2119,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
ProfBegin("Build * Linker * Obj"); ProfBegin("Build * Linker * Obj");
String8 obj_name = str8_lit("* Linker *"); String8 obj_name = str8_lit("* Linker *");
String8 raw_cmd_line = str8_list_join(scratch.arena, &config->raw_cmd_line, &(StringJoin){ str8_lit_comp(""), str8_lit_comp(" "), str8_lit_comp("") }); String8 raw_cmd_line = str8_list_join(scratch.arena, &config->raw_cmd_line, &(StringJoin){ str8_lit_comp(""), str8_lit_comp(" "), str8_lit_comp("") });
String8 obj_data = lnk_make_linker_coff_obj(arena->v[0], config->time_stamp, config->machine, config->work_dir, config->image_name, config->pdb_name, raw_cmd_line, obj_name); String8 obj_data = lnk_make_linker_coff_obj(arena->v[0], config->time_stamp, config->machine, config->work_dir, lnk_get_image_name(config), config->pdb_name, raw_cmd_line, obj_name);
lnk_inputer_push_obj_linkgen(inputer, 0, obj_name, obj_data); lnk_inputer_push_obj_linkgen(inputer, 0, obj_name, obj_data);
ProfEnd(); ProfEnd();
} }
@@ -5205,8 +5205,8 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config)
// Write image in the background // Write image in the background
LNK_WriteThreadContext *image_write_ctx = push_array(scratch.arena, LNK_WriteThreadContext, 1); LNK_WriteThreadContext *image_write_ctx = push_array(scratch.arena, LNK_WriteThreadContext, 1);
image_write_ctx->path = config->image_name; image_write_ctx->path = config->out_path;
image_write_ctx->temp_path = config->temp_image_name; image_write_ctx->temp_path = config->temp_out_path;
image_write_ctx->data = image_ctx.image_data; image_write_ctx->data = image_ctx.image_data;
Thread image_write_thread = thread_launch(lnk_write_thread, image_write_ctx); Thread image_write_thread = thread_launch(lnk_write_thread, image_write_ctx);
@@ -5225,7 +5225,7 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config)
ProfBegin("Build Import Library"); ProfBegin("Build Import Library");
lnk_timer_begin(LNK_Timer_Lib); lnk_timer_begin(LNK_Timer_Lib);
String8 linker_debug_symbols = lnk_make_linker_debug_symbols(scratch.arena, config->machine); String8 linker_debug_symbols = lnk_make_linker_debug_symbols(scratch.arena, config->machine);
String8 lib = pe_make_import_lib(arena->v[0], config->machine, config->time_stamp, str8_skip_last_slash(config->image_name), linker_debug_symbols, config->export_symbol_list); String8 lib = pe_make_import_lib(arena->v[0], config->machine, config->time_stamp, lnk_get_image_name(config), linker_debug_symbols, config->export_symbol_list);
lnk_write_data_to_file_path(config->imp_lib_name, str8_zero(), lib); lnk_write_data_to_file_path(config->imp_lib_name, str8_zero(), lib);
lnk_timer_end(LNK_Timer_Lib); lnk_timer_end(LNK_Timer_Lib);
ProfEnd(); ProfEnd();
@@ -5262,7 +5262,7 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config)
arena, arena,
OperatingSystem_Windows, OperatingSystem_Windows,
rdi_arch_from_coff_machine(config->machine), rdi_arch_from_coff_machine(config->machine),
config->image_name, lnk_get_image_name(config),
image_ctx.image_data, image_ctx.image_data,
debug_info_objs_count, debug_info_objs_count,
debug_info_objs, debug_info_objs,
+32 -20
View File
@@ -90,6 +90,7 @@ global read_only LNK_CmdSwitch g_cmd_switch_map[] =
{ LNK_CmdSwitch_Rad_SharedThreadPool, 0, "RAD_SHARED_THREAD_POOL", "[:STRING]", "Default value \"" LNK_DEFAULT_THREAD_POOL_NAME "\"" }, { LNK_CmdSwitch_Rad_SharedThreadPool, 0, "RAD_SHARED_THREAD_POOL", "[:STRING]", "Default value \"" LNK_DEFAULT_THREAD_POOL_NAME "\"" },
{ LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, 0, "RAD_SHARED_THREAD_POOL_MAX_WORKERS", ":#", "Set maximum number of workers in a thread pool." }, { LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, 0, "RAD_SHARED_THREAD_POOL_MAX_WORKERS", ":#", "Set maximum number of workers in a thread pool." },
{ LNK_CmdSwitch_Rad_Ignore, 0, "RAD_IGNORE", ":#", "Ignore the specified RAD linker warning." }, { LNK_CmdSwitch_Rad_Ignore, 0, "RAD_IGNORE", ":#", "Ignore the specified RAD linker warning." },
{ LNK_CmdSwitch_Rad_ImageAltPath, 0, "RAD_IMAGEALTPATH", ":FILENAME", "Alternative name for the image" },
{ LNK_CmdSwitch_Rad_WriteTempFiles, 0, "RAD_WRITE_TEMP_FILES", "[:NO]", "When speicifed linker writes image and debug info to temporary files and renames after link is done." }, { LNK_CmdSwitch_Rad_WriteTempFiles, 0, "RAD_WRITE_TEMP_FILES", "[:NO]", "When speicifed linker writes image and debug info to temporary files and renames after link is done." },
{ LNK_CmdSwitch_Rad_TimeStamp, 0, "RAD_TIME_STAMP", ":#", "Time stamp embeded in EXE and PDB." }, { LNK_CmdSwitch_Rad_TimeStamp, 0, "RAD_TIME_STAMP", ":#", "Time stamp embeded in EXE and PDB." },
{ LNK_CmdSwitch_Rad_TypeHashAlg, 0, "RAD_TPYE_HASH_ALG", ":{BLAKE3}", "Sets hashing algorithm for type merging." }, { LNK_CmdSwitch_Rad_TypeHashAlg, 0, "RAD_TPYE_HASH_ALG", ":{BLAKE3}", "Sets hashing algorithm for type merging." },
@@ -752,9 +753,8 @@ lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_Me
internal String8 internal String8
lnk_get_image_name(LNK_Config *config) lnk_get_image_name(LNK_Config *config)
{ {
String8 image_name = config->image_name; String8 image_name = config->image_alt_path.size ? config->image_alt_path : config->out_path;
image_name = str8_skip_last_slash(image_name); image_name = str8_skip_last_slash(image_name);
image_name = str8_chop_last_dot(image_name);
return image_name; return image_name;
} }
@@ -1696,7 +1696,7 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
} break; } break;
case LNK_CmdSwitch_Out: { case LNK_CmdSwitch_Out: {
lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->image_name); lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->out_path);
} break; } break;
case LNK_CmdSwitch_Pdb: { case LNK_CmdSwitch_Pdb: {
@@ -1934,19 +1934,27 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
case LNK_CmdSwitch_Rad_Log: { case LNK_CmdSwitch_Rad_Log: {
if (value_strings.node_count == 1) { if (value_strings.node_count == 1) {
if (str8_match_lit("all", value_strings.first->string, StringMatchFlag_CaseInsensitive)) { String8 value = value_strings.first->string;
for (U64 ilog = 0; ilog < LNK_Log_Count; ilog += 1) {
lnk_set_log_status((LNK_LogType)ilog, 1); B32 status = 1;
if (str8_starts_with(value, str8_lit("-"))) {
value = str8_skip(value, 1);
status = 0;
} }
} else if (str8_match_lit("io", value_strings.first->string, StringMatchFlag_CaseInsensitive)) {
lnk_set_log_status(LNK_Log_IO_Read, 1); if (str8_match_lit("all", value, StringMatchFlag_CaseInsensitive)) {
lnk_set_log_status(LNK_Log_IO_Write, 1); for (U64 ilog = 0; ilog < LNK_Log_Count; ilog += 1) {
lnk_set_log_status((LNK_LogType)ilog, status);
}
} else if (str8_match_lit("io", value, StringMatchFlag_CaseInsensitive)) {
lnk_set_log_status(LNK_Log_IO_Read, status);
lnk_set_log_status(LNK_Log_IO_Write, status);
} else { } else {
LNK_LogType log_type = lnk_log_type_from_string(value_strings.first->string); LNK_LogType log_type = lnk_log_type_from_string(value);
if (log_type == LNK_Log_Null) { if (log_type == LNK_Log_Null) {
lnk_error_cmd_switch(LNK_Error_Cmdl, obj, cmd_switch, "unknown parameter \"%S\"", value_strings.first->string); lnk_error_cmd_switch(LNK_Error_Cmdl, obj, cmd_switch, "unknown parameter \"%S\"", value);
} else { } else {
lnk_set_log_status(log_type, 1); lnk_set_log_status(log_type, status);
} }
} }
} else { } else {
@@ -2060,6 +2068,10 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
} }
} break; } break;
case LNK_CmdSwitch_Rad_ImageAltPath: {
lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->image_alt_path);
} break;
case LNK_CmdSwitch_Rad_WriteTempFiles: { case LNK_CmdSwitch_Rad_WriteTempFiles: {
lnk_cmd_switch_parse_flag(obj, cmd_switch, value_strings, &config->write_temp_files); lnk_cmd_switch_parse_flag(obj, cmd_switch, value_strings, &config->write_temp_files);
} break; } break;
@@ -2268,31 +2280,31 @@ lnk_config_from_cmd_line(String8List raw_cmd_line, LNK_CmdLine cmd_line)
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Out)) { if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Out)) {
String8 name = str8_list_first(&config->input_list[LNK_Input_Obj]); String8 name = str8_list_first(&config->input_list[LNK_Input_Obj]);
String8 ext = (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) ? str8_lit("dll") : str8_lit("exe"); String8 ext = (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) ? str8_lit("dll") : str8_lit("exe");
config->image_name = path_replace_file_extension(scratch.arena, name, ext); config->out_path = path_replace_file_extension(scratch.arena, name, ext);
} }
// handle empty /PDB // handle empty /PDB
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Pdb)) { if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Pdb)) {
config->pdb_name = path_replace_file_extension(scratch.arena, config->image_name, str8_lit("pdb")); config->pdb_name = path_replace_file_extension(scratch.arena, config->out_path, str8_lit("pdb"));
} }
// handle empty /RAD_DEBUG_NAME // handle empty /RAD_DEBUG_NAME
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Rad_DebugName)) { if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Rad_DebugName)) {
config->rad_debug_name = path_replace_file_extension(scratch.arena, config->image_name, str8_lit("rdi")); config->rad_debug_name = path_replace_file_extension(scratch.arena, config->out_path, str8_lit("rdi"));
} }
// handle empty /IMPLIB // handle empty /IMPLIB
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ImpLib)) { if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ImpLib)) {
config->imp_lib_name = path_replace_file_extension(scratch.arena, config->image_name, str8_lit("lib")); config->imp_lib_name = path_replace_file_extension(scratch.arena, config->out_path, str8_lit("lib"));
} }
// handle empty /MANIFESTFILE // handle empty /MANIFESTFILE
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ManifestFile)) { if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ManifestFile)) {
config->manifest_name = push_str8f(scratch.arena, "%S.manifest", config->image_name); config->manifest_name = push_str8f(scratch.arena, "%S.manifest", config->out_path);
} }
// convert to full paths // convert to full paths
config->image_name = os_full_path_from_path(arena, config->image_name); config->out_path = os_full_path_from_path(arena, config->out_path);
config->pdb_name = os_full_path_from_path(arena, config->pdb_name); config->pdb_name = os_full_path_from_path(arena, config->pdb_name);
config->rad_debug_name = os_full_path_from_path(arena, config->rad_debug_name); config->rad_debug_name = os_full_path_from_path(arena, config->rad_debug_name);
config->imp_lib_name = os_full_path_from_path(arena, config->imp_lib_name); config->imp_lib_name = os_full_path_from_path(arena, config->imp_lib_name);
@@ -2322,7 +2334,7 @@ lnk_config_from_cmd_line(String8List raw_cmd_line, LNK_CmdLine cmd_line)
// define linker env vars // define linker env vars
hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_pdb"), str8_skip_last_slash(config->pdb_name)); hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_pdb"), str8_skip_last_slash(config->pdb_name));
hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_ext"), str8_skip_last_dot(config->image_name)); hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_ext"), str8_skip_last_dot(config->out_path));
hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_rad_pdb_path"), config->pdb_name); hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_rad_pdb_path"), config->pdb_name);
hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_rad_rdi"), str8_skip_last_slash(config->rad_debug_name)); hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_rad_rdi"), str8_skip_last_slash(config->rad_debug_name));
hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_rad_rdi_path"), config->rad_debug_name); hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_rad_rdi_path"), config->rad_debug_name);
@@ -2353,7 +2365,7 @@ lnk_config_from_cmd_line(String8List raw_cmd_line, LNK_CmdLine cmd_line)
// create temporary files names // create temporary files names
if (config->write_temp_files == LNK_SwitchState_Yes) { if (config->write_temp_files == LNK_SwitchState_Yes) {
config->temp_rad_chunk_map_name = push_str8f(arena, "%S.tmp%x", config->rad_chunk_map_name, config->time_stamp); config->temp_rad_chunk_map_name = push_str8f(arena, "%S.tmp%x", config->rad_chunk_map_name, config->time_stamp);
config->temp_image_name = push_str8f(arena, "%S.tmp%x", config->image_name, config->time_stamp); config->temp_out_path = push_str8f(arena, "%S.tmp%x", config->out_path , config->time_stamp);
config->temp_pdb_name = push_str8f(arena, "%S.tmp%x", config->pdb_name, config->time_stamp); config->temp_pdb_name = push_str8f(arena, "%S.tmp%x", config->pdb_name, config->time_stamp);
config->temp_rad_debug_name = push_str8f(arena, "%S.tmp%x", config->rad_debug_name, config->time_stamp); config->temp_rad_debug_name = push_str8f(arena, "%S.tmp%x", config->rad_debug_name, config->time_stamp);
} }
+6 -4
View File
@@ -88,6 +88,7 @@ typedef enum
LNK_CmdSwitch_Version, LNK_CmdSwitch_Version,
LNK_CmdSwitch_WholeArchive, LNK_CmdSwitch_WholeArchive,
LNK_CmdSwitch_Rad_Age, LNK_CmdSwitch_Rad_Age,
LNK_CmdSwitch_Rad_AltPchDir, LNK_CmdSwitch_Rad_AltPchDir,
LNK_CmdSwitch_Rad_BuildInfo, LNK_CmdSwitch_Rad_BuildInfo,
@@ -100,6 +101,8 @@ typedef enum
LNK_CmdSwitch_Rad_EnvLib, LNK_CmdSwitch_Rad_EnvLib,
LNK_CmdSwitch_Rad_Exe, LNK_CmdSwitch_Rad_Exe,
LNK_CmdSwitch_Rad_Guid, LNK_CmdSwitch_Rad_Guid,
LNK_CmdSwitch_Rad_Ignore,
LNK_CmdSwitch_Rad_ImageAltPath,
LNK_CmdSwitch_Rad_LargePages, LNK_CmdSwitch_Rad_LargePages,
LNK_CmdSwitch_Rad_LinkVer, LNK_CmdSwitch_Rad_LinkVer,
LNK_CmdSwitch_Rad_Log, LNK_CmdSwitch_Rad_Log,
@@ -117,7 +120,6 @@ typedef enum
LNK_CmdSwitch_Rad_RemoveSection, LNK_CmdSwitch_Rad_RemoveSection,
LNK_CmdSwitch_Rad_SharedThreadPool, LNK_CmdSwitch_Rad_SharedThreadPool,
LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers,
LNK_CmdSwitch_Rad_Ignore,
LNK_CmdSwitch_Rad_TimeStamp, LNK_CmdSwitch_Rad_TimeStamp,
LNK_CmdSwitch_Rad_TypeHashAlg, LNK_CmdSwitch_Rad_TypeHashAlg,
LNK_CmdSwitch_Rad_UnresolvedSymbolLimit, LNK_CmdSwitch_Rad_UnresolvedSymbolLimit,
@@ -125,7 +127,6 @@ typedef enum
LNK_CmdSwitch_Rad_Version, LNK_CmdSwitch_Rad_Version,
LNK_CmdSwitch_Rad_Workers, LNK_CmdSwitch_Rad_Workers,
LNK_CmdSwitch_Rad_WriteTempFiles, LNK_CmdSwitch_Rad_WriteTempFiles,
LNK_CmdSwitch_Help, LNK_CmdSwitch_Help,
LNK_CmdSwitch_Count LNK_CmdSwitch_Count
@@ -310,7 +311,8 @@ typedef struct LNK_Config
PathStyle path_style; PathStyle path_style;
LNK_ManifestOpt manifest_opt; LNK_ManifestOpt manifest_opt;
String8 work_dir; String8 work_dir;
String8 image_name; String8 out_path;
String8 image_alt_path;
String8 imp_lib_name; String8 imp_lib_name;
String8List raw_cmd_line; String8List raw_cmd_line;
String8 pdb_name; String8 pdb_name;
@@ -343,7 +345,7 @@ typedef struct LNK_Config
B32 build_imp_lib; B32 build_imp_lib;
B32 build_exp; B32 build_exp;
LNK_SwitchState write_temp_files; LNK_SwitchState write_temp_files;
String8 temp_image_name; String8 temp_out_path;
String8 temp_pdb_name; String8 temp_pdb_name;
String8 temp_rad_debug_name; String8 temp_rad_debug_name;
String8 temp_rad_chunk_map_name; String8 temp_rad_chunk_map_name;
+27 -22
View File
@@ -6335,34 +6335,39 @@ TEST(determ_test)
t_invoke_(t_cl_path(), cl_line, max_U64, arena, &cl_out); t_invoke_(t_cl_path(), cl_line, max_U64, arena, &cl_out);
T_Ok(g_last_exit_code == 0); T_Ok(g_last_exit_code == 0);
// single-threaded link U64 run_count = 25;
String8 refs_path = t_make_file_path(arena, str8_lit("b.types")); T_Ok(run_count > 1);
t_invoke_linkerf("test.obj /debug:full /rad_time_stamp:0 /rad_workers:1 /rad_store_types:%S /out:a.exe", refs_path); String8 test_path = t_make_file_path(arena, str8_lit("test.obj"));
T_Ok(g_last_exit_code == 0);
// rename a -> b // single-threaded link
T_Ok(os_move_file_path(t_make_file_path(arena, str8_lit("b.exe")), t_make_file_path(arena, str8_lit("a.exe")))); t_invoke_linkerf("%S /debug:full /rad_time_stamp:0 /rad_workers:1 /pdbaltpath:main.pdb /rad_log:-all /rad_ignore:74 /out:main.exe", test_path);
T_Ok(os_move_file_path(t_make_file_path(arena, str8_lit("b.pdb")), t_make_file_path(arena, str8_lit("a.pdb")))); T_Ok(g_last_exit_code == 0);
// read b // read b
String8 b_exe = t_read_file(arena, str8_lit("b.exe")); String8 main_exe = t_read_file(arena, str8_lit("main.exe"));
String8 b_pdb = t_read_file(arena, str8_lit("b.pdb")); String8 main_pdb = t_read_file(arena, str8_lit("main.pdb"));
// multi-threaded links // multi-threaded links
for EachIndex(i, 25) { OS_HandleList linkers = {0};
for EachIndex(i, run_count) {
String8 out_path = t_make_file_path(arena, str8f(arena, "%llu.exe", i));
String8 cmdl = str8f(arena, "%S %S /debug:full /rad_time_stamp:0 /rad_imagealtpath:main.exe /pdbaltpath:main.pdb /rad_log:-all /rad_ignore:74 /out:%S", t_radlink_path(), test_path, out_path);
OS_Handle process_handle = os_cmd_line_launch(cmdl);
T_Ok(!os_handle_match(os_handle_zero(), process_handle));
os_handle_list_push(arena, &linkers, process_handle);
}
// wait for linkers
for EachNode(n, OS_HandleNode, linkers.first) { os_process_join(n->v, max_U64, 0); }
for EachIndex(i, run_count) {
Temp temp = temp_begin(arena); Temp temp = temp_begin(arena);
String8 exe = t_read_file(temp.arena, str8f(temp.arena, "%llu.exe", i));
t_delete_file(str8_lit("a.exe")); String8 pdb = t_read_file(temp.arena, str8f(temp.arena, "%llu.pdb", i));
t_delete_file(str8_lit("a.pdb")); T_Ok(exe.size);
T_Ok(pdb.size);
t_invoke_linkerf("test.obj /debug:full /rad_time_stamp:0 /out:a.exe"); T_Ok(str8_match(main_exe, exe, 0));
T_Ok(g_last_exit_code == 0); T_Ok(str8_match(main_pdb, pdb, 0));
String8 a_exe = t_read_file(temp.arena, str8_lit("a.exe"));
String8 a_pdb = t_read_file(temp.arena, str8_lit("a.pdb"));
T_Ok(str8_match(a_exe, b_exe, 0));
T_Ok(str8_match(a_pdb, b_pdb, 0));
temp_end(temp); temp_end(temp);
} }
} }