| ... | @@ -1009,11 +1009,25 @@ pub const File = struct { | ... | @@ -1009,11 +1009,25 @@ pub const File = struct { |
| 1009 | } | 1009 | } |
| 1010 | | 1010 | |
| 1011 | /// Opens a path as a static library and parses it into the linker. | 1011 | /// Opens a path as a static library and parses it into the linker. |
| 1012 | fn openLoadArchive(base: *File, path: Path) anyerror!void { | 1012 | /// If `query` is non-null, allows GNU ld scripts. |
| 1013 | const diags = &base.comp.link_diags; | 1013 | fn openLoadArchive(base: *File, path: Path, opt_query: ?UnresolvedInput.Query) anyerror!void { |
| 1014 | const input = try openArchiveInput(diags, path, false, false); | 1014 | if (opt_query) |query| { |
| 1015 | errdefer input.archive.file.close(); | 1015 | const archive = try openObject(path, query.must_link, query.hidden); |
| 1016 | try loadInput(base, input); | 1016 | errdefer archive.file.close(); |
| | 1017 | loadInput(base, .{ .archive = archive }) catch |err| switch (err) { |
| | 1018 | error.BadMagic, error.UnexpectedEndOfFile => { |
| | 1019 | if (base.tag != .elf) return err; |
| | 1020 | try loadGnuLdScript(base, path, query, archive.file); |
| | 1021 | archive.file.close(); |
| | 1022 | return; |
| | 1023 | }, |
| | 1024 | else => return err, |
| | 1025 | }; |
| | 1026 | } else { |
| | 1027 | const archive = try openObject(path, false, false); |
| | 1028 | errdefer archive.file.close(); |
| | 1029 | try loadInput(base, .{ .archive = archive }); |
| | 1030 | } |
| 1017 | } | 1031 | } |
| 1018 | | 1032 | |
| 1019 | /// Opens a path as a shared library and parses it into the linker. | 1033 | /// Opens a path as a shared library and parses it into the linker. |
| ... | @@ -1060,7 +1074,7 @@ pub const File = struct { | ... | @@ -1060,7 +1074,7 @@ pub const File = struct { |
| 1060 | switch (Compilation.classifyFileExt(arg.path)) { | 1074 | switch (Compilation.classifyFileExt(arg.path)) { |
| 1061 | .shared_library => try openLoadDso(base, new_path, query), | 1075 | .shared_library => try openLoadDso(base, new_path, query), |
| 1062 | .object => try openLoadObject(base, new_path), | 1076 | .object => try openLoadObject(base, new_path), |
| 1063 | .static_library => try openLoadArchive(base, new_path), | 1077 | .static_library => try openLoadArchive(base, new_path, query), |
| 1064 | else => diags.addParseError(path, "GNU ld script references file with unrecognized extension: {s}", .{arg.path}), | 1078 | else => diags.addParseError(path, "GNU ld script references file with unrecognized extension: {s}", .{arg.path}), |
| 1065 | } | 1079 | } |
| 1066 | } else { | 1080 | } else { |
| ... | @@ -1408,33 +1422,51 @@ pub const File = struct { | ... | @@ -1408,33 +1422,51 @@ pub const File = struct { |
| 1408 | assert(mem.startsWith(u8, flag, "-l")); | 1422 | assert(mem.startsWith(u8, flag, "-l")); |
| 1409 | const lib_name = flag["-l".len..]; | 1423 | const lib_name = flag["-l".len..]; |
| 1410 | switch (comp.config.link_mode) { | 1424 | switch (comp.config.link_mode) { |
| 1411 | .dynamic => d: { | 1425 | .dynamic => { |
| 1412 | const path = Path.initCwd( | 1426 | const dso_path = Path.initCwd( |
| 1413 | std.fmt.allocPrint(comp.arena, "{s}" ++ sep ++ "{s}{s}{s}", .{ | 1427 | std.fmt.allocPrint(comp.arena, "{s}" ++ sep ++ "{s}{s}{s}", .{ |
| 1414 | crt_dir, target.libPrefix(), lib_name, target.dynamicLibSuffix(), | 1428 | crt_dir, target.libPrefix(), lib_name, target.dynamicLibSuffix(), |
| 1415 | }) catch return diags.setAllocFailure(), | 1429 | }) catch return diags.setAllocFailure(), |
| 1416 | ); | 1430 | ); |
| 1417 | base.openLoadDso(path, .{ | 1431 | base.openLoadDso(dso_path, .{ |
| 1418 | .preferred_mode = .dynamic, | 1432 | .preferred_mode = .dynamic, |
| 1419 | .search_strategy = .paths_first, | 1433 | .search_strategy = .paths_first, |
| 1420 | }) catch |err| switch (err) { | 1434 | }) catch |err| switch (err) { |
| 1421 | error.FileNotFound => break :d, // also try static | 1435 | error.FileNotFound => { |
| | 1436 | // Also try static. |
| | 1437 | const archive_path = Path.initCwd( |
| | 1438 | std.fmt.allocPrint(comp.arena, "{s}" ++ sep ++ "{s}{s}{s}", .{ |
| | 1439 | crt_dir, target.libPrefix(), lib_name, target.staticLibSuffix(), |
| | 1440 | }) catch return diags.setAllocFailure(), |
| | 1441 | ); |
| | 1442 | base.openLoadArchive(archive_path, .{ |
| | 1443 | .preferred_mode = .dynamic, |
| | 1444 | .search_strategy = .paths_first, |
| | 1445 | }) catch |archive_err| switch (archive_err) { |
| | 1446 | error.LinkFailure => return, // error reported via diags |
| | 1447 | else => |e| diags.addParseError(dso_path, "failed to parse archive {}: {s}", .{ archive_path, @errorName(e) }), |
| | 1448 | }; |
| | 1449 | }, |
| | 1450 | error.LinkFailure => return, // error reported via diags |
| | 1451 | else => |e| diags.addParseError(dso_path, "failed to parse shared library: {s}", .{@errorName(e)}), |
| | 1452 | }; |
| | 1453 | }, |
| | 1454 | .static => { |
| | 1455 | const path = Path.initCwd( |
| | 1456 | std.fmt.allocPrint(comp.arena, "{s}" ++ sep ++ "{s}{s}{s}", .{ |
| | 1457 | crt_dir, target.libPrefix(), lib_name, target.staticLibSuffix(), |
| | 1458 | }) catch return diags.setAllocFailure(), |
| | 1459 | ); |
| | 1460 | // glibc sometimes makes even archive files GNU ld scripts. |
| | 1461 | base.openLoadArchive(path, .{ |
| | 1462 | .preferred_mode = .static, |
| | 1463 | .search_strategy = .no_fallback, |
| | 1464 | }) catch |err| switch (err) { |
| 1422 | error.LinkFailure => return, // error reported via diags | 1465 | error.LinkFailure => return, // error reported via diags |
| 1423 | else => |e| diags.addParseError(path, "failed to parse shared library: {s}", .{@errorName(e)}), | 1466 | else => |e| diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(e)}), |
| 1424 | }; | 1467 | }; |
| 1425 | continue; | | |
| 1426 | }, | 1468 | }, |
| 1427 | .static => {}, | | |
| 1428 | } | 1469 | } |
| 1429 | const path = Path.initCwd( | | |
| 1430 | std.fmt.allocPrint(comp.arena, "{s}" ++ sep ++ "{s}{s}{s}", .{ | | |
| 1431 | crt_dir, target.libPrefix(), lib_name, target.staticLibSuffix(), | | |
| 1432 | }) catch return diags.setAllocFailure(), | | |
| 1433 | ); | | |
| 1434 | base.openLoadArchive(path) catch |err| switch (err) { | | |
| 1435 | error.LinkFailure => return, // error reported via diags | | |
| 1436 | else => |e| diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(e)}), | | |
| 1437 | }; | | |
| 1438 | } | 1470 | } |
| 1439 | }, | 1471 | }, |
| 1440 | .load_object => |path| { | 1472 | .load_object => |path| { |
| ... | @@ -1444,7 +1476,7 @@ pub const File = struct { | ... | @@ -1444,7 +1476,7 @@ pub const File = struct { |
| 1444 | }; | 1476 | }; |
| 1445 | }, | 1477 | }, |
| 1446 | .load_archive => |path| { | 1478 | .load_archive => |path| { |
| 1447 | base.openLoadArchive(path) catch |err| switch (err) { | 1479 | base.openLoadArchive(path, null) catch |err| switch (err) { |
| 1448 | error.LinkFailure => return, // error reported via link_diags | 1480 | error.LinkFailure => return, // error reported via link_diags |
| 1449 | else => |e| comp.link_diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(e)}), | 1481 | else => |e| comp.link_diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(e)}), |
| 1450 | }; | 1482 | }; |