| author | |
| committer | |
| log | 260c5aed86d662d2e2bd03c06d123bef9455053d |
| tree | 9bbf9bcbce9447ecacb5e92b969d0565fb4cce53 |
| parent | 411f9c60b1cb30aec8706ffac75992ac8cc59cba |
| signature | Commit is signed but in an unrecognized format. |
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, 48 insertions(+), 26 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. |
| ... | @@ -879,25 +880,32 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -879,25 +880,32 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 879 | break :blk false; | 880 | break :blk false; |
| 880 | }; | 881 | }; |
| 881 | 882 | ||
| 882 | const DarwinOptions = struct { | 883 | const darwin_can_use_system_linker_and_sdk = |
| 883 | syslibroot: ?[]const u8 = null, | 884 | // comptime conditions |
| 884 | system_linker_hack: bool = false, | 885 | ((build_options.have_llvm and comptime std.Target.current.isDarwin()) and |
| 886 | // runtime conditions | ||
| 887 | (use_lld and std.builtin.os.tag == .macos and options.target.isDarwin())); | ||
| 888 | |||
| 889 | const darwin_system_linker_hack = blk: { | ||
| 890 | if (darwin_can_use_system_linker_and_sdk) { | ||
| 891 | break :blk std.os.getenv("ZIG_SYSTEM_LINKER_HACK") != null; | ||
| 892 | } else { | ||
| 893 | break :blk false; | ||
| 894 | } | ||
| 885 | }; | 895 | }; |
| 886 | 896 | ||
| 887 | const darwin_options: DarwinOptions = if (build_options.have_llvm and comptime std.Target.current.isDarwin()) outer: { | 897 | const sysroot = blk: { |
| 888 | const opts: DarwinOptions = if (use_lld and std.builtin.os.tag == .macos and options.target.isDarwin()) inner: { | 898 | if (options.sysroot) |sysroot| { |
| 899 | break :blk sysroot; | ||
| 900 | } else if (darwin_can_use_system_linker_and_sdk) { | ||
| 889 | // TODO Revisit this targeting versions lower than macOS 11 when LLVM 12 is out. | 901 | // TODO Revisit this targeting versions lower than macOS 11 when LLVM 12 is out. |
| 890 | // See https://github.com/ziglang/zig/issues/6996 | 902 | // See https://github.com/ziglang/zig/issues/6996 |
| 891 | const at_least_big_sur = options.target.os.getVersionRange().semver.min.major >= 11; | 903 | const at_least_big_sur = options.target.os.getVersionRange().semver.min.major >= 11; |
| 892 | const syslibroot = if (at_least_big_sur) try std.zig.system.getSDKPath(arena) else null; | 904 | break :blk if (at_least_big_sur) try std.zig.system.getSDKPath(arena) else null; |
| 893 | const system_linker_hack = std.os.getenv("ZIG_SYSTEM_LINKER_HACK") != null; | 905 | } else { |
| 894 | break :inner .{ | 906 | break :blk null; |
| 895 | .syslibroot = syslibroot, | 907 | } |
| 896 | .system_linker_hack = system_linker_hack, | 908 | }; |
| 897 | }; | ||
| 898 | } else .{}; | ||
| 899 | break :outer opts; | ||
| 900 | } else .{}; | ||
| 901 | 909 | ||
| 902 | const lto = blk: { | 910 | const lto = blk: { |
| 903 | if (options.want_lto) |explicit| { | 911 | if (options.want_lto) |explicit| { |
| ... | @@ -908,7 +916,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -908,7 +916,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 908 | break :blk false; | 916 | break :blk false; |
| 909 | } else if (options.c_source_files.len == 0) { | 917 | } else if (options.c_source_files.len == 0) { |
| 910 | break :blk false; | 918 | break :blk false; |
| 911 | } else if (darwin_options.system_linker_hack) { | 919 | } else if (darwin_system_linker_hack) { |
| 912 | break :blk false; | 920 | break :blk false; |
| 913 | } else switch (options.output_mode) { | 921 | } else switch (options.output_mode) { |
| 914 | .Lib, .Obj => break :blk false, | 922 | .Lib, .Obj => break :blk false, |
| ... | @@ -1281,13 +1289,14 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -1281,13 +1289,14 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 1281 | .module = module, | 1289 | .module = module, |
| 1282 | .target = options.target, | 1290 | .target = options.target, |
| 1283 | .dynamic_linker = options.dynamic_linker, | 1291 | .dynamic_linker = options.dynamic_linker, |
| 1292 | .sysroot = sysroot, | ||
| 1284 | .output_mode = options.output_mode, | 1293 | .output_mode = options.output_mode, |
| 1285 | .link_mode = link_mode, | 1294 | .link_mode = link_mode, |
| 1286 | .object_format = ofmt, | 1295 | .object_format = ofmt, |
| 1287 | .optimize_mode = options.optimize_mode, | 1296 | .optimize_mode = options.optimize_mode, |
| 1288 | .use_lld = use_lld, | 1297 | .use_lld = use_lld, |
| 1289 | .use_llvm = use_llvm, | 1298 | .use_llvm = use_llvm, |
| 1290 | .system_linker_hack = darwin_options.system_linker_hack, | 1299 | .system_linker_hack = darwin_system_linker_hack, |
| 1291 | .link_libc = link_libc, | 1300 | .link_libc = link_libc, |
| 1292 | .link_libcpp = link_libcpp, | 1301 | .link_libcpp = link_libcpp, |
| 1293 | .link_libunwind = link_libunwind, | 1302 | .link_libunwind = link_libunwind, |
| ... | @@ -1295,7 +1304,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -1295,7 +1304,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 1295 | .frameworks = options.frameworks, | 1304 | .frameworks = options.frameworks, |
| 1296 | .framework_dirs = options.framework_dirs, | 1305 | .framework_dirs = options.framework_dirs, |
| 1297 | .system_libs = system_libs, | 1306 | .system_libs = system_libs, |
| 1298 | .syslibroot = darwin_options.syslibroot, | ||
| 1299 | .wasi_emulated_libs = options.wasi_emulated_libs, | 1307 | .wasi_emulated_libs = options.wasi_emulated_libs, |
| 1300 | .lib_dirs = options.lib_dirs, | 1308 | .lib_dirs = options.lib_dirs, |
| 1301 | .rpath_list = options.rpath_list, | 1309 | .rpath_list = options.rpath_list, |
src/link.zig+2-2| ... | @@ -38,6 +38,8 @@ pub const Options = struct { | ... | @@ -38,6 +38,8 @@ pub const Options = struct { |
| 38 | /// Not every Compilation compiles .zig code! For example you could do `zig build-exe foo.o`. | 38 | /// Not every Compilation compiles .zig code! For example you could do `zig build-exe foo.o`. |
| 39 | module: ?*Module, | 39 | module: ?*Module, |
| 40 | dynamic_linker: ?[]const u8, | 40 | dynamic_linker: ?[]const u8, |
| 41 | /// The root path for the dynamic linker and system libraries (as well as frameworks on Darwin) | ||
| 42 | sysroot: ?[]const u8, | ||
| 41 | /// Used for calculating how much space to reserve for symbols in case the binary file | 43 | /// Used for calculating how much space to reserve for symbols in case the binary file |
| 42 | /// does not already have a symbol table. | 44 | /// does not already have a symbol table. |
| 43 | symbol_count_hint: u64 = 32, | 45 | symbol_count_hint: u64 = 32, |
| ... | @@ -104,8 +106,6 @@ pub const Options = struct { | ... | @@ -104,8 +106,6 @@ pub const Options = struct { |
| 104 | llvm_cpu_features: ?[*:0]const u8, | 106 | llvm_cpu_features: ?[*:0]const u8, |
| 105 | /// Extra args passed directly to LLD. Ignored when not linking with LLD. | 107 | /// Extra args passed directly to LLD. Ignored when not linking with LLD. |
| 106 | extra_lld_args: []const []const u8, | 108 | extra_lld_args: []const []const u8, |
| 107 | /// Darwin-only. Set the root path to the system libraries and frameworks. | ||
| 108 | syslibroot: ?[]const u8, | ||
| 109 | 109 | ||
| 110 | objects: []const []const u8, | 110 | objects: []const []const u8, |
| 111 | framework_dirs: []const []const u8, | 111 | 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+6-6| ... | @@ -704,7 +704,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -704,7 +704,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 704 | man.hash.add(allow_shlib_undefined); | 704 | man.hash.add(allow_shlib_undefined); |
| 705 | man.hash.add(self.base.options.bind_global_refs_locally); | 705 | man.hash.add(self.base.options.bind_global_refs_locally); |
| 706 | man.hash.add(self.base.options.system_linker_hack); | 706 | man.hash.add(self.base.options.system_linker_hack); |
| 707 | man.hash.addOptionalBytes(self.base.options.syslibroot); | 707 | man.hash.addOptionalBytes(self.base.options.sysroot); |
| 708 | 708 | ||
| 709 | // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. | 709 | // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. |
| 710 | _ = try man.hit(); | 710 | _ = try man.hit(); |
| ... | @@ -789,7 +789,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -789,7 +789,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 789 | zld.deinit(); | 789 | zld.deinit(); |
| 790 | } | 790 | } |
| 791 | zld.arch = target.cpu.arch; | 791 | zld.arch = target.cpu.arch; |
| 792 | zld.syslibroot = self.base.options.syslibroot; | 792 | zld.syslibroot = self.base.options.sysroot; |
| 793 | zld.stack_size = stack_size; | 793 | zld.stack_size = stack_size; |
| 794 | 794 | ||
| 795 | // Positional arguments to the linker such as object files and static archives. | 795 | // Positional arguments to the linker such as object files and static archives. |
| ... | @@ -833,7 +833,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -833,7 +833,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 833 | try resolvePaths( | 833 | try resolvePaths( |
| 834 | arena, | 834 | arena, |
| 835 | &libs, | 835 | &libs, |
| 836 | self.base.options.syslibroot, | 836 | self.base.options.sysroot, |
| 837 | self.base.options.lib_dirs, | 837 | self.base.options.lib_dirs, |
| 838 | search_lib_names.items, | 838 | search_lib_names.items, |
| 839 | .lib, | 839 | .lib, |
| ... | @@ -856,7 +856,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -856,7 +856,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 856 | try resolvePaths( | 856 | try resolvePaths( |
| 857 | arena, | 857 | arena, |
| 858 | &libs, | 858 | &libs, |
| 859 | self.base.options.syslibroot, | 859 | self.base.options.sysroot, |
| 860 | self.base.options.framework_dirs, | 860 | self.base.options.framework_dirs, |
| 861 | self.base.options.frameworks, | 861 | self.base.options.frameworks, |
| 862 | .framework, | 862 | .framework, |
| ... | @@ -868,7 +868,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -868,7 +868,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 868 | try argv.append("zig"); | 868 | try argv.append("zig"); |
| 869 | try argv.append("ld"); | 869 | try argv.append("ld"); |
| 870 | 870 | ||
| 871 | if (self.base.options.syslibroot) |syslibroot| { | 871 | if (self.base.options.sysroot) |syslibroot| { |
| 872 | try argv.append("-syslibroot"); | 872 | try argv.append("-syslibroot"); |
| 873 | try argv.append(syslibroot); | 873 | try argv.append(syslibroot); |
| 874 | } | 874 | } |
| ... | @@ -1017,7 +1017,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -1017,7 +1017,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 1017 | } | 1017 | } |
| 1018 | } | 1018 | } |
| 1019 | 1019 | ||
| 1020 | if (self.base.options.syslibroot) |dir| { | 1020 | if (self.base.options.sysroot) |dir| { |
| 1021 | try argv.append("-syslibroot"); | 1021 | try argv.append("-syslibroot"); |
| 1022 | try argv.append(dir); | 1022 | try argv.append(dir); |
| 1023 | } | 1023 | } |
src/main.zig+10-1| ... | @@ -379,6 +379,7 @@ const usage_build_generic = | ... | @@ -379,6 +379,7 @@ const usage_build_generic = |
| 379 | \\ -T[script], --script [script] Use a custom linker script | 379 | \\ -T[script], --script [script] Use a custom linker script |
| 380 | \\ --version-script [path] Provide a version .map file | 380 | \\ --version-script [path] Provide a version .map file |
| 381 | \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so) | 381 | \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so) |
| 382 | \\ --sysroot [path] Set the system root directory (usually /) | ||
| 382 | \\ --version [ver] Dynamic library semver | 383 | \\ --version [ver] Dynamic library semver |
| 383 | \\ -fsoname[=name] (Linux) Override the default SONAME value | 384 | \\ -fsoname[=name] (Linux) Override the default SONAME value |
| 384 | \\ -fno-soname (Linux) Disable emitting a SONAME | 385 | \\ -fno-soname (Linux) Disable emitting a SONAME |
| ... | @@ -604,6 +605,7 @@ fn buildOutputType( | ... | @@ -604,6 +605,7 @@ fn buildOutputType( |
| 604 | var link_eh_frame_hdr = false; | 605 | var link_eh_frame_hdr = false; |
| 605 | var link_emit_relocs = false; | 606 | var link_emit_relocs = false; |
| 606 | var each_lib_rpath: ?bool = null; | 607 | var each_lib_rpath: ?bool = null; |
| 608 | var sysroot: ?[]const u8 = null; | ||
| 607 | var libc_paths_file: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_LIBC"); | 609 | var libc_paths_file: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_LIBC"); |
| 608 | var machine_code_model: std.builtin.CodeModel = .default; | 610 | var machine_code_model: std.builtin.CodeModel = .default; |
| 609 | var runtime_args_start: ?usize = null; | 611 | var runtime_args_start: ?usize = null; |
| ... | @@ -865,6 +867,10 @@ fn buildOutputType( | ... | @@ -865,6 +867,10 @@ fn buildOutputType( |
| 865 | if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); | 867 | if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); |
| 866 | i += 1; | 868 | i += 1; |
| 867 | target_dynamic_linker = args[i]; | 869 | target_dynamic_linker = args[i]; |
| 870 | } else if (mem.eql(u8, arg, "--sysroot")) { | ||
| 871 | if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); | ||
| 872 | i += 1; | ||
| 873 | sysroot = args[i]; | ||
| 868 | } else if (mem.eql(u8, arg, "--libc")) { | 874 | } else if (mem.eql(u8, arg, "--libc")) { |
| 869 | if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); | 875 | if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); |
| 870 | i += 1; | 876 | i += 1; |
| ... | @@ -1641,7 +1647,9 @@ fn buildOutputType( | ... | @@ -1641,7 +1647,9 @@ fn buildOutputType( |
| 1641 | want_native_include_dirs = true; | 1647 | want_native_include_dirs = true; |
| 1642 | } | 1648 | } |
| 1643 | 1649 | ||
| 1644 | if (cross_target.isNativeOs() and (system_libs.items.len != 0 or want_native_include_dirs)) { | 1650 | if (sysroot == null and cross_target.isNativeOs() and |
| 1651 | (system_libs.items.len != 0 or want_native_include_dirs)) | ||
| 1652 | { | ||
| 1645 | const paths = std.zig.system.NativePaths.detect(arena, target_info) catch |err| { | 1653 | const paths = std.zig.system.NativePaths.detect(arena, target_info) catch |err| { |
| 1646 | fatal("unable to detect native system paths: {s}", .{@errorName(err)}); | 1654 | fatal("unable to detect native system paths: {s}", .{@errorName(err)}); |
| 1647 | }; | 1655 | }; |
| ... | @@ -1918,6 +1926,7 @@ fn buildOutputType( | ... | @@ -1918,6 +1926,7 @@ fn buildOutputType( |
| 1918 | .is_native_os = cross_target.isNativeOs(), | 1926 | .is_native_os = cross_target.isNativeOs(), |
| 1919 | .is_native_abi = cross_target.isNativeAbi(), | 1927 | .is_native_abi = cross_target.isNativeAbi(), |
| 1920 | .dynamic_linker = target_info.dynamic_linker.get(), | 1928 | .dynamic_linker = target_info.dynamic_linker.get(), |
| 1929 | .sysroot = sysroot, | ||
| 1921 | .output_mode = output_mode, | 1930 | .output_mode = output_mode, |
| 1922 | .root_pkg = root_pkg, | 1931 | .root_pkg = root_pkg, |
| 1923 | .emit_bin = emit_bin_loc, | 1932 | .emit_bin = emit_bin_loc, |