authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-24 07:22:05+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-03-24 07:22:05+01:00
logf99b75360db55413f4accf43a6f4161b14a5de9f
treebb57058b7ac0006f62813de35ce8b610587ee433
parent3aa0a7ecdf3f88d0d37e20c88bf57b69355573fe
parent145f93ba961fb9eea66a39b60e93c2aa5e26ee40
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #15061 from ziglang/fix-15036

build: fix adding rpaths on darwin, improve CheckObjectStep to allow matching FileSource paths

3 files changed, 72 insertions(+), 32 deletions(-)

lib/std/Build/CheckObjectStep.zig+55-28
......@@ -58,6 +58,16 @@ pub fn runAndCompare(self: *CheckObjectStep) *std.Build.RunStep {
5858 return run;
5959}
6060
61const SearchPhrase = struct {
62 string: []const u8,
63 file_source: ?std.Build.FileSource = null,
64
65 fn resolve(phrase: SearchPhrase, b: *std.Build, step: *Step) []const u8 {
66 const file_source = phrase.file_source orelse return phrase.string;
67 return b.fmt("{s} {s}", .{ phrase.string, file_source.getPath2(b, step) });
68 }
69};
70
6171/// There two types of actions currently suported:
6272/// * `.match` - is the main building block of standard matchers with optional eat-all token `{*}`
6373/// and extractors by name such as `{n_value}`. Please note this action is very simplistic in nature
......@@ -72,7 +82,7 @@ pub fn runAndCompare(self: *CheckObjectStep) *std.Build.RunStep {
7282/// they could then be added with this simple program `vmaddr entryoff +`.
7383const Action = struct {
7484 tag: enum { match, not_present, compute_cmp },
75 phrase: []const u8,
85 phrase: SearchPhrase,
7686 expected: ?ComputeCompareExpected = null,
7787
7888 /// Will return true if the `phrase` was found in the `haystack`.
......@@ -83,12 +93,18 @@ const Action = struct {
8393 /// and save under `vmaddr` global name (see `global_vars` param)
8494 /// name {*}libobjc{*}.dylib => will match `name` followed by a token which contains `libobjc` and `.dylib`
8595 /// in that order with other letters in between
86 fn match(act: Action, haystack: []const u8, global_vars: anytype) !bool {
96 fn match(
97 act: Action,
98 b: *std.Build,
99 step: *Step,
100 haystack: []const u8,
101 global_vars: anytype,
102 ) !bool {
87103 assert(act.tag == .match or act.tag == .not_present);
88
104 const phrase = act.phrase.resolve(b, step);
89105 var candidate_var: ?struct { name: []const u8, value: u64 } = null;
90106 var hay_it = mem.tokenize(u8, mem.trim(u8, haystack, " "), " ");
91 var needle_it = mem.tokenize(u8, mem.trim(u8, act.phrase, " "), " ");
107 var needle_it = mem.tokenize(u8, mem.trim(u8, phrase, " "), " ");
92108
93109 while (needle_it.next()) |needle_tok| {
94110 const hay_tok = hay_it.next() orelse return false;
......@@ -133,12 +149,13 @@ const Action = struct {
133149 /// Will return true if the `phrase` is correctly parsed into an RPN program and
134150 /// its reduced, computed value compares using `op` with the expected value, either
135151 /// a literal or another extracted variable.
136 fn computeCmp(act: Action, step: *Step, global_vars: anytype) !bool {
152 fn computeCmp(act: Action, b: *std.Build, step: *Step, global_vars: anytype) !bool {
137153 const gpa = step.owner.allocator;
154 const phrase = act.phrase.resolve(b, step);
138155 var op_stack = std.ArrayList(enum { add, sub, mod, mul }).init(gpa);
139156 var values = std.ArrayList(u64).init(gpa);
140157
141 var it = mem.tokenize(u8, act.phrase, " ");
158 var it = mem.tokenize(u8, phrase, " ");
142159 while (it.next()) |next| {
143160 if (mem.eql(u8, next, "+")) {
144161 try op_stack.append(.add);
......@@ -225,34 +242,32 @@ const ComputeCompareExpected = struct {
225242};
226243
227244const Check = struct {
228 builder: *std.Build,
229245 actions: std.ArrayList(Action),
230246
231 fn create(b: *std.Build) Check {
247 fn create(allocator: Allocator) Check {
232248 return .{
233 .builder = b,
234 .actions = std.ArrayList(Action).init(b.allocator),
249 .actions = std.ArrayList(Action).init(allocator),
235250 };
236251 }
237252
238 fn match(self: *Check, phrase: []const u8) void {
253 fn match(self: *Check, phrase: SearchPhrase) void {
239254 self.actions.append(.{
240255 .tag = .match,
241 .phrase = self.builder.dupe(phrase),
256 .phrase = phrase,
242257 }) catch @panic("OOM");
243258 }
244259
245 fn notPresent(self: *Check, phrase: []const u8) void {
260 fn notPresent(self: *Check, phrase: SearchPhrase) void {
246261 self.actions.append(.{
247262 .tag = .not_present,
248 .phrase = self.builder.dupe(phrase),
263 .phrase = phrase,
249264 }) catch @panic("OOM");
250265 }
251266
252 fn computeCmp(self: *Check, phrase: []const u8, expected: ComputeCompareExpected) void {
267 fn computeCmp(self: *Check, phrase: SearchPhrase, expected: ComputeCompareExpected) void {
253268 self.actions.append(.{
254269 .tag = .compute_cmp,
255 .phrase = self.builder.dupe(phrase),
270 .phrase = phrase,
256271 .expected = expected,
257272 }) catch @panic("OOM");
258273 }
......@@ -260,8 +275,8 @@ const Check = struct {
260275
261276/// Creates a new sequence of actions with `phrase` as the first anchor searched phrase.
262277pub fn checkStart(self: *CheckObjectStep, phrase: []const u8) void {
263 var new_check = Check.create(self.step.owner);
264 new_check.match(phrase);
278 var new_check = Check.create(self.step.owner.allocator);
279 new_check.match(.{ .string = self.step.owner.dupe(phrase) });
265280 self.checks.append(new_check) catch @panic("OOM");
266281}
267282
......@@ -270,7 +285,19 @@ pub fn checkStart(self: *CheckObjectStep, phrase: []const u8) void {
270285pub fn checkNext(self: *CheckObjectStep, phrase: []const u8) void {
271286 assert(self.checks.items.len > 0);
272287 const last = &self.checks.items[self.checks.items.len - 1];
273 last.match(phrase);
288 last.match(.{ .string = self.step.owner.dupe(phrase) });
289}
290
291/// Like `checkNext()` but takes an additional argument `FileSource` which will be
292/// resolved to a full search query in `make()`.
293pub fn checkNextFileSource(
294 self: *CheckObjectStep,
295 phrase: []const u8,
296 file_source: std.Build.FileSource,
297) void {
298 assert(self.checks.items.len > 0);
299 const last = &self.checks.items[self.checks.items.len - 1];
300 last.match(.{ .string = self.step.owner.dupe(phrase), .file_source = file_source });
274301}
275302
276303/// Adds another searched phrase to the latest created Check with `CheckObjectStep.checkStart(...)`
......@@ -279,7 +306,7 @@ pub fn checkNext(self: *CheckObjectStep, phrase: []const u8) void {
279306pub fn checkNotPresent(self: *CheckObjectStep, phrase: []const u8) void {
280307 assert(self.checks.items.len > 0);
281308 const last = &self.checks.items[self.checks.items.len - 1];
282 last.notPresent(phrase);
309 last.notPresent(.{ .string = self.step.owner.dupe(phrase) });
283310}
284311
285312/// Creates a new check checking specifically symbol table parsed and dumped from the object
......@@ -302,8 +329,8 @@ pub fn checkComputeCompare(
302329 program: []const u8,
303330 expected: ComputeCompareExpected,
304331) void {
305 var new_check = Check.create(self.step.owner);
306 new_check.computeCmp(program, expected);
332 var new_check = Check.create(self.step.owner.allocator);
333 new_check.computeCmp(.{ .string = self.step.owner.dupe(program) }, expected);
307334 self.checks.append(new_check) catch @panic("OOM");
308335}
309336
......@@ -343,7 +370,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
343370 switch (act.tag) {
344371 .match => {
345372 while (it.next()) |line| {
346 if (try act.match(line, &vars)) break;
373 if (try act.match(b, step, line, &vars)) break;
347374 } else {
348375 return step.fail(
349376 \\
......@@ -352,12 +379,12 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
352379 \\========= but parsed file does not contain it: =======
353380 \\{s}
354381 \\======================================================
355 , .{ act.phrase, output });
382 , .{ act.phrase.resolve(b, step), output });
356383 }
357384 },
358385 .not_present => {
359386 while (it.next()) |line| {
360 if (try act.match(line, &vars)) {
387 if (try act.match(b, step, line, &vars)) {
361388 return step.fail(
362389 \\
363390 \\========= expected not to find: ===================
......@@ -365,12 +392,12 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
365392 \\========= but parsed file does contain it: ========
366393 \\{s}
367394 \\===================================================
368 , .{ act.phrase, output });
395 , .{ act.phrase.resolve(b, step), output });
369396 }
370397 }
371398 },
372399 .compute_cmp => {
373 const res = act.computeCmp(step, vars) catch |err| switch (err) {
400 const res = act.computeCmp(b, step, vars) catch |err| switch (err) {
374401 error.UnknownVariable => {
375402 return step.fail(
376403 \\========= from parsed file: =====================
......@@ -388,7 +415,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
388415 \\========= from parsed file: =======================
389416 \\{s}
390417 \\===================================================
391 , .{ act.phrase, act.expected.?, output });
418 , .{ act.phrase.resolve(b, step), act.expected.?, output });
392419 }
393420 },
394421 }
lib/std/Build/CompileStep.zig+16
......@@ -1725,6 +1725,22 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
17251725 try zig_args.ensureUnusedCapacity(2 * self.rpaths.items.len);
17261726 for (self.rpaths.items) |rpath| {
17271727 zig_args.appendAssumeCapacity("-rpath");
1728
1729 if (self.target_info.target.isDarwin()) switch (rpath) {
1730 .path => |path| {
1731 // On Darwin, we should not try to expand special runtime paths such as
1732 // * @executable_path
1733 // * @loader_path
1734 if (mem.startsWith(u8, path, "@executable_path") or
1735 mem.startsWith(u8, path, "@loader_path"))
1736 {
1737 zig_args.appendAssumeCapacity(path);
1738 continue;
1739 }
1740 },
1741 .generated => {},
1742 };
1743
17281744 zig_args.appendAssumeCapacity(rpath.getPath2(b, step));
17291745 }
17301746
test/link/macho/dylib/build.zig+1-4
......@@ -52,10 +52,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
5252 check_exe.checkNext("compatibility version 10000");
5353
5454 check_exe.checkStart("cmd RPATH");
55 // TODO check this (perhaps with `checkNextFileSource(dylib.getOutputDirectorySource())`)
56 //check_exe.checkNext(std.fmt.allocPrint(b.allocator, "path {s}", .{
57 // b.pathFromRoot("zig-out/lib"),
58 //}) catch unreachable);
55 check_exe.checkNextFileSource("path", dylib.getOutputDirectorySource());
5956
6057 const run = check_exe.runAndCompare();
6158 run.expectStdOutEqual("Hello world");