| author | |
| committer | |
| log | ed833ab31c93a937c2dafe14346a8cf928da474e |
| tree | c69c9fce09c6da81e59de397e62770e952f29cdd |
| parent | 2a5e70202b11982bde5cadb287cdb1abdcd1a49b |
| signature | Commit is signed but in an unrecognized format. |
There's not much to say about this; it's essentially just another way of
specifying link libraries. Framework directories are handled nearly
identically to library directories, and frameworks are resolved in
`link.resolveInputs` just like other link libraries. The new function
`link.resolveFrameworkInput` is responsible for trying to find the
framework's tbd or dylib file. As in 41d3b9a3e, if the framework
contains a file with no extension, we will attempt to figure out whether
it is a dylib, static archive, or tbd---this logic is quite similar to
how we handle GNU ld scripts.7 files changed, 411 insertions(+), 338 deletions(-)
lib/std/macho.zig+16-8| ... | ... | @@ -1145,16 +1145,16 @@ pub const LC = enum(u32) { |
| 1145 | 1145 | }; |
| 1146 | 1146 | |
| 1147 | 1147 | /// the mach magic number |
| 1148 | pub const MH_MAGIC = 0xfeedface; | |
| 1148 | pub const MH_MAGIC: u32 = 0xfeedface; | |
| 1149 | 1149 | |
| 1150 | 1150 | /// NXSwapInt(MH_MAGIC) |
| 1151 | pub const MH_CIGAM = 0xcefaedfe; | |
| 1151 | pub const MH_CIGAM: u32 = 0xcefaedfe; | |
| 1152 | 1152 | |
| 1153 | 1153 | /// the 64-bit mach magic number |
| 1154 | pub const MH_MAGIC_64 = 0xfeedfacf; | |
| 1154 | pub const MH_MAGIC_64: u32 = 0xfeedfacf; | |
| 1155 | 1155 | |
| 1156 | 1156 | /// NXSwapInt(MH_MAGIC_64) |
| 1157 | pub const MH_CIGAM_64 = 0xcffaedfe; | |
| 1157 | pub const MH_CIGAM_64: u32 = 0xcffaedfe; | |
| 1158 | 1158 | |
| 1159 | 1159 | /// relocatable object file |
| 1160 | 1160 | pub const MH_OBJECT = 0x1; |
| ... | ... | @@ -1281,16 +1281,16 @@ pub const MH_DYLIB_IN_CACHE = 0x80000000; |
| 1281 | 1281 | // Constants for the flags field of the fat_header |
| 1282 | 1282 | |
| 1283 | 1283 | /// the fat magic number |
| 1284 | pub const FAT_MAGIC = 0xcafebabe; | |
| 1284 | pub const FAT_MAGIC: u32 = 0xcafebabe; | |
| 1285 | 1285 | |
| 1286 | 1286 | /// NXSwapLong(FAT_MAGIC) |
| 1287 | pub const FAT_CIGAM = 0xbebafeca; | |
| 1287 | pub const FAT_CIGAM: u32 = 0xbebafeca; | |
| 1288 | 1288 | |
| 1289 | 1289 | /// the 64-bit fat magic number |
| 1290 | pub const FAT_MAGIC_64 = 0xcafebabf; | |
| 1290 | pub const FAT_MAGIC_64: u32 = 0xcafebabf; | |
| 1291 | 1291 | |
| 1292 | 1292 | /// NXSwapLong(FAT_MAGIC_64) |
| 1293 | pub const FAT_CIGAM_64 = 0xbfbafeca; | |
| 1293 | pub const FAT_CIGAM_64: u32 = 0xbfbafeca; | |
| 1294 | 1294 | |
| 1295 | 1295 | /// Segment flags |
| 1296 | 1296 | /// The file contents for this segment is for the high part of the VM space, the low part |
| ... | ... | @@ -2212,3 +2212,11 @@ pub const CompactUnwindEncoding = packed struct(u32) { |
| 2212 | 2212 | has_lsda: u1, |
| 2213 | 2213 | start: u1, |
| 2214 | 2214 | }; |
| 2215 | ||
| 2216 | // Archive files start with the ARMAG identifying string. Then follows a | |
| 2217 | // `struct ar_hdr', and as many bytes of member file data as its `ar_size' | |
| 2218 | // member indicates, for each member file. | |
| 2219 | /// String that begins an archive file. | |
| 2220 | pub const ARMAG = "!<arch>\n"; | |
| 2221 | /// String in ar_fmag at the end of each header. | |
| 2222 | pub const ARFMAG = "`\n"; |
src/Compilation.zig+8-10| ... | ... | @@ -83,7 +83,7 @@ zigc_strat: RtStrat, |
| 83 | 83 | /// Resolved into known paths, any GNU ld scripts already resolved. |
| 84 | 84 | link_inputs: []const link.Input, |
| 85 | 85 | /// Needed only for passing -F args to clang. |
| 86 | framework_dirs: []const []const u8, | |
| 86 | framework_dirs: []const Cache.Directory, | |
| 87 | 87 | /// These are only for DLLs dependencies fulfilled by the `.def` files shipped |
| 88 | 88 | /// with Zig. Static libraries are provided as `link.Input` values. |
| 89 | 89 | windows_libs: std.array_hash_map.String(void), |
| ... | ... | @@ -1350,7 +1350,6 @@ pub const ClangPreprocessorMode = enum { |
| 1350 | 1350 | version, |
| 1351 | 1351 | }; |
| 1352 | 1352 | |
| 1353 | pub const Framework = link.File.MachO.Framework; | |
| 1354 | 1353 | pub const SystemLib = link.SystemLib; |
| 1355 | 1354 | |
| 1356 | 1355 | pub const CacheMode = enum { |
| ... | ... | @@ -1487,6 +1486,7 @@ pub const CreateOptions = struct { |
| 1487 | 1486 | /// The ELF implementation no longer uses this data, however the MachO and COFF |
| 1488 | 1487 | /// implementations still do. |
| 1489 | 1488 | lib_directories: []const Cache.Directory = &.{}, |
| 1489 | framework_directories: []const Cache.Directory = &.{}, | |
| 1490 | 1490 | rpath_list: []const []const u8 = &[0][]const u8{}, |
| 1491 | 1491 | symbol_wrap_set: std.array_hash_map.String(void) = .empty, |
| 1492 | 1492 | c_source_files: []const CSourceFile = &.{}, |
| ... | ... | @@ -1494,8 +1494,6 @@ pub const CreateOptions = struct { |
| 1494 | 1494 | manifest_file: ?[]const u8 = null, |
| 1495 | 1495 | rc_includes: std.zig.RcIncludes = .any, |
| 1496 | 1496 | link_inputs: []const link.Input = &.{}, |
| 1497 | framework_dirs: []const []const u8 = &[0][]const u8{}, | |
| 1498 | frameworks: []const Framework = &.{}, | |
| 1499 | 1497 | windows_lib_names: []const []const u8 = &.{}, |
| 1500 | 1498 | /// This means that if the output mode is an executable it will be a |
| 1501 | 1499 | /// Position Independent Executable. If the output mode is not an |
| ... | ... | @@ -2146,7 +2144,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, |
| 2146 | 2144 | .ubsan_rt_strat = ubsan_rt_strat, |
| 2147 | 2145 | .zigc_strat = zigc_strat, |
| 2148 | 2146 | .link_inputs = options.link_inputs, |
| 2149 | .framework_dirs = options.framework_dirs, | |
| 2147 | .framework_dirs = options.framework_directories, | |
| 2150 | 2148 | .llvm_opt_bisect_limit = options.llvm_opt_bisect_limit, |
| 2151 | 2149 | .skip_linker_dependencies = options.skip_linker_dependencies, |
| 2152 | 2150 | .queued_jobs = .{}, |
| ... | ... | @@ -2208,9 +2206,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, |
| 2208 | 2206 | .z_relro = options.linker_z_relro, |
| 2209 | 2207 | .z_common_page_size = options.linker_z_common_page_size, |
| 2210 | 2208 | .z_max_page_size = options.linker_z_max_page_size, |
| 2211 | .frameworks = options.frameworks, | |
| 2212 | 2209 | .lib_directories = options.lib_directories, |
| 2213 | .framework_dirs = options.framework_dirs, | |
| 2214 | 2210 | .rpath_list = options.rpath_list, |
| 2215 | 2211 | .symbol_wrap_set = options.symbol_wrap_set, |
| 2216 | 2212 | .repro = options.linker_repro orelse (options.root_mod.optimize_mode != .debug), |
| ... | ... | @@ -3416,7 +3412,10 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes |
| 3416 | 3412 | man.hash.add(comp.zigc_strat); |
| 3417 | 3413 | man.hash.add(comp.rc_includes); |
| 3418 | 3414 | man.hash.addListOfBytes(comp.force_undefined_symbols.keys()); |
| 3419 | man.hash.addListOfBytes(comp.framework_dirs); | |
| 3415 | man.hash.add(comp.framework_dirs.len); | |
| 3416 | for (comp.framework_dirs) |framework_dir| { | |
| 3417 | man.hash.addBytes(framework_dir.path orelse "."); | |
| 3418 | } | |
| 3420 | 3419 | man.hash.addListOfBytes(comp.windows_libs.keys()); |
| 3421 | 3420 | |
| 3422 | 3421 | man.hash.addListOfBytes(comp.global_cc_argv); |
| ... | ... | @@ -3482,7 +3481,6 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes |
| 3482 | 3481 | man.hash.add(opts.growable_table); |
| 3483 | 3482 | |
| 3484 | 3483 | // Mach-O specific stuff |
| 3485 | try link.File.MachO.hashAddFrameworks(man, opts.frameworks); | |
| 3486 | 3484 | try man.addInputPathOptional(opts.entitlements, .{}); |
| 3487 | 3485 | man.hash.addOptional(opts.pagezero_size); |
| 3488 | 3486 | man.hash.addOptional(opts.headerpad_size); |
| ... | ... | @@ -6461,7 +6459,7 @@ fn addCommonCCArgs( |
| 6461 | 6459 | |
| 6462 | 6460 | try argv.ensureUnusedCapacity(comp.framework_dirs.len * 2); |
| 6463 | 6461 | for (comp.framework_dirs) |framework_dir| { |
| 6464 | try argv.appendSlice(&.{ "-F", framework_dir }); | |
| 6462 | try argv.appendSlice(&.{ "-F", framework_dir.path orelse "." }); | |
| 6465 | 6463 | } |
| 6466 | 6464 | } |
| 6467 | 6465 | } |
src/link.zig+246-94| ... | ... | @@ -481,7 +481,6 @@ pub const File = struct { |
| 481 | 481 | |
| 482 | 482 | // TODO: remove this. libraries are resolved by the frontend. |
| 483 | 483 | lib_directories: []const Directory, |
| 484 | framework_dirs: []const []const u8, | |
| 485 | 484 | rpath_list: []const []const u8, |
| 486 | 485 | |
| 487 | 486 | /// Zig compiler development linker flags. |
| ... | ... | @@ -501,7 +500,6 @@ pub const File = struct { |
| 501 | 500 | headerpad_max_install_names: bool, |
| 502 | 501 | /// Remove dylibs that are unreachable by the entry point or exported symbols |
| 503 | 502 | dead_strip_dylibs: bool, |
| 504 | frameworks: []const MachO.Framework, | |
| 505 | 503 | /// Force load all members of static archives that implement an |
| 506 | 504 | /// Objective-C class or category |
| 507 | 505 | force_load_objc: bool, |
| ... | ... | @@ -1958,6 +1956,7 @@ pub const UnresolvedInput = union(enum) { |
| 1958 | 1956 | /// Strings that come from GNU ld scripts. Is it a filename? Is it a path? |
| 1959 | 1957 | /// Who knows! Fuck around and find out. |
| 1960 | 1958 | ambiguous_name: AmbiguousNameQuery, |
| 1959 | framework_query: FrameworkQuery, | |
| 1961 | 1960 | |
| 1962 | 1961 | pub const NameQuery = struct { |
| 1963 | 1962 | name: []const u8, |
| ... | ... | @@ -1996,6 +1995,12 @@ pub const UnresolvedInput = union(enum) { |
| 1996 | 1995 | } |
| 1997 | 1996 | }; |
| 1998 | 1997 | |
| 1998 | pub const FrameworkQuery = struct { | |
| 1999 | name: []const u8, | |
| 2000 | needed: bool, | |
| 2001 | weak: bool, | |
| 2002 | }; | |
| 2003 | ||
| 1999 | 2004 | pub const SearchStrategy = enum { |
| 2000 | 2005 | paths_first, |
| 2001 | 2006 | mode_first, |
| ... | ... | @@ -2118,6 +2123,7 @@ pub fn resolveInputs( |
| 2118 | 2123 | /// Allocated with `gpa`. |
| 2119 | 2124 | resolved_inputs: *std.ArrayList(Input), |
| 2120 | 2125 | lib_directories: []const Cache.Directory, |
| 2126 | framework_directories: []const Cache.Directory, | |
| 2121 | 2127 | color: std.zig.Color, |
| 2122 | 2128 | ) Allocator.Error!void { |
| 2123 | 2129 | var checked_paths: std.ArrayList(u8) = .empty; |
| ... | ... | @@ -2129,6 +2135,7 @@ pub fn resolveInputs( |
| 2129 | 2135 | var archive_dedup: ArchiveDedupMap = .empty; |
| 2130 | 2136 | defer archive_dedup.deinit(gpa); |
| 2131 | 2137 | |
| 2138 | // Allocated with `arena`. | |
| 2132 | 2139 | var failed_libs: std.ArrayList(struct { |
| 2133 | 2140 | name: []const u8, |
| 2134 | 2141 | strategy: UnresolvedInput.SearchStrategy, |
| ... | ... | @@ -2136,6 +2143,12 @@ pub fn resolveInputs( |
| 2136 | 2143 | preferred_mode: std.lang.LinkMode, |
| 2137 | 2144 | }) = .empty; |
| 2138 | 2145 | |
| 2146 | // Allocated with `arena`. | |
| 2147 | var failed_frameworks: std.ArrayList(struct { | |
| 2148 | name: []const u8, | |
| 2149 | checked_paths: []const u8, | |
| 2150 | }) = .empty; | |
| 2151 | ||
| 2139 | 2152 | // Convert external system libs into a stack so that items can be |
| 2140 | 2153 | // pushed to it. |
| 2141 | 2154 | // |
| ... | ... | @@ -2337,17 +2350,47 @@ pub fn resolveInputs( |
| 2337 | 2350 | } |
| 2338 | 2351 | continue; |
| 2339 | 2352 | }, |
| 2353 | .framework_query => |framework_query| { | |
| 2354 | checked_paths.clearRetainingCapacity(); | |
| 2355 | for (framework_directories) |framework_directory| { | |
| 2356 | switch (try resolveFrameworkInput( | |
| 2357 | gpa, | |
| 2358 | arena, | |
| 2359 | io, | |
| 2360 | resolved_inputs, | |
| 2361 | &checked_paths, | |
| 2362 | &ld_script_bytes, | |
| 2363 | &archive_dedup, | |
| 2364 | framework_directory, | |
| 2365 | framework_query, | |
| 2366 | )) { | |
| 2367 | .ok => continue :syslib, | |
| 2368 | .no_match => {}, | |
| 2369 | } | |
| 2370 | } | |
| 2371 | try failed_frameworks.append(arena, .{ | |
| 2372 | .name = framework_query.name, | |
| 2373 | .checked_paths = try arena.dupe(u8, checked_paths.items), | |
| 2374 | }); | |
| 2375 | continue :syslib; | |
| 2376 | }, | |
| 2340 | 2377 | } |
| 2341 | 2378 | comptime unreachable; |
| 2342 | 2379 | } |
| 2343 | 2380 | |
| 2344 | if (failed_libs.items.len > 0) { | |
| 2381 | if (failed_libs.items.len > 0 or failed_frameworks.items.len > 0) { | |
| 2345 | 2382 | for (failed_libs.items) |f| { |
| 2346 | 2383 | const searched_paths = if (f.checked_paths.len == 0) " none" else f.checked_paths; |
| 2347 | 2384 | std.log.err("unable to find {t} system library {q} using strategy {t}. searched paths:{s}", .{ |
| 2348 | 2385 | f.preferred_mode, f.name, f.strategy, searched_paths, |
| 2349 | 2386 | }); |
| 2350 | 2387 | } |
| 2388 | for (failed_frameworks.items) |f| { | |
| 2389 | const searched_paths = if (f.checked_paths.len == 0) " none" else f.checked_paths; | |
| 2390 | std.log.err("unable to find system framework {q}. searched paths:{s}", .{ | |
| 2391 | f.name, searched_paths, | |
| 2392 | }); | |
| 2393 | } | |
| 2351 | 2394 | std.process.exit(1); |
| 2352 | 2395 | } |
| 2353 | 2396 | } |
| ... | ... | @@ -2437,16 +2480,15 @@ fn resolveLibInput( |
| 2437 | 2480 | else => |e| fatal("unable to search for so library {qf}: {t}", .{ test_path, e }), |
| 2438 | 2481 | }; |
| 2439 | 2482 | errdefer file.close(io); |
| 2440 | return finishResolveLibInput( | |
| 2441 | io, | |
| 2442 | resolved_inputs, | |
| 2443 | archive_dedup, | |
| 2444 | test_path, | |
| 2445 | file, | |
| 2446 | link_mode, | |
| 2447 | name_query.query, | |
| 2448 | .basename, | |
| 2449 | ); | |
| 2483 | resolved_inputs.appendAssumeCapacity(.{ .dso = .{ | |
| 2484 | .path = test_path, | |
| 2485 | .file = file, | |
| 2486 | .needed = name_query.query.needed, | |
| 2487 | .weak = name_query.query.weak, | |
| 2488 | .reexport = name_query.query.reexport, | |
| 2489 | .fallback_soname = .basename, | |
| 2490 | } }); | |
| 2491 | return .ok; | |
| 2450 | 2492 | } |
| 2451 | 2493 | |
| 2452 | 2494 | // In the case of MinGW, the main check will be .lib but we also need to |
| ... | ... | @@ -2462,16 +2504,13 @@ fn resolveLibInput( |
| 2462 | 2504 | else => |e| fatal("unable to search for static library {qf}: {t}", .{ test_path, e }), |
| 2463 | 2505 | }; |
| 2464 | 2506 | errdefer file.close(io); |
| 2465 | return finishResolveLibInput( | |
| 2466 | io, | |
| 2467 | resolved_inputs, | |
| 2468 | archive_dedup, | |
| 2469 | test_path, | |
| 2470 | file, | |
| 2471 | link_mode, | |
| 2472 | name_query.query, | |
| 2473 | .basename, | |
| 2474 | ); | |
| 2507 | addResolvedStaticLibInput(io, resolved_inputs, archive_dedup, .{ | |
| 2508 | .path = test_path, | |
| 2509 | .file = file, | |
| 2510 | .must_link = name_query.query.must_link, | |
| 2511 | .hidden = name_query.query.hidden, | |
| 2512 | }); | |
| 2513 | return .ok; | |
| 2475 | 2514 | } |
| 2476 | 2515 | |
| 2477 | 2516 | // In the case of OpenBSD, dynamic libraries are always versioned, without |
| ... | ... | @@ -2533,6 +2572,145 @@ fn resolveLibInput( |
| 2533 | 2572 | return .no_match; |
| 2534 | 2573 | } |
| 2535 | 2574 | |
| 2575 | fn resolveFrameworkInput( | |
| 2576 | gpa: Allocator, | |
| 2577 | arena: Allocator, | |
| 2578 | io: Io, | |
| 2579 | /// Allocated via `gpa`. | |
| 2580 | resolved_inputs: *std.ArrayList(Input), | |
| 2581 | /// Allocated via `gpa`. | |
| 2582 | checked_paths: *std.ArrayList(u8), | |
| 2583 | /// Allocated via `gpa`. | |
| 2584 | ld_script_bytes: *std.ArrayList(u8), | |
| 2585 | /// Allocated via `gpa`. | |
| 2586 | archive_dedup: *ArchiveDedupMap, | |
| 2587 | framework_directory: Directory, | |
| 2588 | framework_query: UnresolvedInput.FrameworkQuery, | |
| 2589 | ) Allocator.Error!ResolveLibInputResult { | |
| 2590 | const sep = std.fs.path.sep_str; | |
| 2591 | ||
| 2592 | tbd: { | |
| 2593 | const test_path: Path = .{ | |
| 2594 | .root_dir = framework_directory, | |
| 2595 | .sub_path = try std.fmt.allocPrint( | |
| 2596 | arena, | |
| 2597 | "{s}.framework" ++ sep ++ "{s}.tbd", | |
| 2598 | .{ framework_query.name, framework_query.name }, | |
| 2599 | ), | |
| 2600 | }; | |
| 2601 | try checked_paths.print(gpa, "\n {f}", .{test_path}); | |
| 2602 | var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { | |
| 2603 | error.FileNotFound => break :tbd, | |
| 2604 | else => |e| fatal("unable to search for tbd library {qf}: {t}", .{ test_path, e }), | |
| 2605 | }; | |
| 2606 | errdefer file.close(io); | |
| 2607 | resolved_inputs.appendAssumeCapacity(.{ .tbd = .{ | |
| 2608 | .path = test_path, | |
| 2609 | .file = file, | |
| 2610 | .needed = framework_query.needed, | |
| 2611 | .weak = framework_query.weak, | |
| 2612 | .reexport = false, | |
| 2613 | } }); | |
| 2614 | return .ok; | |
| 2615 | } | |
| 2616 | ||
| 2617 | dylib: { | |
| 2618 | const test_path: Path = .{ | |
| 2619 | .root_dir = framework_directory, | |
| 2620 | .sub_path = try std.fmt.allocPrint( | |
| 2621 | arena, | |
| 2622 | "{s}.framework" ++ sep ++ "{s}.dylib", | |
| 2623 | .{ framework_query.name, framework_query.name }, | |
| 2624 | ), | |
| 2625 | }; | |
| 2626 | try checked_paths.print(gpa, "\n {f}", .{test_path}); | |
| 2627 | var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { | |
| 2628 | error.FileNotFound => break :dylib, | |
| 2629 | else => |e| fatal("unable to search for dynamic library {qf}: {t}", .{ test_path, e }), | |
| 2630 | }; | |
| 2631 | errdefer file.close(io); | |
| 2632 | resolved_inputs.appendAssumeCapacity(.{ .dso = .{ | |
| 2633 | .path = test_path, | |
| 2634 | .file = file, | |
| 2635 | .needed = framework_query.needed, | |
| 2636 | .weak = framework_query.weak, | |
| 2637 | .reexport = false, | |
| 2638 | .fallback_soname = .basename, | |
| 2639 | } }); | |
| 2640 | return .ok; | |
| 2641 | } | |
| 2642 | ||
| 2643 | ambiguous: { | |
| 2644 | const test_path: Path = .{ | |
| 2645 | .root_dir = framework_directory, | |
| 2646 | .sub_path = try std.fmt.allocPrint( | |
| 2647 | arena, | |
| 2648 | "{s}.framework" ++ sep ++ "{s}", | |
| 2649 | .{ framework_query.name, framework_query.name }, | |
| 2650 | ), | |
| 2651 | }; | |
| 2652 | try checked_paths.print(gpa, "\n {f}", .{test_path}); | |
| 2653 | var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { | |
| 2654 | error.FileNotFound => break :ambiguous, | |
| 2655 | else => |e| fatal("unable to search for framework library {qf}: {t}", .{ test_path, e }), | |
| 2656 | }; | |
| 2657 | errdefer file.close(io); | |
| 2658 | ||
| 2659 | const macho_magics: []const [4]u8 = &.{ | |
| 2660 | @bitCast(std.macho.MH_MAGIC), | |
| 2661 | @bitCast(std.macho.MH_CIGAM), | |
| 2662 | @bitCast(std.macho.MH_MAGIC_64), | |
| 2663 | @bitCast(std.macho.MH_CIGAM_64), | |
| 2664 | @bitCast(std.macho.FAT_MAGIC), | |
| 2665 | @bitCast(std.macho.FAT_CIGAM), | |
| 2666 | @bitCast(std.macho.FAT_MAGIC_64), | |
| 2667 | @bitCast(std.macho.FAT_CIGAM_64), | |
| 2668 | }; | |
| 2669 | try ld_script_bytes.resize(gpa, @max(4, std.macho.ARMAG.len)); | |
| 2670 | const n = file.readPositionalAll(io, ld_script_bytes.items, 0) catch |err| | |
| 2671 | fatal("failed to read {qf}: {t}", .{ test_path, err }); | |
| 2672 | const buf = ld_script_bytes.items[0..n]; | |
| 2673 | ||
| 2674 | for (macho_magics) |*macho_magic| { | |
| 2675 | if (mem.startsWith(u8, buf, macho_magic)) { | |
| 2676 | // Appears to be a Mach-O file, so a dylib. | |
| 2677 | resolved_inputs.appendAssumeCapacity(.{ .dso = .{ | |
| 2678 | .path = test_path, | |
| 2679 | .file = file, | |
| 2680 | .needed = framework_query.needed, | |
| 2681 | .weak = framework_query.weak, | |
| 2682 | .reexport = false, | |
| 2683 | .fallback_soname = .basename, | |
| 2684 | } }); | |
| 2685 | return .ok; | |
| 2686 | } | |
| 2687 | } | |
| 2688 | ||
| 2689 | if (mem.startsWith(u8, buf, std.macho.ARMAG)) { | |
| 2690 | // Appears to be an archive file. | |
| 2691 | addResolvedStaticLibInput(io, resolved_inputs, archive_dedup, .{ | |
| 2692 | .path = test_path, | |
| 2693 | .file = file, | |
| 2694 | .must_link = false, | |
| 2695 | .hidden = false, | |
| 2696 | }); | |
| 2697 | return .ok; | |
| 2698 | } | |
| 2699 | ||
| 2700 | // It doesn't look like a dylib or archive, so assume it's a tbd. | |
| 2701 | resolved_inputs.appendAssumeCapacity(.{ .tbd = .{ | |
| 2702 | .path = test_path, | |
| 2703 | .file = file, | |
| 2704 | .needed = framework_query.needed, | |
| 2705 | .weak = framework_query.weak, | |
| 2706 | .reexport = false, | |
| 2707 | } }); | |
| 2708 | return .ok; | |
| 2709 | } | |
| 2710 | ||
| 2711 | return .no_match; | |
| 2712 | } | |
| 2713 | ||
| 2536 | 2714 | /// Deduplicates static archive link inputs based on their path. This is done for efficiency, so |
| 2537 | 2715 | /// that linker implementations do not need to open and scan the archive just to determine that they |
| 2538 | 2716 | /// need not extract any objects. At the time of writing, it also helps avoid "multiple definitions |
| ... | ... | @@ -2556,45 +2734,21 @@ const ArchiveDedupAdapter = struct { |
| 2556 | 2734 | } |
| 2557 | 2735 | }; |
| 2558 | 2736 | |
| 2559 | fn finishResolveLibInput( | |
| 2737 | fn addResolvedStaticLibInput( | |
| 2560 | 2738 | io: Io, |
| 2561 | 2739 | resolved_inputs: *std.ArrayList(Input), |
| 2562 | 2740 | archive_dedup: *ArchiveDedupMap, |
| 2563 | path: Path, | |
| 2564 | file: Io.File, | |
| 2565 | link_mode: std.lang.LinkMode, | |
| 2566 | query: UnresolvedInput.Query, | |
| 2567 | fallback_soname: Input.Dso.FallbackSoname, | |
| 2568 | ) ResolveLibInputResult { | |
| 2569 | switch (link_mode) { | |
| 2570 | .static => { | |
| 2571 | const ctx: ArchiveDedupAdapter = .{ .resolved_inputs = resolved_inputs.items }; | |
| 2572 | const gop = archive_dedup.getOrPutAssumeCapacityAdapted(path, ctx); | |
| 2573 | if (gop.found_existing) { | |
| 2574 | // Ignore duplicate archive input | |
| 2575 | file.close(io); | |
| 2576 | return .ok; | |
| 2577 | } | |
| 2578 | gop.key_ptr.* = @intCast(resolved_inputs.items.len); | |
| 2579 | resolved_inputs.appendAssumeCapacity(.{ .archive = .{ | |
| 2580 | .path = path, | |
| 2581 | .file = file, | |
| 2582 | .must_link = query.must_link, | |
| 2583 | .hidden = query.hidden, | |
| 2584 | } }); | |
| 2585 | }, | |
| 2586 | .dynamic => resolved_inputs.appendAssumeCapacity(.{ | |
| 2587 | .dso = .{ | |
| 2588 | .path = path, | |
| 2589 | .file = file, | |
| 2590 | .needed = query.needed, | |
| 2591 | .weak = query.weak, | |
| 2592 | .reexport = query.reexport, | |
| 2593 | .fallback_soname = fallback_soname, | |
| 2594 | }, | |
| 2595 | }), | |
| 2741 | archive: Input.Object, | |
| 2742 | ) void { | |
| 2743 | const ctx: ArchiveDedupAdapter = .{ .resolved_inputs = resolved_inputs.items }; | |
| 2744 | const gop = archive_dedup.getOrPutAssumeCapacityAdapted(archive.path, ctx); | |
| 2745 | if (gop.found_existing) { | |
| 2746 | // Ignore duplicate archive input | |
| 2747 | archive.file.close(io); | |
| 2748 | } else { | |
| 2749 | gop.key_ptr.* = @intCast(resolved_inputs.items.len); | |
| 2750 | resolved_inputs.appendAssumeCapacity(.{ .archive = archive }); | |
| 2596 | 2751 | } |
| 2597 | return .ok; | |
| 2598 | 2752 | } |
| 2599 | 2753 | |
| 2600 | 2754 | fn resolvePathInput( |
| ... | ... | @@ -2690,19 +2844,24 @@ fn resolvePathInputLib( |
| 2690 | 2844 | try archive_dedup.ensureUnusedCapacity(gpa, 1); |
| 2691 | 2845 | |
| 2692 | 2846 | const test_path: Path = pq.path; |
| 2847 | ||
| 2848 | var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { | |
| 2849 | error.FileNotFound => return .no_match, | |
| 2850 | else => |e| fatal("unable to search for {t} library {qf}: {t}", .{ | |
| 2851 | link_mode, std.fmt.alt(test_path, .formatEscapeChar), e, | |
| 2852 | }), | |
| 2853 | }; | |
| 2854 | errdefer file.close(io); | |
| 2855 | ||
| 2693 | 2856 | // In the case of shared libraries, they might actually be "linker scripts" |
| 2694 | 2857 | // that contain references to other libraries. |
| 2695 | if (pq.query.allow_so_scripts and target.ofmt == .elf and switch (Compilation.classifyFileExt(test_path.sub_path)) { | |
| 2696 | .static_library, .shared_library => true, | |
| 2697 | else => false, | |
| 2698 | }) { | |
| 2699 | var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { | |
| 2700 | error.FileNotFound => return .no_match, | |
| 2701 | else => |e| fatal("unable to search for {t} library {qf}: {t}", .{ | |
| 2702 | link_mode, std.fmt.alt(test_path, .formatEscapeChar), e, | |
| 2703 | }), | |
| 2704 | }; | |
| 2705 | errdefer file.close(io); | |
| 2858 | ld_script: { | |
| 2859 | if (!pq.query.allow_so_scripts) break :ld_script; | |
| 2860 | if (target.ofmt != .elf) break :ld_script; | |
| 2861 | switch (Compilation.classifyFileExt(test_path.sub_path)) { | |
| 2862 | .static_library, .shared_library => {}, | |
| 2863 | else => break :ld_script, | |
| 2864 | } | |
| 2706 | 2865 | try ld_script_bytes.resize(gpa, @max(std.elf.MAGIC.len, std.elf.ARMAG.len)); |
| 2707 | 2866 | const n = file.readPositionalAll(io, ld_script_bytes.items, 0) catch |err| |
| 2708 | 2867 | fatal("failed to read {qf}: {t}", .{ test_path, err }); |
| ... | ... | @@ -2712,16 +2871,7 @@ fn resolvePathInputLib( |
| 2712 | 2871 | mem.startsWith(u8, buf, std.elf.ARMAG_THIN)) |
| 2713 | 2872 | { |
| 2714 | 2873 | // Appears to be an ELF or archive file. |
| 2715 | return finishResolveLibInput( | |
| 2716 | io, | |
| 2717 | resolved_inputs, | |
| 2718 | archive_dedup, | |
| 2719 | test_path, | |
| 2720 | file, | |
| 2721 | link_mode, | |
| 2722 | pq.query, | |
| 2723 | fallback_soname, | |
| 2724 | ); | |
| 2874 | break :ld_script; | |
| 2725 | 2875 | } |
| 2726 | 2876 | const stat = file.stat(io) catch |err| |
| 2727 | 2877 | fatal("failed to stat {f}: {t}", .{ test_path, err }); |
| ... | ... | @@ -2785,21 +2935,23 @@ fn resolvePathInputLib( |
| 2785 | 2935 | return .ok; |
| 2786 | 2936 | } |
| 2787 | 2937 | |
| 2788 | var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { | |
| 2789 | error.FileNotFound => return .no_match, | |
| 2790 | else => |e| fatal("unable to search for {t} library {f}: {t}", .{ link_mode, test_path, e }), | |
| 2791 | }; | |
| 2792 | errdefer file.close(io); | |
| 2793 | return finishResolveLibInput( | |
| 2794 | io, | |
| 2795 | resolved_inputs, | |
| 2796 | archive_dedup, | |
| 2797 | test_path, | |
| 2798 | file, | |
| 2799 | link_mode, | |
| 2800 | pq.query, | |
| 2801 | fallback_soname, | |
| 2802 | ); | |
| 2938 | switch (link_mode) { | |
| 2939 | .dynamic => resolved_inputs.appendAssumeCapacity(.{ .dso = .{ | |
| 2940 | .path = test_path, | |
| 2941 | .file = file, | |
| 2942 | .needed = pq.query.needed, | |
| 2943 | .weak = pq.query.weak, | |
| 2944 | .reexport = pq.query.reexport, | |
| 2945 | .fallback_soname = fallback_soname, | |
| 2946 | } }), | |
| 2947 | .static => addResolvedStaticLibInput(io, resolved_inputs, archive_dedup, .{ | |
| 2948 | .path = test_path, | |
| 2949 | .file = file, | |
| 2950 | .must_link = pq.query.must_link, | |
| 2951 | .hidden = pq.query.hidden, | |
| 2952 | }), | |
| 2953 | } | |
| 2954 | return .ok; | |
| 2803 | 2955 | } |
| 2804 | 2956 | |
| 2805 | 2957 | pub fn openObject(io: Io, path: Path, must_link: bool, hidden: bool) !Input.Object { |
src/link/MachO.zig+9-59| ... | ... | @@ -119,10 +119,6 @@ dead_strip_dylibs: bool, |
| 119 | 119 | undefined_treatment: UndefinedTreatment, |
| 120 | 120 | /// TODO: delete this, libraries need to be resolved by the frontend instead |
| 121 | 121 | lib_directories: []const Directory, |
| 122 | /// Resolved list of framework search directories | |
| 123 | framework_dirs: []const []const u8, | |
| 124 | /// List of input frameworks | |
| 125 | frameworks: []const Framework, | |
| 126 | 122 | /// Install name for the dylib. |
| 127 | 123 | /// TODO: unify with soname |
| 128 | 124 | install_name: ?[]const u8, |
| ... | ... | @@ -196,7 +192,6 @@ pub fn createEmpty( |
| 196 | 192 | .headerpad_size = options.headerpad_size, |
| 197 | 193 | .headerpad_max_install_names = options.headerpad_max_install_names, |
| 198 | 194 | .dead_strip_dylibs = options.dead_strip_dylibs, |
| 199 | .frameworks = options.frameworks, | |
| 200 | 195 | .install_name = options.install_name, |
| 201 | 196 | .entitlements = options.entitlements, |
| 202 | 197 | .compatibility_version = options.compatibility_version, |
| ... | ... | @@ -211,7 +206,6 @@ pub fn createEmpty( |
| 211 | 206 | .undefined_treatment = if (allow_shlib_undefined) .dynamic_lookup else .@"error", |
| 212 | 207 | // TODO delete this, directories must instead be resolved by the frontend |
| 213 | 208 | .lib_directories = options.lib_directories, |
| 214 | .framework_dirs = options.framework_dirs, | |
| 215 | 209 | .force_load_objc = options.force_load_objc, |
| 216 | 210 | .discard_local_symbols = options.discard_local_symbols, |
| 217 | 211 | }; |
| ... | ... | @@ -372,35 +366,6 @@ pub fn flush( |
| 372 | 366 | diags.addParseError(input.path(), "failed to read input file: {t}", .{err}); |
| 373 | 367 | } |
| 374 | 368 | |
| 375 | // frameworks | |
| 376 | for (self.frameworks) |framework| { | |
| 377 | switch (Compilation.classifyFileExt(framework.path.sub_path)) { | |
| 378 | .shared_library => { | |
| 379 | const dso_input = try link.openDsoInput(io, diags, framework.path, framework.needed, framework.weak, false); | |
| 380 | self.classifyInputFile(dso_input) catch |err| | |
| 381 | diags.addParseError(framework.path, "failed to parse input file: {s}", .{@errorName(err)}); | |
| 382 | }, | |
| 383 | .static_library => { | |
| 384 | const archive_input = try link.openArchiveInput(io, diags, framework.path, false, false); | |
| 385 | self.classifyInputFile(archive_input) catch |err| | |
| 386 | diags.addParseError(framework.path, "failed to parse input file: {s}", .{@errorName(err)}); | |
| 387 | }, | |
| 388 | else => { | |
| 389 | dso: { | |
| 390 | const dso_input = link.openDsoInput(io, diags, framework.path, framework.needed, framework.weak, false) catch break :dso; | |
| 391 | self.classifyInputFile(dso_input) catch break :dso; | |
| 392 | continue; | |
| 393 | } | |
| 394 | ar: { | |
| 395 | const archive_input = link.openArchiveInput(io, diags, framework.path, false, false) catch break :ar; | |
| 396 | self.classifyInputFile(archive_input) catch break :ar; | |
| 397 | continue; | |
| 398 | } | |
| 399 | diags.addParseError(framework.path, "unknown file extension", .{}); | |
| 400 | }, | |
| 401 | } | |
| 402 | } | |
| 403 | ||
| 404 | 369 | try self.parseInputFiles(); |
| 405 | 370 | self.parseDependentDylibs() catch |err| { |
| 406 | 371 | switch (err) { |
| ... | ... | @@ -716,20 +681,9 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { |
| 716 | 681 | }, |
| 717 | 682 | }; |
| 718 | 683 | |
| 719 | for (self.framework_dirs) |f_dir| { | |
| 684 | for (comp.framework_dirs) |f_dir| { | |
| 720 | 685 | try argv.append("-F"); |
| 721 | try argv.append(f_dir); | |
| 722 | } | |
| 723 | ||
| 724 | for (self.frameworks) |framework| { | |
| 725 | const name = framework.path.stem(); | |
| 726 | const arg = if (framework.needed) | |
| 727 | try std.fmt.allocPrint(arena, "-needed_framework {s}", .{name}) | |
| 728 | else if (framework.weak) | |
| 729 | try std.fmt.allocPrint(arena, "-weak_framework {s}", .{name}) | |
| 730 | else | |
| 731 | try std.fmt.allocPrint(arena, "-framework {s}", .{name}); | |
| 732 | try argv.append(arg); | |
| 686 | try argv.append(f_dir.path orelse "."); | |
| 733 | 687 | } |
| 734 | 688 | |
| 735 | 689 | if (comp.config.link_libcpp) { |
| ... | ... | @@ -763,7 +717,7 @@ pub fn classifyInputFile(self: *MachO, input: link.Input) !void { |
| 763 | 717 | log.debug("classifying input file {f}", .{path}); |
| 764 | 718 | |
| 765 | 719 | const fh = try self.addFileHandle(file); |
| 766 | var buffer: [Archive.SARMAG]u8 = undefined; | |
| 720 | var buffer: [macho.ARMAG.len]u8 = undefined; | |
| 767 | 721 | |
| 768 | 722 | const fat_arch: ?fat.Arch = try self.parseFatFile(file, path); |
| 769 | 723 | const offset = if (fat_arch) |fa| fa.offset else 0; |
| ... | ... | @@ -778,7 +732,7 @@ pub fn classifyInputFile(self: *MachO, input: link.Input) !void { |
| 778 | 732 | return; |
| 779 | 733 | } |
| 780 | 734 | if (readArMagic(io, file, offset, &buffer) catch null) |ar_magic| blk: { |
| 781 | if (!mem.eql(u8, ar_magic, Archive.ARMAG)) break :blk; | |
| 735 | if (!mem.eql(u8, ar_magic, macho.ARMAG)) break :blk; | |
| 782 | 736 | try self.addArchive(input.archive, fh, fat_arch); |
| 783 | 737 | return; |
| 784 | 738 | } |
| ... | ... | @@ -808,10 +762,10 @@ pub fn readMachHeader(io: Io, file: Io.File, offset: usize) !macho.mach_header_6 |
| 808 | 762 | return hdr; |
| 809 | 763 | } |
| 810 | 764 | |
| 811 | pub fn readArMagic(io: Io, file: Io.File, offset: usize, buffer: *[Archive.SARMAG]u8) ![]const u8 { | |
| 765 | pub fn readArMagic(io: Io, file: Io.File, offset: usize, buffer: *[macho.ARMAG.len]u8) ![]const u8 { | |
| 812 | 766 | const nread = try file.readPositionalAll(io, buffer, offset); |
| 813 | 767 | if (nread != buffer.len) return error.InputOutput; |
| 814 | return buffer[0..Archive.SARMAG]; | |
| 768 | return buffer[0..macho.ARMAG.len]; | |
| 815 | 769 | } |
| 816 | 770 | |
| 817 | 771 | fn addObject(self: *MachO, path: Path, handle_index: File.HandleIndex, offset: u64) !void { |
| ... | ... | @@ -1034,10 +988,6 @@ fn parseDependentDylibs(self: *MachO) !void { |
| 1034 | 988 | const comp = self.base.comp; |
| 1035 | 989 | const gpa = comp.gpa; |
| 1036 | 990 | const io = comp.io; |
| 1037 | const framework_dirs = self.framework_dirs; | |
| 1038 | ||
| 1039 | // TODO delete this, directories must instead be resolved by the frontend | |
| 1040 | const lib_directories = self.lib_directories; | |
| 1041 | 991 | |
| 1042 | 992 | var arena_alloc = std.heap.ArenaAllocator.init(gpa); |
| 1043 | 993 | defer arena_alloc.deinit(); |
| ... | ... | @@ -1072,14 +1022,14 @@ fn parseDependentDylibs(self: *MachO) !void { |
| 1072 | 1022 | const stem = fs.path.stem(id.name); |
| 1073 | 1023 | |
| 1074 | 1024 | // Framework |
| 1075 | for (framework_dirs) |dir| { | |
| 1025 | for (comp.framework_dirs) |dir| { | |
| 1076 | 1026 | test_path.clearRetainingCapacity(); |
| 1077 | if (try accessFrameworkPath(arena, io, &test_path, &checked_paths, dir, stem)) break :full_path test_path.items; | |
| 1027 | if (try accessFrameworkPath(arena, io, &test_path, &checked_paths, dir.path orelse ".", stem)) break :full_path test_path.items; | |
| 1078 | 1028 | } |
| 1079 | 1029 | |
| 1080 | 1030 | // Library |
| 1081 | 1031 | const lib_name = eatPrefix(stem, "lib") orelse stem; |
| 1082 | for (lib_directories) |lib_directory| { | |
| 1032 | for (self.lib_directories) |lib_directory| { | |
| 1083 | 1033 | test_path.clearRetainingCapacity(); |
| 1084 | 1034 | if (try accessLibPath(arena, io, &test_path, &checked_paths, lib_directory.path orelse ".", lib_name)) break :full_path test_path.items; |
| 1085 | 1035 | } |
src/link/MachO/Archive.zig+4-15| ... | ... | @@ -17,7 +17,7 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File |
| 17 | 17 | const offset = if (fat_arch) |ar| ar.offset else 0; |
| 18 | 18 | const end_pos = if (fat_arch) |ar| offset + ar.size else (try handle.stat(io)).size; |
| 19 | 19 | |
| 20 | var pos: usize = offset + SARMAG; | |
| 20 | var pos: usize = offset + macho.ARMAG.len; | |
| 21 | 21 | while (true) { |
| 22 | 22 | if (pos >= end_pos) break; |
| 23 | 23 | if (!mem.isAligned(pos, 2)) pos += 1; |
| ... | ... | @@ -30,9 +30,9 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File |
| 30 | 30 | const hdr = @as(*align(1) const ar_hdr, @ptrCast(&hdr_buffer)).*; |
| 31 | 31 | pos += @sizeOf(ar_hdr); |
| 32 | 32 | |
| 33 | if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) { | |
| 33 | if (!mem.eql(u8, &hdr.ar_fmag, macho.ARFMAG)) { | |
| 34 | 34 | return diags.failParse(path, "invalid header delimiter: expected '{f}', found '{f}'", .{ |
| 35 | std.ascii.hexEscape(ARFMAG, .lower), std.ascii.hexEscape(&hdr.ar_fmag, .lower), | |
| 35 | std.ascii.hexEscape(macho.ARFMAG, .lower), std.ascii.hexEscape(&hdr.ar_fmag, .lower), | |
| 36 | 36 | }); |
| 37 | 37 | } |
| 38 | 38 | |
| ... | ... | @@ -116,17 +116,6 @@ pub fn writeHeader( |
| 116 | 116 | } |
| 117 | 117 | } |
| 118 | 118 | |
| 119 | // Archive files start with the ARMAG identifying string. Then follows a | |
| 120 | // `struct ar_hdr', and as many bytes of member file data as its `ar_size' | |
| 121 | // member indicates, for each member file. | |
| 122 | /// String that begins an archive file. | |
| 123 | pub const ARMAG: *const [SARMAG:0]u8 = "!<arch>\n"; | |
| 124 | /// Size of that string. | |
| 125 | pub const SARMAG: u4 = 8; | |
| 126 | ||
| 127 | /// String in ar_fmag at the end of each header. | |
| 128 | const ARFMAG: *const [2:0]u8 = "`\n"; | |
| 129 | ||
| 130 | 119 | pub const SYMDEF = "__.SYMDEF"; |
| 131 | 120 | pub const SYMDEF64 = "__.SYMDEF_64"; |
| 132 | 121 | pub const SYMDEF_SORTED = "__.SYMDEF SORTED"; |
| ... | ... | @@ -146,7 +135,7 @@ pub const ar_hdr = extern struct { |
| 146 | 135 | /// File size, in ASCII decimal. |
| 147 | 136 | ar_size: [10]u8 = "0\x20\x20\x20\x20\x20\x20\x20\x20\x20".*, |
| 148 | 137 | /// Always contains ARFMAG. |
| 149 | ar_fmag: [2]u8 = ARFMAG.*, | |
| 138 | ar_fmag: [2]u8 = macho.ARFMAG.*, | |
| 150 | 139 | |
| 151 | 140 | fn date(self: ar_hdr) !u64 { |
| 152 | 141 | const value = mem.trimEnd(u8, &self.ar_date, &[_]u8{@as(u8, 0x20)}); |
src/link/MachO/relocatable.zig+2-2| ... | ... | @@ -151,7 +151,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation) link.Error!void { |
| 151 | 151 | |
| 152 | 152 | // Update file offsets of contributing objects |
| 153 | 153 | const total_size: usize = blk: { |
| 154 | var pos: usize = Archive.SARMAG; | |
| 154 | var pos: usize = macho.ARMAG.len; | |
| 155 | 155 | pos += @sizeOf(Archive.ar_hdr); |
| 156 | 156 | pos += Archive.SYMDEF.len + 1; |
| 157 | 157 | pos = mem.alignForward(usize, pos, 8); |
| ... | ... | @@ -194,7 +194,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation) link.Error!void { |
| 194 | 194 | var writer: Writer = .fixed(buffer); |
| 195 | 195 | |
| 196 | 196 | // Write magic |
| 197 | writer.writeAll(Archive.ARMAG) catch unreachable; | |
| 197 | writer.writeAll(macho.ARMAG) catch unreachable; | |
| 198 | 198 | |
| 199 | 199 | // Write symtab |
| 200 | 200 | ar_symtab.write(format, macho_file, &writer) catch |err| |
src/main.zig+126-150| ... | ... | @@ -893,13 +893,6 @@ const ArgsIterator = struct { |
| 893 | 893 | } |
| 894 | 894 | }; |
| 895 | 895 | |
| 896 | /// Similar to `link.Framework` except it doesn't store yet unresolved | |
| 897 | /// path to the framework. | |
| 898 | const Framework = struct { | |
| 899 | needed: bool = false, | |
| 900 | weak: bool = false, | |
| 901 | }; | |
| 902 | ||
| 903 | 896 | const CliModule = struct { |
| 904 | 897 | root_path: []const u8, |
| 905 | 898 | root_src_path: []const u8, |
| ... | ... | @@ -1117,12 +1110,12 @@ fn buildOutputType( |
| 1117 | 1110 | |
| 1118 | 1111 | .llvm_m_args = .empty, |
| 1119 | 1112 | .sysroot = null, |
| 1120 | .lib_directories = .empty, // populated by createModule() | |
| 1121 | 1113 | .lib_dir_args = .empty, // populated from CLI arg parsing |
| 1114 | .lib_directories = .empty, // populated by createModule() | |
| 1115 | .framework_dir_args = .empty, // populated from CLI arg parsing | |
| 1116 | .framework_directories = .empty, // populated by createModule() | |
| 1122 | 1117 | .libc_installation = null, |
| 1123 | 1118 | .want_native_include_dirs = false, |
| 1124 | .frameworks = .empty, | |
| 1125 | .framework_dirs = .empty, | |
| 1126 | 1119 | .rpath_list = .empty, |
| 1127 | 1120 | .each_lib_rpath = null, |
| 1128 | 1121 | .libc_paths_file = EnvVar.ZIG_LIBC.get(environ_map), |
| ... | ... | @@ -1275,13 +1268,25 @@ fn buildOutputType( |
| 1275 | 1268 | } else if (mem.eql(u8, arg, "--library-directory") or mem.eql(u8, arg, "-L")) { |
| 1276 | 1269 | try create_module.lib_dir_args.append(arena, args_iter.nextOrFatal()); |
| 1277 | 1270 | } else if (mem.eql(u8, arg, "-F")) { |
| 1278 | try create_module.framework_dirs.append(arena, args_iter.nextOrFatal()); | |
| 1271 | try create_module.framework_dir_args.append(arena, args_iter.nextOrFatal()); | |
| 1279 | 1272 | } else if (mem.eql(u8, arg, "-framework")) { |
| 1280 | try create_module.frameworks.put(arena, args_iter.nextOrFatal(), .{}); | |
| 1273 | try create_module.cli_link_inputs.append(arena, .{ .framework_query = .{ | |
| 1274 | .name = args_iter.nextOrFatal(), | |
| 1275 | .needed = false, | |
| 1276 | .weak = false, | |
| 1277 | } }); | |
| 1281 | 1278 | } else if (mem.eql(u8, arg, "-weak_framework")) { |
| 1282 | try create_module.frameworks.put(arena, args_iter.nextOrFatal(), .{ .weak = true }); | |
| 1279 | try create_module.cli_link_inputs.append(arena, .{ .framework_query = .{ | |
| 1280 | .name = args_iter.nextOrFatal(), | |
| 1281 | .needed = false, | |
| 1282 | .weak = true, | |
| 1283 | } }); | |
| 1283 | 1284 | } else if (mem.eql(u8, arg, "-needed_framework")) { |
| 1284 | try create_module.frameworks.put(arena, args_iter.nextOrFatal(), .{ .needed = true }); | |
| 1285 | try create_module.cli_link_inputs.append(arena, .{ .framework_query = .{ | |
| 1286 | .name = args_iter.nextOrFatal(), | |
| 1287 | .needed = true, | |
| 1288 | .weak = false, | |
| 1289 | } }); | |
| 1285 | 1290 | } else if (mem.eql(u8, arg, "-install_name")) { |
| 1286 | 1291 | install_name = args_iter.nextOrFatal(); |
| 1287 | 1292 | } else if (mem.cutPrefix(u8, arg, "--compress-debug-sections=")) |param| { |
| ... | ... | @@ -1396,11 +1401,11 @@ fn buildOutputType( |
| 1396 | 1401 | } else if (mem.eql(u8, arg, "-iframework")) { |
| 1397 | 1402 | const path = args_iter.nextOrFatal(); |
| 1398 | 1403 | try cssan.addIncludePath(arena, &cc_argv, .iframework, arg, path, false); |
| 1399 | try create_module.framework_dirs.append(arena, path); // Forward to the backend as -F | |
| 1404 | try create_module.framework_dir_args.append(arena, path); // Forward to the backend as -F | |
| 1400 | 1405 | } else if (mem.eql(u8, arg, "-iframeworkwithsysroot")) { |
| 1401 | 1406 | const path = args_iter.nextOrFatal(); |
| 1402 | 1407 | try cssan.addIncludePath(arena, &cc_argv, .iframeworkwithsysroot, arg, path, false); |
| 1403 | try create_module.framework_dirs.append(arena, path); // Forward to the backend as -F | |
| 1408 | try create_module.framework_dir_args.append(arena, path); // Forward to the backend as -F | |
| 1404 | 1409 | } else if (mem.eql(u8, arg, "--version")) { |
| 1405 | 1410 | const next_arg = args_iter.nextOrFatal(); |
| 1406 | 1411 | version = std.SemanticVersion.parse(next_arg) catch |err| { |
| ... | ... | @@ -1828,7 +1833,7 @@ fn buildOutputType( |
| 1828 | 1833 | } else if (mem.cutPrefix(u8, arg, "-L")) |rest| { |
| 1829 | 1834 | try create_module.lib_dir_args.append(arena, rest); |
| 1830 | 1835 | } else if (mem.cutPrefix(u8, arg, "-F")) |rest| { |
| 1831 | try create_module.framework_dirs.append(arena, rest); | |
| 1836 | try create_module.framework_dir_args.append(arena, rest); | |
| 1832 | 1837 | } else if (mem.cutPrefix(u8, arg, "-l")) |name| { |
| 1833 | 1838 | // We don't know whether this library is part of libc |
| 1834 | 1839 | // or libc++ until we resolve the target, so we append |
| ... | ... | @@ -2532,8 +2537,12 @@ fn buildOutputType( |
| 2532 | 2537 | disable_c_depfile = true; |
| 2533 | 2538 | try cc_argv.appendSlice(arena, it.other_args); |
| 2534 | 2539 | }, |
| 2535 | .framework_dir => try create_module.framework_dirs.append(arena, it.only_arg), | |
| 2536 | .framework => try create_module.frameworks.put(arena, it.only_arg, .{}), | |
| 2540 | .framework_dir => try create_module.framework_dir_args.append(arena, it.only_arg), | |
| 2541 | .framework => try create_module.cli_link_inputs.append(arena, .{ .framework_query = .{ | |
| 2542 | .name = it.only_arg, | |
| 2543 | .needed = false, | |
| 2544 | .weak = false, | |
| 2545 | } }), | |
| 2537 | 2546 | .nostdlibinc => create_module.want_native_include_dirs = false, |
| 2538 | 2547 | .strip => mod_opts.strip = true, |
| 2539 | 2548 | .exec_model => { |
| ... | ... | @@ -2561,7 +2570,11 @@ fn buildOutputType( |
| 2561 | 2570 | }, |
| 2562 | 2571 | .name_done = false, |
| 2563 | 2572 | } }), |
| 2564 | .weak_framework => try create_module.frameworks.put(arena, it.only_arg, .{ .weak = true }), | |
| 2573 | .weak_framework => try create_module.cli_link_inputs.append(arena, .{ .framework_query = .{ | |
| 2574 | .name = it.only_arg, | |
| 2575 | .needed = false, | |
| 2576 | .weak = true, | |
| 2577 | } }), | |
| 2565 | 2578 | .headerpad_max_install_names => headerpad_max_install_names = true, |
| 2566 | 2579 | .compress_debug_sections => { |
| 2567 | 2580 | if (it.only_arg.len == 0) { |
| ... | ... | @@ -2914,11 +2927,23 @@ fn buildOutputType( |
| 2914 | 2927 | fatal("unable to parse minor subsystem version {q}: {t}", .{ minor, err }); |
| 2915 | 2928 | }; |
| 2916 | 2929 | } else if (mem.eql(u8, arg, "-framework")) { |
| 2917 | try create_module.frameworks.put(arena, linker_args_it.nextOrFatal(), .{}); | |
| 2930 | try create_module.cli_link_inputs.append(arena, .{ .framework_query = .{ | |
| 2931 | .name = linker_args_it.nextOrFatal(), | |
| 2932 | .needed = false, | |
| 2933 | .weak = false, | |
| 2934 | } }); | |
| 2918 | 2935 | } else if (mem.eql(u8, arg, "-weak_framework")) { |
| 2919 | try create_module.frameworks.put(arena, linker_args_it.nextOrFatal(), .{ .weak = true }); | |
| 2936 | try create_module.cli_link_inputs.append(arena, .{ .framework_query = .{ | |
| 2937 | .name = linker_args_it.nextOrFatal(), | |
| 2938 | .needed = false, | |
| 2939 | .weak = true, | |
| 2940 | } }); | |
| 2920 | 2941 | } else if (mem.eql(u8, arg, "-needed_framework")) { |
| 2921 | try create_module.frameworks.put(arena, linker_args_it.nextOrFatal(), .{ .needed = true }); | |
| 2942 | try create_module.cli_link_inputs.append(arena, .{ .framework_query = .{ | |
| 2943 | .name = linker_args_it.nextOrFatal(), | |
| 2944 | .needed = true, | |
| 2945 | .weak = false, | |
| 2946 | } }); | |
| 2922 | 2947 | } else if (mem.eql(u8, arg, "-needed_library")) { |
| 2923 | 2948 | try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ |
| 2924 | 2949 | .name = linker_args_it.nextOrFatal(), |
| ... | ... | @@ -3400,59 +3425,6 @@ fn buildOutputType( |
| 3400 | 3425 | } |
| 3401 | 3426 | } |
| 3402 | 3427 | |
| 3403 | var resolved_frameworks = std.array_list.Managed(Compilation.Framework).init(arena); | |
| 3404 | ||
| 3405 | if (create_module.frameworks.keys().len > 0) { | |
| 3406 | var test_path = std.array_list.Managed(u8).init(gpa); | |
| 3407 | defer test_path.deinit(); | |
| 3408 | ||
| 3409 | var checked_paths = std.array_list.Managed(u8).init(gpa); | |
| 3410 | defer checked_paths.deinit(); | |
| 3411 | ||
| 3412 | var failed_frameworks = std.array_list.Managed(struct { | |
| 3413 | name: []const u8, | |
| 3414 | checked_paths: []const u8, | |
| 3415 | }).init(arena); | |
| 3416 | ||
| 3417 | framework: for (create_module.frameworks.keys(), create_module.frameworks.values()) |framework_name, info| { | |
| 3418 | checked_paths.clearRetainingCapacity(); | |
| 3419 | ||
| 3420 | for (create_module.framework_dirs.items) |framework_dir_path| { | |
| 3421 | if (try accessFrameworkPath( | |
| 3422 | io, | |
| 3423 | &test_path, | |
| 3424 | &checked_paths, | |
| 3425 | framework_dir_path, | |
| 3426 | framework_name, | |
| 3427 | )) { | |
| 3428 | const path = Path.initCwd(try arena.dupe(u8, test_path.items)); | |
| 3429 | try resolved_frameworks.append(.{ | |
| 3430 | .needed = info.needed, | |
| 3431 | .weak = info.weak, | |
| 3432 | .path = path, | |
| 3433 | }); | |
| 3434 | continue :framework; | |
| 3435 | } | |
| 3436 | } | |
| 3437 | ||
| 3438 | try failed_frameworks.append(.{ | |
| 3439 | .name = framework_name, | |
| 3440 | .checked_paths = try arena.dupe(u8, checked_paths.items), | |
| 3441 | }); | |
| 3442 | } | |
| 3443 | ||
| 3444 | if (failed_frameworks.items.len > 0) { | |
| 3445 | for (failed_frameworks.items) |f| { | |
| 3446 | const searched_paths = if (f.checked_paths.len == 0) " none" else f.checked_paths; | |
| 3447 | std.log.err("unable to find framework {q}. searched paths: {s}", .{ | |
| 3448 | f.name, searched_paths, | |
| 3449 | }); | |
| 3450 | } | |
| 3451 | process.exit(1); | |
| 3452 | } | |
| 3453 | } | |
| 3454 | // After this point, resolved_frameworks is used instead of frameworks. | |
| 3455 | ||
| 3456 | 3428 | if (create_module.resolved_options.output_mode == .Obj and target.ofmt == .coff) { |
| 3457 | 3429 | const total_obj_count = create_module.c_source_files.items.len + |
| 3458 | 3430 | @intFromBool(root_src_file != null) + |
| ... | ... | @@ -3689,6 +3661,7 @@ fn buildOutputType( |
| 3689 | 3661 | .emit_docs = emit_docs_resolved, |
| 3690 | 3662 | .emit_implib = emit_implib_resolved, |
| 3691 | 3663 | .lib_directories = create_module.lib_directories.items, |
| 3664 | .framework_directories = create_module.framework_directories.items, | |
| 3692 | 3665 | .rpath_list = create_module.rpath_list.items, |
| 3693 | 3666 | .symbol_wrap_set = symbol_wrap_set, |
| 3694 | 3667 | .c_source_files = create_module.c_source_files.items, |
| ... | ... | @@ -3697,8 +3670,6 @@ fn buildOutputType( |
| 3697 | 3670 | .rc_includes = rc_includes, |
| 3698 | 3671 | .mingw_unicode_entry_point = mingw_unicode_entry_point, |
| 3699 | 3672 | .link_inputs = create_module.link_inputs.items, |
| 3700 | .framework_dirs = create_module.framework_dirs.items, | |
| 3701 | .frameworks = resolved_frameworks.items, | |
| 3702 | 3673 | .windows_lib_names = create_module.windows_libs.keys(), |
| 3703 | 3674 | .want_compiler_rt = if (zig_cc_explicitly_link_compiler_rt) true else want_compiler_rt, |
| 3704 | 3675 | .want_ubsan_rt = want_ubsan_rt, |
| ... | ... | @@ -4041,13 +4012,13 @@ const CreateModule = struct { |
| 4041 | 4012 | /// CPU features. |
| 4042 | 4013 | llvm_m_args: std.ArrayList([]const u8), |
| 4043 | 4014 | sysroot: ?[]const u8, |
| 4044 | lib_directories: std.ArrayList(Directory), | |
| 4045 | 4015 | lib_dir_args: std.ArrayList([]const u8), |
| 4016 | lib_directories: std.ArrayList(Directory), | |
| 4017 | framework_dir_args: std.ArrayList([]const u8), | |
| 4018 | framework_directories: std.ArrayList(Directory), | |
| 4046 | 4019 | libc_installation: ?LibCInstallation, |
| 4047 | 4020 | want_native_include_dirs: bool, |
| 4048 | frameworks: std.array_hash_map.String(Framework), | |
| 4049 | 4021 | native_system_include_paths: []const []const u8, |
| 4050 | framework_dirs: std.ArrayList([]const u8), | |
| 4051 | 4022 | rpath_list: std.ArrayList([]const u8), |
| 4052 | 4023 | each_lib_rpath: ?bool, |
| 4053 | 4024 | libc_paths_file: ?[]const u8, |
| ... | ... | @@ -4158,7 +4129,7 @@ fn createModule( |
| 4158 | 4129 | var unresolved_link_inputs: std.ArrayList(link.UnresolvedInput) = .empty; |
| 4159 | 4130 | defer unresolved_link_inputs.deinit(gpa); |
| 4160 | 4131 | try unresolved_link_inputs.ensureUnusedCapacity(gpa, create_module.cli_link_inputs.items.len); |
| 4161 | var any_name_queries_remaining = false; | |
| 4132 | var any_named_library_queries = false; | |
| 4162 | 4133 | for (create_module.cli_link_inputs.items) |cli_link_input| switch (cli_link_input) { |
| 4163 | 4134 | .name_query => |nq| { |
| 4164 | 4135 | const lib_name = nq.name; |
| ... | ... | @@ -4199,39 +4170,52 @@ fn createModule( |
| 4199 | 4170 | } |
| 4200 | 4171 | |
| 4201 | 4172 | unresolved_link_inputs.appendAssumeCapacity(cli_link_input); |
| 4202 | any_name_queries_remaining = true; | |
| 4173 | any_named_library_queries = true; | |
| 4174 | }, | |
| 4175 | .framework_query => { | |
| 4176 | unresolved_link_inputs.appendAssumeCapacity(cli_link_input); | |
| 4177 | any_named_library_queries = true; | |
| 4203 | 4178 | }, |
| 4204 | 4179 | else => { |
| 4205 | 4180 | unresolved_link_inputs.appendAssumeCapacity(cli_link_input); |
| 4206 | 4181 | }, |
| 4207 | 4182 | }; // After this point, unresolved_link_inputs is used instead of cli_link_inputs. |
| 4208 | 4183 | |
| 4209 | if (any_name_queries_remaining) create_module.want_native_include_dirs = true; | |
| 4184 | if (any_named_library_queries) create_module.want_native_include_dirs = true; | |
| 4210 | 4185 | |
| 4211 | 4186 | // Resolve the library path arguments with respect to sysroot. |
| 4212 | 4187 | try create_module.lib_directories.ensureUnusedCapacity(arena, create_module.lib_dir_args.items.len); |
| 4213 | if (create_module.sysroot) |root| { | |
| 4214 | for (create_module.lib_dir_args.items) |lib_dir_arg| { | |
| 4215 | if (fs.path.isAbsolute(lib_dir_arg)) { | |
| 4216 | const stripped_dir = lib_dir_arg[fs.path.parsePath(lib_dir_arg).root.len..]; | |
| 4217 | const full_path = try fs.path.join(arena, &[_][]const u8{ root, stripped_dir }); | |
| 4218 | addLibDirectoryWarn(io, &create_module.lib_directories, full_path); | |
| 4219 | } else { | |
| 4220 | addLibDirectoryWarn(io, &create_module.lib_directories, lib_dir_arg); | |
| 4188 | for (create_module.lib_dir_args.items) |dir_arg| { | |
| 4189 | const path: []const u8 = path: { | |
| 4190 | if (fs.path.isAbsolute(dir_arg)) { | |
| 4191 | if (create_module.sysroot) |sysroot| { | |
| 4192 | // Change the path root to the given sysroot. | |
| 4193 | const stripped_dir = dir_arg[fs.path.parsePath(dir_arg).root.len..]; | |
| 4194 | break :path try fs.path.join(arena, &.{ sysroot, stripped_dir }); | |
| 4195 | } | |
| 4221 | 4196 | } |
| 4222 | } | |
| 4223 | } else { | |
| 4224 | for (create_module.lib_dir_args.items) |lib_dir_arg| { | |
| 4225 | addLibDirectoryWarn(io, &create_module.lib_directories, lib_dir_arg); | |
| 4226 | } | |
| 4197 | break :path dir_arg; | |
| 4198 | }; | |
| 4199 | appendLibDirOrWarn(io, &create_module.lib_directories, path); | |
| 4227 | 4200 | } |
| 4228 | 4201 | create_module.lib_dir_args = undefined; // From here we use lib_directories instead. |
| 4229 | 4202 | |
| 4230 | if (resolved_target.is_native_os and target.os.tag.isDarwin()) { | |
| 4231 | // If we want to link against frameworks, we need system headers. | |
| 4232 | if (create_module.frameworks.count() > 0) | |
| 4233 | create_module.want_native_include_dirs = true; | |
| 4203 | // Likewise for framework path arguments. | |
| 4204 | try create_module.framework_directories.ensureUnusedCapacity(arena, create_module.framework_dir_args.items.len); | |
| 4205 | for (create_module.framework_dir_args.items) |dir_arg| { | |
| 4206 | const path: []const u8 = path: { | |
| 4207 | if (fs.path.isAbsolute(dir_arg)) { | |
| 4208 | if (create_module.sysroot) |sysroot| { | |
| 4209 | // Change the path root to the given sysroot. | |
| 4210 | const stripped_dir = dir_arg[fs.path.parsePath(dir_arg).root.len..]; | |
| 4211 | break :path try fs.path.join(arena, &.{ sysroot, stripped_dir }); | |
| 4212 | } | |
| 4213 | } | |
| 4214 | break :path dir_arg; | |
| 4215 | }; | |
| 4216 | appendLibDirOrWarn(io, &create_module.framework_directories, path); | |
| 4234 | 4217 | } |
| 4218 | create_module.framework_dir_args = undefined; // From here we use framework_directories instead. | |
| 4235 | 4219 | |
| 4236 | 4220 | if (create_module.each_lib_rpath orelse resolved_target.is_native_os) { |
| 4237 | 4221 | try create_module.rpath_list.ensureUnusedCapacity(arena, create_module.lib_directories.items.len); |
| ... | ... | @@ -4253,11 +4237,17 @@ fn createModule( |
| 4253 | 4237 | |
| 4254 | 4238 | create_module.native_system_include_paths = try paths.include_dirs.toOwnedSlice(arena); |
| 4255 | 4239 | |
| 4256 | try create_module.framework_dirs.appendSlice(arena, paths.framework_dirs.items); | |
| 4257 | 4240 | try create_module.rpath_list.appendSlice(arena, paths.rpaths.items); |
| 4258 | 4241 | |
| 4259 | 4242 | try create_module.lib_directories.ensureUnusedCapacity(arena, paths.lib_dirs.items.len); |
| 4260 | for (paths.lib_dirs.items) |path| addLibDirectoryWarn2(io, &create_module.lib_directories, path, true); | |
| 4243 | for (paths.lib_dirs.items) |path| { | |
| 4244 | appendLibDirOrWarnAllowMissing(io, &create_module.lib_directories, path); | |
| 4245 | } | |
| 4246 | ||
| 4247 | try create_module.framework_directories.ensureUnusedCapacity(arena, paths.framework_dirs.items.len); | |
| 4248 | for (paths.framework_dirs.items) |path| { | |
| 4249 | appendLibDirOrWarnAllowMissing(io, &create_module.framework_directories, path); | |
| 4250 | } | |
| 4261 | 4251 | } |
| 4262 | 4252 | |
| 4263 | 4253 | if (create_module.libc_paths_file) |paths_file| { |
| ... | ... | @@ -4266,7 +4256,7 @@ fn createModule( |
| 4266 | 4256 | } |
| 4267 | 4257 | |
| 4268 | 4258 | if (target.os.tag == .windows and (target.abi == .msvc or target.abi == .itanium) and |
| 4269 | any_name_queries_remaining) | |
| 4259 | any_named_library_queries) | |
| 4270 | 4260 | { |
| 4271 | 4261 | if (create_module.libc_installation == null) { |
| 4272 | 4262 | create_module.libc_installation = LibCInstallation.findNative(arena, io, .{ |
| ... | ... | @@ -4277,9 +4267,19 @@ fn createModule( |
| 4277 | 4267 | fatal("unable to find native libc installation: {t}", .{err}); |
| 4278 | 4268 | }; |
| 4279 | 4269 | } |
| 4270 | ||
| 4280 | 4271 | try create_module.lib_directories.ensureUnusedCapacity(arena, 2); |
| 4281 | addLibDirectoryWarn(io, &create_module.lib_directories, create_module.libc_installation.?.msvc_lib_dir.?); | |
| 4282 | addLibDirectoryWarn(io, &create_module.lib_directories, create_module.libc_installation.?.kernel32_lib_dir.?); | |
| 4272 | ||
| 4273 | appendLibDirOrWarn( | |
| 4274 | io, | |
| 4275 | &create_module.lib_directories, | |
| 4276 | create_module.libc_installation.?.msvc_lib_dir.?, | |
| 4277 | ); | |
| 4278 | appendLibDirOrWarn( | |
| 4279 | io, | |
| 4280 | &create_module.lib_directories, | |
| 4281 | create_module.libc_installation.?.kernel32_lib_dir.?, | |
| 4282 | ); | |
| 4283 | 4283 | } |
| 4284 | 4284 | |
| 4285 | 4285 | // Destructively mutates but does not transfer ownership of `unresolved_link_inputs`. |
| ... | ... | @@ -4291,6 +4291,7 @@ fn createModule( |
| 4291 | 4291 | &unresolved_link_inputs, |
| 4292 | 4292 | &create_module.link_inputs, |
| 4293 | 4293 | create_module.lib_directories.items, |
| 4294 | create_module.framework_directories.items, | |
| 4294 | 4295 | color, |
| 4295 | 4296 | ) catch |err| fatal("failed to resolve link inputs: {t}", .{err}); |
| 4296 | 4297 | |
| ... | ... | @@ -6085,33 +6086,6 @@ const ClangSearchSanitizer = struct { |
| 6085 | 6086 | }; |
| 6086 | 6087 | }; |
| 6087 | 6088 | |
| 6088 | fn accessFrameworkPath( | |
| 6089 | io: Io, | |
| 6090 | test_path: *std.array_list.Managed(u8), | |
| 6091 | checked_paths: *std.array_list.Managed(u8), | |
| 6092 | framework_dir_path: []const u8, | |
| 6093 | framework_name: []const u8, | |
| 6094 | ) !bool { | |
| 6095 | const sep = fs.path.sep_str; | |
| 6096 | ||
| 6097 | for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| { | |
| 6098 | test_path.clearRetainingCapacity(); | |
| 6099 | try test_path.print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{ | |
| 6100 | framework_dir_path, framework_name, framework_name, ext, | |
| 6101 | }); | |
| 6102 | try checked_paths.print("\n {s}", .{test_path.items}); | |
| 6103 | Io.Dir.cwd().access(io, test_path.items, .{}) catch |err| switch (err) { | |
| 6104 | error.FileNotFound => continue, | |
| 6105 | else => |e| fatal("unable to search for {s} framework {q}: {t}", .{ | |
| 6106 | ext, test_path.items, e, | |
| 6107 | }), | |
| 6108 | }; | |
| 6109 | return true; | |
| 6110 | } | |
| 6111 | ||
| 6112 | return false; | |
| 6113 | } | |
| 6114 | ||
| 6115 | 6089 | fn parseRcIncludes(arg: []const u8) std.zig.RcIncludes { |
| 6116 | 6090 | return stringToEnum(std.zig.RcIncludes, arg) orelse |
| 6117 | 6091 | fatal("unsupported rc includes type: {q}", .{arg}); |
| ... | ... | @@ -6222,24 +6196,26 @@ fn anyObjectLinkInputs(link_inputs: []const link.UnresolvedInput) bool { |
| 6222 | 6196 | return false; |
| 6223 | 6197 | } |
| 6224 | 6198 | |
| 6225 | fn addLibDirectoryWarn(io: Io, lib_directories: *std.ArrayList(Directory), path: []const u8) void { | |
| 6226 | return addLibDirectoryWarn2(io, lib_directories, path, false); | |
| 6199 | fn appendLibDirOrWarn(io: Io, dirs: *std.ArrayList(Directory), path: []const u8) void { | |
| 6200 | if (Io.Dir.cwd().openDir(io, path, .{})) |handle| { | |
| 6201 | dirs.appendAssumeCapacity(.{ | |
| 6202 | .path = path, | |
| 6203 | .handle = handle, | |
| 6204 | }); | |
| 6205 | } else |err| { | |
| 6206 | warn("unable to open library directory {q}: {t}", .{ path, err }); | |
| 6207 | } | |
| 6227 | 6208 | } |
| 6228 | ||
| 6229 | fn addLibDirectoryWarn2( | |
| 6230 | io: Io, | |
| 6231 | lib_directories: *std.ArrayList(Directory), | |
| 6232 | path: []const u8, | |
| 6233 | ignore_not_found: bool, | |
| 6234 | ) void { | |
| 6235 | lib_directories.appendAssumeCapacity(.{ | |
| 6236 | .handle = Io.Dir.cwd().openDir(io, path, .{}) catch |err| { | |
| 6237 | if (err == error.FileNotFound and ignore_not_found) return; | |
| 6238 | warn("unable to open library directory {q}: {t}", .{ path, err }); | |
| 6239 | return; | |
| 6240 | }, | |
| 6241 | .path = path, | |
| 6242 | }); | |
| 6209 | fn appendLibDirOrWarnAllowMissing(io: Io, dirs: *std.ArrayList(Directory), path: []const u8) void { | |
| 6210 | if (Io.Dir.cwd().openDir(io, path, .{})) |handle| { | |
| 6211 | dirs.appendAssumeCapacity(.{ | |
| 6212 | .path = path, | |
| 6213 | .handle = handle, | |
| 6214 | }); | |
| 6215 | } else |err| switch (err) { | |
| 6216 | error.FileNotFound => {}, // ignore | |
| 6217 | else => |e| warn("unable to open library directory {q}: {t}", .{ path, e }), | |
| 6218 | } | |
| 6243 | 6219 | } |
| 6244 | 6220 | |
| 6245 | 6221 | const IoImpl = switch (build_options.io_mode) { |