| author | |
| committer | |
| log | 16228e87d6d7d8929305083e8c76168603780f5f |
| tree | f535e98a621b25ca4d0e271c1ae61fcf028125c5 |
| parent | 3e4f3a1924150e22e0ca87e906681ebadcf8433e |
| signature |
This feature is necessary for cross-compiling code that dynamically
links system libraries, at least with the current feature set of lld.5 files changed, 46 insertions(+), 24 deletions(-)
src/Compilation.zig+25-17| ... | @@ -612,6 +612,7 @@ pub const InitOptions = struct { | ... | @@ -612,6 +612,7 @@ pub const InitOptions = struct { |
| 612 | output_mode: std.builtin.OutputMode, | 612 | output_mode: std.builtin.OutputMode, |
| 613 | thread_pool: *ThreadPool, | 613 | thread_pool: *ThreadPool, |
| 614 | dynamic_linker: ?[]const u8 = null, | 614 | dynamic_linker: ?[]const u8 = null, |
| 615 | sysroot: ?[]const u8 = null, | ||
| 615 | /// `null` means to not emit a binary file. | 616 | /// `null` means to not emit a binary file. |
| 616 | emit_bin: ?EmitLoc, | 617 | emit_bin: ?EmitLoc, |
| 617 | /// `null` means to not emit a C header file. | 618 | /// `null` means to not emit a C header file. |
| ... | @@ -868,25 +869,32 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -868,25 +869,32 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 868 | break :blk false; | 869 | break :blk false; |
| 869 | }; | 870 | }; |
| 870 | 871 | ||
| 871 | const DarwinOptions = struct { | 872 | const darwin_can_use_system_linker_and_sdk = |
| 872 | syslibroot: ?[]const u8 = null, | 873 | // comptime conditions |
| 873 | system_linker_hack: bool = false, | 874 | ((build_options.have_llvm and comptime std.Target.current.isDarwin()) and |
| 875 | // runtime conditions | ||
| 876 | (use_lld and std.builtin.os.tag == .macos and options.target.isDarwin())); | ||
| 877 | |||
| 878 | const darwin_system_linker_hack = blk: { | ||
| 879 | if (darwin_can_use_system_linker_and_sdk) { | ||
| 880 | break :blk std.os.getenv("ZIG_SYSTEM_LINKER_HACK") != null; | ||
| 881 | } else { | ||
| 882 | break :blk false; | ||
| 883 | } | ||
| 874 | }; | 884 | }; |
| 875 | 885 | ||
| 876 | const darwin_options: DarwinOptions = if (build_options.have_llvm and comptime std.Target.current.isDarwin()) outer: { | 886 | const sysroot = blk: { |
| 877 | const opts: DarwinOptions = if (use_lld and std.builtin.os.tag == .macos and options.target.isDarwin()) inner: { | 887 | if (options.sysroot) |sysroot| { |
| 888 | break :blk sysroot; | ||
| 889 | } else if (darwin_can_use_system_linker_and_sdk) { | ||
| 878 | // TODO Revisit this targeting versions lower than macOS 11 when LLVM 12 is out. | 890 | // TODO Revisit this targeting versions lower than macOS 11 when LLVM 12 is out. |
| 879 | // See https://github.com/ziglang/zig/issues/6996 | 891 | // See https://github.com/ziglang/zig/issues/6996 |
| 880 | const at_least_big_sur = options.target.os.getVersionRange().semver.min.major >= 11; | 892 | const at_least_big_sur = options.target.os.getVersionRange().semver.min.major >= 11; |
| 881 | const syslibroot = if (at_least_big_sur) try std.zig.system.getSDKPath(arena) else null; | 893 | break :blk if (at_least_big_sur) try std.zig.system.getSDKPath(arena) else null; |
| 882 | const system_linker_hack = std.os.getenv("ZIG_SYSTEM_LINKER_HACK") != null; | 894 | } else { |
| 883 | break :inner .{ | 895 | break :blk null; |
| 884 | .syslibroot = syslibroot, | 896 | } |
| 885 | .system_linker_hack = system_linker_hack, | 897 | }; |
| 886 | }; | ||
| 887 | } else .{}; | ||
| 888 | break :outer opts; | ||
| 889 | } else .{}; | ||
| 890 | 898 | ||
| 891 | const lto = blk: { | 899 | const lto = blk: { |
| 892 | if (options.want_lto) |explicit| { | 900 | if (options.want_lto) |explicit| { |
| ... | @@ -897,7 +905,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -897,7 +905,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 897 | break :blk false; | 905 | break :blk false; |
| 898 | } else if (options.c_source_files.len == 0) { | 906 | } else if (options.c_source_files.len == 0) { |
| 899 | break :blk false; | 907 | break :blk false; |
| 900 | } else if (darwin_options.system_linker_hack) { | 908 | } else if (darwin_system_linker_hack) { |
| 901 | break :blk false; | 909 | break :blk false; |
| 902 | } else switch (options.output_mode) { | 910 | } else switch (options.output_mode) { |
| 903 | .Lib, .Obj => break :blk false, | 911 | .Lib, .Obj => break :blk false, |
| ... | @@ -1273,13 +1281,14 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -1273,13 +1281,14 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 1273 | .module = module, | 1281 | .module = module, |
| 1274 | .target = options.target, | 1282 | .target = options.target, |
| 1275 | .dynamic_linker = options.dynamic_linker, | 1283 | .dynamic_linker = options.dynamic_linker, |
| 1284 | .sysroot = sysroot, | ||
| 1276 | .output_mode = options.output_mode, | 1285 | .output_mode = options.output_mode, |
| 1277 | .link_mode = link_mode, | 1286 | .link_mode = link_mode, |
| 1278 | .object_format = ofmt, | 1287 | .object_format = ofmt, |
| 1279 | .optimize_mode = options.optimize_mode, | 1288 | .optimize_mode = options.optimize_mode, |
| 1280 | .use_lld = use_lld, | 1289 | .use_lld = use_lld, |
| 1281 | .use_llvm = use_llvm, | 1290 | .use_llvm = use_llvm, |
| 1282 | .system_linker_hack = darwin_options.system_linker_hack, | 1291 | .system_linker_hack = darwin_system_linker_hack, |
| 1283 | .link_libc = link_libc, | 1292 | .link_libc = link_libc, |
| 1284 | .link_libcpp = link_libcpp, | 1293 | .link_libcpp = link_libcpp, |
| 1285 | .link_libunwind = link_libunwind, | 1294 | .link_libunwind = link_libunwind, |
| ... | @@ -1287,7 +1296,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -1287,7 +1296,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 1287 | .frameworks = options.frameworks, | 1296 | .frameworks = options.frameworks, |
| 1288 | .framework_dirs = options.framework_dirs, | 1297 | .framework_dirs = options.framework_dirs, |
| 1289 | .system_libs = system_libs, | 1298 | .system_libs = system_libs, |
| 1290 | .syslibroot = darwin_options.syslibroot, | ||
| 1291 | .lib_dirs = options.lib_dirs, | 1299 | .lib_dirs = options.lib_dirs, |
| 1292 | .rpath_list = options.rpath_list, | 1300 | .rpath_list = options.rpath_list, |
| 1293 | .strip = strip, | 1301 | .strip = strip, |
src/link.zig+2-2| ... | @@ -37,6 +37,8 @@ pub const Options = struct { | ... | @@ -37,6 +37,8 @@ pub const Options = struct { |
| 37 | /// Not every Compilation compiles .zig code! For example you could do `zig build-exe foo.o`. | 37 | /// Not every Compilation compiles .zig code! For example you could do `zig build-exe foo.o`. |
| 38 | module: ?*Module, | 38 | module: ?*Module, |
| 39 | dynamic_linker: ?[]const u8, | 39 | dynamic_linker: ?[]const u8, |
| 40 | /// The root path for the dynamic linker and system libraries (as well as frameworks on Darwin) | ||
| 41 | sysroot: ?[]const u8, | ||
| 40 | /// Used for calculating how much space to reserve for symbols in case the binary file | 42 | /// Used for calculating how much space to reserve for symbols in case the binary file |
| 41 | /// does not already have a symbol table. | 43 | /// does not already have a symbol table. |
| 42 | symbol_count_hint: u64 = 32, | 44 | symbol_count_hint: u64 = 32, |
| ... | @@ -103,8 +105,6 @@ pub const Options = struct { | ... | @@ -103,8 +105,6 @@ pub const Options = struct { |
| 103 | llvm_cpu_features: ?[*:0]const u8, | 105 | llvm_cpu_features: ?[*:0]const u8, |
| 104 | /// Extra args passed directly to LLD. Ignored when not linking with LLD. | 106 | /// Extra args passed directly to LLD. Ignored when not linking with LLD. |
| 105 | extra_lld_args: []const []const u8, | 107 | extra_lld_args: []const []const u8, |
| 106 | /// Darwin-only. Set the root path to the system libraries and frameworks. | ||
| 107 | syslibroot: ?[]const u8, | ||
| 108 | 108 | ||
| 109 | objects: []const []const u8, | 109 | objects: []const []const u8, |
| 110 | framework_dirs: []const []const u8, | 110 | framework_dirs: []const []const u8, |
src/link/Elf.zig+5| ... | @@ -1354,6 +1354,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { | ... | @@ -1354,6 +1354,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1354 | man.hash.add(allow_shlib_undefined); | 1354 | man.hash.add(allow_shlib_undefined); |
| 1355 | man.hash.add(self.base.options.bind_global_refs_locally); | 1355 | man.hash.add(self.base.options.bind_global_refs_locally); |
| 1356 | man.hash.add(self.base.options.tsan); | 1356 | man.hash.add(self.base.options.tsan); |
| 1357 | man.hash.addOptionalBytes(self.base.options.sysroot); | ||
| 1357 | 1358 | ||
| 1358 | // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. | 1359 | // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. |
| 1359 | _ = try man.hit(); | 1360 | _ = try man.hit(); |
| ... | @@ -1423,6 +1424,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { | ... | @@ -1423,6 +1424,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1423 | 1424 | ||
| 1424 | try argv.append("-error-limit=0"); | 1425 | try argv.append("-error-limit=0"); |
| 1425 | 1426 | ||
| 1427 | if (self.base.options.sysroot) |sysroot| { | ||
| 1428 | try argv.append(try std.fmt.allocPrint(arena, "--sysroot={s}", .{sysroot})); | ||
| 1429 | } | ||
| 1430 | |||
| 1426 | if (self.base.options.lto) { | 1431 | if (self.base.options.lto) { |
| 1427 | switch (self.base.options.optimize_mode) { | 1432 | switch (self.base.options.optimize_mode) { |
| 1428 | .Debug => {}, | 1433 | .Debug => {}, |
src/link/MachO.zig+4-4| ... | @@ -590,7 +590,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -590,7 +590,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 590 | man.hash.add(allow_shlib_undefined); | 590 | man.hash.add(allow_shlib_undefined); |
| 591 | man.hash.add(self.base.options.bind_global_refs_locally); | 591 | man.hash.add(self.base.options.bind_global_refs_locally); |
| 592 | man.hash.add(self.base.options.system_linker_hack); | 592 | man.hash.add(self.base.options.system_linker_hack); |
| 593 | man.hash.addOptionalBytes(self.base.options.syslibroot); | 593 | man.hash.addOptionalBytes(self.base.options.sysroot); |
| 594 | 594 | ||
| 595 | // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. | 595 | // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. |
| 596 | _ = try man.hit(); | 596 | _ = try man.hit(); |
| ... | @@ -720,7 +720,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -720,7 +720,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 720 | for (self.base.options.lib_dirs) |path| { | 720 | for (self.base.options.lib_dirs) |path| { |
| 721 | if (fs.path.isAbsolute(path)) { | 721 | if (fs.path.isAbsolute(path)) { |
| 722 | var candidates = std.ArrayList([]const u8).init(arena); | 722 | var candidates = std.ArrayList([]const u8).init(arena); |
| 723 | if (self.base.options.syslibroot) |syslibroot| { | 723 | if (self.base.options.sysroot) |syslibroot| { |
| 724 | const full_path = try fs.path.join(arena, &[_][]const u8{ syslibroot, path }); | 724 | const full_path = try fs.path.join(arena, &[_][]const u8{ syslibroot, path }); |
| 725 | try candidates.append(full_path); | 725 | try candidates.append(full_path); |
| 726 | } | 726 | } |
| ... | @@ -813,7 +813,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -813,7 +813,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 813 | try argv.append("zig"); | 813 | try argv.append("zig"); |
| 814 | try argv.append("ld"); | 814 | try argv.append("ld"); |
| 815 | 815 | ||
| 816 | if (self.base.options.syslibroot) |syslibroot| { | 816 | if (self.base.options.sysroot) |syslibroot| { |
| 817 | try argv.append("-syslibroot"); | 817 | try argv.append("-syslibroot"); |
| 818 | try argv.append(syslibroot); | 818 | try argv.append(syslibroot); |
| 819 | } | 819 | } |
| ... | @@ -959,7 +959,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -959,7 +959,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 959 | } | 959 | } |
| 960 | } | 960 | } |
| 961 | 961 | ||
| 962 | if (self.base.options.syslibroot) |dir| { | 962 | if (self.base.options.sysroot) |dir| { |
| 963 | try argv.append("-syslibroot"); | 963 | try argv.append("-syslibroot"); |
| 964 | try argv.append(dir); | 964 | try argv.append(dir); |
| 965 | } | 965 | } |
src/main.zig+10-1| ... | @@ -377,6 +377,7 @@ const usage_build_generic = | ... | @@ -377,6 +377,7 @@ const usage_build_generic = |
| 377 | \\ -T[script], --script [script] Use a custom linker script | 377 | \\ -T[script], --script [script] Use a custom linker script |
| 378 | \\ --version-script [path] Provide a version .map file | 378 | \\ --version-script [path] Provide a version .map file |
| 379 | \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so) | 379 | \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so) |
| 380 | \\ --sysroot [path] Set the system root directory (usually /) | ||
| 380 | \\ --version [ver] Dynamic library semver | 381 | \\ --version [ver] Dynamic library semver |
| 381 | \\ -fsoname[=name] (Linux) Override the default SONAME value | 382 | \\ -fsoname[=name] (Linux) Override the default SONAME value |
| 382 | \\ -fno-soname (Linux) Disable emitting a SONAME | 383 | \\ -fno-soname (Linux) Disable emitting a SONAME |
| ... | @@ -602,6 +603,7 @@ fn buildOutputType( | ... | @@ -602,6 +603,7 @@ fn buildOutputType( |
| 602 | var link_eh_frame_hdr = false; | 603 | var link_eh_frame_hdr = false; |
| 603 | var link_emit_relocs = false; | 604 | var link_emit_relocs = false; |
| 604 | var each_lib_rpath: ?bool = null; | 605 | var each_lib_rpath: ?bool = null; |
| 606 | var sysroot: ?[]const u8 = null; | ||
| 605 | var libc_paths_file: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_LIBC"); | 607 | var libc_paths_file: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_LIBC"); |
| 606 | var machine_code_model: std.builtin.CodeModel = .default; | 608 | var machine_code_model: std.builtin.CodeModel = .default; |
| 607 | var runtime_args_start: ?usize = null; | 609 | var runtime_args_start: ?usize = null; |
| ... | @@ -859,6 +861,10 @@ fn buildOutputType( | ... | @@ -859,6 +861,10 @@ fn buildOutputType( |
| 859 | if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); | 861 | if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); |
| 860 | i += 1; | 862 | i += 1; |
| 861 | target_dynamic_linker = args[i]; | 863 | target_dynamic_linker = args[i]; |
| 864 | } else if (mem.eql(u8, arg, "--sysroot")) { | ||
| 865 | if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); | ||
| 866 | i += 1; | ||
| 867 | sysroot = args[i]; | ||
| 862 | } else if (mem.eql(u8, arg, "--libc")) { | 868 | } else if (mem.eql(u8, arg, "--libc")) { |
| 863 | if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); | 869 | if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); |
| 864 | i += 1; | 870 | i += 1; |
| ... | @@ -1621,7 +1627,9 @@ fn buildOutputType( | ... | @@ -1621,7 +1627,9 @@ fn buildOutputType( |
| 1621 | want_native_include_dirs = true; | 1627 | want_native_include_dirs = true; |
| 1622 | } | 1628 | } |
| 1623 | 1629 | ||
| 1624 | if (cross_target.isNativeOs() and (system_libs.items.len != 0 or want_native_include_dirs)) { | 1630 | if (sysroot == null and cross_target.isNativeOs() and |
| 1631 | (system_libs.items.len != 0 or want_native_include_dirs)) | ||
| 1632 | { | ||
| 1625 | const paths = std.zig.system.NativePaths.detect(arena, target_info) catch |err| { | 1633 | const paths = std.zig.system.NativePaths.detect(arena, target_info) catch |err| { |
| 1626 | fatal("unable to detect native system paths: {s}", .{@errorName(err)}); | 1634 | fatal("unable to detect native system paths: {s}", .{@errorName(err)}); |
| 1627 | }; | 1635 | }; |
| ... | @@ -1898,6 +1906,7 @@ fn buildOutputType( | ... | @@ -1898,6 +1906,7 @@ fn buildOutputType( |
| 1898 | .is_native_os = cross_target.isNativeOs(), | 1906 | .is_native_os = cross_target.isNativeOs(), |
| 1899 | .is_native_abi = cross_target.isNativeAbi(), | 1907 | .is_native_abi = cross_target.isNativeAbi(), |
| 1900 | .dynamic_linker = target_info.dynamic_linker.get(), | 1908 | .dynamic_linker = target_info.dynamic_linker.get(), |
| 1909 | .sysroot = sysroot, | ||
| 1901 | .output_mode = output_mode, | 1910 | .output_mode = output_mode, |
| 1902 | .root_pkg = root_pkg, | 1911 | .root_pkg = root_pkg, |
| 1903 | .emit_bin = emit_bin_loc, | 1912 | .emit_bin = emit_bin_loc, |