Skip to content
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

Emit errors with cargo:error= #11312

Closed
wants to merge 4 commits into from

Conversation

kornelski
Copy link
Contributor

@kornelski kornelski commented Oct 31, 2022

Fixes #10159 (#10159 (comment))

This adds support for cargo:error directive similar to cargo:warning to let custom build scripts fail in a clear way.

Presence of a cargo:error directive hides the full dump of stderr/stdout (unless --verbose is used). This is under assumption that scripts which opt-in to fail with cargo:error will make this message comprehensive, and any other output would be only a distraction.

I haven't made cargo:error fail the compilation, which remains dependent on the script's exit code. This way this feature is technically backwards-compatible with crates that might have used cargo:error as their custom key-value metadata.

To let crate authors to emit high-quality errors with explanations, I've added support for multi-line errors and warnings. The syntax for it is +=, which appends extra line to the preceding error/warning:

cargo:error=the error message
cargo:error+=additional lines
cargo:error+=for the error message

@rustbot
Copy link
Collaborator

rustbot commented Oct 31, 2022

r? @epage

(rustbot has picked a reviewer for you, use r? to override)

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Oct 31, 2022
src/cargo/core/compiler/custom_build.rs Show resolved Hide resolved
Comment on lines -786 to -787
let msg = "The following warnings were emitted during compilation:";
self.emit_warnings(Some(msg), &unit, cx)?;
Copy link
Contributor

Choose a reason for hiding this comment

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

Note: this is a change of behavior

Copy link
Contributor Author

@kornelski kornelski Nov 1, 2022

Choose a reason for hiding this comment

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

Is this necessary? AFAIK there's no such message for regular (rustc) compilation errors.

Copy link
Contributor

Choose a reason for hiding this comment

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

My intention wasn't to say "this is a bad change of behavior" but to just raise awareness of how the message is changing. We used to have an introductory statement in this case but will no longer. I felt this would be worth highlighting when this gets a wider view during FCP

Comment on lines +436 to +462
let errors = match errors_seen {
0 => " due to a custom build script failure".to_string(),
1 => " due to the previous error".to_string(),
count => format!(" due to {count} previous errors"),
};
let warnings = match warnings_seen {
0 => String::new(),
1 => "; 1 warning emitted".to_string(),
count => format!("; {count} warnings emitted"),
};
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we be covering more of these cases in tests?

src/cargo/core/compiler/custom_build.rs Show resolved Hide resolved
Comment on lines +409 to +411
"warning" => diagnostics.push(Diagnostic::Warning(value.to_owned())),
"error" => diagnostics.push(Diagnostic::Error(value.to_owned())),
"warning+" => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we split this out into a separate Issue/PR so we can make sure we are agreed on the semantics we want for this before going to the review stage and so we don't block your other work on it?

Copy link
Contributor Author

@kornelski kornelski Nov 1, 2022

Choose a reason for hiding this comment

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

Do you mean just the += syntax?

I've considered alternatives:

  • do nothing. Authors of crates like openssl-sys have a lot of explaining to do, so they will either have to cram everything into a one long line, or they will emit lots of lines with cargo:error= or cargo:warning=. Long lines are unclear, and repeated cargo:warning= directives give noisy formatting that is inconsistent with rustc error output.

  • support line breaks with a character sequence inside a one-liner message. No obvious sequence comes to my mind. Something recognizable like \n would be ambiguous with line breaks in string literals and require double-escaping println!("\\n") and escaping of backslashes inside the error message. It's a hassle.

  • there could be some other line prefix syntax for "append to previous line" instead of error+=, e.g. start next line with a tab character (like HTTP/1.1 headers) "\tsecond line" or some other syntax like "...second line", but keeping cargo: prefix seems safe, and = vs += should be intuitive to Rust programmers.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, += syntax. While discussing alternatives can be interesting, again I feel its best that we have a dedicated discussion on this, so please split this out. This is not strictly required for merging error messages.

Copy link
Contributor

Choose a reason for hiding this comment

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

This was discussed in the cargo team meeting. We came up with several concerns and it would be best to have a dedicated Issue for finishing the conversation on them.

