From f09f960ce44ef00c4c05be5919068790898cc049 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 27 Nov 2020 17:54:22 -0700 Subject: [PATCH] Merge branch 'kubkon-elf-soname-opt-in' into master closes #7162 --- src/Compilation.zig | 4 ++-- src/glibc.zig | 7 +++--- src/link.zig | 2 +- src/link/Elf.zig | 17 +++++---------- src/main.zig | 53 +++++++++++++++++++++++++++++++++++---------- 5 files changed, 54 insertions(+), 29 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index b4839e46c4..fedeca9b89 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -360,7 +360,7 @@ pub const InitOptions = struct { link_emit_relocs: bool = false, linker_script: ?[]const u8 = null, version_script: ?[]const u8 = null, - override_soname: ?[]const u8 = null, + soname: ?[]const u8 = null, linker_gc_sections: ?bool = null, linker_allow_shlib_undefined: ?bool = null, linker_bind_global_refs_locally: ?bool = null, @@ -810,7 +810,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { .emit_relocs = options.link_emit_relocs, .rdynamic = options.rdynamic, .extra_lld_args = options.lld_argv, - .override_soname = options.override_soname, + .soname = options.soname, .version = options.version, .libc_installation = libc_dirs.libc_installation, .pic = pic, diff --git a/src/glibc.zig b/src/glibc.zig index 108aeb6f77..3d63f5d3de 100644 --- a/src/glibc.zig +++ b/src/glibc.zig @@ -911,13 +911,14 @@ fn buildSharedLib( const tracy = trace(@src()); defer tracy.end(); + const basename = try std.fmt.allocPrint(arena, "lib{s}.so.{d}", .{ lib.name, lib.sover }); const emit_bin = Compilation.EmitLoc{ .directory = bin_directory, - .basename = try std.fmt.allocPrint(arena, "lib{s}.so.{d}", .{ lib.name, lib.sover }), + .basename = basename, }; const version: std.builtin.Version = .{ .major = lib.sover, .minor = 0, .patch = 0 }; const ld_basename = path.basename(comp.getTarget().standardDynamicLinkerPath().get().?); - const override_soname = if (mem.eql(u8, lib.name, "ld")) ld_basename else null; + const soname = if (mem.eql(u8, lib.name, "ld")) ld_basename else basename; const map_file_path = try path.join(arena, &[_][]const u8{ bin_directory.path.?, all_map_basename }); const c_source_files = [1]Compilation.CSourceFile{ .{ @@ -955,7 +956,7 @@ fn buildSharedLib( .clang_passthrough_mode = comp.clang_passthrough_mode, .version = version, .version_script = map_file_path, - .override_soname = override_soname, + .soname = soname, .c_source_files = &c_source_files, .is_compiler_rt_or_libc = true, }); diff --git a/src/link.zig b/src/link.zig index 7b0271f978..389e4d215c 100644 --- a/src/link.zig +++ b/src/link.zig @@ -87,7 +87,7 @@ pub const Options = struct { subsystem: ?std.Target.SubSystem, linker_script: ?[]const u8, version_script: ?[]const u8, - override_soname: ?[]const u8, + soname: ?[]const u8, llvm_cpu_features: ?[*:0]const u8, /// Extra args passed directly to LLD. Ignored when not linking with LLD. extra_lld_args: []const []const u8, diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 7d4662c68d..2f4dfb7f7a 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1313,10 +1313,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { man.hash.addOptionalBytes(self.base.options.dynamic_linker); } } - if (is_dyn_lib) { - man.hash.addOptionalBytes(self.base.options.override_soname); - man.hash.addOptional(self.base.options.version); - } + man.hash.addOptionalBytes(self.base.options.soname); + man.hash.addOptional(self.base.options.version); man.hash.addStringSet(self.base.options.system_libs); man.hash.add(allow_shlib_undefined); man.hash.add(self.base.options.bind_global_refs_locally); @@ -1505,13 +1503,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { } if (is_dyn_lib) { - const soname = self.base.options.override_soname orelse if (self.base.options.version) |ver| - try std.fmt.allocPrint(arena, "lib{}.so.{}", .{ self.base.options.root_name, ver.major }) - else - try std.fmt.allocPrint(arena, "lib{}.so", .{self.base.options.root_name}); - try argv.append("-soname"); - try argv.append(soname); - + if (self.base.options.soname) |soname| { + try argv.append("-soname"); + try argv.append(soname); + } if (self.base.options.version_script) |version_script| { try argv.append("-version-script"); try argv.append(version_script); diff --git a/src/main.zig b/src/main.zig index 359632bdde..c325180e92 100644 --- a/src/main.zig +++ b/src/main.zig @@ -304,6 +304,8 @@ const usage_build_generic = \\ --version-script [path] Provide a version .map file \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so) \\ --version [ver] Dynamic library semver + \\ -fsoname[=name] (linux) Override the default SONAME value + \\ -fno-soname (linux) Disable emitting a SONAME \\ -rdynamic Add all symbols to the dynamic symbol table \\ -rpath [path] Add directory to the runtime library search path \\ -feach-lib-rpath Ensure adding rpath for each used dynamic library @@ -348,6 +350,12 @@ const repl_help = \\ ; +const SOName = union(enum) { + no, + yes_default_value, + yes: []const u8, +}; + const Emit = union(enum) { no, yes_default_path, @@ -450,6 +458,7 @@ fn buildOutputType( var target_ofmt: ?[]const u8 = null; var output_mode: std.builtin.OutputMode = undefined; var emit_h: Emit = undefined; + var soname: SOName = undefined; var ensure_libc_on_non_freestanding = false; var ensure_libcpp_on_non_freestanding = false; var link_libc = false; @@ -464,7 +473,6 @@ fn buildOutputType( var linker_script: ?[]const u8 = null; var version_script: ?[]const u8 = null; var disable_c_depfile = false; - var override_soname: ?[]const u8 = null; var linker_gc_sections: ?bool = null; var linker_allow_shlib_undefined: ?bool = null; var linker_bind_global_refs_locally: ?bool = null; @@ -561,6 +569,8 @@ fn buildOutputType( // .translate_c, .zig_test, .run => emit_h = .no, // else => unreachable, //} + + soname = .yes_default_value; const args = all_args[2..]; var i: usize = 0; args_loop: while (i < args.len) : (i += 1) { @@ -821,6 +831,12 @@ fn buildOutputType( use_clang = false; } else if (mem.eql(u8, arg, "-rdynamic")) { rdynamic = true; + } else if (mem.eql(u8, arg, "-fsoname")) { + soname = .yes_default_value; + } else if (mem.startsWith(u8, arg, "-fsoname=")) { + soname = .{ .yes = arg["-fsoname=".len..] }; + } else if (mem.eql(u8, arg, "-fno-soname")) { + soname = .no; } else if (mem.eql(u8, arg, "-femit-bin")) { emit_bin = .yes_default_path; } else if (mem.startsWith(u8, arg, "-femit-bin=")) { @@ -948,6 +964,7 @@ fn buildOutputType( }, .cc, .cpp => { emit_h = .no; + soname = .no; strip = true; ensure_libc_on_non_freestanding = true; ensure_libcpp_on_non_freestanding = arg_mode == .cpp; @@ -1091,33 +1108,33 @@ fn buildOutputType( if (i >= linker_args.items.len) { fatal("expected linker arg after '{}'", .{arg}); } - const soname = linker_args.items[i]; - override_soname = soname; + const name = linker_args.items[i]; + soname = .{ .yes = name }; // Use it as --name. // Example: libsoundio.so.2 var prefix: usize = 0; - if (mem.startsWith(u8, soname, "lib")) { + if (mem.startsWith(u8, name, "lib")) { prefix = 3; } - var end: usize = soname.len; - if (mem.endsWith(u8, soname, ".so")) { + var end: usize = name.len; + if (mem.endsWith(u8, name, ".so")) { end -= 3; } else { var found_digit = false; - while (end > 0 and std.ascii.isDigit(soname[end - 1])) { + while (end > 0 and std.ascii.isDigit(name[end - 1])) { found_digit = true; end -= 1; } - if (found_digit and end > 0 and soname[end - 1] == '.') { + if (found_digit and end > 0 and name[end - 1] == '.') { end -= 1; } else { - end = soname.len; + end = name.len; } - if (mem.endsWith(u8, soname[prefix..end], ".so")) { + if (mem.endsWith(u8, name[prefix..end], ".so")) { end -= 3; } } - provided_name = soname[prefix..end]; + provided_name = name[prefix..end]; } else if (mem.eql(u8, arg, "-rpath")) { i += 1; if (i >= linker_args.items.len) { @@ -1419,6 +1436,18 @@ fn buildOutputType( const have_enable_cache = enable_cache orelse false; const optional_version = if (have_version) version else null; + const resolved_soname: ?[]const u8 = switch (soname) { + .yes => |explicit| explicit, + .no => null, + .yes_default_value => switch (object_format) { + .elf => if (have_version) + try std.fmt.allocPrint(arena, "lib{s}.so.{d}", .{ root_name, version.major }) + else + try std.fmt.allocPrint(arena, "lib{s}.so", .{root_name}), + else => null, + }, + }; + const emit_bin_loc: ?Compilation.EmitLoc = switch (emit_bin) { .no => null, .yes_default_path => Compilation.EmitLoc{ @@ -1645,7 +1674,7 @@ fn buildOutputType( .linker_script = linker_script, .version_script = version_script, .disable_c_depfile = disable_c_depfile, - .override_soname = override_soname, + .soname = resolved_soname, .linker_gc_sections = linker_gc_sections, .linker_allow_shlib_undefined = linker_allow_shlib_undefined, .linker_bind_global_refs_locally = linker_bind_global_refs_locally,