diff --git a/src/Compilation.zig b/src/Compilation.zig index 954acd44b76b..7233345a7bbe 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -635,6 +635,7 @@ pub const InitOptions = struct { linker_script: ?[]const u8 = null, version_script: ?[]const u8 = null, soname: ?[]const u8 = null, + linker_allow_undefined_version: ?bool = null, linker_gc_sections: ?bool = null, linker_allow_shlib_undefined: ?bool = null, linker_bind_global_refs_locally: ?bool = null, @@ -1619,6 +1620,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .shared_memory = options.linker_shared_memory, .global_base = options.linker_global_base, .export_symbol_names = options.linker_export_symbol_names, + .allow_undefined_version = options.linker_allow_undefined_version, .print_gc_sections = options.linker_print_gc_sections, .print_icf_sections = options.linker_print_icf_sections, .print_map = options.linker_print_map, @@ -2446,7 +2448,7 @@ fn prepareWholeEmitSubPath(arena: Allocator, opt_emit: ?EmitLoc) error{OutOfMemo /// to remind the programmer to update multiple related pieces of code that /// are in different locations. Bump this number when adding or deleting /// anything from the link cache manifest. -pub const link_hash_implementation_version = 10; +pub const link_hash_implementation_version = 11; fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void { const gpa = comp.gpa; @@ -2456,7 +2458,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - comptime assert(link_hash_implementation_version == 10); + comptime assert(link_hash_implementation_version == 11); if (comp.bin_file.options.module) |mod| { const main_zig_file = try mod.main_mod.root.joinString(arena, mod.main_mod.root_src_path); @@ -2569,6 +2571,8 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes man.hash.add(comp.bin_file.options.tsan); man.hash.addOptionalBytes(comp.bin_file.options.sysroot); man.hash.add(comp.bin_file.options.linker_optimization); + man.hash.addOptional(comp.bin_file.options.allow_undefined_version); + // WASM specific stuff man.hash.add(comp.bin_file.options.import_memory); diff --git a/src/link.zig b/src/link.zig index 1648d6a63efa..74b88640fb30 100644 --- a/src/link.zig +++ b/src/link.zig @@ -193,6 +193,7 @@ pub const Options = struct { sort_section: ?SortSection, major_subsystem_version: ?u32, minor_subsystem_version: ?u32, + allow_undefined_version: ?bool = null, gc_sections: ?bool = null, allow_shlib_undefined: ?bool, subsystem: ?std.Target.SubSystem, diff --git a/src/link/Coff/lld.zig b/src/link/Coff/lld.zig index cbefcbd91e73..d209d24517f5 100644 --- a/src/link/Coff/lld.zig +++ b/src/link/Coff/lld.zig @@ -63,7 +63,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod man = comp.cache_parent.obtain(); self.base.releaseLock(); - comptime assert(Compilation.link_hash_implementation_version == 10); + comptime assert(Compilation.link_hash_implementation_version == 11); for (self.base.options.objects) |obj| { _ = try man.addFile(obj.path, null); diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 63642d4c6a5c..6ac058c8d2a6 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1984,7 +1984,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v // We are about to obtain this lock, so here we give other processes a chance first. self.base.releaseLock(); - comptime assert(Compilation.link_hash_implementation_version == 10); + comptime assert(Compilation.link_hash_implementation_version == 11); try man.addOptionalFile(self.base.options.linker_script); try man.addOptionalFile(self.base.options.version_script); @@ -2047,6 +2047,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v man.hash.add(self.base.options.tsan); man.hash.addOptionalBytes(self.base.options.sysroot); man.hash.add(self.base.options.linker_optimization); + man.hash.addOptional(self.base.options.allow_undefined_version); // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. _ = try man.hit(); @@ -2185,6 +2186,12 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append(arg); } + const allow_undefined_version = self.base.options.allow_undefined_version orelse false; + if (allow_undefined_version) { + try argv.append("--undefined-version"); + } else { + try argv.append("--no-undefined-version"); + } if (gc_sections) { try argv.append("--gc-sections"); } diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig index b94da1d284f0..f37a071ac4ad 100644 --- a/src/link/MachO/zld.zig +++ b/src/link/MachO/zld.zig @@ -55,7 +55,7 @@ pub fn linkWithZld( // We are about to obtain this lock, so here we give other processes a chance first. macho_file.base.releaseLock(); - comptime assert(Compilation.link_hash_implementation_version == 10); + comptime assert(Compilation.link_hash_implementation_version == 11); for (options.objects) |obj| { _ = try man.addFile(obj.path, null); diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index fdac89f8373e..087c117a0f70 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -3308,7 +3308,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l // We are about to obtain this lock, so here we give other processes a chance first. wasm.base.releaseLock(); - comptime assert(Compilation.link_hash_implementation_version == 10); + comptime assert(Compilation.link_hash_implementation_version == 11); for (options.objects) |obj| { _ = try man.addFile(obj.path, null); @@ -4376,7 +4376,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! // We are about to obtain this lock, so here we give other processes a chance first. wasm.base.releaseLock(); - comptime assert(Compilation.link_hash_implementation_version == 10); + comptime assert(Compilation.link_hash_implementation_version == 11); for (wasm.base.options.objects) |obj| { _ = try man.addFile(obj.path, null); diff --git a/src/main.zig b/src/main.zig index cbc7283eefb9..a4d7ae93f3e0 100644 --- a/src/main.zig +++ b/src/main.zig @@ -506,6 +506,8 @@ const usage_build_generic = \\ -search_static_only Only search for static libs. \\ -T[script], --script [script] Use a custom linker script \\ --version-script [path] Provide a version .map file + \\ --undefined-version Allow unused version in version script (disabled by default) + \\ --no-undefined-version Makes unused version in version script a fatal error \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so) \\ --sysroot [path] Set the system root directory (usually /) \\ --version [ver] Dynamic library semver @@ -826,6 +828,7 @@ fn buildOutputType( var version_script: ?[]const u8 = null; var disable_c_depfile = false; var linker_sort_section: ?link.SortSection = null; + var linker_allow_undefined_version: ?bool = null; var linker_gc_sections: ?bool = null; var linker_compress_debug_sections: ?link.CompressDebugSections = null; var linker_allow_shlib_undefined: ?bool = null; @@ -2372,7 +2375,11 @@ fn buildOutputType( fatal("unable to parse /version '{s}': {s}", .{ arg, @errorName(err) }); }; have_version = true; - } else if (mem.eql(u8, arg, "--version")) { + } else if (mem.eql(u8, arg, "--undefined-version")) { + linker_allow_undefined_version = true; + } else if (mem.eql(u8, arg, "--no-undefined-version")) { + linker_allow_undefined_version = false; + } else if (mem.eql(u8, arg, "--version")) { try std.io.getStdOut().writeAll("zig ld " ++ build_options.version ++ "\n"); process.exit(0); } else { @@ -3456,6 +3463,7 @@ fn buildOutputType( .version_script = version_script, .disable_c_depfile = disable_c_depfile, .soname = resolved_soname, + .linker_allow_undefined_version = linker_allow_undefined_version, .linker_sort_section = linker_sort_section, .linker_gc_sections = linker_gc_sections, .linker_allow_shlib_undefined = linker_allow_shlib_undefined,