Skip to content

linker: fail the compilation if there were linker errors #13562

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 19, 2022

Conversation

kcbanner
Copy link
Contributor

This fixes #13432 and #13235

There was no check for linker errors after flushing, which meant that if the link failed the build would continue, trying to copy the non-existent artifact, and also write the manifest as if it had succeeded.

I added Compilation.lockAndParseLldStderr to consume the stderr result of the lld call, and accumulate it in lld_errors. These errors are then surfaced via the same mechanism the other compilation errors are.

@kcbanner
Copy link
Contributor Author

CI failure looks like #13549

@kubkon
Copy link
Member

kubkon commented Nov 17, 2022

Can you try rebasing now that your fix has landed in master?

@kcbanner
Copy link
Contributor Author

Rebased, CI is passing :D

Copy link
Member

@Vexu Vexu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if it is intentional but it would make sense to me to render the error notes of plain errors in the same way as other errors:

diff --git a/src/Compilation.zig b/src/Compilation.zig
index fac2ed688..af323e7fa 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -514,7 +514,7 @@ pub const AllErrors = struct {
                     }
                     ttyconf.setColor(stderr, .Reset);
                     for (plain.notes) |note| {
-                        try note.renderToWriter(ttyconf, stderr, "error", .Red, indent + 4);
+                        try note.renderToWriter(ttyconf, stderr, "note", .Cyan, indent + 4);
                     }
                 },
             }

@@ -4985,6 +5025,49 @@ pub fn lockAndSetMiscFailure(
return setMiscFailure(comp, tag, format, args);
}

fn parseLddStderr(comp: *Compilation, comptime prefix: []const u8, stderr: []const u8) Allocator.Error!void {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fn parseLddStderr(comp: *Compilation, comptime prefix: []const u8, stderr: []const u8) Allocator.Error!void {
fn parseLldStderr(comp: *Compilation, comptime prefix: []const u8, stderr: []const u8) Allocator.Error!void {

err.context_lines = context_lines.toOwnedSlice();
}

const duped_msg = try comp.gpa.dupe(u8, line);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const duped_msg = try comp.gpa.dupe(u8, line);
var it = std.mem.split(u8, line, "error: ");
_ = it.first();
const trimmed = it.rest();
const duped_msg = try std.fmt.allocPrint(comp.gpa, "{s}: {s}", .{ prefix, trimmed });

This turns error: ld.lld: error: ... into just error: ld.lld: ... which is nicer IMO.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified in the lld source all the errors come through the same function so should have the error: prefix. Updated.

Comment on lines +5047 to +5057
var trimmed = mem.trimRight(u8, line, &std.ascii.whitespace);
if (mem.startsWith(u8, trimmed, context_prefix)) {
trimmed = trimmed[context_prefix.len..];
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could be trimmed from both sides since the error notes are already indented but if you want to preserve the errors in their original form I'm OK with that too.

Suggested change
var trimmed = mem.trimRight(u8, line, &std.ascii.whitespace);
if (mem.startsWith(u8, trimmed, context_prefix)) {
trimmed = trimmed[context_prefix.len..];
}
var trimmed = line;
if (mem.startsWith(u8, line, context_prefix)) {
trimmed = mem.trim(u8, trimmed[context_prefix.len..], &std.ascii.whitespace);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think preserving the beginning whitespace is nicer for this case, to maintain alignment:

error: lld-link: undefined symbol: definitely_not_existing
    note: referenced by C:\cygwin64\home\kcbanner\temp\zig_link_problem\src\main.zig:6
    note:               C:\cygwin64\home\kcbanner\temp\zig_link_problem\zig-cache\o\90ba81227403799d17d7062446163b66\zig_link_problem.exe.obj:(main.main)

@kcbanner
Copy link
Contributor Author

kcbanner commented Nov 19, 2022

Thanks for the review! Agreed on the formatting change, updated.

There was no check for linker errors after flushing,
which meant that if the link failed the build would
continue and try to copy the non-existant exe, and
also write the manifest as if it had succeeded.

Also adds parsing of lld output, which is surfaced at the
end of the compilation with the other errors instead
of via stderr
@Vexu Vexu merged commit f746e11 into ziglang:master Nov 19, 2022
@kcbanner kcbanner deleted the lld_error_parsing branch January 8, 2023 22:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

zig build doesn't notice the missing exe after lld-link fails
3 participants