@@ -52,7 +52,8 @@ use std::sync::{Arc, Mutex};
5252/// build script has finished running. Read [the doc] for more.
5353///
5454/// [the doc]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#cargo-warning
55- const CARGO_WARNING : & str = "cargo:warning=" ;
55+ const OLD_CARGO_WARNING_SYNTAX : & str = "cargo:warning=" ;
56+ const NEW_CARGO_WARNING_SYNTAX : & str = "cargo::warning=" ;
5657
5758/// Contains the parsed output of a custom build script.
5859#[ derive( Clone , Debug , Hash , Default ) ]
@@ -435,7 +436,10 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Job> {
435436 let output = cmd
436437 . exec_with_streaming (
437438 & mut |stdout| {
438- if let Some ( warning) = stdout. strip_prefix ( CARGO_WARNING ) {
439+ if let Some ( warning) = stdout
440+ . strip_prefix ( OLD_CARGO_WARNING_SYNTAX )
441+ . or ( stdout. strip_prefix ( NEW_CARGO_WARNING_SYNTAX ) )
442+ {
439443 warnings_in_case_of_panic. push ( warning. to_owned ( ) ) ;
440444 }
441445 if extra_verbose {
@@ -638,47 +642,120 @@ impl BuildOutput {
638642 let mut warnings = Vec :: new ( ) ;
639643 let whence = format ! ( "build script of `{}`" , pkg_descr) ;
640644
645+ // Old syntax:
646+ // cargo:rustc-flags=VALUE
647+ // cargo:KEY=VALUE (for other unreserved keys)
648+ // New syntax:
649+ // cargo::rustc-flags=VALUE
650+ // cargo::metadata=KEY=VALUE (for other unreserved keys)
651+ // Due to backwards compatibility, no new keys can be added to this old format.
652+ // All new keys must use the new format: `cargo::metadata=KEY=VALUE`.
653+ const RESERVED_PREFIXES : & [ & str ] = & [
654+ "rustc-flags=" ,
655+ "rustc-link-lib=" ,
656+ "rustc-link-search=" ,
657+ "rustc-link-arg-cdylib=" ,
658+ "rustc-link-arg-bins=" ,
659+ "rustc-link-arg-bin=" ,
660+ "rustc-link-arg-tests=" ,
661+ "rustc-link-arg-benches=" ,
662+ "rustc-link-arg-examples=" ,
663+ "rustc-link-arg=" ,
664+ "rustc-cfg=" ,
665+ "rustc-check-cfg=" ,
666+ "rustc-env=" ,
667+ "warning=" ,
668+ "rerun-if-changed=" ,
669+ "rerun-if-env-changed=" ,
670+ ] ;
671+ const DOCS_LINK_SUGGESTION : & str = "See https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script \
672+ for more information about build script outputs.";
673+
674+ fn parse_directive < ' a > (
675+ whence : & str ,
676+ line : & str ,
677+ data : & ' a str ,
678+ new_syntax : bool ,
679+ is_metadata : bool ,
680+ ) -> CargoResult < ( & ' a str , & ' a str ) > {
681+ let mut iter = data. splitn ( 2 , "=" ) ;
682+ let key = iter. next ( ) ;
683+ let value = iter. next ( ) ;
684+ match ( key, value) {
685+ ( Some ( a) , Some ( b) ) => Ok ( ( a, b. trim_end ( ) ) ) ,
686+ _ => bail ! (
687+ "invalid output in {}: `{}`\n \
688+ Expected a line with `{}{}KEY=VALUE` with an `=` character, \
689+ but none was found.\n \
690+ {}",
691+ whence,
692+ line,
693+ if new_syntax { "cargo::" } else { "cargo:" } ,
694+ if is_metadata { "metadata=" } else { "" } ,
695+ DOCS_LINK_SUGGESTION
696+ ) ,
697+ }
698+ }
699+
641700 for line in input. split ( |b| * b == b'\n' ) {
642701 let line = match str:: from_utf8 ( line) {
643702 Ok ( line) => line. trim ( ) ,
644703 Err ( ..) => continue ,
645704 } ;
646- let mut iter = line. splitn ( 2 , ':' ) ;
647- if iter. next ( ) != Some ( "cargo" ) {
648- // skip this line since it doesn't start with "cargo:"
649- continue ;
705+ let mut new_syntax = false ;
706+ let ( key, value) = if let Some ( data) = line. strip_prefix ( "cargo::" ) {
707+ new_syntax = true ;
708+
709+ // For instance, `cargo::rustc-flags=foo`.
710+ if RESERVED_PREFIXES
711+ . iter ( )
712+ . any ( |prefix| data. starts_with ( prefix) )
713+ {
714+ parse_directive ( whence. as_str ( ) , line, data, new_syntax, false ) ?
715+ }
716+ // For instance, `cargo::metadata=foo=bar`.
717+ else if let Some ( data) = data. strip_prefix ( "metadata=" ) {
718+ // Reserved keys should not be used with the `cargo::metadata=` syntax.
719+ if let Some ( prefix) = RESERVED_PREFIXES
720+ . iter ( )
721+ . find ( |prefix| data. starts_with ( * prefix) )
722+ {
723+ bail ! ( "invalid output in {}: `{}`\n \
724+ The reserved key cannot be used in the `cargo::metadata=` syntax. Please use `cargo::{}VAlUE` instead.\n \
725+ {}", whence, line, prefix, DOCS_LINK_SUGGESTION
726+ )
727+ }
728+ parse_directive ( whence. as_str ( ) , line, data, new_syntax, true ) ?
729+ } else {
730+ bail ! ( "invalid output in {}: `{}`\n \
731+ Expected a line with `cargo::metadata=KEY=VALUE` but it did not have the `metadata=` part.\n \
732+ {}", whence, line, DOCS_LINK_SUGGESTION
733+ )
734+ }
650735 }
651- let data = match iter. next ( ) {
652- Some ( val) => val,
653- None => continue ,
654- } ;
655-
656- // getting the `key=value` part of the line
657- let mut iter = data. splitn ( 2 , '=' ) ;
658- let key = iter. next ( ) ;
659- let value = iter. next ( ) ;
660- let ( key, value) = match ( key, value) {
661- ( Some ( a) , Some ( b) ) => ( a, b. trim_end ( ) ) ,
662- // Line started with `cargo:` but didn't match `key=value`.
663- _ => bail ! ( "invalid output in {}: `{}`\n \
664- Expected a line with `cargo:key=value` with an `=` character, \
665- but none was found.\n \
666- See https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script \
667- for more information about build script outputs.", whence, line) ,
736+ // For backwards compatibility, we also accept lines that start with "cargo:".
737+ else if let Some ( data) = line. strip_prefix ( "cargo:" ) {
738+ // For instance, `cargo:rustc-flags=foo` or `cargo:foo=bar`.
739+ parse_directive ( whence. as_str ( ) , line, data, false , false ) ?
740+ }
741+ // Skip this line since it doesn't start with "cargo:" or "cargo::".
742+ else {
743+ continue ;
668744 } ;
669745
670746 // This will rewrite paths if the target directory has been moved.
671747 let value = value. replace (
672748 script_out_dir_when_generated. to_str ( ) . unwrap ( ) ,
673749 script_out_dir. to_str ( ) . unwrap ( ) ,
674750 ) ;
675-
751+ let syntax_prefix = if new_syntax { "cargo::" } else { "cargo:" } ;
676752 macro_rules! check_and_add_target {
677753 ( $target_kind: expr, $is_target_kind: expr, $link_type: expr) => {
678754 if !targets. iter( ) . any( |target| $is_target_kind( target) ) {
679755 bail!(
680- "invalid instruction `cargo: {}` from {}\n \
756+ "invalid instruction `{} {}` from {}\n \
681757 The package {} does not have a {} target.",
758+ syntax_prefix,
682759 key,
683760 whence,
684761 pkg_descr,
@@ -701,14 +778,14 @@ impl BuildOutput {
701778 "rustc-link-arg-cdylib" | "rustc-cdylib-link-arg" => {
702779 if !targets. iter ( ) . any ( |target| target. is_cdylib ( ) ) {
703780 warnings. push ( format ! (
704- "cargo: {} was specified in the build script of {}, \
781+ "{} {} was specified in the build script of {}, \
705782 but that package does not contain a cdylib target\n \
706783 \n \
707784 Allowing this was an unintended change in the 1.50 \
708785 release, and may become an error in the future. \
709786 For more information, see \
710787 <https://github.com/rust-lang/cargo/issues/9562>.",
711- key, pkg_descr
788+ syntax_prefix , key, pkg_descr
712789 ) ) ;
713790 }
714791 linker_args. push ( ( LinkType :: Cdylib , value) )
@@ -721,11 +798,13 @@ impl BuildOutput {
721798 let bin_name = parts. next ( ) . unwrap ( ) . to_string ( ) ;
722799 let arg = parts. next ( ) . ok_or_else ( || {
723800 anyhow:: format_err!(
724- "invalid instruction `cargo:{}={}` from {}\n \
725- The instruction should have the form cargo:{}=BIN=ARG",
801+ "invalid instruction `{}{}={}` from {}\n \
802+ The instruction should have the form {}{}=BIN=ARG",
803+ syntax_prefix,
726804 key,
727805 value,
728806 whence,
807+ syntax_prefix,
729808 key
730809 )
731810 } ) ?;
@@ -734,8 +813,9 @@ impl BuildOutput {
734813 . any ( |target| target. is_bin ( ) && target. name ( ) == bin_name)
735814 {
736815 bail ! (
737- "invalid instruction `cargo: {}` from {}\n \
816+ "invalid instruction `{} {}` from {}\n \
738817 The package {} does not have a bin target with the name `{}`.",
818+ syntax_prefix,
739819 key,
740820 whence,
741821 pkg_descr,
@@ -761,7 +841,10 @@ impl BuildOutput {
761841 if extra_check_cfg {
762842 check_cfgs. push ( value. to_string ( ) ) ;
763843 } else {
764- warnings. push ( format ! ( "cargo:{} requires -Zcheck-cfg=output flag" , key) ) ;
844+ warnings. push ( format ! (
845+ "{}{} requires -Zcheck-cfg=output flag" ,
846+ syntax_prefix, key
847+ ) ) ;
765848 }
766849 }
767850 "rustc-env" => {
@@ -836,9 +919,9 @@ impl BuildOutput {
836919 } )
837920 }
838921
839- /// Parses [`cargo:rustc-flags`] instruction.
922+ /// Parses [`cargo:: rustc-flags`] instruction.
840923 ///
841- /// [`cargo:rustc-flags`]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#cargorustc-flagsflags
924+ /// [`cargo:: rustc-flags`]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#cargorustc-flagsflags
842925 pub fn parse_rustc_flags (
843926 value : & str ,
844927 whence : & str ,
@@ -884,9 +967,9 @@ impl BuildOutput {
884967 Ok ( ( library_paths, library_links) )
885968 }
886969
887- /// Parses [`cargo:rustc-env`] instruction.
970+ /// Parses [`cargo:: rustc-env`] instruction.
888971 ///
889- /// [`cargo:rustc-env`]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-env
972+ /// [`cargo:: rustc-env`]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-env
890973 pub fn parse_rustc_env ( value : & str , whence : & str ) -> CargoResult < ( String , String ) > {
891974 let mut iter = value. splitn ( 2 , '=' ) ;
892975 let name = iter. next ( ) ;
0 commit comments