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 {...@@ -280,6 +280,10 @@ pub fn main() !void {
280 builder.enable_darling = true;280 builder.enable_darling = true;
281 } else if (mem.eql(u8, arg, "-fno-darling")) {281 } else if (mem.eql(u8, arg, "-fno-darling")) {
282 builder.enable_darling = false;282 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;
283 } else if (mem.eql(u8, arg, "-freference-trace")) {287 } else if (mem.eql(u8, arg, "-freference-trace")) {
284 builder.reference_trace = 256;288 builder.reference_trace = 256;
285 } else if (mem.startsWith(u8, arg, "-freference-trace=")) {289 } else if (mem.startsWith(u8, arg, "-freference-trace=")) {
...@@ -1341,6 +1345,8 @@ fn usage(b: *std.Build, out_stream: anytype) !void {...@@ -1341,6 +1345,8 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
1341 \\Advanced Options:1345 \\Advanced Options:
1342 \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error1346 \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error
1343 \\ -fno-reference-trace Disable reference trace1347 \\ -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
1344 \\ --build-file [file] Override path to build.zig1350 \\ --build-file [file] Override path to build.zig
1345 \\ --cache-dir [path] Override path to local Zig cache directory1351 \\ --cache-dir [path] Override path to local Zig cache directory
1346 \\ --global-cache-dir [path] Override path to global Zig cache directory1352 \\ --global-cache-dir [path] Override path to global Zig cache directory
lib/std/Build.zig+1
...@@ -123,6 +123,7 @@ pub const Graph = struct {...@@ -123,6 +123,7 @@ pub const Graph = struct {
123 incremental: ?bool = null,123 incremental: ?bool = null,
124 random_seed: u32 = 0,124 random_seed: u32 = 0,
125 dependency_cache: InitializedDepMap = .empty,125 dependency_cache: InitializedDepMap = .empty,
126 allow_so_scripts: ?bool = null,
126};127};
127128
128const AvailableDeps = []const struct { []const u8, []const u8 };129const AvailableDeps = []const struct { []const u8, []const u8 };
lib/std/Build/Step/Compile.zig+10
...@@ -186,6 +186,15 @@ want_lto: ?bool = null,...@@ -186,6 +186,15 @@ want_lto: ?bool = null,
186use_llvm: ?bool,186use_llvm: ?bool,
187use_lld: ?bool,187use_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
189/// This is an advanced setting that can change the intent of this Compile step.198/// This is an advanced setting that can change the intent of this Compile step.
190/// If this value is non-null, it means that this Compile step exists to199/// If this value is non-null, it means that this Compile step exists to
191/// check for compile errors and return *success* if they match, and failure200/// check for compile errors and return *success* if they match, and failure
...@@ -1036,6 +1045,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {...@@ -1036,6 +1045,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
1036 if (b.reference_trace) |some| {1045 if (b.reference_trace) |some| {
1037 try zig_args.append(try std.fmt.allocPrint(arena, "-freference-trace={d}", .{some}));1046 try zig_args.append(try std.fmt.allocPrint(arena, "-freference-trace={d}", .{some}));
1038 }1047 }
1048 try addFlag(&zig_args, "allow-so-scripts", compile.allow_so_scripts orelse b.graph.allow_so_scripts);
10391049
1040 try addFlag(&zig_args, "llvm", compile.use_llvm);1050 try addFlag(&zig_args, "llvm", compile.use_llvm);
1041 try addFlag(&zig_args, "lld", compile.use_lld);1051 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...@@ -1337,6 +1337,12 @@ pub fn parseInputReportingFailure(self: *Elf, path: Path, needed: bool, must_lin
1337 .needed = needed,1337 .needed = needed,
1338 }, &self.shared_objects, &self.files, target) catch |err| switch (err) {1338 }, &self.shared_objects, &self.files, target) catch |err| switch (err) {
1339 error.LinkFailure => return, // already reported1339 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 },
1340 else => |e| diags.addParseError(path, "failed to parse shared object: {s}", .{@errorName(e)}),1346 else => |e| diags.addParseError(path, "failed to parse shared object: {s}", .{@errorName(e)}),
1341 },1347 },
1342 .static_library => parseArchive(self, path, must_link) catch |err| switch (err) {1348 .static_library => parseArchive(self, path, must_link) catch |err| switch (err) {
src/main.zig+9-1
...@@ -555,6 +555,8 @@ const usage_build_generic =...@@ -555,6 +555,8 @@ const usage_build_generic =
555 \\ -fno-each-lib-rpath Prevent adding rpath for each used dynamic library555 \\ -fno-each-lib-rpath Prevent adding rpath for each used dynamic library
556 \\ -fallow-shlib-undefined Allows undefined symbols in shared libraries556 \\ -fallow-shlib-undefined Allows undefined symbols in shared libraries
557 \\ -fno-allow-shlib-undefined Disallows undefined symbols in shared libraries557 \\ -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
558 \\ --build-id[=style] At a minor link-time expense, coordinates stripped binaries560 \\ --build-id[=style] At a minor link-time expense, coordinates stripped binaries
559 \\ fast, uuid, sha1, md5 with debug symbols via a '.note.gnu.build-id' section561 \\ fast, uuid, sha1, md5 with debug symbols via a '.note.gnu.build-id' section
560 \\ 0x[hexstring] Maximum 32 bytes562 \\ 0x[hexstring] Maximum 32 bytes
...@@ -1003,6 +1005,7 @@ fn buildOutputType(...@@ -1003,6 +1005,7 @@ fn buildOutputType(
1003 .libc_paths_file = try EnvVar.ZIG_LIBC.get(arena),1005 .libc_paths_file = try EnvVar.ZIG_LIBC.get(arena),
1004 .link_objects = .{},1006 .link_objects = .{},
1005 .native_system_include_paths = &.{},1007 .native_system_include_paths = &.{},
1008 .allow_so_scripts = false,
1006 };1009 };
10071010
1008 // before arg parsing, check for the NO_COLOR and CLICOLOR_FORCE environment variables1011 // before arg parsing, check for the NO_COLOR and CLICOLOR_FORCE environment variables
...@@ -1573,6 +1576,10 @@ fn buildOutputType(...@@ -1573,6 +1576,10 @@ fn buildOutputType(
1573 linker_allow_shlib_undefined = true;1576 linker_allow_shlib_undefined = true;
1574 } else if (mem.eql(u8, arg, "-fno-allow-shlib-undefined")) {1577 } else if (mem.eql(u8, arg, "-fno-allow-shlib-undefined")) {
1575 linker_allow_shlib_undefined = false;1578 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;
1576 } else if (mem.eql(u8, arg, "-z")) {1583 } else if (mem.eql(u8, arg, "-z")) {
1577 const z_arg = args_iter.nextOrFatal();1584 const z_arg = args_iter.nextOrFatal();
1578 if (mem.eql(u8, z_arg, "nodelete")) {1585 if (mem.eql(u8, z_arg, "nodelete")) {
...@@ -3679,6 +3686,7 @@ const CreateModule = struct {...@@ -3679,6 +3686,7 @@ const CreateModule = struct {
3679 each_lib_rpath: ?bool,3686 each_lib_rpath: ?bool,
3680 libc_paths_file: ?[]const u8,3687 libc_paths_file: ?[]const u8,
3681 link_objects: std.ArrayListUnmanaged(Compilation.LinkObject),3688 link_objects: std.ArrayListUnmanaged(Compilation.LinkObject),
3689 allow_so_scripts: bool,
3682};3690};
36833691
3684fn createModule(3692fn createModule(
...@@ -6950,7 +6958,7 @@ fn accessLibPath(...@@ -6950,7 +6958,7 @@ fn accessLibPath(
69506958
6951 // In the case of .so files, they might actually be "linker scripts"6959 // In the case of .so files, they might actually be "linker scripts"
6952 // that contain references to other libraries.6960 // 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")) {
6954 var file = fs.cwd().openFile(test_path.items, .{}) catch |err| switch (err) {6962 var file = fs.cwd().openFile(test_path.items, .{}) catch |err| switch (err) {
6955 error.FileNotFound => break :main_check,6963 error.FileNotFound => break :main_check,
6956 else => |e| fatal("unable to search for {s} library '{s}': {s}", .{6964 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 {...@@ -2145,6 +2145,7 @@ fn testLdScript(b: *Build, opts: Options) *Step {
2145 exe.addLibraryPath(dso.getEmittedBinDirectory());2145 exe.addLibraryPath(dso.getEmittedBinDirectory());
2146 exe.addRPath(dso.getEmittedBinDirectory());2146 exe.addRPath(dso.getEmittedBinDirectory());
2147 exe.linkLibC();2147 exe.linkLibC();
2148 exe.allow_so_scripts = true;
21482149
2149 const run = addRunArtifact(exe);2150 const run = addRunArtifact(exe);
2150 run.expectExitCode(0);2151 run.expectExitCode(0);
...@@ -2164,6 +2165,7 @@ fn testLdScriptPathError(b: *Build, opts: Options) *Step {...@@ -2164,6 +2165,7 @@ fn testLdScriptPathError(b: *Build, opts: Options) *Step {
2164 exe.linkSystemLibrary2("a", .{});2165 exe.linkSystemLibrary2("a", .{});
2165 exe.addLibraryPath(scripts.getDirectory());2166 exe.addLibraryPath(scripts.getDirectory());
2166 exe.linkLibC();2167 exe.linkLibC();
2168 exe.allow_so_scripts = true;
21672169
2168 // TODO: A future enhancement could make this error message also mention2170 // TODO: A future enhancement could make this error message also mention
2169 // the file that references the missing library.2171 // the file that references the missing library.
...@@ -2201,6 +2203,7 @@ fn testLdScriptAllowUndefinedVersion(b: *Build, opts: Options) *Step {...@@ -2201,6 +2203,7 @@ fn testLdScriptAllowUndefinedVersion(b: *Build, opts: Options) *Step {
2201 });2203 });
2202 exe.linkLibrary(so);2204 exe.linkLibrary(so);
2203 exe.linkLibC();2205 exe.linkLibC();
2206 exe.allow_so_scripts = true;
22042207
2205 const run = addRunArtifact(exe);2208 const run = addRunArtifact(exe);
2206 run.expectStdErrEqual("3\n");2209 run.expectStdErrEqual("3\n");
...@@ -2223,6 +2226,7 @@ fn testLdScriptDisallowUndefinedVersion(b: *Build, opts: Options) *Step {...@@ -2223,6 +2226,7 @@ fn testLdScriptDisallowUndefinedVersion(b: *Build, opts: Options) *Step {
2223 const ld = b.addWriteFiles().add("add.ld", "VERSION { ADD_1.0 { global: add; sub; local: *; }; }");2226 const ld = b.addWriteFiles().add("add.ld", "VERSION { ADD_1.0 { global: add; sub; local: *; }; }");
2224 so.setLinkerScript(ld);2227 so.setLinkerScript(ld);
2225 so.linker_allow_undefined_version = false;2228 so.linker_allow_undefined_version = false;
2229 so.allow_so_scripts = true;
22262230
2227 expectLinkErrors(2231 expectLinkErrors(
2228 so,2232 so,