authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2021-06-21 22:45:43+02:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2021-06-26 12:49:08+02:00
log16228e87d6d7d8929305083e8c76168603780f5f
treef535e98a621b25ca4d0e271c1ae61fcf028125c5
parent3e4f3a1924150e22e0ca87e906681ebadcf8433e
signaturelock-open Commit is signed but in an unrecognized format.

stage2: add --sysroot link option

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 };
870871
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 };
875885
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/6996891 // 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 .{};
890898
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 file42 /// 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,
108108
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);
13571358
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 {
14231424
1424 try argv.append("-error-limit=0");1425 try argv.append("-error-limit=0");
14251426
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);
594594
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");
815815
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 }
961961
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 script377 \\ -T[script], --script [script] Use a custom linker script
378 \\ --version-script [path] Provide a version .map file378 \\ --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 semver381 \\ --version [ver] Dynamic library semver
381 \\ -fsoname[=name] (Linux) Override the default SONAME value382 \\ -fsoname[=name] (Linux) Override the default SONAME value
382 \\ -fno-soname (Linux) Disable emitting a SONAME383 \\ -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 }
16231629
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,