@@ -50,6 +50,11 @@ use std::path::{Path, PathBuf};
5050use std:: str:: { self , FromStr } ;
5151use std:: sync:: { Arc , Mutex } ;
5252
53+ /// A build script instruction that tells Cargo to display an error after the
54+ /// build script has finished running. Read [the doc] for more.
55+ ///
56+ /// [the doc]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#cargo-error
57+ const CARGO_ERROR_SYNTAX : & str = "cargo::error=" ;
5358/// Deprecated: A build script instruction that tells Cargo to display a warning after the
5459/// build script has finished running. Read [the doc] for more.
5560///
@@ -60,6 +65,15 @@ const OLD_CARGO_WARNING_SYNTAX: &str = "cargo:warning=";
6065///
6166/// [the doc]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#cargo-warning
6267const NEW_CARGO_WARNING_SYNTAX : & str = "cargo::warning=" ;
68+
69+ #[ derive( Clone , Debug , Hash , PartialEq , Eq , PartialOrd , Ord ) ]
70+ pub enum Severity {
71+ Error ,
72+ Warning ,
73+ }
74+
75+ pub type LogMessage = ( Severity , String ) ;
76+
6377/// Contains the parsed output of a custom build script.
6478#[ derive( Clone , Debug , Hash , Default , PartialEq , Eq , PartialOrd , Ord ) ]
6579pub struct BuildOutput {
@@ -82,11 +96,13 @@ pub struct BuildOutput {
8296 pub rerun_if_changed : Vec < PathBuf > ,
8397 /// Environment variables which, when changed, will cause a rebuild.
8498 pub rerun_if_env_changed : Vec < String > ,
85- /// Warnings generated by this build.
99+ /// Errors and warnings generated by this build.
86100 ///
87- /// These are only displayed if this is a "local" package, `-vv` is used,
88- /// or there is a build error for any target in this package.
89- pub warnings : Vec < String > ,
101+ /// These are only displayed if this is a "local" package, `-vv` is used, or
102+ /// there is a build error for any target in this package. Note that any log
103+ /// message of severity `Error` will by itself cause a build error, and will
104+ /// cause all log messages to be displayed.
105+ pub log_messages : Vec < LogMessage > ,
90106}
91107
92108/// Map of packages to build script output.
@@ -474,15 +490,18 @@ fn build_work(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResul
474490 state. running ( & cmd) ;
475491 let timestamp = paths:: set_invocation_time ( & script_run_dir) ?;
476492 let prefix = format ! ( "[{} {}] " , id. name( ) , id. version( ) ) ;
477- let mut warnings_in_case_of_panic = Vec :: new ( ) ;
493+ let mut log_messages_in_case_of_panic = Vec :: new ( ) ;
478494 let output = cmd
479495 . exec_with_streaming (
480496 & mut |stdout| {
497+ if let Some ( error) = stdout. strip_prefix ( CARGO_ERROR_SYNTAX ) {
498+ log_messages_in_case_of_panic. push ( ( Severity :: Error , error. to_owned ( ) ) ) ;
499+ }
481500 if let Some ( warning) = stdout
482501 . strip_prefix ( OLD_CARGO_WARNING_SYNTAX )
483502 . or ( stdout. strip_prefix ( NEW_CARGO_WARNING_SYNTAX ) )
484503 {
485- warnings_in_case_of_panic . push ( warning. to_owned ( ) ) ;
504+ log_messages_in_case_of_panic . push ( ( Severity :: Warning , warning. to_owned ( ) ) ) ;
486505 }
487506 if extra_verbose {
488507 state. stdout ( format ! ( "{}{}" , prefix, stdout) ) ?;
@@ -522,15 +541,29 @@ fn build_work(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResul
522541 build_error_context
523542 } ) ;
524543
544+ // If the build failed
525545 if let Err ( error) = output {
526- insert_warnings_in_build_outputs (
546+ insert_log_messages_in_build_outputs (
527547 build_script_outputs,
528548 id,
529549 metadata_hash,
530- warnings_in_case_of_panic ,
550+ log_messages_in_case_of_panic ,
531551 ) ;
532552 return Err ( error) ;
533553 }
554+ // ... or it logged any errors
555+ else if log_messages_in_case_of_panic
556+ . iter ( )
557+ . any ( |( severity, _) | * severity == Severity :: Error )
558+ {
559+ insert_log_messages_in_build_outputs (
560+ build_script_outputs,
561+ id,
562+ metadata_hash,
563+ log_messages_in_case_of_panic,
564+ ) ;
565+ anyhow:: bail!( "build script logged errors" ) ;
566+ }
534567
535568 let output = output. unwrap ( ) ;
536569
@@ -611,22 +644,23 @@ fn build_work(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResul
611644 Ok ( job)
612645}
613646
614- /// When a build script run fails, store only warnings and nuke other outputs,
615- /// as they are likely broken.
616- fn insert_warnings_in_build_outputs (
647+ /// When a build script run fails, store only log messages, and nuke other
648+ /// outputs, as they are likely broken.
649+ fn insert_log_messages_in_build_outputs (
617650 build_script_outputs : Arc < Mutex < BuildScriptOutputs > > ,
618651 id : PackageId ,
619652 metadata_hash : Metadata ,
620- warnings : Vec < String > ,
653+ log_messages : Vec < LogMessage > ,
621654) {
622- let build_output_with_only_warnings = BuildOutput {
623- warnings ,
655+ let build_output_with_only_log_messages = BuildOutput {
656+ log_messages ,
624657 ..BuildOutput :: default ( )
625658 } ;
626- build_script_outputs
627- . lock ( )
628- . unwrap ( )
629- . insert ( id, metadata_hash, build_output_with_only_warnings) ;
659+ build_script_outputs. lock ( ) . unwrap ( ) . insert (
660+ id,
661+ metadata_hash,
662+ build_output_with_only_log_messages,
663+ ) ;
630664}
631665
632666impl BuildOutput {
@@ -678,7 +712,7 @@ impl BuildOutput {
678712 let mut metadata = Vec :: new ( ) ;
679713 let mut rerun_if_changed = Vec :: new ( ) ;
680714 let mut rerun_if_env_changed = Vec :: new ( ) ;
681- let mut warnings = Vec :: new ( ) ;
715+ let mut log_messages = Vec :: new ( ) ;
682716 let whence = format ! ( "build script of `{}`" , pkg_descr) ;
683717 // Old syntax:
684718 // cargo:rustc-flags=VALUE
@@ -850,15 +884,18 @@ impl BuildOutput {
850884 "rustc-link-search" => library_paths. push ( PathBuf :: from ( value) ) ,
851885 "rustc-link-arg-cdylib" | "rustc-cdylib-link-arg" => {
852886 if !targets. iter ( ) . any ( |target| target. is_cdylib ( ) ) {
853- warnings. push ( format ! (
854- "{}{} was specified in the build script of {}, \
887+ log_messages. push ( (
888+ Severity :: Warning ,
889+ format ! (
890+ "{}{} was specified in the build script of {}, \
855891 but that package does not contain a cdylib target\n \
856892 \n \
857893 Allowing this was an unintended change in the 1.50 \
858894 release, and may become an error in the future. \
859895 For more information, see \
860896 <https://github.com/rust-lang/cargo/issues/9562>.",
861- syntax_prefix, key, pkg_descr
897+ syntax_prefix, key, pkg_descr
898+ ) ,
862899 ) ) ;
863900 }
864901 linker_args. push ( ( LinkArgTarget :: Cdylib , value) )
@@ -944,10 +981,10 @@ impl BuildOutput {
944981 if nightly_features_allowed
945982 || rustc_bootstrap_allows ( library_name. as_deref ( ) )
946983 {
947- warnings . push ( format ! ( "Cannot set `RUSTC_BOOTSTRAP={}` from {}.\n \
984+ log_messages . push ( ( Severity :: Warning , format ! ( "Cannot set `RUSTC_BOOTSTRAP={}` from {}.\n \
948985 note: Crates cannot set `RUSTC_BOOTSTRAP` themselves, as doing so would subvert the stability guarantees of Rust for your project.",
949986 val, whence
950- ) ) ;
987+ ) ) ) ;
951988 } else {
952989 // Setting RUSTC_BOOTSTRAP would change the behavior of the crate.
953990 // Abort with an error.
@@ -963,7 +1000,8 @@ impl BuildOutput {
9631000 env. push ( ( key, val) ) ;
9641001 }
9651002 }
966- "warning" => warnings. push ( value. to_string ( ) ) ,
1003+ "error" => log_messages. push ( ( Severity :: Error , value. to_string ( ) ) ) ,
1004+ "warning" => log_messages. push ( ( Severity :: Warning , value. to_string ( ) ) ) ,
9671005 "rerun-if-changed" => rerun_if_changed. push ( PathBuf :: from ( value) ) ,
9681006 "rerun-if-env-changed" => rerun_if_env_changed. push ( value. to_string ( ) ) ,
9691007 "metadata" => {
@@ -988,7 +1026,7 @@ impl BuildOutput {
9881026 metadata,
9891027 rerun_if_changed,
9901028 rerun_if_env_changed,
991- warnings ,
1029+ log_messages ,
9921030 } )
9931031 }
9941032
0 commit comments