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 {
612612 output_mode: std.builtin.OutputMode,
613613 thread_pool: *ThreadPool,
614614 dynamic_linker: ?[]const u8 = null,
615 sysroot: ?[]const u8 = null,
615616 /// `null` means to not emit a binary file.
616617 emit_bin: ?EmitLoc,
617618 /// `null` means to not emit a C header file.
......@@ -868,25 +869,32 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
868869 break :blk false;
869870 };
870871
871 const DarwinOptions = struct {
872 syslibroot: ?[]const u8 = null,
873 system_linker_hack: bool = false,
872 const darwin_can_use_system_linker_and_sdk =
873 // comptime conditions
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 }
874884 };
875885
876 const darwin_options: DarwinOptions = if (build_options.have_llvm and comptime std.Target.current.isDarwin()) outer: {
877 const opts: DarwinOptions = if (use_lld and std.builtin.os.tag == .macos and options.target.isDarwin()) inner: {
886 const sysroot = blk: {
887 if (options.sysroot) |sysroot| {
888 break :blk sysroot;
889 } else if (darwin_can_use_system_linker_and_sdk) {
878890 // TODO Revisit this targeting versions lower than macOS 11 when LLVM 12 is out.
879891 // See https://github.com/ziglang/zig/issues/6996
880892 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;
882 const system_linker_hack = std.os.getenv("ZIG_SYSTEM_LINKER_HACK") != null;
883 break :inner .{
884 .syslibroot = syslibroot,
885 .system_linker_hack = system_linker_hack,
886 };
887 } else .{};
888 break :outer opts;
889 } else .{};
893 break :blk if (at_least_big_sur) try std.zig.system.getSDKPath(arena) else null;
894 } else {
895 break :blk null;
896 }
897 };
890898
891899 const lto = blk: {
892900 if (options.want_lto) |explicit| {
......@@ -897,7 +905,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
897905 break :blk false;
898906 } else if (options.c_source_files.len == 0) {
899907 break :blk false;
900 } else if (darwin_options.system_linker_hack) {
908 } else if (darwin_system_linker_hack) {
901909 break :blk false;
902910 } else switch (options.output_mode) {
903911 .Lib, .Obj => break :blk false,
......@@ -1273,13 +1281,14 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
12731281 .module = module,
12741282 .target = options.target,
12751283 .dynamic_linker = options.dynamic_linker,
1284 .sysroot = sysroot,
12761285 .output_mode = options.output_mode,
12771286 .link_mode = link_mode,
12781287 .object_format = ofmt,
12791288 .optimize_mode = options.optimize_mode,
12801289 .use_lld = use_lld,
12811290 .use_llvm = use_llvm,
1282 .system_linker_hack = darwin_options.system_linker_hack,
1291 .system_linker_hack = darwin_system_linker_hack,
12831292 .link_libc = link_libc,
12841293 .link_libcpp = link_libcpp,
12851294 .link_libunwind = link_libunwind,
......@@ -1287,7 +1296,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
12871296 .frameworks = options.frameworks,
12881297 .framework_dirs = options.framework_dirs,
12891298 .system_libs = system_libs,
1290 .syslibroot = darwin_options.syslibroot,
12911299 .lib_dirs = options.lib_dirs,
12921300 .rpath_list = options.rpath_list,
12931301 .strip = strip,
src/link.zig+2-2
......@@ -37,6 +37,8 @@ pub const Options = struct {
3737 /// Not every Compilation compiles .zig code! For example you could do `zig build-exe foo.o`.
3838 module: ?*Module,
3939 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,
4042 /// Used for calculating how much space to reserve for symbols in case the binary file
4143 /// does not already have a symbol table.
4244 symbol_count_hint: u64 = 32,
......@@ -103,8 +105,6 @@ pub const Options = struct {
103105 llvm_cpu_features: ?[*:0]const u8,
104106 /// Extra args passed directly to LLD. Ignored when not linking with LLD.
105107 extra_lld_args: []const []const u8,
106 /// Darwin-only. Set the root path to the system libraries and frameworks.
107 syslibroot: ?[]const u8,
108108
109109 objects: []const []const u8,
110110 framework_dirs: []const []const u8,
src/link/Elf.zig+5
......@@ -1354,6 +1354,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
13541354 man.hash.add(allow_shlib_undefined);
13551355 man.hash.add(self.base.options.bind_global_refs_locally);
13561356 man.hash.add(self.base.options.tsan);
1357 man.hash.addOptionalBytes(self.base.options.sysroot);
13571358
13581359 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
13591360 _ = try man.hit();
......@@ -1423,6 +1424,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
14231424
14241425 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
14261431 if (self.base.options.lto) {
14271432 switch (self.base.options.optimize_mode) {
14281433 .Debug => {},
src/link/MachO.zig+4-4
......@@ -590,7 +590,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
590590 man.hash.add(allow_shlib_undefined);
591591 man.hash.add(self.base.options.bind_global_refs_locally);
592592 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
595595 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
596596 _ = try man.hit();
......@@ -720,7 +720,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
720720 for (self.base.options.lib_dirs) |path| {
721721 if (fs.path.isAbsolute(path)) {
722722 var candidates = std.ArrayList([]const u8).init(arena);
723 if (self.base.options.syslibroot) |syslibroot| {
723 if (self.base.options.sysroot) |syslibroot| {
724724 const full_path = try fs.path.join(arena, &[_][]const u8{ syslibroot, path });
725725 try candidates.append(full_path);
726726 }
......@@ -813,7 +813,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
813813 try argv.append("zig");
814814 try argv.append("ld");
815815
816 if (self.base.options.syslibroot) |syslibroot| {
816 if (self.base.options.sysroot) |syslibroot| {
817817 try argv.append("-syslibroot");
818818 try argv.append(syslibroot);
819819 }
......@@ -959,7 +959,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
959959 }
960960 }
961961
962 if (self.base.options.syslibroot) |dir| {
962 if (self.base.options.sysroot) |dir| {
963963 try argv.append("-syslibroot");
964964 try argv.append(dir);
965965 }
src/main.zig+10-1
......@@ -377,6 +377,7 @@ const usage_build_generic =
377377 \\ -T[script], --script [script] Use a custom linker script
378378 \\ --version-script [path] Provide a version .map file
379379 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)
380 \\ --sysroot [path] Set the system root directory (usually /)
380381 \\ --version [ver] Dynamic library semver
381382 \\ -fsoname[=name] (Linux) Override the default SONAME value
382383 \\ -fno-soname (Linux) Disable emitting a SONAME
......@@ -602,6 +603,7 @@ fn buildOutputType(
602603 var link_eh_frame_hdr = false;
603604 var link_emit_relocs = false;
604605 var each_lib_rpath: ?bool = null;
606 var sysroot: ?[]const u8 = null;
605607 var libc_paths_file: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_LIBC");
606608 var machine_code_model: std.builtin.CodeModel = .default;
607609 var runtime_args_start: ?usize = null;
......@@ -859,6 +861,10 @@ fn buildOutputType(
859861 if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg});
860862 i += 1;
861863 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];
862868 } else if (mem.eql(u8, arg, "--libc")) {
863869 if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg});
864870 i += 1;
......@@ -1621,7 +1627,9 @@ fn buildOutputType(
16211627 want_native_include_dirs = true;
16221628 }
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 {
16251633 const paths = std.zig.system.NativePaths.detect(arena, target_info) catch |err| {
16261634 fatal("unable to detect native system paths: {s}", .{@errorName(err)});
16271635 };
......@@ -1898,6 +1906,7 @@ fn buildOutputType(
18981906 .is_native_os = cross_target.isNativeOs(),
18991907 .is_native_abi = cross_target.isNativeAbi(),
19001908 .dynamic_linker = target_info.dynamic_linker.get(),
1909 .sysroot = sysroot,
19011910 .output_mode = output_mode,
19021911 .root_pkg = root_pkg,
19031912 .emit_bin = emit_bin_loc,