Comment on lines 405 to 406
} else if let Some(error) = stdout.strip_prefix(CARGO_ERROR) {
diagnostics.push(Diagnostic::Error(error.to_owned()));
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add a test for this

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is covered by custom_build_script_failed_custom_error test

Copy link
Contributor

Choose a reason for hiding this comment

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

That test is in the commit for += and will be split out of this PR.

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've moved part of the test to earlier commits

@@ -735,7 +743,8 @@ impl BuildOutput {
env.push((key, val));
}
}
"warning" => warnings.push(value.to_string()),
// "error" is not parsed here for backwards compatibility, and because this function is for successful outputs
Copy link
Contributor

Choose a reason for hiding this comment

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

I haven't made cargo:error fail the compilation, which remains dependent on the script's exit code. This way this feature is technically backwards-compatible with crates that might have used cargo:error as their custom key-value metadata.

This is referring to

cargo:KEY=VALUE — Metadata, used by links scripts.

See https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script

That is a bit of a compatibility trap as theoretically any new directive is a breaking change.

The previous direction from the cargo team was

Treat the script as having errored whether or not it returns an error code.

I feel like not doing this is a behavior trap for users. I would recommend re-raising this in the Issue and for us to come up with a compatible solution that allows erroring.

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've elaborated on the design here: #10159 (comment)

@epage epage added S-blocked and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. S-blocked labels Oct 31, 2022
@kornelski
Copy link
Contributor Author

kornelski commented Nov 29, 2022

@epage @joshtriplett I'm waiting on the decisions:

  • is the cargo:warning+=second line syntax fine for multi-line warnings and errors? I don't have strong feelings about any particular syntax, but I think some support for multi-line errors is important for quality of the error messages. BTW, you may want to also consider Rerun-if-changed without disabling other heuristics as a side-effect #4587 needs some syntax for "add to existing set instead of replacing it", which could use += syntax too.

  • how to handle when build script prints cargo:error= and does not return a failure exit code. For this I suggest downgrading the error message to a warning, and emitting another warning that the build script behaved inconsistently. This way exit code remains the sole way of signaling build failure, and this change won't intertwine output parsing with control flow.

I think you should be able to discuss these issues without me changing the code back and forth, so I don't think they're blocked on the PR changes, but rather the PR is waiting for team's decisions.

@epage
Copy link
Contributor

epage commented Nov 29, 2022

As I've previously said, we should decouple the += conversation from the cargo:error conversation. If you don't want to directly split this out into a separate PR, maybe create a Issue about it for us to discuss? Our contributing guidelines do ask for having Issues first and then, once Accepted, for PRs.

I have not been able to meet with the team for the past while. I'm hoping I can this next time. I have added these to the agenda.

@epage epage added the S-waiting-on-author Status: The marked PR is awaiting some action (such as code changes) from the PR author. label Jan 31, 2023
@bors
Copy link
Contributor

bors commented Feb 2, 2023

☔ The latest upstream changes (presumably #11252) made this pull request unmergeable. Please resolve the merge conflicts.

@weihanglo
Copy link
Member

Just note that with #12332 and later #12201, there should be no more backward compatibility concern for adding the cargo::error directive.

@ratmice
Copy link

ratmice commented Dec 31, 2023

I'm curious if @kornelski is considering picking this up again (given his other patch?),
If not, I would be happy to work on it.

Edit: moved some comments here to #13233

@epage
Copy link
Contributor

epage commented Jan 1, 2024

+= needs some more fundamental design discussions and needs its own issue separate from error=

@epage
Copy link
Contributor

epage commented Jul 18, 2024

As this is over a year stale, I'm going to go ahead and close this

@epage epage closed this Jul 18, 2024
@ratmice
Copy link

ratmice commented Jul 18, 2024

@epage #13233 was created for discussion of the design of += already.

@kornelski kornelski deleted the build-cargo-error branch July 18, 2024 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: The marked PR is awaiting some action (such as code changes) from the PR author.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Presentation of build script errors is noisy, difficult to understand
6 participants