WIP /RAD_TYPE_SERVER

env vars

replace HashTable with HashMap in config
This commit is contained in:
Nikita Smith
2026-06-02 12:11:12 -07:00
committed by Ryan Fleury
parent 4c8d66b431
commit 541d3afefa
16 changed files with 1055 additions and 344 deletions
+31 -2
View File
@@ -680,18 +680,22 @@ hash_map_hash_from_path(String8 path)
internal HashMapNode * internal HashMapNode *
hash_map_push_string_string(Arena *arena, HashMap *hm, String8 key, String8 value) hash_map_push_string_string(Arena *arena, HashMap *hm, String8 key, String8 value)
{ {
key = push_str8_copy(arena, key);
value = push_str8_copy(arena, value);
return hash_map_push(arena, hm, hash_map_hasher(key), (HashMapKeyValue){ .key = { .key_string = key }, .value = { .value_string = value } }, hash_map_match_string); return hash_map_push(arena, hm, hash_map_hasher(key), (HashMapKeyValue){ .key = { .key_string = key }, .value = { .value_string = value } }, hash_map_match_string);
} }
internal HashMapNode * internal HashMapNode *
hash_map_push_string_raw(Arena *arena, HashMap *hm, String8 key, void *value) hash_map_push_string_raw(Arena *arena, HashMap *hm, String8 key, void *value)
{ {
key = push_str8_copy(arena, key);
return hash_map_push(arena, hm, hash_map_hasher(key), (HashMapKeyValue){ .key = { .key_string = key }, .value = { .value_raw = value } }, hash_map_match_string); return hash_map_push(arena, hm, hash_map_hasher(key), (HashMapKeyValue){ .key = { .key_string = key }, .value = { .value_raw = value } }, hash_map_match_string);
} }
internal HashMapNode * internal HashMapNode *
hash_map_push_string_u64(Arena *arena, HashMap *hm, String8 key, U64 value) hash_map_push_string_u64(Arena *arena, HashMap *hm, String8 key, U64 value)
{ {
key = push_str8_copy(arena, key);
return hash_map_push(arena, hm, hash_map_hasher(key), (HashMapKeyValue){ .key = { .key_string = key }, .value = { .value_u64 = value } }, hash_map_match_string); return hash_map_push(arena, hm, hash_map_hasher(key), (HashMapKeyValue){ .key = { .key_string = key }, .value = { .value_u64 = value } }, hash_map_match_string);
} }
@@ -740,18 +744,22 @@ hash_map_push_raw_u64(Arena *arena, HashMap *hm, void *key, U64 value)
internal HashMapNode * internal HashMapNode *
hash_map_push_path_u64(Arena *arena, HashMap *hm, String8 path, U64 value) hash_map_push_path_u64(Arena *arena, HashMap *hm, String8 path, U64 value)
{ {
return hash_map_push(arena, hm, hash_map_hasher(path), (HashMapKeyValue){ .key = { .key_string = path }, .value = { .value_u64 = value } }, hash_map_match_path); path = push_str8_copy(arena, path);
return hash_map_push(arena, hm, hash_map_hash_from_path(path), (HashMapKeyValue){ .key = { .key_string = path }, .value = { .value_u64 = value } }, hash_map_match_path);
} }
internal HashMapNode * internal HashMapNode *
hash_map_push_path_string(Arena *arena, HashMap *hm, String8 path, String8 value) hash_map_push_path_string(Arena *arena, HashMap *hm, String8 path, String8 value)
{ {
return hash_map_push(arena, hm, hash_map_hasher(path), (HashMapKeyValue){ .key = { .key_string = path }, .value = { .value_string = value } }, hash_map_match_path); path = push_str8_copy(arena, path);
value = push_str8_copy(arena, value);
return hash_map_push(arena, hm, hash_map_hash_from_path(path), (HashMapKeyValue){ .key = { .key_string = path }, .value = { .value_string = value } }, hash_map_match_path);
} }
internal HashMapNode * internal HashMapNode *
hash_map_push_path_raw(Arena *arena, HashMap *hm, String8 path, void *value) hash_map_push_path_raw(Arena *arena, HashMap *hm, String8 path, void *value)
{ {
path = push_str8_copy(arena, path);
return hash_map_push(arena, hm, hash_map_hash_from_path(path), (HashMapKeyValue){ .key = { .key_string = path }, .value = { .value_raw = value } }, hash_map_match_path); return hash_map_push(arena, hm, hash_map_hash_from_path(path), (HashMapKeyValue){ .key = { .key_string = path }, .value = { .value_raw = value } }, hash_map_match_path);
} }
@@ -777,6 +785,13 @@ hash_map_search_string_raw(HashMap *hm, String8 key)
return n ? n->v.value.value_raw : 0; return n ? n->v.value.value_raw : 0;
} }
internal String8 *
hash_map_search_string_string(HashMap *hm, String8 key)
{
HashMapNode *n = hash_map_search(hm, hash_map_hasher(key), (HashMapKey){ .key_string = key }, hash_map_match_string);
return n ? &n->v.value.value_string : 0;
}
internal U32 * internal U32 *
hash_map_search_string_u32(HashMap *hm, String8 key) hash_map_search_string_u32(HashMap *hm, String8 key)
{ {
@@ -791,6 +806,20 @@ hash_map_search_string_u64(HashMap *hm, String8 key)
return n ? &n->v.value.value_u64 : 0; return n ? &n->v.value.value_u64 : 0;
} }
internal U64 *
hash_map_search_path_u64(HashMap *hm, String8 key)
{
HashMapNode *n = hash_map_search(hm, hash_map_hash_from_path(key), (HashMapKey){ .key_string = key }, hash_map_match_path);
return n ? &n->v.value.value_u64 : 0;
}
internal String8 *
hash_map_search_path_string(HashMap *hm, String8 key)
{
HashMapNode *n = hash_map_search(hm, hash_map_hash_from_path(key), (HashMapKey){ .key_string = key }, hash_map_match_path);
return n ? &n->v.value.value_string : 0;
}
internal void * internal void *
hash_map_search_path_raw(HashMap *hm, String8 key) hash_map_search_path_raw(HashMap *hm, String8 key)
{ {
+3
View File
@@ -177,8 +177,11 @@ internal HashMapNode * hash_map_push_path_raw (Arena *arena, HashMap *hm, St
internal void * hash_map_search_stringf_raw (HashMap *hm, char *fmt, ...); internal void * hash_map_search_stringf_raw (HashMap *hm, char *fmt, ...);
internal void * hash_map_search_string_raw (HashMap *hm, String8 key); internal void * hash_map_search_string_raw (HashMap *hm, String8 key);
internal String8 * hash_map_search_string_string(HashMap *hm, String8 key);
internal U32 * hash_map_search_string_u32 (HashMap *hm, String8 key); internal U32 * hash_map_search_string_u32 (HashMap *hm, String8 key);
internal U64 * hash_map_search_string_u64 (HashMap *hm, String8 key); internal U64 * hash_map_search_string_u64 (HashMap *hm, String8 key);
internal U64 * hash_map_search_path_u64 (HashMap *hm, String8 key);
internal String8 * hash_map_search_path_string (HashMap *hm, String8 key);
internal void * hash_map_search_path_raw (HashMap *hm, String8 key); internal void * hash_map_search_path_raw (HashMap *hm, String8 key);
internal void * hash_map_search_u64_raw (HashMap *hm, U64 key); internal void * hash_map_search_u64_raw (HashMap *hm, U64 key);
internal U64 * hash_map_search_u64_u64 (HashMap *hm, U64 key); internal U64 * hash_map_search_u64_u64 (HashMap *hm, U64 key);
+397 -105
View File
@@ -124,75 +124,106 @@
internal LNK_CmdLine internal LNK_CmdLine
lnk_make_default_cmd_line(Arena *arena, LNK_CmdLine user_cmd_line) lnk_make_default_cmd_line(Arena *arena, LNK_CmdLine user_cmd_line)
{ {
Temp scratch = scratch_begin(&arena, 1);
LNK_CmdLine cmd_line = {0}; LNK_CmdLine cmd_line = {0};
// default flags char *default_opts[] = {
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Align, "%u", KB(4)); "/ALIGN:4096",
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Debug, "none"); "/DEBUG:none",
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_FileAlign, "%u", 512); "/FILEALIGN:512",
if (lnk_cmd_line_has_switch(user_cmd_line, LNK_CmdSwitch_Dll)) { "/HIGHENTROPYVA",
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_SubSystem, "%S", pe_string_from_subsystem(PE_WindowsSubsystem_WINDOWS_GUI)); "/MANIFESTUAC:\"level='asInvoker' uiAccess='false'\"",
} "/NXCOMPAT",
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_HighEntropyVa, ""); "/LARGEADDRESSAWARE",
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_ManifestUac, "\"level='asInvoker' uiAccess='false'\""); "/PDBALTPATH:%_RAD_PDB_PATH%",
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_NxCompat, ""); "/PDBPAGESIZE:4096",
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_LargeAddressAware, ""); (char*)str8f(scratch.arena, "/HEAP:%llu,%llu", MB(1), KB(4)).str,
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_PdbAltPath, "%%_RAD_PDB_PATH%%"); (char*)str8f(scratch.arena, "/STACK:%llu,%llu", MB(1), KB(4)).str,
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_PdbPageSize, "%u", KB(4));
if (!lnk_cmd_line_has_switch(user_cmd_line, LNK_CmdSwitch_Brepro)) {
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Rad_TimeStamp, "%u", get_process_start_time_unix());
}
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Rad_TypeHashAlg, "BLAKE3");
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Rad_Age, "%u", 1);
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, "");
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Rad_DoMerge, "");
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Rad_EnvLib, "");
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Rad_Exe, "");
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Rad_Guid, "imageblake3");
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Rad_LargePages, "no");
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Rad_LinkVer, "14.0");
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Rad_OsVer, "6.0");
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Rad_PageSize, "%u", KB(4));
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Rad_PathStyle, "system");
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Rad_Workers, "%u", get_system_info()->logical_processor_count);
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Rad_DebugAltPath, "%%_RAD_RDI_PATH%%");
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Rad_MemoryMapFiles, "");
if (BUILD_DEBUG) {
lnk_cmd_line_push_optionf(arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "debug");
lnk_cmd_line_push_optionf(arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "io_write");
} else {
lnk_cmd_line_push_optionf(arena, &cmd_line, LNK_CmdSwitch_Rad_Ignore, "%u", LNK_Error_InvalidTypeIndex);
}
// default section merges "/RAD_BOOT_MODE:LINKER",
lnk_cmd_line_push_optionf(arena, &cmd_line, LNK_CmdSwitch_Merge, ".xdata=.rdata"); //"/RAD_BUILD_EXP",
lnk_cmd_line_push_optionf(arena, &cmd_line, LNK_CmdSwitch_Merge, ".00cfg=.rdata"); "/RAD_BUILD_IMPLIB",
"/RAD_TPYE_HASH_ALG:BLAKE3",
"/RAD_AGE:1",
"/RAD_CHECK_UNUSED_DELAY_LOAD_DLL",
"/RAD_DO_MERGE",
"/RAD_ENV_LIB",
"/RAD_EXE",
"/RAD_GUID:imageblake3",
"/RAD_LARGE_PAGES:no",
"/RAD_LINK_VER:14.0",
"/RAD_OS_VER:6.0",
"/RAD_PAGE_SIZE:4096",
"/RAD_PATH_STYLE:system",
"/RAD_PDB_HASH_TYPE_NAMES:NONE",
"/RAD_PDB_HASH_TYPE_NAME_LENGTH:8",
"/RAD_DEBUGALTPATH:%_RAD_RDI_PATH%",
"/RAD_MEMORY_MAP_FILES",
"/RAD_MAP_LINES_FOR_UNRESOLVED_SYMBOLS",
"/RAD_UNRESOLVED_SYMBOL_LIMIT:1000",
"/RAD_UNRESOLVED_SYMBOL_REF_LIMIT:10",
(char*)str8f(scratch.arena, "/RAD_MT_PATH:%s", LNK_MANIFEST_MERGE_TOOL_NAME).str,
(char*)str8f(scratch.arena, "/RAD_DATA_DIR_COUNT:%u", PE_DataDirectoryIndex_COUNT).str,
};
char *push_opts[] = {
"/MERGE:.xdata=.rdata",
"/MERGE:.00cfg=.rdata",
// TODO: .tls must be always first contribution in .data section because compiler generates TLS relative movs // TODO: .tls must be always first contribution in .data section because compiler generates TLS relative movs
//lnk_cmd_line_push_optionf(arena, &cmd_line, LNK_CmdSwitch_Merge, ".tls=.data"); //"/MERGE:.tls=.data",
lnk_cmd_line_push_optionf(arena, &cmd_line, LNK_CmdSwitch_Merge, ".idata=.data"); "/MERGE:.idata=.data",
lnk_cmd_line_push_optionf(arena, &cmd_line, LNK_CmdSwitch_Merge, ".didat=.data"); "/MERGE:.didat=.data",
lnk_cmd_line_push_optionf(arena, &cmd_line, LNK_CmdSwitch_Merge, ".edata=.rdata"); "/MERGE:.edata=.rdata",
lnk_cmd_line_push_optionf(arena, &cmd_line, LNK_CmdSwitch_Merge, ".RAD_LINK_PE_DEBUG_DIR=.rdata"); "/MERGE:.RAD_LINK_PE_DEBUG_DIR=.rdata",
lnk_cmd_line_push_optionf(arena, &cmd_line, LNK_CmdSwitch_Merge, ".RAD_LINK_PE_DEBUG_DATA=.rdata"); "/MERGE:.RAD_LINK_PE_DEBUG_DATA=.rdata",
// sections to remove from the image "/RAD_REMOVE_SECTION:.debug",
lnk_cmd_line_push_optionf(arena, &cmd_line, LNK_CmdSwitch_Rad_RemoveSection, ".debug"); "/RAD_REMOVE_SECTION:.gehcont",
lnk_cmd_line_push_optionf(arena, &cmd_line, LNK_CmdSwitch_Rad_RemoveSection, ".gehcont"); "/RAD_REMOVE_SECTION:.gfids",
lnk_cmd_line_push_optionf(arena, &cmd_line, LNK_CmdSwitch_Rad_RemoveSection, ".gfids"); "/RAD_REMOVE_SECTION:.gxfg",
lnk_cmd_line_push_optionf(arena, &cmd_line, LNK_CmdSwitch_Rad_RemoveSection, ".gxfg");
// set limits on unresolved symbol errors (char*)str8f(scratch.arena, "/RAD_WORKERS:%u", get_system_info()->logical_processor_count).str,
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Rad_MapLinesForUnresolvedSymbols, "");
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Rad_UnresolvedSymbolLimit, "1000");
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Rad_UnresolvedSymbolRefLimit, "10");
// set default max worker count // errors that are too verbose in release build
if (lnk_cmd_line_has_switch(user_cmd_line, LNK_CmdSwitch_Rad_SharedThreadPool)) { (char*)str8f(scratch.arena, "/RAD_IGNORE:%d", LNK_Warning_UnknownSwitch * (BUILD_DEBUG ? -1 : 1)).str,
lnk_cmd_line_push_optionf(arena, &cmd_line, LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, ""); (char*)str8f(scratch.arena, "/RAD_IGNORE:%d", LNK_Warning_UnknownDirective * (BUILD_DEBUG ? -1 : 1)).str,
(char*)str8f(scratch.arena, "/RAD_IGNORE:%d", LNK_Error_InvalidTypeIndex * (BUILD_DEBUG ? -1 : 1)).str,
#if BUILD_DEBUG
"/RAD_LOG:debug",
"/RAD_LOG:io_write",
#else
(char*)str8f(scratch.arena, "/RAD_IGNORE:%u", LNK_Error_InvalidTypeIndex).str,
#endif
};
#define DefaultOpt(...) do { \
LNK_CmdLine parsed_cmd_line = lnk_cmd_line_from_stringf_windows_rules(arena, __VA_ARGS__); \
for EachNode(cmd, LNK_CmdOption, parsed_cmd_line.first_option) { \
if (!lnk_cmd_line_has_switch(user_cmd_line, lnk_cmd_switch_type_from_string(cmd->string))) { \
String8List value_strings = str8_list_copy(arena, &cmd->value_strings); \
lnk_cmd_line_push_option_list(arena, &cmd_line, cmd->string, value_strings); \
} \
} \
} while (0)
#define PushOpt(...) do { \
LNK_CmdLine parsed_cmd_line = lnk_cmd_line_from_stringf_windows_rules(arena, __VA_ARGS__); \
lnk_cmd_line_concat_in_place(&cmd_line, &parsed_cmd_line); \
} while (0)
if (lnk_cmd_line_has_switch(user_cmd_line, LNK_CmdSwitch_Dll)) {
DefaultOpt("/SUBSYSTEM:%S", pe_string_from_subsystem(PE_WindowsSubsystem_WINDOWS_GUI));
}
if (!lnk_cmd_line_has_switch(user_cmd_line, LNK_CmdSwitch_Brepro)) {
DefaultOpt("/RAD_TIME_STAMP:%u", get_process_start_time_unix());
}
for EachIndex(i, ArrayCount(default_opts)) {
DefaultOpt("%s", default_opts[i]);
} }
if ( ! lnk_cmd_line_has_switch(user_cmd_line, LNK_CmdSwitch_Rad_MtPath)) { for EachIndex(i, ArrayCount(push_opts)) {
lnk_cmd_line_push_option_if_not_presentf(arena, &cmd_line, LNK_CmdSwitch_Rad_MtPath, "%s", LNK_MANIFEST_MERGE_TOOL_NAME); PushOpt("%s", push_opts[i]);
} }
// when /FORCE is specified on the command line, do not stop on these errors // when /FORCE is specified on the command line, do not stop on these errors
@@ -202,39 +233,37 @@ lnk_make_default_cmd_line(Arena *arena, LNK_CmdLine user_cmd_line)
} }
#endif #endif
// errors that are too verbose in release build #undef DefaultOpt
U64 debug_opt = BUILD_DEBUG ? -1 : 1; #undef PushOpt
lnk_cmd_line_push_optionf(arena, &cmd_line, LNK_CmdSwitch_Rad_Ignore, "%d", LNK_Warning_UnknownSwitch * debug_opt); scratch_end(scratch);
lnk_cmd_line_push_optionf(arena, &cmd_line, LNK_CmdSwitch_Rad_Ignore, "%d", LNK_Warning_UnknownDirective * debug_opt);
lnk_cmd_line_push_optionf(arena, &cmd_line, LNK_CmdSwitch_Rad_Ignore, "%d", LNK_Error_InvalidTypeIndex * debug_opt);
return cmd_line; return cmd_line;
} }
internal LNK_Config * internal LNK_Config *
lnk_config_from_argcv(Arena *arena, int argc, char **argv) lnk_config_from_argcv(CmdLine *cmdline)
{ {
Temp scratch = scratch_begin(&arena, 1); Temp scratch = scratch_begin(0,0);
String8List raw_cmd_line = {0}; String8List raw_cmd_line = {0};
for (U64 i = 1; i < argc; i += 1) { str8_list_push(arena, &raw_cmd_line, str8_cstring(argv[i])); } for (U64 i = 1; i < cmdline->argc; i += 1) { str8_list_push(scratch.arena, &raw_cmd_line, str8_cstring(cmdline->argv[i])); }
#if PROFILE_TELEMETRY #if PROFILE_TELEMETRY
tmMessage(0, TMMF_ICON_NOTE, "Command Line: %.*s", str8_varg(str8_list_join(scratch.arena, &raw_cmd_line, &(StringJoin){ .sep = str8_lit_comp(" ") }))); tmMessage(0, TMMF_ICON_NOTE, "Command Line: %.*s", str8_varg(str8_list_join(scratch.arena, &raw_cmd_line, &(StringJoin){ .sep = str8_lit_comp(" ") })));
#endif #endif
// make command line // make command line
LNK_CmdLine cmd_line = {0}; LNK_CmdLine cmd_line_msvc = {0};
{ {
String8List unwrapped_cmd_line = lnk_unwrap_rsp(scratch.arena, raw_cmd_line); String8List unwrapped_cmd_line = lnk_unwrap_rsp(scratch.arena, raw_cmd_line);
LNK_CmdLine user_cmd_line = lnk_cmd_line_parse_windows_rules(scratch.arena, unwrapped_cmd_line); LNK_CmdLine user_cmd_line = lnk_cmd_line_parse_windows_rules(scratch.arena, unwrapped_cmd_line);
user_cmd_line.raw_cmd_line = raw_cmd_line;
LNK_CmdLine default_cmd_line = lnk_make_default_cmd_line(scratch.arena, user_cmd_line); LNK_CmdLine default_cmd_line = lnk_make_default_cmd_line(scratch.arena, user_cmd_line);
lnk_cmd_line_concat_in_place(&cmd_line, &default_cmd_line); lnk_cmd_line_concat_in_place(&cmd_line_msvc, &default_cmd_line);
lnk_cmd_line_concat_in_place(&cmd_line, &user_cmd_line); lnk_cmd_line_concat_in_place(&cmd_line_msvc, &user_cmd_line);
} }
// init config // init config
LNK_Config *config = lnk_config_from_cmd_line(raw_cmd_line, cmd_line); LNK_Config *config = lnk_config_init(cmd_line_msvc);
scratch_end(scratch); scratch_end(scratch);
return config; return config;
@@ -1228,6 +1257,20 @@ lnk_array_from_lib_member_list(Arena *arena, LNK_LibMemberRefList list)
return result; return result;
} }
internal LNK_Link *
lnk_link_init(TP_Arena *arena, LNK_Config *config)
{
LNK_Link *link = push_array(arena->v[0], LNK_Link, 1);
link->arena = arena_alloc(.name = "LINK");
link->last_symbol_input = &link->objs.first;
link->last_include = &config->include_symbol_list.first;
link->last_default_lib = &config->input_default_lib_list.first;
link->last_obj_lib = &config->input_obj_lib_list.first;
link->last_cmd_lib = &config->input_list[LNK_Input_Lib].first;
link->try_to_resolve_entry_point = 1;
return link;
}
internal LNK_ObjNode * internal LNK_ObjNode *
lnk_load_objs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, LNK_Link *link, U64 *objs_count_out) lnk_load_objs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, LNK_Link *link, U64 *objs_count_out)
{ {
@@ -1243,7 +1286,7 @@ lnk_load_objs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *
lnk_log(LNK_Log_InputObj, "[ Obj Input Size %M ]", input_size); lnk_log(LNK_Log_InputObj, "[ Obj Input Size %M ]", input_size);
} }
LNK_ObjNode *new_objs = lnk_obj_from_input_many(tp, arena, config->machine, new_input_objs.count, new_input_objs.v); LNK_ObjNode *new_objs = lnk_obj_from_input_many(tp, arena, config, new_input_objs.count, new_input_objs.v);
// if machine type was unspecified on the command line, derive it from obj file // if machine type was unspecified on the command line, derive it from obj file
if (config->machine == COFF_MachineType_Unknown) { if (config->machine == COFF_MachineType_Unknown) {
@@ -1727,7 +1770,7 @@ lnk_link_inputs(TP_Context *tp,
B32 link_whole_archive = config->whole_archive_all; B32 link_whole_archive = config->whole_archive_all;
if ( ! link_whole_archive) { if ( ! link_whole_archive) {
String8 lib_name = str8_chop_last_dot(str8_skip_last_slash(lib->path)); String8 lib_name = str8_chop_last_dot(str8_skip_last_slash(lib->path));
link_whole_archive = hash_table_search_path(config->whole_archive_ht, lib_name) != 0; link_whole_archive = hash_map_search_path_u64(&config->whole_archive_ht, lib_name) != 0;
} }
ProfBeginV("Search %S", str8_skip_last_slash(lib->path)); ProfBeginV("Search %S", str8_skip_last_slash(lib->path));
@@ -1911,23 +1954,14 @@ lnk_link_inputs(TP_Context *tp,
ProfEnd(); ProfEnd();
} }
internal LNK_LinkResult internal LNK_LinkResult
lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab) lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab)
{ {
ProfBeginFunction(); ProfBeginFunction();
Temp scratch = scratch_begin(arena->v, arena->count); Temp scratch = scratch_begin(arena->v, arena->count);
// LNK_Link *link = lnk_link_init(arena, config); // TODO: factor out
// init link context
//
LNK_Link *link = push_array(arena->v[0], LNK_Link, 1);
link->arena = arena_alloc(.name = "LINK");
link->last_symbol_input = &link->objs.first;
link->last_include = &config->include_symbol_list.first;
link->last_default_lib = &config->input_default_lib_list.first;
link->last_obj_lib = &config->input_obj_lib_list.first;
link->last_cmd_lib = &config->input_list[LNK_Input_Lib].first;
link->try_to_resolve_entry_point = 1;
// input :null_obj // input :null_obj
String8 null_obj = lnk_make_null_obj(inputer->arena); String8 null_obj = lnk_make_null_obj(inputer->arena);
@@ -5292,21 +5326,34 @@ THREAD_POOL_TASK_FUNC(lnk_p2r_worker)
scratch_end(scratch); scratch_end(scratch);
} }
internal LNK_Obj **
lnk_debug_filter_objs(Arena *arena, LNK_Obj **objs, U64 objs_count, U64 *count_out)
{
U64 debug_info_objs_count = 0;
LNK_Obj **debug_info_objs = push_array(arena, LNK_Obj *, objs_count);
for EachIndex(obj_idx, objs_count) {
LNK_Obj *obj = objs[obj_idx];
// filter out internal objs from debug info output
if (obj->exclude_from_debug_info) {
continue;
}
debug_info_objs[debug_info_objs_count++] = obj;
}
if (count_out) {
*count_out = debug_info_objs_count;
}
return debug_info_objs;
}
internal void internal void
lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config) lnk_run_linker(TP_Context *tp, TP_Arena *arena, LNK_Config *config)
{ {
ProfBeginFunction(); ProfBeginFunction();
Temp scratch = scratch_begin(arena->v, arena->count); Temp scratch = scratch_begin(arena->v, arena->count);
if (lnk_get_log_status(LNK_Log_Debug)) {
String8 full_cmd_line = str8_list_join(scratch.arena, &config->raw_cmd_line, &(StringJoin){ .sep = str8_lit_comp(" ") });
lnk_fprintf(stderr, "--------------------------------------------------------------------------------\n");
lnk_fprintf(stderr, "Command Line: %.*s\n", str8_varg(full_cmd_line));
lnk_fprintf(stderr, "Work Dir : %.*s\n", str8_varg(config->work_dir));
lnk_fprintf(stderr, "--------------------------------------------------------------------------------\n");
}
// //
// Input Context // Input Context
// //
@@ -5368,12 +5415,7 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config)
lnk_timer_begin(LNK_Timer_Debug); lnk_timer_begin(LNK_Timer_Debug);
U64 debug_info_objs_count = 0; U64 debug_info_objs_count = 0;
LNK_Obj **debug_info_objs = push_array(scratch.arena, LNK_Obj *, objs_count); LNK_Obj **debug_info_objs = lnk_debug_filter_objs(scratch.arena, objs, objs_count, &debug_info_objs_count);
for EachIndex(obj_idx, objs_count) {
LNK_Obj *obj = objs[obj_idx];
if (obj->exclude_from_debug_info) { continue; }
debug_info_objs[debug_info_objs_count++] = obj;
}
// //
// CodeView // CodeView
@@ -5401,7 +5443,7 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config)
config->pdb_hash_type_name_length, config->pdb_hash_type_name_length,
config->pdb_hash_type_name_map); config->pdb_hash_type_name_map);
} }
pdb_data = lnk_build_pdb(tp, arena, image_ctx.image_data, config, symtab, &cv, cv_types); pdb_data = lnk_build_pdb(tp, arena, image_ctx.image_data, config, symtab, &cv, cv_types, LNK_PDB_BuilderFlag_All);
if (config->debug_mode == LNK_DebugMode_Full) { if (config->debug_mode == LNK_DebugMode_Full) {
lnk_write_data_list_to_file_path(config->pdb_name, config->temp_pdb_name, pdb_data); lnk_write_data_list_to_file_path(config->pdb_name, config->temp_pdb_name, pdb_data);
} }
@@ -5488,7 +5530,7 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config)
stripped_cv.debug_s_arr = debug_s_arr; stripped_cv.debug_s_arr = debug_s_arr;
stripped_cv.symbol_input_ranges = push_array(scratch.arena, Rng1U64, tp->worker_count); stripped_cv.symbol_input_ranges = push_array(scratch.arena, Rng1U64, tp->worker_count);
String8List pdb_data = lnk_build_pdb(tp, arena, image_ctx.image_data, config, symtab, &stripped_cv, (LNK_MergedTypes){0}); String8List pdb_data = lnk_build_pdb(tp, arena, image_ctx.image_data, config, symtab, &stripped_cv, (LNK_MergedTypes){0}, LNK_PDB_BuilderFlag_All);
lnk_write_data_list_to_file_path(config->pdb_stripped_name, str8f(scratch.arena, "%S.tmp", config->pdb_stripped_name), pdb_data); lnk_write_data_list_to_file_path(config->pdb_stripped_name, str8f(scratch.arena, "%S.tmp", config->pdb_stripped_name), pdb_data);
} }
@@ -5510,15 +5552,265 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config)
ProfEnd(); ProfEnd();
} }
internal void
lnk_run_type_server(TP_Context *tp, TP_Arena *arena, LNK_Config *config)
{
ProfBeginFunction();
Temp scratch = scratch_begin(arena->v, arena->count);
// generate GUID
Guid type_server_guid = {0};
{
blake3_hasher hasher = {0};
blake3_hasher_init(&hasher);
blake3_hasher_update(&hasher, config->pdb_name.str, config->pdb_name.size);
blake3_hasher_update(&hasher, (U8*)&config->time_stamp, sizeof(config->time_stamp));
blake3_hasher_finalize(&hasher, type_server_guid.v, sizeof(type_server_guid.v));
}
// push default type-server switches
lnk_config_pushf(config, "/PDB:\"%S.type_server.pdb\"", str8_chop_last_dot(config->pdb_name));
lnk_config_pushf(config, "/DEBUG:FULL");
lnk_config_pushf(config, "/NOD");
lnk_config_pushf(config, "/RAD_WRITE_TEMP_FILES");
lnk_config_pushf(config, "/RAD_MEMORY_MAP_FILES:READ_WRITE");
lnk_config_pushf(config, "/RAD_GUID:%S", string_from_guid(scratch.arena, type_server_guid));
// load objs
U64 objs_count = 0;
LNK_Obj **objs = 0;
{
LNK_Inputer *inputer = lnk_inputer_init();
LNK_Link *link = lnk_link_init(arena, config);
// input :null_obj
String8 null_obj = lnk_make_null_obj(inputer->arena);
lnk_inputer_push_obj_linkgen(inputer, 0, str8_lit("* Null *"), null_obj);
// input objs on command line
for (String8Node *obj_path = config->input_list[LNK_Input_Obj].first; obj_path != 0; obj_path = obj_path->next) {
lnk_inputer_push_obj_thin(inputer, 0, obj_path->string);
}
LNK_ObjNode *obj_nodes = lnk_load_objs(tp, arena, config, inputer, 0, link, &objs_count);
objs = push_array(scratch.arena, LNK_Obj *, objs_count);
for EachIndex(obj_idx, objs_count) { objs[obj_idx] = &obj_nodes[obj_idx].data; }
}
// obj filters
{
// internal filter
objs = lnk_debug_filter_objs(scratch.arena, objs, objs_count, &objs_count);
// command line filter
{
U64 result_count = 0;
LNK_Obj **result = push_array(scratch.arena, LNK_Obj *, objs_count);
for EachIndex(obj_idx, objs_count) {
LNK_Obj *obj = objs[obj_idx];
B32 skip = 0;
if (config->type_server_match_obj.node_count) {
skip = 1;
for EachNode(filter_n, String8Node, config->type_server_match_obj.first) {
if (str8_match_wildcard(obj->path, filter_n->string, StringMatchFlag_CaseInsensitive|StringMatchFlag_SlashInsensitive)) {
skip = 0;
break;
}
}
}
if (skip) { continue; }
result[result_count++] = obj;
}
objs_count = result_count;
objs = result;
}
}
// compute size of objs compiled with /Z7
U64 debug_t_total_size = 0;
{
for EachIndex(obj_idx, objs_count) {
LNK_Obj *obj = objs[obj_idx];
// register debug info sections
U64 type_sect_indices_count = 0;
U32 type_sect_indices[4] = {0};
if (obj->debug_t_sect_idx < obj->header.section_count_no_null) { type_sect_indices[type_sect_indices_count++] = obj->debug_t_sect_idx; }
else if (obj->debug_p_sect_idx < obj->header.section_count_no_null) { type_sect_indices[type_sect_indices_count++] = obj->debug_p_sect_idx; }
for EachIndex(i, type_sect_indices_count) {
U64 section_idx = type_sect_indices[i];
COFF_SectionHeader *section_table = lnk_coff_section_table_from_obj(obj);
COFF_SectionHeader *debug_t_header = &section_table[section_idx];
String8 debug_t_data = str8_substr(obj->data, r1u64(debug_t_header->foff, debug_t_header->foff + debug_t_header->fsize));
CV_Leaf first_leaf = {0};
if (cv_read_leaf(debug_t_data, sizeof(CV_Signature), CV_LeafAlign, &first_leaf) >= sizeof(CV_LeafHeader)) {
if ( ! cv_is_leaf_type_server(first_leaf.kind)) {
debug_t_total_size += debug_t_data.size;
}
}
}
}
}
if (debug_t_total_size) {
// merge & write types
LNK_CodeViewInput cv = lnk_make_code_view_input(tp, arena, config, objs_count, objs);
LNK_MergedTypes cv_types = lnk_merge_types(tp, arena, &cv);
String8List pdb = lnk_build_pdb(tp, arena, str8_zero(), config, 0, &cv, cv_types, LNK_PDB_BuilderFlag_Tpi|LNK_PDB_BuilderFlag_Ipi);
lnk_write_data_list_to_file_path(config->pdb_name, config->temp_pdb_name, pdb);
typedef struct Edit {
struct Edit *next;
String8 data;
U64 offset;
LNK_Obj *obj;
} Edit;
Edit *edits = 0;
for EachIndex(obj_idx, objs_count) {
LNK_Obj *obj = objs[obj_idx];
// skip objs in libraries
if (obj->link_member) { continue; }
if (obj->debug_t_sect_idx < obj->header.section_count_no_null) {
COFF_SectionHeader *section_table = lnk_coff_section_table_from_obj(obj);
COFF_SectionHeader *section_header = &section_table[obj->debug_t_sect_idx];
// skip type servers
if (cv_debug_t_is_type_server_ref(&cv.debug_t_arr[obj_idx])) { continue; }
CV_LeafTypeServer2 ts_info = { .sig70 = config->guid, .age = 1 };
String8List ts_srl = {0};
str8_list_push(scratch.arena, &ts_srl, str8_struct(&ts_info));
str8_list_push(scratch.arena, &ts_srl, push_cstr(scratch.arena, config->pdb_name));
// type server srl -> CodeView leaf
String8 ts_string = str8_list_join(scratch.arena, &ts_srl, 0);
String8 ts_leaf = cv_make_leaf(scratch.arena, CV_LeafKind_TYPESERVER2, ts_string, CV_LeafAlign);
// make type server .debug$T
String8List debug_t_list = {0};
str8_list_push(scratch.arena, &debug_t_list, str8_struct((&(CV_Signature){ CV_Signature_C13 })));
str8_list_push(scratch.arena, &debug_t_list, ts_leaf);
String8 debug_t = str8_list_join(scratch.arena, &debug_t_list, 0);
// realloc seciton if there is not enough room in the section header
if (debug_t.size > section_header->fsize) {
section_header->foff = obj->data.size;
section_header->fsize = debug_t.size;
// append to the obj
struct Edit *e = push_array(scratch.arena, struct Edit, 1);
e->data = debug_t;
e->offset = obj->data.size;
e->obj = obj;
SLLStackPush(edits, e);
} else {
section_header->fsize = debug_t.size;
Rng1U64 section_frange = rng_1u64(section_header->foff, section_header->foff + section_header->fsize);
String8 section_data = str8_substr(obj->data, section_frange);
MemoryCopyStr8(section_data.str, debug_t);
}
}
// discard precompiled headers types, they are already in the type server
if (obj->debug_p_sect_idx < obj->header.section_count_no_null) {
COFF_SectionHeader *section_table = lnk_coff_section_table_from_obj(obj);
COFF_SectionHeader *section_header = &section_table[obj->debug_p_sect_idx];
section_header->flags |= COFF_SectionFlag_LnkRemove;
}
// discard type hashes sectiosn, there is no /Z7 sections in the file
if (obj->debug_h_sect_idx < obj->header.section_count_no_null) {
COFF_SectionHeader *section_table = lnk_coff_section_table_from_obj(obj);
COFF_SectionHeader *section_header = &section_table[obj->debug_h_sect_idx];
section_header->flags |= COFF_SectionFlag_LnkRemove;
}
// edit obj
if (edits) {
#if OS_WINDOWS
AssertAlways(UnmapViewOfFile(obj->data.str));
#else
NotImplemented;
#endif
File handle = file_open(AccessFlag_Append|AccessFlag_Read|AccessFlag_Write, obj->path);
for EachNode(e, struct Edit, edits) {
AssertAlways(file_write(handle, r1u64(e->offset, e->offset + e->data.size), e->data.str) == e->data.size);
}
file_close(handle);
}
}
}
#if 0
// relaunch the binary with the same command line, but with boot mode set to LINKER
if (config->type_server == LNK_SwitchState_Yes) {
String8 curr_cmdl = str8_list_join(scratch.arena, &config->raw_cmd_line, &(StringJoin){.sep=str8_lit(" ")});
String8 linker_cmdl = str8f(scratch.arena, "%S %S /RAD_TYPE_SERVER:NO /RAD_BOOT_MODE:LINKER", get_process_info()->binary_file_path, curr_cmdl);
ProcessLaunchParams launch_opts = {
.path = get_process_info()->binary_path,
.inherit_env = 1,
.consoleless = 1,
.cmd_line = lnk_arg_list_parse_windows_rules(scratch.arena, linker_cmdl),
};
Process process_handle = process_launch(&launch_opts);
if (process_match(process_handle, process_zero())) {
String8 e = str8f(scratch.arena, "failed to launch radlink(%S) after type server step\n");
lnk_invalid_path((char*)e.str);
}
}
#endif
scratch_end(scratch);
ProfEnd();
}
internal void internal void
entry_point(CmdLine *cmdline) entry_point(CmdLine *cmdline)
{ {
Temp scratch = scratch_begin(0,0); Temp scratch = scratch_begin(0,0);
lnk_log_begin(); lnk_log_begin();
LNK_Config *config = lnk_config_from_argcv(scratch.arena, cmdline->argc, cmdline->argv);
LNK_Config *config = lnk_config_from_argcv(cmdline);
TP_Context *tp = tp_alloc(scratch.arena, config->worker_count, config->max_worker_count, config->shared_thread_pool_name); TP_Context *tp = tp_alloc(scratch.arena, config->worker_count, config->max_worker_count, config->shared_thread_pool_name);
TP_Arena *tp_arena = tp_arena_alloc(tp); TP_Arena *tp_arena = tp_arena_alloc(tp);
lnk_run(tp, tp_arena, config);
// detect type server from the environment
{
HashMap env = lnk_env_vars_from_process_info(scratch.arena, get_process_info(), LNK_EnvVarRule_Current);
LNK_EnvVar *type_server_var = lnk_env_var_from_mapf(&env, "RAD_TYPE_SERVER");
if (type_server_var) {
U64 do_type_server = 0;
if (lnk_env_var_to_u64(&env, type_server_var, &do_type_server)) {
if (do_type_server) {
lnk_config_pushf(config, "/RAD_TYPE_SERVER");
lnk_log(LNK_Log_Debug, "type server mode was enabled from the environment\n");
}
}
}
}
if (lnk_get_log_status(LNK_Log_Debug)) {
String8 full_cmd_line = str8_list_join(scratch.arena, &config->raw_cmd_line, &(StringJoin){ .sep = str8_lit_comp(" ") });
lnk_fprintf(stderr, "--------------------------------------------------------------------------------\n");
lnk_fprintf(stderr, "Command Line: %.*s\n", str8_varg(full_cmd_line));
lnk_fprintf(stderr, "Work Dir : %.*s\n", str8_varg(config->work_dir));
lnk_fprintf(stderr, "--------------------------------------------------------------------------------\n");
}
switch (config->boot_mode) {
case LNK_BootMode_Linker: lnk_run_linker (tp, tp_arena, config); break;
case LNK_BootMode_TypeServer: lnk_run_type_server(tp, tp_arena, config); break;
}
lnk_log_end(); lnk_log_end();
scratch_end(scratch); scratch_end(scratch);
} }
+2 -1
View File
@@ -319,7 +319,7 @@ typedef struct
// --- Config ----------------------------------------------------------------- // --- Config -----------------------------------------------------------------
internal LNK_Config * lnk_config_from_argcv(Arena *arena, int argc, char **argv); internal LNK_Config * lnk_config_from_cmdline(CmdLine *cmdline);
// --- Entry Point ------------------------------------------------------------- // --- Entry Point -------------------------------------------------------------
@@ -375,6 +375,7 @@ internal void lnk_lib_member_ref_list_concat_in_place_array(LNK_L
internal int lnk_lib_member_ref_is_before(void *raw_a, void *raw_b); internal int lnk_lib_member_ref_is_before(void *raw_a, void *raw_b);
internal LNK_LibMemberRef ** lnk_array_from_lib_member_list(Arena *arena, LNK_LibMemberRefList list); internal LNK_LibMemberRef ** lnk_array_from_lib_member_list(Arena *arena, LNK_LibMemberRefList list);
internal LNK_Link * lnk_link_init (TP_Arena *arena, LNK_Config *config);
internal LNK_ObjNode * lnk_load_objs (TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, LNK_Link *link, U64 *objs_count_out); internal LNK_ObjNode * lnk_load_objs (TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, LNK_Link *link, U64 *objs_count_out);
internal void lnk_load_libs (TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_Link *link); internal void lnk_load_libs (TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_Link *link);
internal void lnk_link_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, LNK_Link *link); internal void lnk_link_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, LNK_Link *link);
+193 -6
View File
@@ -143,6 +143,7 @@ lnk_cmd_line_concat_in_place(LNK_CmdLine *list, LNK_CmdLine *to_concat)
internal LNK_CmdLine internal LNK_CmdLine
lnk_cmd_line_parse_windows_rules(Arena *arena, String8List arg_list) lnk_cmd_line_parse_windows_rules(Arena *arena, String8List arg_list)
{ {
Temp scratch = scratch_begin(&arena, 1);
LNK_CmdLine cmd_line = {0}; LNK_CmdLine cmd_line = {0};
cmd_line.raw_cmd_line = str8_list_copy(arena, &arg_list); cmd_line.raw_cmd_line = str8_list_copy(arena, &arg_list);
@@ -161,17 +162,41 @@ lnk_cmd_line_parse_windows_rules(Arena *arena, String8List arg_list)
String8 value_string = str8_skip(arg, param_start_pos + 1); String8 value_string = str8_skip(arg, param_start_pos + 1);
// make value list // make value list
String8List value_list = str8_split_by_string_chars(arena, value_string, str8_lit(","), 0); String8List value_list_unowned = str8_split_by_string_chars(scratch.arena, value_string, str8_lit(","), 0);
String8List value_list = str8_list_copy(arena, &value_list_unowned);
// push command // push command
option_name = push_str8_copy(arena, option_name);
lnk_cmd_line_push_option_list(arena, &cmd_line, option_name, value_list); lnk_cmd_line_push_option_list(arena, &cmd_line, option_name, value_list);
} else { } else {
str8_list_push(arena, &cmd_line.input_list, arg); str8_list_push(arena, &cmd_line.input_list, push_str8_copy(arena, arg));
} }
} }
scratch_end(scratch);
return cmd_line; return cmd_line;
} }
internal LNK_CmdLine
lnk_cmd_line_from_stringfv_windows_rules(Arena *arena, char *fmt, va_list args)
{
Temp scratch = scratch_begin(&arena, 1);
String8 string = push_str8fv(scratch.arena, fmt, args);
String8List arg_list = lnk_arg_list_parse_windows_rules(scratch.arena, string);
LNK_CmdLine result = lnk_cmd_line_parse_windows_rules(arena, arg_list);
scratch_end(scratch);
return result;
}
internal LNK_CmdLine
lnk_cmd_line_from_stringf_windows_rules(Arena *arena, char *fmt, ...)
{
va_list args;
va_start(args, fmt);
LNK_CmdLine result = lnk_cmd_line_from_stringfv_windows_rules(arena, fmt, args);
va_end(args);
return result;
}
internal LNK_CmdOption * internal LNK_CmdOption *
lnk_cmd_line_option_from_string(LNK_CmdLine cmd_line, String8 string) lnk_cmd_line_option_from_string(LNK_CmdLine cmd_line, String8 string)
{ {
@@ -245,7 +270,159 @@ lnk_data_from_cmd_line(Arena *arena, LNK_CmdLine cmd_line)
} }
internal String8 internal String8
lnk_expand_env_vars_windows(Arena *arena, HashTable *env_vars, String8 string) lnk_env_var_chain_separator_from_rule(LNK_EnvVarRule rule)
{
String8 result = {0};
switch (rule) {
case LNK_EnvVarRule_Batch: { result = str8_lit(";"); } break;
case LNK_EnvVarRule_Bash: { result = str8_lit(":"); } break;
default: break;
}
return result;
}
internal LNK_EnvVar *
lnk_env_var_push(Arena *arena, HashMap *env_vars, String8 key, String8 value, LNK_EnvVarRule rule)
{
LNK_EnvVar *env_var = lnk_env_var_from_map(env_vars, key);
if (env_var == 0) {
env_var = push_array(arena, LNK_EnvVar, 1);
env_var->raw_value = value;
env_var->rule = rule;
hash_map_push_path_raw(arena, env_vars, key, env_var);
}
return env_var;
}
internal LNK_EnvVar *
lnk_env_var_push_string(Arena *arena, HashMap *env_vars, String8 string, LNK_EnvVarRule rule)
{
LNK_EnvVar *result = 0;
string = str8_skip_chop_whitespace(string);
// string -> (key, value)
String8 key = {0};
String8 val = {0};
switch (rule) {
case LNK_EnvVarRule_Batch: {
if (string.size >= 2) {
if (str8_match_wildcard(string, str8_lit("\"*\""), 0)) {
string = str8_chop(str8_skip(string, 1), 1);
}
}
U64 sep_idx = str8_find_needle(string, 0, str8_lit("="), 0);
if (sep_idx < string.size) {
// extract key and value
key = str8_skip_chop_whitespace(str8_prefix(string, sep_idx));
val = str8_skip_chop_whitespace(str8_skip(string, sep_idx+1));
// strip quotes
if (str8_match_wildcard(val, str8_lit("\"*\""), 0) || // "*"
str8_match_wildcard(val, str8_lit("\'*\'"), 0)) { // '*'
val = str8_chop(str8_skip(val, 1), 1);
}
}
} break;
case LNK_EnvVarRule_Bash: {
U64 sep_idx = str8_find_needle(string, 0, str8_lit("="), 0);
if (sep_idx < string.size) {
// extract key and value
key = str8_skip_chop_whitespace(str8_prefix(string, sep_idx));
val = str8_skip_chop_whitespace(str8_skip(string, sep_idx+1));
// strip quotes
if (str8_match_wildcard(val, str8_lit("\"*\""), 0) || // "*"
str8_match_wildcard(val, str8_lit("\'*\'"), 0)) { // '*'
val = str8_chop(str8_skip(val, 1), 1);
}
}
} break;
default: break;
}
if (key.size > 0) {
result = lnk_env_var_push(arena, env_vars, key, val, rule);
}
return result;
}
internal LNK_EnvVar *
lnk_env_var_push_batch(Arena *arena, HashMap *env_vars, String8 string)
{
return lnk_env_var_push_string(arena, env_vars, string, LNK_EnvVarRule_Batch);
}
internal LNK_EnvVar *
lnk_env_var_push_bash(Arena *arena, HashMap *env_vars, String8 string)
{
return lnk_env_var_push_string(arena, env_vars, string, LNK_EnvVarRule_Bash);
}
internal LNK_EnvVar *
lnk_env_var_batchf(Arena *arena, HashMap *env_vars, char *fmt, ...)
{
va_list args;
va_start(args, fmt);
String8 string = push_str8fv(arena, fmt, args);
va_end(args);
LNK_EnvVar *result = lnk_env_var_push_string(arena, env_vars, string, LNK_EnvVarRule_Batch);
return result;
}
internal LNK_EnvVar *
lnk_env_var_bashf(Arena *arena, HashMap *env_vars, char *fmt, ...)
{
va_list args;
va_start(args, fmt);
String8 string = push_str8fv(arena, fmt, args);
va_end(args);
LNK_EnvVar *result = lnk_env_var_push_string(arena, env_vars, string, LNK_EnvVarRule_Bash);
return result;
}
internal LNK_EnvVar *
lnk_env_var_from_mapf(HashMap *env_vars, char *fmt, ...)
{
Temp scratch = scratch_begin(0,0);
va_list args;
va_start(args, fmt);
String8 key = push_str8fv(scratch.arena, fmt, args);
va_end(args);
LNK_EnvVar *result = hash_map_search_path_raw(env_vars, key);
scratch_end(scratch);
return result;
}
internal LNK_EnvVar *
lnk_env_var_from_map(HashMap *env_vars, String8 key)
{
return hash_map_search_path_raw(env_vars, key);
}
internal String8List
lnk_value_list_from_env_var(Arena *arena, LNK_EnvVar *env_var)
{
return str8_split_by_string_chars(arena, env_var->raw_value, lnk_env_var_chain_separator_from_rule(env_var->rule), 0);
}
internal B32
lnk_env_var_to_u64(HashMap *env_vars, LNK_EnvVar *env_var, U64 *value_out)
{
String8 value = str8_skip_chop_whitespace(env_var->raw_value);
if (str8_match_wildcard(value, str8_lit("\"*\""), 0) ||
str8_match_wildcard(value, str8_lit("\'*\'"), 0)) {
value = str8_chop(str8_skip(value, 1), 1);
}
return try_u64_from_str8_c_rules(value, value_out);
}
internal String8
lnk_expand_env_vars_windows(Arena *arena, HashMap *env_vars, String8 string)
{ {
Temp scratch = scratch_begin(&arena, 1); Temp scratch = scratch_begin(&arena, 1);
@@ -260,9 +437,9 @@ lnk_expand_env_vars_windows(Arena *arena, HashTable *env_vars, String8 string)
if (open < close) { if (open < close) {
String8 env_var_name = str8_substr(string, rng_1u64(open+1, close)); String8 env_var_name = str8_substr(string, rng_1u64(open+1, close));
BucketNode *match = hash_table_search_path(env_vars, env_var_name); LNK_EnvVar *env_var = lnk_env_var_from_map(env_vars, env_var_name);
if (match) { if (env_var) {
str8_list_push(scratch.arena, &list, match->v.value_string); str8_list_push(scratch.arena, &list, env_var->raw_value);
i = close+1; i = close+1;
} else { } else {
str8_list_pushf(scratch.arena, &list, "%%%S", env_var_name); str8_list_pushf(scratch.arena, &list, "%%%S", env_var_name);
@@ -277,3 +454,13 @@ lnk_expand_env_vars_windows(Arena *arena, HashTable *env_vars, String8 string)
return result; return result;
} }
internal HashMap
lnk_env_vars_from_process_info(Arena *arena, ProcessInfo *proc_info, LNK_EnvVarRule rule)
{
HashMap env_vars = {0};
for EachNode(node, String8Node, proc_info->environment.first) {
lnk_env_var_push_string(arena, &env_vars, str8_copy(arena, node->string), rule);
}
return env_vars;
}
+45 -7
View File
@@ -19,18 +19,56 @@ typedef struct LNK_CmdLine
String8List raw_cmd_line; String8List raw_cmd_line;
} LNK_CmdLine; } LNK_CmdLine;
typedef enum LNK_EnvVarRule
{
LNK_EnvVarRule_Null,
LNK_EnvVarRule_Batch,
LNK_EnvVarRule_Bash,
#if OS_WINDOWS
LNK_EnvVarRule_Current,
#elif OS_LINUX
LNK_EnvVarRule_Current,
#else
# error "define env var rules"
#endif
} LNK_EnvVarRule;
typedef struct LNK_EnvVar
{
LNK_EnvVarRule rule;
String8 raw_value;
String8List chain_values;
} LNK_EnvVar;
// --- List Helpers ------------------------------------------------------------
internal void lnk_cmd_line_concat_in_place(LNK_CmdLine *list, LNK_CmdLine *to_concat);
// --- Command Line ------------------------------------------------------------
internal String8List lnk_arg_list_parse_windows_rules (Arena *arena, String8 string); internal String8List lnk_arg_list_parse_windows_rules (Arena *arena, String8 string);
internal LNK_CmdLine lnk_cmd_line_parse_windows_rules (Arena *arena, String8List arg_list); internal LNK_CmdLine lnk_cmd_line_parse_windows_rules (Arena *arena, String8List arg_list);
internal LNK_CmdLine lnk_cmd_line_from_stringfv_windows_rules(Arena *arena, char *fmt, va_list args);
internal LNK_CmdLine lnk_cmd_line_from_stringf_windows_rules (Arena *arena, char *fmt, ...);
internal LNK_CmdOption * lnk_cmd_line_push_option_list (Arena *arena, LNK_CmdLine *cmd_line, String8 string, String8List value_strings);
internal LNK_CmdOption * lnk_cmd_line_push_option (Arena *arena, LNK_CmdLine *cmd_line, char *string, char *value);
internal LNK_CmdOption * lnk_cmd_line_push_option_if_not_present (Arena *arena, LNK_CmdLine *cmd_line, char *string, char *value);
internal String8List lnk_data_from_cmd_line (Arena *arena, LNK_CmdLine cmd_line);
internal LNK_CmdOption * lnk_cmd_line_option_from_string (LNK_CmdLine cmd_line, String8 string); internal LNK_CmdOption * lnk_cmd_line_option_from_string (LNK_CmdLine cmd_line, String8 string);
internal B32 lnk_cmd_line_has_option_string (LNK_CmdLine cmd_line, String8 string); internal B32 lnk_cmd_line_has_option_string (LNK_CmdLine cmd_line, String8 string);
internal B32 lnk_cmd_line_has_option (LNK_CmdLine cmd_line, char *string); internal B32 lnk_cmd_line_has_option (LNK_CmdLine cmd_line, char *string);
internal LNK_CmdOption * lnk_cmd_line_push_option(Arena *arena, LNK_CmdLine *cmd_line, char *string, char *value); // --- Env Vars ----------------------------------------------------------------
internal LNK_CmdOption * lnk_cmd_line_push_option_if_not_present(Arena *arena, LNK_CmdLine *cmd_line, char *string, char *value);
internal void lnk_cmd_line_concat_in_place(LNK_CmdLine *list, LNK_CmdLine *to_concat); internal HashMap lnk_env_vars_from_process_info(Arena *arena, ProcessInfo *proc_info, LNK_EnvVarRule rule);
internal String8List lnk_data_from_cmd_line(Arena *arena, LNK_CmdLine cmd_line);
internal String8 lnk_expand_env_vars_windows(Arena *arena, HashTable *env_vars, String8 string);
internal LNK_EnvVar * lnk_env_var_from_map (HashMap *env, String8 key);
internal LNK_EnvVar * lnk_env_var_from_mapf (HashMap *env, char *fmt, ...);
internal LNK_EnvVar * lnk_env_var_push (Arena *arena, HashMap *env, String8 key, String8 value, LNK_EnvVarRule rule);
internal LNK_EnvVar * lnk_env_var_push_string (Arena *arena, HashMap *env, String8 string, LNK_EnvVarRule rule);
internal LNK_EnvVar * lnk_env_var_push_batch (Arena *arena, HashMap *env, String8 string);
internal LNK_EnvVar * lnk_env_var_push_bash (Arena *arena, HashMap *env, String8 string);
internal LNK_EnvVar * lnk_env_var_pushf (Arena *arena, HashMap *env, LNK_EnvVarRule rule, char *fmt, ...);
internal String8List lnk_value_list_from_env_var(Arena *arena, LNK_EnvVar *env_var);
internal B32 lnk_env_var_to_u64 (HashMap *env, LNK_EnvVar *var, U64 *value_out);
internal String8 lnk_expand_env_vars_windows(Arena *arena, HashMap *env, String8 string);
+189 -114
View File
@@ -63,11 +63,15 @@ global read_only LNK_CmdSwitch g_cmd_switch_map[] =
{ LNK_CmdSwitch_Rad_Age, 0, "RAD_AGE", ":#", "Age embeded in EXE and PDB, used to validate incremental build. Default is 1." }, { LNK_CmdSwitch_Rad_Age, 0, "RAD_AGE", ":#", "Age embeded in EXE and PDB, used to validate incremental build. Default is 1." },
{ LNK_CmdSwitch_Rad_AltPchDir, 0, "RAD_ALT_PCH_DIR", ":PATH", "Alternative directory to search for PCH object files." }, { LNK_CmdSwitch_Rad_AltPchDir, 0, "RAD_ALT_PCH_DIR", ":PATH", "Alternative directory to search for PCH object files." },
//{ LNK_CmdSwitch_Rad_BuildExp, 0, "RAD_BUILD_EXP", "[:NO]", "Build export data." },
{ LNK_CmdSwitch_Rad_BuildInfo, 0, "RAD_BUILD_INFO", "", "Print build info and exit." }, { LNK_CmdSwitch_Rad_BuildInfo, 0, "RAD_BUILD_INFO", "", "Print build info and exit." },
{ LNK_CmdSwitch_Rad_BuildImpLib, 0, "RAD_BUILD_IMPLIB", "[:NO]", "Build import library." },
{ LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, 0, "RAD_CHECK_UNUSED_DELAY_LOAD_DLL", "[:NO]", "Check for unused delay load dlls." }, { LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, 0, "RAD_CHECK_UNUSED_DELAY_LOAD_DLL", "[:NO]", "Check for unused delay load dlls." },
{ LNK_CmdSwitch_Rad_DataDirCount, 0, "RAD_DATA_DIR_COUNT", ":#", "Internal default for PE optional header data directory count." },
{ LNK_CmdSwitch_Rad_Map, 0, "RAD_MAP", ":FILENAME", "Emit file with the output image's layout description." }, { LNK_CmdSwitch_Rad_Map, 0, "RAD_MAP", ":FILENAME", "Emit file with the output image's layout description." },
{ LNK_CmdSwitch_Rad_MapLinesForUnresolvedSymbols, 0, "RAD_MAP_LINES_FOR_UNRESOLVED_SYMBOLS", "[:NO]", "Use debug info to print source file location for unresolved symbol" }, { LNK_CmdSwitch_Rad_MapLinesForUnresolvedSymbols, 0, "RAD_MAP_LINES_FOR_UNRESOLVED_SYMBOLS", "[:NO]", "Use debug info to print source file location for unresolved symbol" },
{ LNK_CmdSwitch_Rad_MemoryMapFiles, 0, "RAD_MEMORY_MAP_FILES", "[:NO]", "When enabled, files are memory-mapped instead of being read entirely on request." }, { LNK_CmdSwitch_Rad_MemoryMapFiles, 0, "RAD_MEMORY_MAP_FILES", "[:{NO|READ_ONLY|READ_WRITE}]", "When enabled, files are memory-mapped instead of being read entirely on request." },
{ LNK_CmdSwitch_Rad_BootMode, 0, "RAD_BOOT_MODE", "[:LINKER|TYPE_SERVER]", "Overrides default boot program." },
{ LNK_CmdSwitch_Rad_Debug, 0, "RAD_DEBUG", "[:NO]", "Emit RAD debug info file." }, { LNK_CmdSwitch_Rad_Debug, 0, "RAD_DEBUG", "[:NO]", "Emit RAD debug info file." },
{ LNK_CmdSwitch_Rad_DebugAltPath, 0, "RAD_DEBUGALTPATH", ":PATH", "Alternative output path fof the RDI." }, { LNK_CmdSwitch_Rad_DebugAltPath, 0, "RAD_DEBUGALTPATH", ":PATH", "Alternative output path fof the RDI." },
{ LNK_CmdSwitch_Rad_DebugName, 0, "RAD_DEBUG_NAME", ":FILENAME", "Set file name for RAD debug info file." }, { LNK_CmdSwitch_Rad_DebugName, 0, "RAD_DEBUG_NAME", ":FILENAME", "Set file name for RAD debug info file." },
@@ -98,6 +102,10 @@ global read_only LNK_CmdSwitch g_cmd_switch_map[] =
{ LNK_CmdSwitch_Rad_UnresolvedSymbolRefLimit, 0, "RAD_UNRESOLVED_SYMBOL_REF_LIMIT", ":#", "Limit number of unresolved symbol references linker reports." }, { LNK_CmdSwitch_Rad_UnresolvedSymbolRefLimit, 0, "RAD_UNRESOLVED_SYMBOL_REF_LIMIT", ":#", "Limit number of unresolved symbol references linker reports." },
{ LNK_CmdSwitch_Rad_Version, 0, "RAD_VERSION", "", "Print version and exit." }, { LNK_CmdSwitch_Rad_Version, 0, "RAD_VERSION", "", "Print version and exit." },
{ LNK_CmdSwitch_Rad_Workers, 0, "RAD_WORKERS", ":#", "Set number of workers created in the pool. Number is capped at 1024. When /RAD_SHARED_THREAD_POOL is specified this number cant exceed /RAD_SHARED_THREAD_POOL_MAX_WORKERS." }, { LNK_CmdSwitch_Rad_Workers, 0, "RAD_WORKERS", ":#", "Set number of workers created in the pool. Number is capped at 1024. When /RAD_SHARED_THREAD_POOL is specified this number cant exceed /RAD_SHARED_THREAD_POOL_MAX_WORKERS." },
{ LNK_CmdSwitch_Rad_WorkDir, 0, "RAD_WORK_DIR", ":PATH", "Working directory used for stable debug paths." },
{ LNK_CmdSwitch_RadTypeServer, 0, "RAD_TYPE_SERVER", "", "Boot in type server mode." },
{ LNK_CmdSwitch_RadTypeServer_MatchObj, 0, "RAD_TYPE_SERVER_MATCH_OBJ", ":OBJ_PATH", "Obj paths that match OBJ_PATH have their type server replaced." },
{ LNK_CmdSwitch_Help, 0, "HELP", "", "" }, { LNK_CmdSwitch_Help, 0, "HELP", "", "" },
{ LNK_CmdSwitch_Help, 0, "?", "", "" }, { LNK_CmdSwitch_Help, 0, "?", "", "" },
@@ -210,32 +218,18 @@ lnk_type_name_hash_mode_from_string(String8 name)
return LNK_TypeNameHashMode_Null; return LNK_TypeNameHashMode_Null;
} }
internal LNK_CmdOption * internal String8List
lnk_cmd_line_push_option_if_not_presentf(Arena *arena, LNK_CmdLine *cmd_line, LNK_CmdSwitchType cmd_switch_type, char *param_fmt, ...) lnk_cmd_line_values_from_switch(Arena *arena, LNK_CmdLine cmd_line, LNK_CmdSwitchType cmd_switch)
{ {
LNK_CmdOption *opt = 0; String8List values = {0};
String8 cmd_switch_name = lnk_string_from_cmd_switch_type(cmd_switch_type);
if (!lnk_cmd_line_has_option_string(*cmd_line, cmd_switch_name)) {
va_list param_args;
va_start(param_args, param_fmt);
String8 param_str = push_str8fv(arena, param_fmt, param_args);
va_end(param_args);
opt = lnk_cmd_line_push_option_string(arena, cmd_line, cmd_switch_name, param_str);
}
return opt;
}
internal LNK_CmdOption *
lnk_cmd_line_push_optionf(Arena *arena, LNK_CmdLine *cmd_line, LNK_CmdSwitchType cmd_switch, char *param_fmt, ...)
{
va_list param_args;
va_start(param_args, param_fmt);
String8 param_str = push_str8fv(arena, param_fmt, param_args);
va_end(param_args);
String8 cmd_switch_name = lnk_string_from_cmd_switch_type(cmd_switch); String8 cmd_switch_name = lnk_string_from_cmd_switch_type(cmd_switch);
LNK_CmdOption *opt = lnk_cmd_line_push_option_string(arena, cmd_line, cmd_switch_name, param_str); for EachNode(cmd, LNK_CmdOption, cmd_line.first_option) {
return opt; if (str8_match(cmd->string, cmd_switch_name, StringMatchFlag_CaseInsensitive)) {
String8List value_strings = str8_list_copy(arena, &cmd->value_strings);
str8_list_concat_in_place(&values, &value_strings);
}
}
return values;
} }
internal B32 internal B32
@@ -363,7 +357,7 @@ lnk_cmd_switch_parse_tuple(LNK_Obj *obj, LNK_CmdSwitchType cmd_switch, String8Li
tuple_out->v[1] = b; tuple_out->v[1] = b;
return 1; return 1;
} else { } else {
lnk_error_cmd_switch(LNK_Error_Cmdl, obj, cmd_switch, "unable ot parse second parameter \"%S\"", value_strings.last->string); lnk_error_cmd_switch(LNK_Error_Cmdl, obj, cmd_switch, "unable to parse second parameter \"%S\"", value_strings.last->string);
} }
} else { } else {
lnk_error_cmd_switch(LNK_Error_Cmdl, obj, cmd_switch, "unable to parse first parameter \"%S\"", value_strings.first->string); lnk_error_cmd_switch(LNK_Error_Cmdl, obj, cmd_switch, "unable to parse first parameter \"%S\"", value_strings.first->string);
@@ -930,7 +924,7 @@ lnk_is_section_removed(LNK_Config *config, String8 section_name)
internal B32 internal B32
lnk_is_dll_delay_load(LNK_Config *config, String8 dll_name) lnk_is_dll_delay_load(LNK_Config *config, String8 dll_name)
{ {
return hash_table_search_path_u64(config->delay_load_ht, dll_name, 0); return hash_map_search_path_u64(&config->delay_load_ht, dll_name) != 0;
} }
internal String8 internal String8
@@ -954,21 +948,21 @@ internal void
lnk_push_disallow_lib(LNK_Config *config, String8 path) lnk_push_disallow_lib(LNK_Config *config, String8 path)
{ {
String8 lib_name = lnk_get_lib_name(path); String8 lib_name = lnk_get_lib_name(path);
hash_table_push_path_u64(config->arena, config->disallow_lib_ht, lib_name, 0); hash_map_push_path_u64(config->arena, &config->disallow_lib_ht, lib_name, 1);
} }
internal B32 internal B32
lnk_is_lib_disallowed(LNK_Config *config, String8 path) lnk_is_lib_disallowed(LNK_Config *config, String8 path)
{ {
String8 lib_name = lnk_get_lib_name(path); String8 lib_name = lnk_get_lib_name(path);
return hash_table_search_path(config->disallow_lib_ht, lib_name) != 0; return hash_map_search_path_u64(&config->disallow_lib_ht, lib_name) != 0;
} }
internal void internal void
lnk_include_symbol(LNK_Config *config, String8 name, LNK_Obj *obj) lnk_include_symbol(LNK_Config *config, String8 name, LNK_Obj *obj)
{ {
// is this a duplicate symbol? // is this a duplicate symbol?
if (hash_table_search_string_raw(config->include_symbol_ht, name)) { if (hash_map_search_string_raw(&config->include_symbol_ht, name)) {
return; return;
} }
@@ -981,7 +975,7 @@ lnk_include_symbol(LNK_Config *config, String8 name, LNK_Obj *obj)
SLLQueuePush(config->include_symbol_list.first, config->include_symbol_list.last, node); SLLQueuePush(config->include_symbol_list.first, config->include_symbol_list.last, node);
config->include_symbol_list.count += 1; config->include_symbol_list.count += 1;
hash_table_push_string_raw(config->arena, config->include_symbol_ht, name, node); hash_map_push_string_raw(config->arena, &config->include_symbol_ht, name, node);
} }
internal void internal void
@@ -1117,6 +1111,23 @@ lnk_unwrap_rsp(Arena *arena, String8List arg_list)
return result; return result;
} }
internal void
lnk_apply_write_temp_files(Arena *arena, LNK_Config *config)
{
if (config->rad_chunk_map_name.size) {
config->temp_rad_chunk_map_name = push_str8f(arena, "%S.tmp%x", config->rad_chunk_map_name, config->time_stamp);
}
if (config->out_path.size) {
config->temp_out_path = push_str8f(arena, "%S.tmp%x", config->out_path, config->time_stamp);
}
if (config->pdb_name.size) {
config->temp_pdb_name = push_str8f(arena, "%S.tmp%x", config->pdb_name, config->time_stamp);
}
if (config->rad_debug_name.size) {
config->temp_rad_debug_name = push_str8f(arena, "%S.tmp%x", config->rad_debug_name, config->time_stamp);
}
}
internal void internal void
lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List value_strings, LNK_Obj *obj) lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List value_strings, LNK_Obj *obj)
{ {
@@ -1153,19 +1164,19 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
if (value_strings.node_count == 1) { if (value_strings.node_count == 1) {
LNK_AltName alt_name; LNK_AltName alt_name;
if (lnk_parse_alt_name_directive(value_strings.first->string, obj, &alt_name)) { if (lnk_parse_alt_name_directive(value_strings.first->string, obj, &alt_name)) {
String8 to_extant = {0}; String8 *to_extant = hash_map_search_string_string(&config->alt_name_ht, alt_name.from);
if (hash_table_search_string_string(config->alt_name_ht, alt_name.from, &to_extant)) { if (to_extant) {
if (str8_match(to_extant, alt_name.to, 0)) { if (str8_match(*to_extant, alt_name.to, 0)) {
// ignore, duplicate // ignore, duplicate
} else { } else {
lnk_error_obj(LNK_Error_AlternateNameConflict, obj, "conflicting alternative name: existing '%S=%S' vs. new '%S=%S'", alt_name.from, to_extant, alt_name.from, alt_name.to); lnk_error_obj(LNK_Error_AlternateNameConflict, obj, "conflicting alternative name: existing '%S=%S' vs. new '%S=%S'", alt_name.from, *to_extant, alt_name.from, alt_name.to);
} }
} else { } else {
alt_name.from = push_str8_copy(config->arena, alt_name.from); alt_name.from = push_str8_copy(config->arena, alt_name.from);
alt_name.to = push_str8_copy(config->arena, alt_name.to); alt_name.to = push_str8_copy(config->arena, alt_name.to);
lnk_alt_name_list_push(config->arena, &config->alt_name_list, alt_name); lnk_alt_name_list_push(config->arena, &config->alt_name_list, alt_name);
hash_table_push_string_string(config->arena, config->alt_name_ht, alt_name.from, alt_name.to); hash_map_push_string_string(config->arena, &config->alt_name_ht, alt_name.from, alt_name.to);
} }
} }
} else { } else {
@@ -1252,9 +1263,9 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
case LNK_CmdSwitch_DelayLoad: { case LNK_CmdSwitch_DelayLoad: {
for (String8Node *name_n = value_strings.first; name_n != 0; name_n = name_n->next) { for (String8Node *name_n = value_strings.first; name_n != 0; name_n = name_n->next) {
if (hash_table_search_path_u64(config->delay_load_ht, name_n->string, 0)) { continue; } if (hash_map_search_path_u64(&config->delay_load_ht, name_n->string)) { continue; }
String8 name = push_str8_copy(config->arena, name_n->string); String8 name = push_str8_copy(config->arena, name_n->string);
hash_table_push_path_u64(config->arena, config->delay_load_ht, name, 0); hash_map_push_path_u64(config->arena, &config->delay_load_ht, name, 1);
str8_list_push(config->arena, &config->delay_load_dll_list, name); str8_list_push(config->arena, &config->delay_load_dll_list, name);
} }
} break; } break;
@@ -1283,7 +1294,7 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
PE_ExportParse export_parse = {0}; PE_ExportParse export_parse = {0};
if (lnk_parse_export_directive_ex(config->arena, value_strings, obj, &export_parse)) { if (lnk_parse_export_directive_ex(config->arena, value_strings, obj, &export_parse)) {
String8 export_name = pe_name_from_export_parse(&export_parse); String8 export_name = pe_name_from_export_parse(&export_parse);
PE_ExportParseNode *exp_n = hash_table_search_string_raw(config->export_ht, export_name); PE_ExportParseNode *exp_n = hash_map_search_string_raw(&config->export_ht, export_name);
if (exp_n == 0) { if (exp_n == 0) {
// make sure export is defined // make sure export is defined
@@ -1294,7 +1305,7 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
// push new export // push new export
exp_n = pe_export_parse_list_push(config->arena, &config->export_symbol_list, export_parse); exp_n = pe_export_parse_list_push(config->arena, &config->export_symbol_list, export_parse);
hash_table_push_string_raw(config->arena, config->export_ht, export_name, exp_n); hash_map_push_string_raw(config->arena, &config->export_ht, export_name, exp_n);
} else { } else {
B32 is_ambiguous = 1; B32 is_ambiguous = 1;
PE_ExportParse *extant_export = &exp_n->data; PE_ExportParse *extant_export = &exp_n->data;
@@ -1332,7 +1343,7 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
break; break;
} }
LNK_AltName *current = hash_table_search_string_raw(config->fail_if_mismatch_ht, dir.from); LNK_AltName *current = hash_map_search_string_raw(&config->fail_if_mismatch_ht, dir.from);
if (current) { if (current) {
if ( ! str8_match(current->to, dir.to, 0)) { if ( ! str8_match(current->to, dir.to, 0)) {
lnk_error_cmd_switch(LNK_Error_FailIfMismatch, obj, cmd_switch, lnk_error_cmd_switch(LNK_Error_FailIfMismatch, obj, cmd_switch,
@@ -1347,7 +1358,7 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
n->from = push_str8_copy(config->arena, dir.from); n->from = push_str8_copy(config->arena, dir.from);
n->to = push_str8_copy(config->arena, dir.to); n->to = push_str8_copy(config->arena, dir.to);
n->obj = obj; n->obj = obj;
hash_table_push_string_raw(config->arena, config->fail_if_mismatch_ht, n->from, n); hash_map_push_string_raw(config->arena, &config->fail_if_mismatch_ht, n->from, n);
} }
} break; } break;
@@ -1616,10 +1627,10 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
} else { } else {
for (String8Node *lib_n = value_strings.first; lib_n != 0; lib_n = lib_n->next) { for (String8Node *lib_n = value_strings.first; lib_n != 0; lib_n = lib_n->next) {
String8 lib_name = lnk_get_lib_name(lib_n->string); String8 lib_name = lnk_get_lib_name(lib_n->string);
if (hash_table_search_path_raw(config->disallow_lib_ht, lib_name)) { if (hash_map_search_path_u64(&config->disallow_lib_ht, lib_name)) {
continue; continue;
} }
hash_table_push_path_raw(config->arena, config->disallow_lib_ht, lib_name, 0); hash_map_push_path_u64(config->arena, &config->disallow_lib_ht, lib_name, 1);
} }
} }
} break; } break;
@@ -1782,7 +1793,7 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
String8 lib_name; String8 lib_name;
if (lnk_cmd_switch_parse_string(obj, cmd_switch, value_strings, &lib_name)) { if (lnk_cmd_switch_parse_string(obj, cmd_switch, value_strings, &lib_name)) {
lib_name = str8_chop_last_dot(str8_skip_last_slash(lib_name)); lib_name = str8_chop_last_dot(str8_skip_last_slash(lib_name));
hash_table_push_path_string(config->arena, config->whole_archive_ht, lib_name, str8_zero()); hash_map_push_path_u64(config->arena, &config->whole_archive_ht, lib_name, 1);
} }
} }
} break; } break;
@@ -1800,15 +1811,40 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
str8_list_concat_in_place(&config->alt_pch_dirs, &dirs); str8_list_concat_in_place(&config->alt_pch_dirs, &dirs);
} break; } break;
//case LNK_CmdSwitch_Rad_BuildExp: {
// LNK_SwitchState state;
// if (lnk_cmd_switch_parse_flag(obj, cmd_switch, value_strings, &state)) {
// config->build_exp = (state == LNK_SwitchState_Yes);
// }
//} break;
case LNK_CmdSwitch_Rad_BuildInfo: { case LNK_CmdSwitch_Rad_BuildInfo: {
lnk_print_build_info(); lnk_print_build_info();
abort_self(0); abort_self(0);
} break; } break;
case LNK_CmdSwitch_Rad_BuildImpLib: {
LNK_SwitchState state;
if (lnk_cmd_switch_parse_flag(obj, cmd_switch, value_strings, &state)) {
config->build_imp_lib = (state == LNK_SwitchState_Yes);
}
} break;
case LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll: { case LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll: {
lnk_cmd_switch_set_flag_64(obj, cmd_switch, value_strings, &config->flags, LNK_ConfigFlag_CheckUnusedDelayLoadDll); lnk_cmd_switch_set_flag_64(obj, cmd_switch, value_strings, &config->flags, LNK_ConfigFlag_CheckUnusedDelayLoadDll);
} break; } break;
case LNK_CmdSwitch_Rad_DataDirCount: {
U64 data_dir_count = 0;
if (lnk_cmd_switch_parse_u64(obj, cmd_switch, value_strings, &data_dir_count, LNK_ParseU64Flag_CheckUnder32bit)) {
if (1 <= data_dir_count && data_dir_count <= PE_DataDirectoryIndex_COUNT) {
config->data_dir_count = data_dir_count;
} else {
lnk_error_cmd_switch(LNK_Error_Cmdl, obj, cmd_switch, "invalid data directory count %llu, expected 1 through %u", data_dir_count, PE_DataDirectoryIndex_COUNT);
}
}
} break;
case LNK_CmdSwitch_Rad_Map: { case LNK_CmdSwitch_Rad_Map: {
lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->rad_chunk_map_name); lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->rad_chunk_map_name);
config->rad_chunk_map = LNK_SwitchState_Yes; config->rad_chunk_map = LNK_SwitchState_Yes;
@@ -1819,7 +1855,39 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
} break; } break;
case LNK_CmdSwitch_Rad_MemoryMapFiles: { case LNK_CmdSwitch_Rad_MemoryMapFiles: {
lnk_cmd_switch_set_flag_32(obj, cmd_switch, value_strings, &config->io_flags, LNK_IO_Flags_MemoryMapFiles); if (value_strings.node_count == 0) {
config->io_flags &= ~LNK_IO_Flags_MemoryMapFilesReadWrite;
config->io_flags |= LNK_IO_Flags_MemoryMapFilesReadOnly;
} else if (value_strings.node_count == 1) {
String8 value = value_strings.first->string;
if (str8_matchi(value, str8_lit("no"))) {
config->io_flags &= ~(LNK_IO_Flags_MemoryMapFilesReadOnly|LNK_IO_Flags_MemoryMapFilesReadWrite);
} else if (str8_matchi(value, str8_lit("yes")) || str8_matchi(value, str8_lit("read_only"))) {
config->io_flags &= ~LNK_IO_Flags_MemoryMapFilesReadWrite;
config->io_flags |= LNK_IO_Flags_MemoryMapFilesReadOnly;
} else if (str8_matchi(value, str8_lit("read_write"))) {
config->io_flags &= ~LNK_IO_Flags_MemoryMapFilesReadOnly;
config->io_flags |= LNK_IO_Flags_MemoryMapFilesReadWrite;
} else {
lnk_error_cmd_switch(LNK_Error_Cmdl, obj, cmd_switch, "invalid parameter: \"%S\", expected NO, READ_ONLY, or READ_WRITE", value);
}
} else {
lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, obj, cmd_switch);
}
} break;
case LNK_CmdSwitch_Rad_BootMode: {
if (value_strings.node_count == 1) {
if (str8_matchi(value_strings.first->string, str8_lit("linker"))) {
config->boot_mode = LNK_BootMode_Linker;
} else if (str8_matchi(value_strings.first->string, str8_lit("type_server"))) {
config->boot_mode = LNK_BootMode_TypeServer;
} else {
lnk_error_cmd_switch(LNK_Error_Boot, obj, cmd_switch, "unknown value: \"%S\".", value_strings.first->string);
}
} else {
lnk_error_cmd_switch_invalid_param_count(LNK_Error_Boot, obj, cmd_switch);
}
} break; } break;
case LNK_CmdSwitch_Rad_Debug: { case LNK_CmdSwitch_Rad_Debug: {
@@ -2049,6 +2117,9 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
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);
if (config->write_temp_files == LNK_SwitchState_Yes) {
lnk_apply_write_temp_files(config->arena, config);
}
} break; } break;
case LNK_CmdSwitch_Rad_TimeStamp: { case LNK_CmdSwitch_Rad_TimeStamp: {
@@ -2086,17 +2157,47 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
} }
} break; } break;
case LNK_CmdSwitch_Rad_WorkDir: {
lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->work_dir);
} break;
case LNK_CmdSwitch_Help: { case LNK_CmdSwitch_Help: {
lnk_print_help(); lnk_print_help();
abort_self(0); abort_self(0);
} break; } break;
case LNK_CmdSwitch_RadTypeServer: {
if (lnk_cmd_switch_parse_flag(obj, cmd_switch, value_strings, &config->type_server)) {
if (config->type_server == LNK_SwitchState_Yes) {
config->boot_mode = LNK_BootMode_TypeServer;
}
}
} break;
case LNK_CmdSwitch_RadTypeServer_MatchObj: {
String8List value_strings_copy = str8_list_copy(config->arena, &value_strings);
str8_list_concat_in_place(&config->type_server_match_obj, &value_strings_copy);
} break;
} }
scratch_end(scratch); scratch_end(scratch);
} }
internal void
lnk_config_pushf(LNK_Config *config, char *fmt, ...)
{
va_list args;
va_start(args, fmt);
LNK_CmdLine cmd_line = lnk_cmd_line_from_stringfv_windows_rules(config->arena, fmt, args);
va_end(args);
for EachNode(cmd, LNK_CmdOption, cmd_line.first_option) {
lnk_apply_cmd_option_to_config(config, cmd->string, cmd->value_strings, &(LNK_Obj){0});
}
}
internal LNK_Config * internal LNK_Config *
lnk_config_from_cmd_line(String8List raw_cmd_line, LNK_CmdLine cmd_line) lnk_config_init(LNK_CmdLine cmd_line)
{ {
ProfBeginFunction(); ProfBeginFunction();
Temp scratch = scratch_begin(0,0); Temp scratch = scratch_begin(0,0);
@@ -2104,40 +2205,25 @@ lnk_config_from_cmd_line(String8List raw_cmd_line, LNK_CmdLine cmd_line)
Arena *arena = arena_alloc(); Arena *arena = arena_alloc();
LNK_Config *config = push_array(arena, LNK_Config, 1); LNK_Config *config = push_array(arena, LNK_Config, 1);
config->arena = arena; config->arena = arena;
config->raw_cmd_line = str8_list_copy(arena, &raw_cmd_line); config->raw_cmd_line = str8_list_copy(arena, &cmd_line.raw_cmd_line);
config->work_dir = get_current_path(arena); config->work_dir = get_current_path(arena);
config->build_imp_lib = 1;
config->build_exp = 1;
config->heap_reserve = MB(1);
config->heap_commit = KB(4);
config->stack_reserve = MB(1);
config->stack_commit = KB(4);
config->pdb_hash_type_names = LNK_TypeNameHashMode_None;
config->pdb_hash_type_name_length = 8;
config->data_dir_count = PE_DataDirectoryIndex_COUNT;
config->export_ht = hash_table_init(arena, max_U16/2);
config->alt_name_ht = hash_table_init(arena, 0x100);
config->include_symbol_ht = hash_table_init(arena, 0x100);
config->delay_load_ht = hash_table_init(arena, 0x100);
config->disallow_lib_ht = hash_table_init(arena, 0x100);
config->fail_if_mismatch_ht = hash_table_init(arena, 0x100);
config->whole_archive_ht = hash_table_init(arena, 0x100);
// process command line switches // apply command line switches
for (LNK_CmdOption *cmd = cmd_line.first_option; cmd != 0; cmd = cmd->next) { for EachNode(cmd, LNK_CmdOption, cmd_line.first_option) {
lnk_apply_cmd_option_to_config(config, cmd->string, cmd->value_strings, 0); lnk_apply_cmd_option_to_config(config, cmd->string, cmd->value_strings, 0);
} }
// in shared thread pool mode force fixed number of workers
if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Rad_SharedThreadPool) &&
!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers)) {
config->max_worker_count = get_system_info()->logical_processor_count;
}
// :manifest_input // :manifest_input
if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ManifestInput)) { if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ManifestInput)) {
if (config->manifest_opt == LNK_ManifestOpt_Embed) { if (config->manifest_opt == LNK_ManifestOpt_Embed) {
for (LNK_CmdOption *cmd = cmd_line.first_option; cmd != 0; cmd = cmd->next) { String8List manifest_list = lnk_cmd_line_values_from_switch(arena, cmd_line, LNK_CmdSwitch_ManifestInput);
LNK_CmdSwitchType cmd_switch = lnk_cmd_switch_type_from_string(cmd->string);
if (cmd_switch == LNK_CmdSwitch_ManifestInput) {
String8List manifest_list = str8_list_copy(arena, &cmd->value_strings);
str8_list_concat_in_place(&config->input_list[LNK_Input_Manifest], &manifest_list); str8_list_concat_in_place(&config->input_list[LNK_Input_Manifest], &manifest_list);
}
}
} else { } else {
lnk_error_cmd_switch(LNK_Error_Cmdl, 0, LNK_CmdSwitch_ManifestInput, "missing /MANIFEST:EMBED"); lnk_error_cmd_switch(LNK_Error_Cmdl, 0, LNK_CmdSwitch_ManifestInput, "missing /MANIFEST:EMBED");
} }
@@ -2153,7 +2239,7 @@ lnk_config_from_cmd_line(String8List raw_cmd_line, LNK_CmdLine cmd_line)
} }
// input files // input files
for (String8Node *input_node = cmd_line.input_list.first; input_node != 0; input_node = input_node->next) { for EachNode(input_node, String8Node, cmd_line.input_list.first) {
String8 path = push_str8_copy(arena, input_node->string); String8 path = push_str8_copy(arena, input_node->string);
String8 ext = str8_skip_last_dot(path); String8 ext = str8_skip_last_dot(path);
@@ -2285,57 +2371,46 @@ lnk_config_from_cmd_line(String8List raw_cmd_line, LNK_CmdLine cmd_line)
config->imp_lib_name = full_path_from_path(arena, config->imp_lib_name); config->imp_lib_name = full_path_from_path(arena, config->imp_lib_name);
config->manifest_name = full_path_from_path(arena, config->manifest_name); config->manifest_name = full_path_from_path(arena, config->manifest_name);
// collect env vars // set up env vars
HashTable *env_vars = hash_table_init(scratch.arena, 512); HashMap env_vars = lnk_env_vars_from_process_info(scratch.arena, get_process_info(), LNK_EnvVarRule_Batch);
{ {
#if OS_WINDOWS
ProcessInfo *process_info = get_process_info();
for (String8Node *node = process_info->environment.first; node != 0; node = node->next) {
String8List list = str8_split_by_string_chars(scratch.arena, node->string, str8_lit("="), 0);
String8 key = list.first->string;
String8 val = str8_zero();
if (list.node_count == 2) {
val = list.last->string;
} else if (list.node_count > 2) {
U64 sep_idx = str8_find_needle(node->string, node->string.size, str8_lit("="), 0);
val = str8_skip(node->string, sep_idx+1);
}
hash_table_push_path_string(scratch.arena, env_vars, key, val);
}
#endif
}
// 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)); struct { String8 key, value; } key_value_str8_table[] = {
hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_ext"), str8_skip_last_dot(config->out_path)); { str8_lit("_pdb"), str8_skip_last_slash(config->pdb_name) },
hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_rad_pdb_path"), config->pdb_name); { str8_lit("_ext"), str8_skip_last_dot(config->out_path) },
hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_rad_rdi"), str8_skip_last_slash(config->rad_debug_name)); { str8_lit("_rad_pdb_path"), config->pdb_name },
hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_rad_rdi_path"), config->rad_debug_name); { str8_lit("_rad_rdi"), str8_skip_last_slash(config->rad_debug_name) },
{ str8_lit("_radi_rdi_path"), config->rad_debug_name },
// collect LIB and LIBPATH };
if (config->flags & LNK_ConfigFlag_EnvLib) { for EachElement(i, key_value_str8_table) {
BucketNode *lib = hash_table_search_path(env_vars, str8_lit("lib")); if (lnk_env_var_from_map(&env_vars, key_value_str8_table[i].key)) {
if (lib) { lnk_log(LNK_Log_Debug, "Env var already exists: %S\n",key_value_str8_table[i].key);
String8List val_list = str8_split_by_string_chars(scratch.arena, lib->v.value_string, str8_lit(";"), 0); }
String8List val_list_copy = str8_list_copy(arena, &val_list); lnk_env_var_batchf(scratch.arena, &env_vars, "%S=%S", key_value_str8_table[i].key, key_value_str8_table[i].value);
str8_list_concat_in_place(&config->lib_dir_list, &val_list_copy);
} }
BucketNode *lib_path = hash_table_search_path(env_vars, str8_lit("libpath")); if (config->flags & LNK_ConfigFlag_EnvLib) {
if (lib_path) { // collect LIB and LIBPATH
String8List val_list = str8_split_by_string_chars(scratch.arena, lib->v.value_string, str8_lit(";"), 0); struct { String8List *config_list; char *key; } key_str8_list[] = {
String8List val_list_copy = str8_list_copy(arena, &val_list); { &config->lib_dir_list, "lib" },
str8_list_concat_in_place(&config->lib_dir_list, &val_list_copy); { &config->lib_dir_list, "lib_path" },
};
for EachElement(i, key_str8_list) {
LNK_EnvVar *var = lnk_env_var_from_mapf(&env_vars, key_str8_list[i].key);
if (var) {
String8List value = lnk_value_list_from_env_var(arena, var);
String8List value_copy = str8_list_copy(config->arena, &value);
str8_list_concat_in_place(key_str8_list[i].config_list, &value_copy);
}
}
} }
} }
// :PdbAltPath // :PdbAltPath
config->pdb_alt_path = lnk_expand_env_vars_windows(arena, env_vars, config->pdb_alt_path); config->pdb_alt_path = lnk_expand_env_vars_windows(arena, &env_vars, config->pdb_alt_path);
// :Rad_DebugAltPath // :Rad_DebugAltPath
config->rad_debug_alt_path = lnk_expand_env_vars_windows(arena, env_vars, config->rad_debug_alt_path); config->rad_debug_alt_path = lnk_expand_env_vars_windows(arena, &env_vars, config->rad_debug_alt_path);
// create temporary files names // create temporary files names
if (config->write_temp_files == LNK_SwitchState_Yes) { if (config->write_temp_files == LNK_SwitchState_Yes) {
+31 -14
View File
@@ -3,6 +3,13 @@
#pragma once #pragma once
// entry points
typedef enum
{
LNK_BootMode_Linker,
LNK_BootMode_TypeServer,
} LNK_BootMode;
#if OS_WINDOWS #if OS_WINDOWS
# define LNK_MANIFEST_MERGE_TOOL_NAME "mt.exe" # define LNK_MANIFEST_MERGE_TOOL_NAME "mt.exe"
#elif OS_LINUX || OS_MAC #elif OS_LINUX || OS_MAC
@@ -88,13 +95,16 @@ 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_BuildExp,
LNK_CmdSwitch_Rad_BuildInfo, LNK_CmdSwitch_Rad_BuildInfo,
LNK_CmdSwitch_Rad_BuildImpLib,
LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll,
LNK_CmdSwitch_Rad_DataDirCount,
LNK_CmdSwitch_Rad_Debug, LNK_CmdSwitch_Rad_Debug,
LNK_CmdSwitch_Rad_DebugAltPath, LNK_CmdSwitch_Rad_DebugAltPath,
LNK_CmdSwitch_Rad_BootMode,
LNK_CmdSwitch_Rad_DebugName, LNK_CmdSwitch_Rad_DebugName,
LNK_CmdSwitch_Rad_DelayBind, LNK_CmdSwitch_Rad_DelayBind,
LNK_CmdSwitch_Rad_DoMerge, LNK_CmdSwitch_Rad_DoMerge,
@@ -110,6 +120,7 @@ typedef enum
LNK_CmdSwitch_Rad_Map, LNK_CmdSwitch_Rad_Map,
LNK_CmdSwitch_Rad_MapLinesForUnresolvedSymbols, LNK_CmdSwitch_Rad_MapLinesForUnresolvedSymbols,
LNK_CmdSwitch_Rad_MemoryMapFiles, LNK_CmdSwitch_Rad_MemoryMapFiles,
LNK_CmdSwitch_Rad_Mode,
LNK_CmdSwitch_Rad_MtPath, LNK_CmdSwitch_Rad_MtPath,
LNK_CmdSwitch_Rad_OsVer, LNK_CmdSwitch_Rad_OsVer,
LNK_CmdSwitch_Rad_PageSize, LNK_CmdSwitch_Rad_PageSize,
@@ -126,7 +137,12 @@ typedef enum
LNK_CmdSwitch_Rad_UnresolvedSymbolRefLimit, LNK_CmdSwitch_Rad_UnresolvedSymbolRefLimit,
LNK_CmdSwitch_Rad_Version, LNK_CmdSwitch_Rad_Version,
LNK_CmdSwitch_Rad_Workers, LNK_CmdSwitch_Rad_Workers,
LNK_CmdSwitch_Rad_WorkDir,
LNK_CmdSwitch_Rad_WriteTempFiles, LNK_CmdSwitch_Rad_WriteTempFiles,
LNK_CmdSwitch_RadTypeServer,
LNK_CmdSwitch_RadTypeServer_MatchObj,
LNK_CmdSwitch_Help, LNK_CmdSwitch_Help,
LNK_CmdSwitch_Count LNK_CmdSwitch_Count
@@ -262,9 +278,11 @@ typedef enum
LNK_TypeNameHashMode_Full, LNK_TypeNameHashMode_Full,
} LNK_TypeNameHashMode; } LNK_TypeNameHashMode;
typedef struct LNK_Config typedef struct LNK_Config
{ {
Arena *arena; Arena *arena;
LNK_BootMode boot_mode;
LNK_ConfigFlags flags; LNK_ConfigFlags flags;
LNK_DebugMode debug_mode; LNK_DebugMode debug_mode;
B32 ghash; B32 ghash;
@@ -352,19 +370,21 @@ typedef struct LNK_Config
String8 delay_load_helper_name; String8 delay_load_helper_name;
String8List remove_sections; String8List remove_sections;
LNK_IO_Flags io_flags; LNK_IO_Flags io_flags;
HashTable *export_ht; HashMap export_ht;
HashTable *alt_name_ht; HashMap alt_name_ht;
HashTable *include_symbol_ht; HashMap include_symbol_ht;
HashTable *delay_load_ht; HashMap delay_load_ht;
HashTable *disallow_lib_ht; HashMap disallow_lib_ht;
HashTable *fail_if_mismatch_ht; HashMap fail_if_mismatch_ht;
HashTable *whole_archive_ht; HashMap whole_archive_ht;
B32 whole_archive_all; B32 whole_archive_all;
U64 unresolved_symbol_limit; U64 unresolved_symbol_limit;
U64 unresolved_symbol_ref_limit; U64 unresolved_symbol_ref_limit;
LNK_SwitchState map_lines_for_unresolved_symbols; LNK_SwitchState map_lines_for_unresolved_symbols;
String8List alt_pch_dirs; String8List alt_pch_dirs;
LLVM_GHashAlg type_hash_alg; LLVM_GHashAlg type_hash_alg;
LNK_SwitchState type_server;
String8List type_server_match_obj;
} LNK_Config; } LNK_Config;
// --- MSVC Error Codes -------------------------------------------------------- // --- MSVC Error Codes --------------------------------------------------------
@@ -503,11 +523,7 @@ internal LNK_InputType lnk_input_type_from_string(String8 string);
internal LNK_DebugMode lnk_debug_mode_from_string(String8 string); internal LNK_DebugMode lnk_debug_mode_from_string(String8 string);
internal LNK_TypeNameHashMode lnk_type_name_hash_mode_from_string(String8 string); internal LNK_TypeNameHashMode lnk_type_name_hash_mode_from_string(String8 string);
// --- Command Line Helpers ---------------------------------------------------- internal String8List lnk_cmd_line_values_from_switch(Arena *arena, LNK_CmdLine cmd_line, LNK_CmdSwitchType cmd_switch_type);
internal LNK_CmdOption * lnk_cmd_line_push_option_if_not_presentf(Arena *arena, LNK_CmdLine *cmd_line, LNK_CmdSwitchType cmd_switch_type, char *param_fmt, ...);
internal LNK_CmdOption * lnk_cmd_line_push_optionf (Arena *arena, LNK_CmdLine *cmd_line, LNK_CmdSwitchType cmd_switch_type, char *param_fmt, ...);
internal B32 lnk_cmd_line_has_switch (LNK_CmdLine cmd_line, LNK_CmdSwitchType cmd_switch_type); internal B32 lnk_cmd_line_has_switch (LNK_CmdLine cmd_line, LNK_CmdSwitchType cmd_switch_type);
// --- Errors ------------------------------------------------------------------ // --- Errors ------------------------------------------------------------------
@@ -564,6 +580,7 @@ internal void lnk_whole_archive(LNK_Config *config, String8 lib_name);
// --- Config ------------------------------------------------------------------ // --- Config ------------------------------------------------------------------
internal void lnk_apply_cmd_option_to_config(LNK_Config *config, String8 name, String8List value_list, struct LNK_Obj *obj); internal void lnk_apply_cmd_option_to_config(LNK_Config *config, String8 name, String8List value_list, struct LNK_Obj *obj);
internal void lnk_config_pushf(LNK_Config *config, char *fmt, ...);
internal LNK_Config * lnk_config_from_cmd_line(String8List raw_cmd_line, LNK_CmdLine cmd_line); internal LNK_Config * lnk_config_init(LNK_CmdLine cmd_line);
+16 -3
View File
@@ -2461,11 +2461,15 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task)
} }
internal String8List internal String8List
lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, String8 image_data, LNK_Config *config, LNK_SymbolTable *symtab, LNK_CodeViewInput *cv, LNK_MergedTypes cv_types) lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, String8 image_data, LNK_Config *config, LNK_SymbolTable *symtab, LNK_CodeViewInput *cv, LNK_MergedTypes cv_types, LNK_PDB_BuilderFlags builder_flags)
{ {
ProfBeginFunction(); ProfBeginFunction();
Temp scratch = scratch_begin(tp_arena->v, tp_arena->count); Temp scratch = scratch_begin(tp_arena->v, tp_arena->count);
if (builder_flags == LNK_PDB_BuilderFlag_All) {
builder_flags = ~0;
}
LNK_BuildPdb task = { LNK_BuildPdb task = {
.image_data = image_data, .image_data = image_data,
.symtab = symtab, .symtab = symtab,
@@ -2495,18 +2499,22 @@ lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, String8 image_data, LNK_Config
} }
// push types // push types
if (builder_flags & LNK_PDB_BuilderFlag_Ipi) {
pdb_type_server_push_parallel(tp, task.pdb->type_servers[CV_TypeIndexSource_IPI], cv_types.count[CV_TypeIndexSource_IPI], cv_types.v[CV_TypeIndexSource_IPI]); pdb_type_server_push_parallel(tp, task.pdb->type_servers[CV_TypeIndexSource_IPI], cv_types.count[CV_TypeIndexSource_IPI], cv_types.v[CV_TypeIndexSource_IPI]);
}
if (builder_flags & LNK_PDB_BuilderFlag_Tpi) {
pdb_type_server_push_parallel(tp, task.pdb->type_servers[CV_TypeIndexSource_TPI], cv_types.count[CV_TypeIndexSource_TPI], cv_types.v[CV_TypeIndexSource_TPI]); pdb_type_server_push_parallel(tp, task.pdb->type_servers[CV_TypeIndexSource_TPI], cv_types.count[CV_TypeIndexSource_TPI], cv_types.v[CV_TypeIndexSource_TPI]);
}
ProfBegin("Merge String Tables"); ProfBegin("Merge String Tables");
task.string_ht = cv_dedup_string_tables(tp_arena, tp, cv->obj_count, cv->debug_s_arr); task.string_ht = cv_dedup_string_tables(tp_arena, tp, cv->obj_count, cv->debug_s_arr);
cv_string_hash_table_assign_buffer_offsets(tp, task.string_ht); cv_string_hash_table_assign_buffer_offsets(tp, task.string_ht);
ProfEnd(); ProfEnd();
if (builder_flags & LNK_PDB_BuilderFlag_Modules) {
ProfScope ("Alloc Modules") ProfScope ("Alloc Modules")
for EachIndex(obj_idx, cv->obj_count) { for EachIndex(obj_idx, cv->obj_count)
task.mod_arr[obj_idx] = dbi_push_module(task.pdb->dbi, cv->obj_arr[obj_idx]->path, lnk_obj_get_lib_path(cv->obj_arr[obj_idx])); task.mod_arr[obj_idx] = dbi_push_module(task.pdb->dbi, cv->obj_arr[obj_idx]->path, lnk_obj_get_lib_path(cv->obj_arr[obj_idx]));
}
ProfScope("Move Global Symbols") ProfScope("Move Global Symbols")
tp_for_parallel(tp, 0, tp->worker_count, lnk_move_global_symbols_to_gsi, &task); tp_for_parallel(tp, 0, tp->worker_count, lnk_move_global_symbols_to_gsi, &task);
@@ -2516,11 +2524,13 @@ lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, String8 image_data, LNK_Config
ProfScope("Write Modules") ProfScope("Write Modules")
tp_for_parallel(tp, 0, tp->worker_count, lnk_write_pdb_modules, &task); tp_for_parallel(tp, 0, tp->worker_count, lnk_write_pdb_modules, &task);
}
ProfBegin("Add string tables"); ProfBegin("Add string tables");
pdb_strtab_add_cv_string_hash_table(&task.pdb->info->strtab, task.string_ht); pdb_strtab_add_cv_string_hash_table(&task.pdb->info->strtab, task.string_ht);
ProfEnd(); ProfEnd();
if (builder_flags & LNK_PDB_BuilderFlag_SC) {
ProfBegin("Build Section Contrib Map"); ProfBegin("Build Section Contrib Map");
{ {
ProfBegin("Build DBI Section Headers"); ProfBegin("Build DBI Section Headers");
@@ -2542,7 +2552,9 @@ lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, String8 image_data, LNK_Config
dbi_sec_list_concat_arr(&task.pdb->dbi->sec_contrib_list, cv->obj_count, task.sc_list); dbi_sec_list_concat_arr(&task.pdb->dbi->sec_contrib_list, cv->obj_count, task.sc_list);
} }
ProfEnd(); ProfEnd();
}
if (builder_flags & LNK_PDB_BuilderFlag_NATVIS) {
ProfBegin("Build NatVis"); ProfBegin("Build NatVis");
{ {
String8Array natvis_file_path_arr = str8_array_from_list(scratch.arena, &config->natvis_list); String8Array natvis_file_path_arr = str8_array_from_list(scratch.arena, &config->natvis_list);
@@ -2572,6 +2584,7 @@ lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, String8 image_data, LNK_Config
} }
} }
ProfEnd(); ProfEnd();
}
pdb_build(tp, tp_arena, task.pdb, task.string_ht, 0, cv->is_stripped); pdb_build(tp, tp_arena, task.pdb, task.string_ht, 0, cv->is_stripped);
+11 -1
View File
@@ -130,6 +130,16 @@ typedef struct
//////////////////////////////// ////////////////////////////////
// PDB // PDB
typedef enum
{
LNK_PDB_BuilderFlag_All = 0,
LNK_PDB_BuilderFlag_Tpi = (1<<0),
LNK_PDB_BuilderFlag_Ipi = (1<<1),
LNK_PDB_BuilderFlag_Modules = (1<<2),
LNK_PDB_BuilderFlag_SC = (1<<4),
LNK_PDB_BuilderFlag_NATVIS = (1<<5),
} LNK_PDB_BuilderFlags;
typedef struct typedef struct
{ {
String8 image_data; String8 image_data;
@@ -180,5 +190,5 @@ internal void lnk_replace_type_names_with_hashes (TP_Context *tp, TP
//////////////////////////////// ////////////////////////////////
// PDB // PDB
internal String8List lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, String8 image_data, LNK_Config *config, LNK_SymbolTable *symtab, LNK_CodeViewInput *cv, LNK_MergedTypes cv_types); internal String8List lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, String8 image_data, LNK_Config *config, LNK_SymbolTable *symtab, LNK_CodeViewInput *cv, LNK_MergedTypes cv_types, LNK_PDB_BuilderFlags builder_flags);
+18 -1
View File
@@ -215,6 +215,22 @@ THREAD_POOL_TASK_FUNC(lnk_memory_map_file_task)
Temp scratch = scratch_begin(&arena, 1); Temp scratch = scratch_begin(&arena, 1);
#if OS_WINDOWS #if OS_WINDOWS
String16 path16 = str16_from_8(scratch.arena, task->path_arr.v[task_id]); String16 path16 = str16_from_8(scratch.arena, task->path_arr.v[task_id]);
if (task->io_flags & LNK_IO_Flags_MemoryMapFilesReadWrite) {
HANDLE file_handle = CreateFileW(path16.str, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (file_handle != INVALID_HANDLE_VALUE) {
HANDLE mapping_handle = CreateFileMappingA(file_handle, 0, PAGE_READWRITE, 0, 0, 0);
if (mapping_handle != INVALID_HANDLE_VALUE) {
LARGE_INTEGER file_size = {0};
GetFileSizeEx(file_handle, &file_size);
void *file_data = MapViewOfFile(mapping_handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, file_size.QuadPart);
if (file_data) {
task->data_arr.v[task_id] = str8(file_data, file_size.QuadPart);
}
CloseHandle(mapping_handle);
}
CloseHandle(file_handle);
}
} else {
HANDLE file_handle = CreateFileW(path16.str, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); HANDLE file_handle = CreateFileW(path16.str, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (file_handle != INVALID_HANDLE_VALUE) { if (file_handle != INVALID_HANDLE_VALUE) {
HANDLE mapping_handle = CreateFileMappingA(file_handle, 0, PAGE_WRITECOPY, 0, 0, 0); HANDLE mapping_handle = CreateFileMappingA(file_handle, 0, PAGE_WRITECOPY, 0, 0, 0);
@@ -229,6 +245,7 @@ THREAD_POOL_TASK_FUNC(lnk_memory_map_file_task)
} }
CloseHandle(file_handle); CloseHandle(file_handle);
} }
}
#elif OS_LINUX #elif OS_LINUX
int fd = open((char *)push_cstr(scratch.arena, task->path_arr.v[task_id]).str, O_RDONLY); int fd = open((char *)push_cstr(scratch.arena, task->path_arr.v[task_id]).str, O_RDONLY);
if (fd != -1) { if (fd != -1) {
@@ -253,7 +270,7 @@ lnk_read_data_from_file_path_parallel(TP_Context *tp, Arena *arena, LNK_IO_Flags
ProfBeginFunction(); ProfBeginFunction();
LNK_DiskReader reader = {0}; LNK_DiskReader reader = {0};
if (io_flags & LNK_IO_Flags_MemoryMapFiles) { if (io_flags & (LNK_IO_Flags_MemoryMapFilesReadWrite|LNK_IO_Flags_MemoryMapFilesReadOnly)) {
reader.io_flags = io_flags; reader.io_flags = io_flags;
reader.path_arr = path_arr; reader.path_arr = path_arr;
reader.data_arr.count = path_arr.count; reader.data_arr.count = path_arr.count;
+2 -1
View File
@@ -3,7 +3,8 @@
typedef U32 LNK_IO_Flags; typedef U32 LNK_IO_Flags;
enum enum
{ {
LNK_IO_Flags_MemoryMapFiles = (1 << 0), LNK_IO_Flags_MemoryMapFilesReadOnly = (1 << 0),
LNK_IO_Flags_MemoryMapFilesReadWrite = (1 << 1),
}; };
typedef struct typedef struct
+4 -3
View File
@@ -55,6 +55,7 @@ typedef enum
LNK_Error_AlternateNameConflict, LNK_Error_AlternateNameConflict,
LNK_Error_RelocationAgainstRemovedSection, LNK_Error_RelocationAgainstRemovedSection,
LNK_Error_FailIfMismatch, LNK_Error_FailIfMismatch,
LNK_Error_Boot,
LNK_Error_StopLast, LNK_Error_StopLast,
LNK_Error_ContinueFirst, LNK_Error_ContinueFirst,
@@ -160,7 +161,7 @@ internal LNK_LogType lnk_log_type_from_string(String8 string);
internal LNK_ErrorCodeStatus lnk_get_error_code_status(LNK_ErrorCode code); internal LNK_ErrorCodeStatus lnk_get_error_code_status(LNK_ErrorCode code);
internal void lnk_internal_error(LNK_InternalError code, char *file, int line, char *fmt, ...); internal void lnk_internal_error(LNK_InternalError code, char *file, int line, char *fmt, ...);
#define lnk_invalid_path(...) lnk_internal_error(LNK_InternalError_InvalidPath, __FILE__, __LINE__, __VA_ARGS__) #define lnk_invalid_path(...) lnk_internal_error(LNK_InternalError_InvalidPath, __FILE__, __LINE__, ## __VA_ARGS__)
#define lnk_not_implemented(...) lnk_internal_error(LNK_InternalError_NotImplemented, __FILE__, __LINE__, __VA_ARGS__) #define lnk_not_implemented(...) lnk_internal_error(LNK_InternalError_NotImplemented, __FILE__, __LINE__, ## __VA_ARGS__)
#define lnk_incomplete_switch(...) lnk_internal_error(LNK_InternalError_IncompleteSwitch, __FILE__, __LINE__, __VA_ARGS__) #define lnk_incomplete_switch(...) lnk_internal_error(LNK_InternalError_IncompleteSwitch, __FILE__, __LINE__, ## __VA_ARGS__)
+29 -4
View File
@@ -338,26 +338,51 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
obj->associated_sections = associated_sections; obj->associated_sections = associated_sections;
obj->self = &task->objs[task_id]; obj->self = &task->objs[task_id];
obj->link_member = input->link_member; obj->link_member = input->link_member;
obj->debug_t_sect_idx = ~0;
obj->debug_p_sect_idx = ~0;
obj->debug_h_sect_idx = ~0;
}
internal
THREAD_POOL_TASK_FUNC(lnk_obj_find_debug_t)
{
LNK_Obj *obj = &((LNK_ObjNode *)raw_task)[task_id].data;
COFF_SectionHeader *section_table = lnk_coff_section_table_from_obj(obj);
for EachIndex(sect_idx, obj->header.section_count_no_null) {
COFF_SectionHeader *sect_header = &section_table[sect_idx];
String8 sect_name = coff_name_from_section_header(str8_zero(), sect_header);
if (str8_match(sect_name, str8_lit(".debug$T"), 0)) {
obj->debug_t_sect_idx = sect_idx;
} else if (str8_match(sect_name, str8_lit(".debug$P"), 0)) {
obj->debug_p_sect_idx = sect_idx;
} else if (str8_match(sect_name, str8_lit(".debug$H"), 0)) {
obj->debug_h_sect_idx = sect_idx;
}
}
} }
internal LNK_ObjNode * internal LNK_ObjNode *
lnk_obj_from_input_many(TP_Context *tp, TP_Arena *arena, COFF_MachineType machine, U64 inputs_count, LNK_Input **inputs) lnk_obj_from_input_many(TP_Context *tp, TP_Arena *arena, LNK_Config *config, U64 inputs_count, LNK_Input **inputs)
{ {
LNK_ObjNode *objs = 0; LNK_ObjNode *objs = 0;
if (inputs_count) { if (inputs_count) {
objs = push_array(arena->v[0], LNK_ObjNode, inputs_count); objs = push_array(arena->v[0], LNK_ObjNode, inputs_count);
tp_for_parallel(tp, arena, inputs_count, lnk_obj_initer, &(LNK_ObjIniter){ .inputs = inputs, .objs = objs, .machine = machine }); tp_for_parallel(tp, arena, inputs_count, lnk_obj_initer, &(LNK_ObjIniter){ .inputs = inputs, .objs = objs, .machine = config->machine });
if (lnk_do_debug_info(config)) {
tp_for_parallel(tp, arena, inputs_count, lnk_obj_find_debug_t, objs);
}
} }
return objs; return objs;
} }
internal LNK_ObjNode * internal LNK_ObjNode *
lnk_obj_from_input(Arena *arena, COFF_MachineType machine, LNK_Input *input) lnk_obj_from_input(Arena *arena, LNK_Config *config, LNK_Input *input)
{ {
Temp scratch = scratch_begin(&arena, 1); Temp scratch = scratch_begin(&arena, 1);
TP_Context *tp = tp_alloc(scratch.arena, 1, 1, str8_zero()); TP_Context *tp = tp_alloc(scratch.arena, 1, 1, str8_zero());
TP_Arena tp_arena = { .count = 1, .v = &arena }; TP_Arena tp_arena = { .count = 1, .v = &arena };
LNK_ObjNode *result = lnk_obj_from_input_many(tp, &tp_arena, machine, 1, &input); LNK_ObjNode *result = lnk_obj_from_input_many(tp, &tp_arena, config, 1, &input);
scratch_end(scratch); scratch_end(scratch);
return result; return result;
} }
+3
View File
@@ -9,6 +9,9 @@ typedef struct LNK_Obj
{ {
String8 path; String8 path;
String8 data; String8 data;
U32 debug_t_sect_idx;
U32 debug_p_sect_idx;
U32 debug_h_sect_idx;
U32 input_idx; U32 input_idx;
COFF_FileHeaderInfo header; COFF_FileHeaderInfo header;
U32 *comdats; U32 *comdats;
+2 -3
View File
@@ -5583,9 +5583,8 @@ TEST(cyclic_type)
String8 output = g_errors; String8 output = g_errors;
B32 is_cycle_detected = 0; B32 is_cycle_detected = 0;
while (output.size && !is_cycle_detected) { while (output.size && !is_cycle_detected) {
is_cycle_detected = t_match_linef(&output, String8 line = str8_chop_line(&output);
"Error(043): %S: LF_POINTER(type_index: 0x1000) forward refs member type index 0x1001 (leaf struct offset: 0x0)", is_cycle_detected = str8_match_wildcard(line, str8_lit("Error(*): *: LF_POINTER(type_index: *) forward refs member type index * (leaf struct offset: *)"), StringMatchFlag_CaseInsensitive);
t_make_file_path(arena, str8_lit("cycle.obj")));
t_chop_line(&output); t_chop_line(&output);
} }
T_Ok(is_cycle_detected); T_Ok(is_cycle_detected);