From 46390ba0b86a7c4c467f2f3cd1b135a8af703fff Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 18 Oct 2024 23:36:53 -0700 Subject: [PATCH] reworked manifest handling - manifest files wont be created unless symbols are resolved - delay mt.exe presence check until we launch it - create explicit case that writes manifests to disk - moved manifest dependency collection step to happen after obj input - removed /rad_delete_manifest --- src/linker/lnk.c | 278 ++++++++++++++++++++++++---------------- src/linker/lnk.h | 6 +- src/linker/lnk_config.c | 54 +++----- src/linker/lnk_config.h | 5 +- src/linker/lnk_error.h | 1 + src/linker/lnk_obj.c | 14 +- src/linker/lnk_obj.h | 2 +- 7 files changed, 199 insertions(+), 161 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 8e8160ff..98f1fc9a 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -270,21 +270,27 @@ lnk_make_full_path(Arena *arena, String8 work_dir, PathStyle system_path_style, //////////////////////////////// -internal String8List +internal String8 lnk_make_linker_manifest(Arena *arena, B32 manifest_uac, String8 manifest_level, String8 manifest_ui_access, String8List manifest_dependency_list) { + // TODO: we write a temp file with manifest attributes collected from obj directives and command line switches + // so we can pass file to mt.exe or llvm-mt.exe, when we have our own tool for merging manifest we can switch + // to writing manifest file in memory to skip roun-trip to disk + + Temp scratch = scratch_begin(&arena, 1); + String8List srl = {0}; - str8_serial_begin(arena, &srl); - str8_serial_push_string(arena, &srl, str8_lit( + str8_serial_begin(scratch.arena, &srl); + str8_serial_push_string(scratch.arena, &srl, str8_lit( "\n" "\n")); if (manifest_uac) { - String8 uac = push_str8f(arena, + String8 uac = push_str8f(scratch.arena, " \n" " \n" " \n" @@ -294,64 +300,119 @@ lnk_make_linker_manifest(Arena *arena, " \n", manifest_level, manifest_ui_access); - str8_serial_push_string(arena, &srl, uac); + str8_serial_push_string(scratch.arena, &srl, uac); } for (String8Node *node = manifest_dependency_list.first; node != 0; node = node->next) { - String8 dep = push_str8f(arena, + String8 dep = push_str8f(scratch.arena, " \n" " \n" " \n" " \n" " \n", node->string); - str8_serial_push_string(arena, &srl, dep); + str8_serial_push_string(scratch.arena, &srl, dep); } - str8_serial_push_string(arena, &srl, str8_lit("\n")); - return srl; + str8_serial_push_string(scratch.arena, &srl, str8_lit("\n")); + + String8 result = str8_list_join(arena, &srl, 0); + + scratch_end(scratch); + return result; } internal void -lnk_merge_manifest_files(Arena *arena, String8 mt_path, String8 manifest_name, String8List manifest_path_list) +lnk_merge_manifest_files(String8 mt_path, String8 out_name, String8List manifest_path_list) { ProfBeginFunction(); - - Temp scratch = scratch_begin(&arena,1); + Temp scratch = scratch_begin(0,0); String8List invoke_cmd_line = {0}; - str8_list_push(arena, &invoke_cmd_line, mt_path); - String8 work_dir = os_get_current_path(arena); + str8_list_push(scratch.arena, &invoke_cmd_line, mt_path); + str8_list_pushf(scratch.arena, &invoke_cmd_line, "-out:%S", out_name); + str8_list_pushf(scratch.arena, &invoke_cmd_line, "-nologo"); + + // register input manifest files on command line + String8 work_dir = os_get_current_path(scratch.arena); for (String8Node *man_node = manifest_path_list.first; man_node != 0; man_node = man_node->next) { - String8 full_path = path_absolute_dst_from_relative_dst_src(arena, man_node->string, work_dir); - full_path = path_convert_slashes(arena, full_path, PathStyle_UnixAbsolute); - str8_list_pushf(arena, &invoke_cmd_line, "-manifest"); - str8_list_push(arena, &invoke_cmd_line, full_path); + // resolve relativ path inputs + String8 full_path = path_absolute_dst_from_relative_dst_src(scratch.arena, man_node->string, work_dir); + + // normalize slashes + full_path = path_convert_slashes(scratch.arena, full_path, PathStyle_UnixAbsolute); + + // push input to command line + str8_list_pushf(scratch.arena, &invoke_cmd_line, "-manifest"); + str8_list_push(scratch.arena, &invoke_cmd_line, full_path); } - str8_list_pushf(arena, &invoke_cmd_line, "-out:%S", manifest_name); - str8_list_pushf(arena, &invoke_cmd_line, "-nologo"); + // launch mt.exe with our command line OS_ProcessLaunchParams launch_opts = {0}; launch_opts.cmd_line = invoke_cmd_line; launch_opts.path = str8_chop_last_slash(mt_path); launch_opts.inherit_env = 1; launch_opts.consoleless = 1; - OS_Handle mt_handle = os_process_launch(&launch_opts); - if (!os_handle_match(mt_handle, os_handle_zero())) { - if (os_process_join(mt_handle, max_U64)) { - if (!os_file_path_exists(manifest_name)) { - lnk_error(LNK_Error_Mt, "something went wrong, manifest was not written to \"%S\"", manifest_name); - } - } - os_process_detach(mt_handle); + if (os_handle_match(mt_handle, os_handle_zero())) { + lnk_error(LNK_Error_Mt, "unable to start process: %S", mt_path); } else { - lnk_error(LNK_Error_Mt, "unable to start process for %S", mt_path); + os_process_join(mt_handle, max_U64); + os_process_detach(mt_handle); } scratch_end(scratch); ProfEnd(); } + +internal String8 +lnk_manifest_from_inputs(Arena *arena, + String8 mt_path, + String8 manifest_name, + B32 manifest_uac, + String8 manifest_level, + String8 manifest_ui_access, + String8List input_manifest_path_list, + String8List deps_list) +{ + String8 manifest_data; + + if (input_manifest_path_list.node_count > 0) { + ProfBegin("Merge Manifests"); + Temp scratch = scratch_begin(&arena, 1); + + String8 linker_manifest = lnk_make_linker_manifest(scratch.arena, manifest_uac, manifest_level, manifest_ui_access, deps_list); + + // write linker manifest to temp file + String8 linker_manifest_path = push_str8f(scratch.arena, "%S.manifest.temp", manifest_name); + lnk_write_data_to_file_path(linker_manifest_path, linker_manifest); + + // push linker manifest + str8_list_push(scratch.arena, &input_manifest_path_list, linker_manifest_path); + + // launch mt.exe to merge input manifests + String8 merged_manifest_path = push_str8f(scratch.arena, "%S.manifest.merged", manifest_name); + lnk_merge_manifest_files(mt_path, merged_manifest_path, input_manifest_path_list); + + // read mt.exe output from disk + manifest_data = os_data_from_file_path(arena, merged_manifest_path); + if (manifest_data.size == 0) { + lnk_error(LNK_Error_Mt, "unable to find mt.exe output manifest on disk, expected path \"%S\"", merged_manifest_path); + } + + // cleanup disk + os_delete_file_at_path(linker_manifest_path); + os_delete_file_at_path(merged_manifest_path); + + scratch_end(scratch); + ProfEnd(); + } else { + manifest_data = lnk_make_linker_manifest(arena, manifest_uac, manifest_level, manifest_ui_access, deps_list); + } + + return manifest_data; +} + internal String8 lnk_res_from_data(Arena *arena, String8 data) { @@ -3203,6 +3264,8 @@ l.count += 1; \ // inputs String8List include_symbol_list = config->include_symbol_list; String8List input_disallow_lib_list = config->disallow_lib_list; + String8List input_manifest_path_list = str8_list_copy(tp_arena->v[0], &config->input_list[LNK_Input_Manifest]); + String8List manifest_dep_list = str8_list_copy(scratch.arena, &config->manifest_dependency_list); LNK_AltNameList alt_name_list = config->alt_name_list; LNK_InputLibList input_libs[LNK_InputSource_Count] = {0}; LNK_InputObjList input_obj_list = {0}; @@ -3564,7 +3627,7 @@ l.count += 1; \ case State_InputObjs: { ProfBegin("Input Objs [Count %llu]", input_obj_list.count); - ProfBegin("Gather Objs"); + ProfBegin("Collect Obj Paths"); LNK_InputObjList unique_obj_input_list = {0}; for (LNK_InputObj *input = input_obj_list.first, *next; input != 0; input = next) { next = input->next; @@ -3636,12 +3699,16 @@ l.count += 1; \ } } ProfEnd(); + + // collect manifest dependencies + String8List obj_dep_list = lnk_collect_manifest_dependency_list(tp, tp_arena, obj_node_arr); + str8_list_concat_in_place(&manifest_dep_list, &obj_dep_list); - // gather libs for input + // collect libs for input LNK_InputLibList lib_list = lnk_collect_default_lib_obj_arr(tp, tp_arena, obj_node_arr); // TODO: put these on temp arena str8_list_concat_in_place(&input_libs[LNK_InputSource_Obj], &lib_list); - // gather symbols for input + // collect symbols for input LNK_SymbolList new_defn_list = lnk_run_symbol_collector(tp, tp_arena, obj_node_arr, LNK_Symbol_DefinedExtern); LNK_SymbolList new_weak_list = lnk_run_symbol_collector(tp, tp_arena, obj_node_arr, LNK_Symbol_Weak); LNK_SymbolList new_undef_list = lnk_run_symbol_collector(tp, tp_arena, obj_node_arr, LNK_Symbol_Undefined); // TODO: allocate these on temp arena @@ -3778,77 +3845,60 @@ l.count += 1; \ String8List res_data_list = {0}; String8List res_path_list = {0}; - ProfBegin("Build * Resources *"); - { - // load .res from disk - for (String8Node *node = config->input_list[LNK_Input_Res].first; node != 0; node = node->next) { - String8 res_data = os_data_from_file_path(tp_arena->v[0], node->string); - if (res_data.size > 0) { - if (pe_is_res(res_data)) { - String8 stable_res_path = lnk_make_full_path(tp_arena->v[0], config->work_dir, config->path_style, node->string); - str8_list_push(scratch.arena, &res_path_list, stable_res_path); - str8_list_push(tp_arena->v[0], &res_data_list, res_data); - } else { - lnk_error(LNK_Error_IllData, "file is not of RES format: %S", node->string); - } + // do we have manifest deps passed through pragma alone? + LNK_ManifestOpt manifest_opt = config->manifest_opt; + if (manifest_dep_list.node_count > 0 && manifest_opt == LNK_ManifestOpt_Null) { + manifest_opt = LNK_ManifestOpt_Embed; + } + + switch (manifest_opt) { + case LNK_ManifestOpt_Embed: { + ProfBegin("Embed Manifest"); + // TODO: currently we convert manifest to res and parse res again, this unnecessary instead push manifest + // resource to the tree directly + String8 manifest_data = lnk_manifest_from_inputs(scratch.arena, config->mt_path, config->manifest_name, config->manifest_uac, config->manifest_level, config->manifest_ui_access, input_manifest_path_list, manifest_dep_list); + String8 manifest_res = lnk_res_from_data(scratch.arena, manifest_data); + str8_list_push(scratch.arena, &res_data_list, manifest_res); + str8_list_push(scratch.arena, &res_path_list, str8_lit("* Manifest *")); + ProfEnd(); + } break; + case LNK_ManifestOpt_WriteToFile: { + ProfBeginDynamic("Write Manifest To: %.*s", str8_varg(config->manifest_name)); + Temp temp = temp_begin(scratch.arena); + String8 manifest_data = lnk_manifest_from_inputs(temp.arena, config->mt_path, config->manifest_name, config->manifest_uac, config->manifest_level, config->manifest_ui_access, input_manifest_path_list, manifest_dep_list); + lnk_write_data_to_file_path(config->manifest_name, manifest_data); + temp_end(temp); + ProfEnd(); + } break; + case LNK_ManifestOpt_Null: { + Assert(input_manifest_path_list.node_count == 0); + Assert(manifest_dep_list.node_count == 0); + } break; + case LNK_ManifestOpt_No: { + // omit manifest generation + } break; + } + + ProfBegin("Load .res files from disk"); + for (String8Node *node = config->input_list[LNK_Input_Res].first; node != 0; node = node->next) { + String8 res_data = os_data_from_file_path(scratch.arena, node->string); + if (res_data.size > 0) { + if (pe_is_res(res_data)) { + str8_list_push(scratch.arena, &res_data_list, res_data); + String8 stable_res_path = lnk_make_full_path(scratch.arena, config->work_dir, config->path_style, node->string); + str8_list_push(scratch.arena, &res_path_list, stable_res_path); } else { - lnk_error(LNK_Error_FileNotFound, "unable to open res file: %S", node->string); + lnk_error(LNK_Error_LoadRes, "file is not of RES format: %S", node->string); } + } else { + lnk_error(LNK_Error_LoadRes, "unable to open res file: %S", node->string); } } ProfEnd(); - // handle manifest - ProfBegin("Manifest"); - { - LNK_Obj **obj_arr = lnk_obj_arr_from_list(scratch.arena, obj_list); - String8List obj_dep_list = lnk_collect_manifest_dependency_list(tp, tp_arena, obj_arr, obj_list.count); - String8List cmd_dep_list = str8_list_copy(scratch.arena, &config->manifest_dependency_list); - - String8List dep_list = {0}; - str8_list_concat_in_place(&dep_list, &obj_dep_list); - str8_list_concat_in_place(&dep_list, &cmd_dep_list); - - B32 create_manifest = config->input_list[LNK_Input_Manifest].node_count > 0 || - dep_list.node_count > 0 || - config->manifest_opt == LNK_ManifestOpt_Embed; - if (create_manifest) { - String8List input_manifest_path_list = str8_list_copy(tp_arena->v[0], &config->input_list[LNK_Input_Manifest]); - - // TODO: we write a temp file with manifest attributes collected from obj directives and command line switches - // so we can pass file to mt.exe or llvm-mt.exe, when we have our own tool for merging manifest we can switch - // to writing manifest file in memory to skip roun-trip to disk - String8List linker_manifest_data_list = lnk_make_linker_manifest(tp_arena->v[0], config->manifest_uac, config->manifest_level, config->manifest_ui_access, dep_list); - String8 linker_manifest_path = push_str8f(scratch.arena, "%S.manifest.temp", config->manifest_name); - lnk_write_data_list_to_file_path(linker_manifest_path, linker_manifest_data_list); - str8_list_push(tp_arena->v[0], &input_manifest_path_list, linker_manifest_path); - - String8 merged_manifest_path = push_str8f(scratch.arena, "%S.manifest.merged", config->manifest_name); - lnk_merge_manifest_files(tp_arena->v[0], config->mt_path, merged_manifest_path, input_manifest_path_list); - - if (config->manifest_opt == LNK_ManifestOpt_Embed) { - // TODO: currently we convert manifest to res and parse res again, this unnecessary instead push manifest - // resource to the tree directly - - String8 manifest_data = os_data_from_file_path(scratch.arena, merged_manifest_path); - if (manifest_data.size == 0) { - lnk_error(LNK_Error_Mt, "unable to locate manifest to embed on disk, path \"%S\"", merged_manifest_path); - } - String8 manifest_res = lnk_res_from_data(tp_arena->v[0], manifest_data); - str8_list_push(tp_arena->v[0], &res_data_list, manifest_res); - str8_list_push(tp_arena->v[0], &res_path_list, merged_manifest_path); - } - - // cleanup disk - os_delete_file_at_path(linker_manifest_path); - if (config->delete_manifest == LNK_SwitchState_Yes) { - os_delete_file_at_path(merged_manifest_path); - } - } - } - ProfEnd(); // Manifest - if (res_data_list.node_count > 0) { + ProfBegin("Build * Resources *"); + String8 obj_name = str8_lit("* Resources *"); String8 obj_data = lnk_obj_from_res_file_list(tp, tp_arena->v[0], @@ -3861,11 +3911,13 @@ l.count += 1; \ config->work_dir, config->path_style, obj_name); - + LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->dedup_id = obj_name; - input->path = obj_name; - input->data = obj_data; + input->dedup_id = obj_name; + input->path = obj_name; + input->data = obj_data; + + ProfEnd(); } } break; case State_BuildAndInputLinkerObj: { @@ -4002,7 +4054,7 @@ l.count += 1; \ // remove empty section headers from output image lnk_section_table_remove_empties(st, symtab); - // gather output sections + // collect output sections LNK_SectionArray out_sect_arr = lnk_section_table_get_output_sections(scratch.arena, st); // push back null section where we store image header @@ -4258,6 +4310,13 @@ l.count += 1; \ entry_search_attempts += 1; continue; } + if (unresolved_undef_list.count) { + if (report_unresolved_symbols) { + report_unresolved_symbols = 0; + state_list_push(scratch.arena, state_list, State_ReportUnresolvedSymbols); + continue; + } + } if (build_res_obj) { build_res_obj = 0; state_list_push(scratch.arena, state_list, State_BuildAndInputResObj); @@ -4268,23 +4327,16 @@ l.count += 1; \ state_list_push(scratch.arena, state_list, State_BuildAndInputLinkerObj); continue; } - if (check_unused_delay_loads) { - check_unused_delay_loads = 0; - state_list_push(scratch.arena, state_list, State_CheckUnusedDelayLoads); - continue; - } - if (unresolved_undef_list.count) { - if (report_unresolved_symbols) { - report_unresolved_symbols = 0; - state_list_push(scratch.arena, state_list, State_ReportUnresolvedSymbols); - continue; - } - } if (do_comdat_rewire) { do_comdat_rewire = 0; state_list_push(scratch.arena, state_list, State_RewireComdats); continue; } + if (check_unused_delay_loads) { + check_unused_delay_loads = 0; + state_list_push(scratch.arena, state_list, State_CheckUnusedDelayLoads); + continue; + } /// --- inputs are ready --- diff --git a/src/linker/lnk.h b/src/linker/lnk.h index dc4c07c3..a0875c6d 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -252,9 +252,9 @@ internal void lnk_push_loaded_lib(Arena *arena, HashTable *default_lib_ht, Ha //////////////////////////////// // Manifest -internal String8List lnk_make_linker_manifest(Arena *arena, B32 manifest_uac, String8 manifest_level, String8 manifest_ui_access, String8List manifest_dependency_list); -internal void lnk_merge_manifest_files(Arena *arena, String8 mt_path, String8 manifest_name, String8List manifest_path_list); -internal String8 lnk_res_from_data(Arena *arena, String8 data); +internal String8 lnk_make_linker_manifest(Arena *arena, B32 manifest_uac, String8 manifest_level, String8 manifest_ui_access, String8List manifest_dependency_list); +internal void lnk_merge_manifest_files(String8 mt_path, String8 out_name, String8List manifest_path_list); +internal String8 lnk_res_from_data(Arena *arena, String8 data); //////////////////////////////// // Resources diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index aef66a52..45e099c7 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -125,7 +125,6 @@ read_only struct { LNK_CmdSwitch_Rad_Debug, "RAD_DEBUG", "[:NO]", "Emit RAD debug info file." }, { LNK_CmdSwitch_Rad_DebugName, "RAD_DEBUG_NAME", ":FILENAME", "Sets file name for RAD debug info file." }, { LNK_CmdSwitch_Rad_DelayBind, "RAD_DELAY_BIND", "[:NO]", "" }, - { LNK_CmdSwitch_Rad_DeleteManifest, "RAD_DELETE_MANIFEST", "[:NO]", "" }, { LNK_CmdSwitch_Rad_DoMerge, "RAD_DO_MERGE", "[:NO]", "" }, { LNK_CmdSwitch_Rad_EnvLib, "RAD_ENV_LIB", "[:NO]", "" }, { LNK_CmdSwitch_Rad_Exe, "RAD_EXE", "[:NO]", "" }, @@ -472,16 +471,13 @@ lnk_get_mt_path(Arena *arena) #pragma comment(lib, "shlwapi.lib") #include - String8 mt_path = str8(0,0); - local_persist wchar_t raw_mt_path[MAX_PATH + 1] = L"mt.exe"; - B32 is_mt_found = PathFindOnPathW(&raw_mt_path[0], 0); - if (is_mt_found) { - String16 mt_path_16 = str16_cstring(&raw_mt_path[0]); - mt_path = str8_from_16(arena, mt_path_16); - mt_path = path_convert_slashes(arena, mt_path, PathStyle_WindowsAbsolute); - } else { - lnk_error(LNK_Error_Cmdl, "mt.exe not found, please specify path with /RAD_MT_PATH or run vcvarsall.bat"); - } + local_persist wchar_t raw_mt_path[MAX_PATH*2] = L"mt.exe"; + PathFindOnPathW(&raw_mt_path[0], 0); + + String16 mt_path_16 = str16_cstring_capped(&raw_mt_path[0], raw_mt_path + sizeof(raw_mt_path)); + String8 mt_path = str8_from_16(arena, mt_path_16); + + mt_path = path_convert_slashes(arena, mt_path, PathStyle_WindowsAbsolute); #undef OS_WINDOWS #define OS_WINDOWS 1 @@ -870,17 +866,16 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_PathStyle, "system"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SectVirtOff, "0x1000"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Workers, "%u", os_get_system_info()->logical_processor_count); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Manifest, "embed"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_TargetOs, "windows"); - //lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "debug"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapDefined, "0x3ffff"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapInternal, "0x1000"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapWeak, "0x3ffff"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapLib, "0x3ffff"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_DeleteManifest, ""); -#if !BUILD_DEBUG - //lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SuppressError, "37"); +#if BUILD_DEBUG + lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "debug"); +#else + lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SuppressError, "37"); #endif if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Rad_MtPath)) { @@ -1135,9 +1130,6 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) if (param_arr.count > 0) { if (str8_match(param_arr.v[0], str8_lit("embed"), StringMatchFlag_CaseInsensitive)) { config->manifest_opt = LNK_ManifestOpt_Embed; - if (config->delete_manifest == LNK_SwitchState_Null) { - config->delete_manifest = 1; - } if (param_arr.count == 1) { if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Dll)) { @@ -1175,13 +1167,17 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, cmd_switch); } } else if (cmd->value_strings.node_count == 0) { - config->manifest_opt = LNK_ManifestOpt_Embed; + config->manifest_opt = LNK_ManifestOpt_WriteToFile; } } break; case LNK_CmdSwitch_ManifestDependency: { String8List manifest_dependency_list = str8_list_copy(arena, &cmd->value_strings); str8_list_concat_in_place(&config->manifest_dependency_list, &manifest_dependency_list); + + if (config->manifest_opt == LNK_ManifestOpt_Null) { + config->manifest_opt = LNK_ManifestOpt_WriteToFile; + } } break; case LNK_CmdSwitch_ManifestFile: { @@ -1419,10 +1415,6 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) lnk_cmd_switch_set_flag_64(cmd->value_strings, cmd_switch, &config->flags, LNK_ConfigFlag_DelayBind); } break; - case LNK_CmdSwitch_Rad_DeleteManifest: { - lnk_cmd_switch_parse_flag(cmd->value_strings, cmd_switch, &config->delete_manifest); - } break; - case LNK_CmdSwitch_Rad_DoMerge: { lnk_cmd_switch_set_flag_64(cmd->value_strings, cmd_switch, &config->flags, LNK_ConfigFlag_Merge); } break; @@ -1611,14 +1603,7 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) // :manifest_input if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ManifestInput)) { - switch (config->manifest_opt) { - case LNK_ManifestOpt_Null: { - lnk_error_cmd_switch(LNK_Error_Cmdl, LNK_CmdSwitch_ManifestInput, "missing /MANIFEST:EMBED"); - } break; - case LNK_ManifestOpt_No: { - lnk_error_cmd_switch(LNK_Warning_Cmdl, LNK_CmdSwitch_ManifestInput, "missing /MANIFEST:EMBED, ignoring inputs"); - } break; - case LNK_ManifestOpt_Embed: { + if (config->manifest_opt == LNK_ManifestOpt_Embed) { for (LNK_CmdOption *cmd = cmd_line.first_option; cmd != 0; cmd = cmd->next) { LNK_CmdSwitchType cmd_switch = lnk_cmd_switch_type_from_string(cmd->string); if (cmd_switch == LNK_CmdSwitch_ManifestInput) { @@ -1626,7 +1611,8 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) str8_list_concat_in_place(&config->input_list[LNK_Input_Manifest], &manifest_list); } } - } break; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, LNK_CmdSwitch_ManifestInput, "missing /MANIFEST:EMBED"); } } @@ -1754,7 +1740,7 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) // handle empty /MANIFESTFILE if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ManifestFile)) { - config->manifest_name = make_file_path_with_ext(arena, config->image_name, str8_lit("manifest")); + config->manifest_name = push_str8f(arena, "%S.manifest", config->image_name); } if (lnk_get_log_status(LNK_Log_Debug)) { diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index 895b76cd..eb3af973 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -123,7 +123,6 @@ typedef enum LNK_CmdSwitch_Rad_Debug, LNK_CmdSwitch_Rad_DebugName, LNK_CmdSwitch_Rad_DelayBind, - LNK_CmdSwitch_Rad_DeleteManifest, LNK_CmdSwitch_Rad_DoMerge, LNK_CmdSwitch_Rad_EnvLib, LNK_CmdSwitch_Rad_Exe, @@ -205,8 +204,9 @@ typedef U32 LNK_GuardFlags; typedef enum { LNK_ManifestOpt_Null, + LNK_ManifestOpt_WriteToFile, LNK_ManifestOpt_Embed, - LNK_ManifestOpt_No + LNK_ManifestOpt_No, } LNK_ManifestOpt; typedef struct LNK_AltNameList @@ -273,7 +273,6 @@ typedef struct LNK_Config String8List disallow_lib_list; String8List delay_load_dll_list; String8List natvis_list; - LNK_SwitchState delete_manifest; String8 manifest_name; B32 manifest_uac; String8 manifest_level; diff --git a/src/linker/lnk_error.h b/src/linker/lnk_error.h index 9e75a312..89ed588d 100644 --- a/src/linker/lnk_error.h +++ b/src/linker/lnk_error.h @@ -28,6 +28,7 @@ typedef enum LNK_Error_UnsupportedMachine, LNK_Error_Mt, LNK_Error_UnableToSerializeMsf, + LNK_Error_LoadRes, LNK_Error_StopLast, LNK_Error_First, diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index 79250547..badcc9bb 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -259,11 +259,11 @@ THREAD_POOL_TASK_FUNC(lnk_manifest_dependency_collector) Rng1U64 range = task->range_arr[task_id]; String8List *list = &task->out_arr[task_id]; - LNK_Obj **obj_ptr = &task->in_arr[range.min]; - LNK_Obj **obj_opl = &task->in_arr[range.max]; + LNK_ObjNode *obj_ptr = &task->in_arr[range.min]; + LNK_ObjNode *obj_opl = &task->in_arr[range.max]; for (; obj_ptr < obj_opl; obj_ptr += 1) { - LNK_Obj *obj = *obj_ptr; + LNK_Obj *obj = &obj_ptr->data; LNK_DirectiveList *dirs = &obj->directive_info.v[LNK_Directive_ManifestDependency]; for (LNK_Directive *dir = dirs->first; dir != 0; dir = dir->next) { String8List dep = str8_list_copy(arena, &dir->value_list); @@ -273,14 +273,14 @@ THREAD_POOL_TASK_FUNC(lnk_manifest_dependency_collector) } internal String8List -lnk_collect_manifest_dependency_list(TP_Context *tp, TP_Arena *arena, LNK_Obj **obj_arr, U64 obj_count) +lnk_collect_manifest_dependency_list(TP_Context *tp, TP_Arena *arena, LNK_ObjNodeArray obj_node_arr) { - Temp scratch = scratch_begin(0,0); + Temp scratch = scratch_begin(arena->v, arena->count); LNK_ManifestDependencyCollector task_data = {0}; - task_data.in_arr = obj_arr; + task_data.in_arr = obj_node_arr.v; task_data.out_arr = push_array(scratch.arena, String8List, tp->worker_count); - task_data.range_arr = tp_divide_work(scratch.arena, obj_count, tp->worker_count); + task_data.range_arr = tp_divide_work(scratch.arena, obj_node_arr.count, tp->worker_count); tp_for_parallel(tp, arena, tp->worker_count, lnk_manifest_dependency_collector, &task_data); String8List result = str8_list_arr_concat(task_data.out_arr, tp->worker_count); diff --git a/src/linker/lnk_obj.h b/src/linker/lnk_obj.h index 21cd8629..370059d1 100644 --- a/src/linker/lnk_obj.h +++ b/src/linker/lnk_obj.h @@ -151,7 +151,7 @@ typedef struct typedef struct { - LNK_Obj **in_arr; + LNK_ObjNode *in_arr; String8List *out_arr; Rng1U64 *range_arr; } LNK_ManifestDependencyCollector;