authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-14 22:57:12-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-23 16:27:38-07:00
log4706ec81d4f864bc08804d9600937848ff9e4290
tree2771856f2b8da6be686fd81e2d8c76c7b7d51a84
parent5b016e290a5ba335b295afeae104af6b3396a425

introduce a CLI flag to enable .so scripts; default off

The compiler defaults this value to off so that users whose system shared libraries are all ELF files don't have to pay the cost of checking every file to find out if it is a text file instead. When a GNU ld script is encountered, the error message instructs users about the CLI flag that will immediately solve their problem.

6 files changed, 36 insertions(+), 1 deletions(-)

lib/compiler/build_runner.zig+6
......@@ -280,6 +280,10 @@ pub fn main() !void {
280280 builder.enable_darling = true;
281281 } else if (mem.eql(u8, arg, "-fno-darling")) {
282282 builder.enable_darling = false;
283 } else if (mem.eql(u8, arg, "-fallow-so-scripts")) {
284 graph.allow_so_scripts = true;
285 } else if (mem.eql(u8, arg, "-fno-allow-so-scripts")) {
286 graph.allow_so_scripts = false;
283287 } else if (mem.eql(u8, arg, "-freference-trace")) {
284288 builder.reference_trace = 256;
285289 } else if (mem.startsWith(u8, arg, "-freference-trace=")) {
......@@ -1341,6 +1345,8 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
13411345 \\Advanced Options:
13421346 \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error
13431347 \\ -fno-reference-trace Disable reference trace
1348 \\ -fallow-so-scripts Allows .so files to be GNU ld scripts
1349 \\ -fno-allow-so-scripts (default) .so files must be ELF files
13441350 \\ --build-file [file] Override path to build.zig
13451351 \\ --cache-dir [path] Override path to local Zig cache directory
13461352 \\ --global-cache-dir [path] Override path to global Zig cache directory
lib/std/Build.zig+1
......@@ -123,6 +123,7 @@ pub const Graph = struct {
123123 incremental: ?bool = null,
124124 random_seed: u32 = 0,
125125 dependency_cache: InitializedDepMap = .empty,
126 allow_so_scripts: ?bool = null,
126127};
127128
128129const AvailableDeps = []const struct { []const u8, []const u8 };
lib/std/Build/Step/Compile.zig+10
......@@ -186,6 +186,15 @@ want_lto: ?bool = null,
186186use_llvm: ?bool,
187187use_lld: ?bool,
188188
189/// Corresponds to the `-fallow-so-scripts` / `-fno-allow-so-scripts` CLI
190/// flags, overriding the global user setting provided to the `zig build`
191/// command.
192///
193/// The compiler defaults this value to off so that users whose system shared
194/// libraries are all ELF files don't have to pay the cost of checking every
195/// file to find out if it is a text file instead.
196allow_so_scripts: ?bool = null,
197
189198/// This is an advanced setting that can change the intent of this Compile step.
190199/// If this value is non-null, it means that this Compile step exists to
191200/// check for compile errors and return *success* if they match, and failure
......@@ -1036,6 +1045,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
10361045 if (b.reference_trace) |some| {
10371046 try zig_args.append(try std.fmt.allocPrint(arena, "-freference-trace={d}", .{some}));
10381047 }
1048 try addFlag(&zig_args, "allow-so-scripts", compile.allow_so_scripts orelse b.graph.allow_so_scripts);
10391049
10401050 try addFlag(&zig_args, "llvm", compile.use_llvm);
10411051 try addFlag(&zig_args, "lld", compile.use_lld);
src/link/Elf.zig+6
......@@ -1337,6 +1337,12 @@ pub fn parseInputReportingFailure(self: *Elf, path: Path, needed: bool, must_lin
13371337 .needed = needed,
13381338 }, &self.shared_objects, &self.files, target) catch |err| switch (err) {
13391339 error.LinkFailure => return, // already reported
1340 error.BadMagic, error.UnexpectedEndOfFile => {
1341 var notes = diags.addErrorWithNotes(2) catch return diags.setAllocFailure();
1342 notes.addMsg("failed to parse shared object: {s}", .{@errorName(err)}) catch return diags.setAllocFailure();
1343 notes.addNote("while parsing {}", .{path}) catch return diags.setAllocFailure();
1344 notes.addNote("{s}", .{@as([]const u8, "the file may be a GNU ld script, in which case it is not an ELF file but a text file referencing other libraries to link. In this case, avoid depending on the library, convince your system administrators to refrain from using this kind of file, or pass -fallow-so-scripts to force the compiler to check every shared library in case it is an ld script.")}) catch return diags.setAllocFailure();
1345 },
13401346 else => |e| diags.addParseError(path, "failed to parse shared object: {s}", .{@errorName(e)}),
13411347 },
13421348 .static_library => parseArchive(self, path, must_link) catch |err| switch (err) {
src/main.zig+9-1
......@@ -555,6 +555,8 @@ const usage_build_generic =
555555 \\ -fno-each-lib-rpath Prevent adding rpath for each used dynamic library
556556 \\ -fallow-shlib-undefined Allows undefined symbols in shared libraries
557557 \\ -fno-allow-shlib-undefined Disallows undefined symbols in shared libraries
558 \\ -fallow-so-scripts Allows .so files to be GNU ld scripts
559 \\ -fno-allow-so-scripts (default) .so files must be ELF files
558560 \\ --build-id[=style] At a minor link-time expense, coordinates stripped binaries
559561 \\ fast, uuid, sha1, md5 with debug symbols via a '.note.gnu.build-id' section
560562 \\ 0x[hexstring] Maximum 32 bytes
......@@ -1003,6 +1005,7 @@ fn buildOutputType(
10031005 .libc_paths_file = try EnvVar.ZIG_LIBC.get(arena),
10041006 .link_objects = .{},
10051007 .native_system_include_paths = &.{},
1008 .allow_so_scripts = false,
10061009 };
10071010
10081011 // before arg parsing, check for the NO_COLOR and CLICOLOR_FORCE environment variables
......@@ -1573,6 +1576,10 @@ fn buildOutputType(
15731576 linker_allow_shlib_undefined = true;
15741577 } else if (mem.eql(u8, arg, "-fno-allow-shlib-undefined")) {
15751578 linker_allow_shlib_undefined = false;
1579 } else if (mem.eql(u8, arg, "-fallow-so-scripts")) {
1580 create_module.allow_so_scripts = true;
1581 } else if (mem.eql(u8, arg, "-fno-allow-so-scripts")) {
1582 create_module.allow_so_scripts = false;
15761583 } else if (mem.eql(u8, arg, "-z")) {
15771584 const z_arg = args_iter.nextOrFatal();
15781585 if (mem.eql(u8, z_arg, "nodelete")) {
......@@ -3679,6 +3686,7 @@ const CreateModule = struct {
36793686 each_lib_rpath: ?bool,
36803687 libc_paths_file: ?[]const u8,
36813688 link_objects: std.ArrayListUnmanaged(Compilation.LinkObject),
3689 allow_so_scripts: bool,
36823690};
36833691
36843692fn createModule(
......@@ -6950,7 +6958,7 @@ fn accessLibPath(
69506958
69516959 // In the case of .so files, they might actually be "linker scripts"
69526960 // that contain references to other libraries.
6953 if (target.ofmt == .elf and mem.endsWith(u8, test_path.items, ".so")) {
6961 if (create_module.allow_so_scripts and target.ofmt == .elf and mem.endsWith(u8, test_path.items, ".so")) {
69546962 var file = fs.cwd().openFile(test_path.items, .{}) catch |err| switch (err) {
69556963 error.FileNotFound => break :main_check,
69566964 else => |e| fatal("unable to search for {s} library '{s}': {s}", .{
test/link/elf.zig+4
......@@ -2145,6 +2145,7 @@ fn testLdScript(b: *Build, opts: Options) *Step {
21452145 exe.addLibraryPath(dso.getEmittedBinDirectory());
21462146 exe.addRPath(dso.getEmittedBinDirectory());
21472147 exe.linkLibC();
2148 exe.allow_so_scripts = true;
21482149
21492150 const run = addRunArtifact(exe);
21502151 run.expectExitCode(0);
......@@ -2164,6 +2165,7 @@ fn testLdScriptPathError(b: *Build, opts: Options) *Step {
21642165 exe.linkSystemLibrary2("a", .{});
21652166 exe.addLibraryPath(scripts.getDirectory());
21662167 exe.linkLibC();
2168 exe.allow_so_scripts = true;
21672169
21682170 // TODO: A future enhancement could make this error message also mention
21692171 // the file that references the missing library.
......@@ -2201,6 +2203,7 @@ fn testLdScriptAllowUndefinedVersion(b: *Build, opts: Options) *Step {
22012203 });
22022204 exe.linkLibrary(so);
22032205 exe.linkLibC();
2206 exe.allow_so_scripts = true;
22042207
22052208 const run = addRunArtifact(exe);
22062209 run.expectStdErrEqual("3\n");
......@@ -2223,6 +2226,7 @@ fn testLdScriptDisallowUndefinedVersion(b: *Build, opts: Options) *Step {
22232226 const ld = b.addWriteFiles().add("add.ld", "VERSION { ADD_1.0 { global: add; sub; local: *; }; }");
22242227 so.setLinkerScript(ld);
22252228 so.linker_allow_undefined_version = false;
2229 so.allow_so_scripts = true;
22262230
22272231 expectLinkErrors(
22282232 so,