diff --git a/src/linker/lnk.c b/src/linker/lnk.c index d506f377..c7c9f869 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -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); - 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); ProfEnd(); @@ -2119,7 +2119,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer ProfBegin("Build * Linker * Obj"); 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 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); ProfEnd(); } @@ -5205,8 +5205,8 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config) // Write image in the background LNK_WriteThreadContext *image_write_ctx = push_array(scratch.arena, LNK_WriteThreadContext, 1); - image_write_ctx->path = config->image_name; - image_write_ctx->temp_path = config->temp_image_name; + image_write_ctx->path = config->out_path; + image_write_ctx->temp_path = config->temp_out_path; image_write_ctx->data = image_ctx.image_data; 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"); lnk_timer_begin(LNK_Timer_Lib); 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_timer_end(LNK_Timer_Lib); ProfEnd(); @@ -5262,7 +5262,7 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config) arena, OperatingSystem_Windows, rdi_arch_from_coff_machine(config->machine), - config->image_name, + lnk_get_image_name(config), image_ctx.image_data, debug_info_objs_count, debug_info_objs, diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index ac8d606e..768d495e 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -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_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_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_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." }, @@ -752,9 +753,8 @@ lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_Me internal String8 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_chop_last_dot(image_name); return image_name; } @@ -1696,7 +1696,7 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List } break; 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; 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: { if (value_strings.node_count == 1) { - if (str8_match_lit("all", value_strings.first->string, StringMatchFlag_CaseInsensitive)) { + String8 value = value_strings.first->string; + + B32 status = 1; + if (str8_starts_with(value, str8_lit("-"))) { + value = str8_skip(value, 1); + status = 0; + } + + if (str8_match_lit("all", value, StringMatchFlag_CaseInsensitive)) { for (U64 ilog = 0; ilog < LNK_Log_Count; ilog += 1) { - lnk_set_log_status((LNK_LogType)ilog, 1); + lnk_set_log_status((LNK_LogType)ilog, status); } - } else if (str8_match_lit("io", value_strings.first->string, StringMatchFlag_CaseInsensitive)) { - lnk_set_log_status(LNK_Log_IO_Read, 1); - lnk_set_log_status(LNK_Log_IO_Write, 1); + } 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 { - 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) { - 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 { - lnk_set_log_status(log_type, 1); + lnk_set_log_status(log_type, status); } } } else { @@ -2060,6 +2068,10 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List } } 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: { lnk_cmd_switch_parse_flag(obj, cmd_switch, value_strings, &config->write_temp_files); } break; @@ -2266,33 +2278,33 @@ lnk_config_from_cmd_line(String8List raw_cmd_line, LNK_CmdLine cmd_line) // handle empty /OUT if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Out)) { - 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"); - config->image_name = path_replace_file_extension(scratch.arena, name, ext); + 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"); + config->out_path = path_replace_file_extension(scratch.arena, name, ext); } // handle empty /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 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 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 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 - 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->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); @@ -2322,7 +2334,7 @@ lnk_config_from_cmd_line(String8List raw_cmd_line, LNK_CmdLine cmd_line) // 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("_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_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); @@ -2353,7 +2365,7 @@ lnk_config_from_cmd_line(String8List raw_cmd_line, LNK_CmdLine cmd_line) // create temporary files names 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_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_rad_debug_name = push_str8f(arena, "%S.tmp%x", config->rad_debug_name, config->time_stamp); } diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index 45817553..6e7e7951 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -88,6 +88,7 @@ typedef enum LNK_CmdSwitch_Version, LNK_CmdSwitch_WholeArchive, + LNK_CmdSwitch_Rad_Age, LNK_CmdSwitch_Rad_AltPchDir, LNK_CmdSwitch_Rad_BuildInfo, @@ -100,6 +101,8 @@ typedef enum LNK_CmdSwitch_Rad_EnvLib, LNK_CmdSwitch_Rad_Exe, LNK_CmdSwitch_Rad_Guid, + LNK_CmdSwitch_Rad_Ignore, + LNK_CmdSwitch_Rad_ImageAltPath, LNK_CmdSwitch_Rad_LargePages, LNK_CmdSwitch_Rad_LinkVer, LNK_CmdSwitch_Rad_Log, @@ -117,7 +120,6 @@ typedef enum LNK_CmdSwitch_Rad_RemoveSection, LNK_CmdSwitch_Rad_SharedThreadPool, LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, - LNK_CmdSwitch_Rad_Ignore, LNK_CmdSwitch_Rad_TimeStamp, LNK_CmdSwitch_Rad_TypeHashAlg, LNK_CmdSwitch_Rad_UnresolvedSymbolLimit, @@ -125,7 +127,6 @@ typedef enum LNK_CmdSwitch_Rad_Version, LNK_CmdSwitch_Rad_Workers, LNK_CmdSwitch_Rad_WriteTempFiles, - LNK_CmdSwitch_Help, LNK_CmdSwitch_Count @@ -310,7 +311,8 @@ typedef struct LNK_Config PathStyle path_style; LNK_ManifestOpt manifest_opt; String8 work_dir; - String8 image_name; + String8 out_path; + String8 image_alt_path; String8 imp_lib_name; String8List raw_cmd_line; String8 pdb_name; @@ -343,7 +345,7 @@ typedef struct LNK_Config B32 build_imp_lib; B32 build_exp; LNK_SwitchState write_temp_files; - String8 temp_image_name; + String8 temp_out_path; String8 temp_pdb_name; String8 temp_rad_debug_name; String8 temp_rad_chunk_map_name; diff --git a/src/torture/torture_radlink.c b/src/torture/torture_radlink.c index c345b8d6..df945b0d 100644 --- a/src/torture/torture_radlink.c +++ b/src/torture/torture_radlink.c @@ -6335,34 +6335,39 @@ TEST(determ_test) t_invoke_(t_cl_path(), cl_line, max_U64, arena, &cl_out); T_Ok(g_last_exit_code == 0); + U64 run_count = 25; + T_Ok(run_count > 1); + String8 test_path = t_make_file_path(arena, str8_lit("test.obj")); + // single-threaded link - String8 refs_path = t_make_file_path(arena, str8_lit("b.types")); - t_invoke_linkerf("test.obj /debug:full /rad_time_stamp:0 /rad_workers:1 /rad_store_types:%S /out:a.exe", refs_path); + 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(g_last_exit_code == 0); - // rename a -> b - 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_Ok(os_move_file_path(t_make_file_path(arena, str8_lit("b.pdb")), t_make_file_path(arena, str8_lit("a.pdb")))); - // read b - String8 b_exe = t_read_file(arena, str8_lit("b.exe")); - String8 b_pdb = t_read_file(arena, str8_lit("b.pdb")); + String8 main_exe = t_read_file(arena, str8_lit("main.exe")); + String8 main_pdb = t_read_file(arena, str8_lit("main.pdb")); // 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); - - t_delete_file(str8_lit("a.exe")); - t_delete_file(str8_lit("a.pdb")); - - t_invoke_linkerf("test.obj /debug:full /rad_time_stamp:0 /out:a.exe"); - T_Ok(g_last_exit_code == 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)); - + String8 exe = t_read_file(temp.arena, str8f(temp.arena, "%llu.exe", i)); + String8 pdb = t_read_file(temp.arena, str8f(temp.arena, "%llu.pdb", i)); + T_Ok(exe.size); + T_Ok(pdb.size); + T_Ok(str8_match(main_exe, exe, 0)); + T_Ok(str8_match(main_pdb, pdb, 0)); temp_end(temp); } }