vergen/feature/
rustc.rs

1// Copyright (c) 2022 vergen developers
2//
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. All files in the project carrying such notice may not be copied,
7// modified, or distributed except according to those terms.
8
9use anyhow::{Error, Result};
10use bon::Builder;
11use rustc_version::{Channel, VersionMeta, version_meta};
12use std::env;
13use vergen_lib::{
14    AddEntries, CargoRerunIfChanged, CargoRustcEnvMap, CargoWarning, DefaultConfig, VergenKey,
15    add_default_map_entry, add_map_entry,
16    constants::{
17        RUSTC_CHANNEL_NAME, RUSTC_COMMIT_DATE, RUSTC_COMMIT_HASH, RUSTC_HOST_TRIPLE_NAME,
18        RUSTC_LLVM_VERSION, RUSTC_SEMVER_NAME,
19    },
20};
21
22/// The `VERGEN_RUSTC_*` configuration features
23///
24/// **NOTE** - All rustc instructions are considered deterministic.  If you change
25/// the version of rustc you are compiling with, these values should change if
26/// being used in the generated binary.
27///
28/// | Variable | Sample |
29/// | -------  | ------ |
30/// | `VERGEN_RUSTC_CHANNEL` | nightly |
31/// | `VERGEN_RUSTC_COMMIT_DATE` | 2021-02-24 |
32/// | `VERGEN_RUSTC_COMMIT_HASH` | a8486b64b0c87dabd045453b6c81500015d122d6 |
33/// | `VERGEN_RUSTC_HOST_TRIPLE` | apple-darwin |
34/// | `VERGEN_RUSTC_LLVM_VERSION` | 11.0 |
35/// | `VERGEN_RUSTC_SEMVER` | 1.52.0-nightly |
36///
37/// # Example
38/// Emit all of the rustc instructions
39///
40/// ```
41/// # use anyhow::Result;
42/// # use vergen::Emitter;
43/// # use vergen::Rustc;
44/// #
45/// # fn main() -> Result<()> {
46/// let rustc = Rustc::all_rustc();
47/// Emitter::default().add_instructions(&rustc)?.emit();
48/// #   Ok(())
49/// # }
50/// ```
51///
52/// Emit some of the rustc instructions
53///
54/// ```
55/// # use anyhow::Result;
56/// # use vergen::Emitter;
57/// # use vergen::Rustc;
58/// #
59/// # fn main() -> Result<()> {
60/// let rustc = Rustc::builder().channel(true).semver(true).build();
61/// Emitter::default().add_instructions(&rustc)?.emit();
62/// #   Ok(())
63/// # }
64/// ```
65///
66/// Override output with your own value
67///
68/// ```
69/// # use anyhow::Result;
70/// # use std::env;
71/// # use vergen::Emitter;
72/// # use vergen::Rustc;
73/// #
74/// # fn main() -> Result<()> {
75/// temp_env::with_var("VERGEN_RUSTC_CHANNEL", Some("this is the channel I want output"), || {
76///     let result = || -> Result<()> {
77///         let rustc = Rustc::builder().channel(true).semver(true).build();
78///         Emitter::default().add_instructions(&rustc)?.emit();   
79///         Ok(())  
80///     }();
81///     assert!(result.is_ok());
82/// });
83/// #   Ok(())
84/// # }
85/// ```
86///
87#[derive(Builder, Clone, Copy, Debug, PartialEq)]
88#[allow(clippy::struct_excessive_bools)]
89pub struct Rustc {
90    /// Configures the default values.
91    /// If set to `true` all defaults are in "enabled" state.
92    /// If set to `false` all defaults are in "disabled" state.
93    #[builder(field)]
94    all: bool,
95    #[cfg(test)]
96    #[builder(field)]
97    str_to_test: Option<&'static str>,
98    /// Enable the rustc channel
99    #[builder(default = all)]
100    channel: bool,
101    /// Enable the rustc commit date
102    #[builder(default = all)]
103    commit_date: bool,
104    /// Enable the rustc SHA
105    #[builder(default = all)]
106    commit_hash: bool,
107    /// Enable rustc host triple
108    #[builder(default = all)]
109    host_triple: bool,
110    /// Enable rustc LLVM version
111    #[builder(default = all)]
112    llvm_version: bool,
113    /// Enable the rustc semver
114    #[builder(default = all)]
115    semver: bool,
116}
117
118impl<S: rustc_builder::State> RustcBuilder<S> {
119    /// Convenience method that switches the defaults of [`RustcBuilder`]
120    /// to enable all of the `VERGEN_RUSTC_*` instructions. It can only be
121    /// called at the start of the building process, i.e. when no config
122    /// has been set yet to avoid overwrites.
123    fn all(mut self) -> Self {
124        self.all = true;
125        self
126    }
127}
128
129impl Rustc {
130    /// Enable all of the `VERGEN_RUSTC_*` options
131    #[must_use]
132    pub fn all_rustc() -> Self {
133        Self::builder().all().build()
134    }
135
136    fn any(self) -> bool {
137        self.channel
138            || self.commit_date
139            || self.commit_hash
140            || self.host_triple
141            || self.llvm_version
142            || self.semver
143    }
144
145    #[cfg(not(test))]
146    fn add_rustc_map_entries(
147        self,
148        cargo_rustc_env: &mut CargoRustcEnvMap,
149        cargo_warning: &mut CargoWarning,
150    ) -> Result<()> {
151        self.add_rustc_to_map(version_meta(), cargo_rustc_env, cargo_warning)
152    }
153
154    #[cfg(test)]
155    fn add_rustc_map_entries(
156        self,
157        cargo_rustc_env: &mut CargoRustcEnvMap,
158        cargo_warning: &mut CargoWarning,
159    ) -> Result<()> {
160        use rustc_version::version_meta_for;
161
162        let vm = if let Some(rustc_str) = self.str_to_test {
163            version_meta_for(rustc_str)
164        } else {
165            version_meta()
166        };
167        self.add_rustc_to_map(vm, cargo_rustc_env, cargo_warning)
168    }
169
170    #[allow(clippy::too_many_lines)]
171    fn add_rustc_to_map(
172        self,
173        rustc_res: std::result::Result<VersionMeta, rustc_version::Error>,
174        cargo_rustc_env: &mut CargoRustcEnvMap,
175        cargo_warning: &mut CargoWarning,
176    ) -> Result<()> {
177        let rustc = rustc_res?;
178
179        if self.channel {
180            if let Ok(_value) = env::var(RUSTC_CHANNEL_NAME) {
181                add_default_map_entry(
182                    false,
183                    VergenKey::RustcChannel,
184                    cargo_rustc_env,
185                    cargo_warning,
186                );
187            } else {
188                let channel = match rustc.channel {
189                    Channel::Dev => "dev",
190                    Channel::Nightly => "nightly",
191                    Channel::Beta => "beta",
192                    Channel::Stable => "stable",
193                };
194                add_map_entry(VergenKey::RustcChannel, channel, cargo_rustc_env);
195            }
196        }
197
198        if self.commit_date {
199            if let Ok(_value) = env::var(RUSTC_COMMIT_DATE) {
200                add_default_map_entry(
201                    false,
202                    VergenKey::RustcCommitDate,
203                    cargo_rustc_env,
204                    cargo_warning,
205                );
206            } else if let Some(commit_date) = rustc.commit_date {
207                add_map_entry(VergenKey::RustcCommitDate, commit_date, cargo_rustc_env);
208            } else {
209                add_default_map_entry(
210                    false,
211                    VergenKey::RustcCommitDate,
212                    cargo_rustc_env,
213                    cargo_warning,
214                );
215            }
216        }
217
218        if self.commit_hash {
219            if let Ok(_value) = env::var(RUSTC_COMMIT_HASH) {
220                add_default_map_entry(
221                    false,
222                    VergenKey::RustcCommitHash,
223                    cargo_rustc_env,
224                    cargo_warning,
225                );
226            } else if let Some(commit_hash) = rustc.commit_hash {
227                add_map_entry(VergenKey::RustcCommitHash, commit_hash, cargo_rustc_env);
228            } else {
229                add_default_map_entry(
230                    false,
231                    VergenKey::RustcCommitHash,
232                    cargo_rustc_env,
233                    cargo_warning,
234                );
235            }
236        }
237
238        if self.host_triple {
239            if let Ok(_value) = env::var(RUSTC_HOST_TRIPLE_NAME) {
240                add_default_map_entry(
241                    false,
242                    VergenKey::RustcHostTriple,
243                    cargo_rustc_env,
244                    cargo_warning,
245                );
246            } else {
247                add_map_entry(VergenKey::RustcHostTriple, rustc.host, cargo_rustc_env);
248            }
249        }
250
251        if self.llvm_version {
252            if let Ok(_value) = env::var(RUSTC_LLVM_VERSION) {
253                add_default_map_entry(
254                    false,
255                    VergenKey::RustcLlvmVersion,
256                    cargo_rustc_env,
257                    cargo_warning,
258                );
259            } else if let Some(llvm_version) = rustc.llvm_version {
260                add_map_entry(
261                    VergenKey::RustcLlvmVersion,
262                    format!("{llvm_version}"),
263                    cargo_rustc_env,
264                );
265            } else {
266                add_default_map_entry(
267                    false,
268                    VergenKey::RustcLlvmVersion,
269                    cargo_rustc_env,
270                    cargo_warning,
271                );
272            }
273        }
274
275        if self.semver {
276            if let Ok(_value) = env::var(RUSTC_SEMVER_NAME) {
277                add_default_map_entry(
278                    false,
279                    VergenKey::RustcSemver,
280                    cargo_rustc_env,
281                    cargo_warning,
282                );
283            } else {
284                add_map_entry(
285                    VergenKey::RustcSemver,
286                    format!("{}", rustc.semver),
287                    cargo_rustc_env,
288                );
289            }
290        }
291
292        Ok(())
293    }
294
295    #[cfg(test)]
296    fn with_rustc_str(&mut self, rustc_str: &'static str) -> &mut Self {
297        self.str_to_test = Some(rustc_str);
298        self
299    }
300}
301
302impl AddEntries for Rustc {
303    fn add_map_entries(
304        &self,
305        _idempotent: bool,
306        cargo_rustc_env: &mut CargoRustcEnvMap,
307        _cargo_rerun_if_changed: &mut CargoRerunIfChanged,
308        cargo_warning: &mut CargoWarning,
309    ) -> Result<()> {
310        if self.any() {
311            self.add_rustc_map_entries(cargo_rustc_env, cargo_warning)
312        } else {
313            Ok(())
314        }
315    }
316
317    fn add_default_entries(
318        &self,
319        config: &DefaultConfig,
320        cargo_rustc_env_map: &mut CargoRustcEnvMap,
321        _cargo_rerun_if_changed: &mut CargoRerunIfChanged,
322        cargo_warning: &mut CargoWarning,
323    ) -> Result<()> {
324        if *config.fail_on_error() {
325            let error = Error::msg(format!("{:?}", config.error()));
326            Err(error)
327        } else {
328            if self.channel {
329                add_default_map_entry(
330                    false,
331                    VergenKey::RustcChannel,
332                    cargo_rustc_env_map,
333                    cargo_warning,
334                );
335            }
336            if self.commit_date {
337                add_default_map_entry(
338                    false,
339                    VergenKey::RustcCommitDate,
340                    cargo_rustc_env_map,
341                    cargo_warning,
342                );
343            }
344            if self.commit_hash {
345                add_default_map_entry(
346                    false,
347                    VergenKey::RustcCommitHash,
348                    cargo_rustc_env_map,
349                    cargo_warning,
350                );
351            }
352            if self.host_triple {
353                add_default_map_entry(
354                    false,
355                    VergenKey::RustcHostTriple,
356                    cargo_rustc_env_map,
357                    cargo_warning,
358                );
359            }
360            if self.llvm_version {
361                add_default_map_entry(
362                    false,
363                    VergenKey::RustcLlvmVersion,
364                    cargo_rustc_env_map,
365                    cargo_warning,
366                );
367            }
368            if self.semver {
369                add_default_map_entry(
370                    false,
371                    VergenKey::RustcSemver,
372                    cargo_rustc_env_map,
373                    cargo_warning,
374                );
375            }
376
377            Ok(())
378        }
379    }
380}
381
382#[cfg(test)]
383mod test {
384    use super::Rustc;
385    use crate::Emitter;
386    use anyhow::Result;
387    use serial_test::serial;
388    use std::io::Write;
389    use temp_env::with_var;
390    use vergen_lib::count_idempotent;
391
392    #[test]
393    #[serial]
394    #[allow(clippy::clone_on_copy, clippy::redundant_clone)]
395    fn rustc_clone_works() {
396        let rustc = Rustc::all_rustc();
397        let another = rustc.clone();
398        assert_eq!(another, rustc);
399    }
400
401    #[test]
402    #[serial]
403    fn rustc_debug_works() -> Result<()> {
404        let rustc = Rustc::all_rustc();
405        let mut buf = vec![];
406        write!(buf, "{rustc:?}")?;
407        assert!(!buf.is_empty());
408        Ok(())
409    }
410
411    #[test]
412    #[serial]
413    fn rustc_default() -> Result<()> {
414        let rustc = Rustc::builder().build();
415        let emitter = Emitter::default().add_instructions(&rustc)?.test_emit();
416        assert_eq!(0, emitter.cargo_rustc_env_map().len());
417        assert_eq!(0, count_idempotent(emitter.cargo_rustc_env_map()));
418        assert_eq!(0, emitter.cargo_warning().len());
419        Ok(())
420    }
421
422    #[test]
423    #[serial]
424    fn rustc_all_idempotent() -> Result<()> {
425        let rustc = Rustc::all_rustc();
426        let config = Emitter::default()
427            .idempotent()
428            .add_instructions(&rustc)?
429            .test_emit();
430        assert_eq!(6, config.cargo_rustc_env_map().len());
431        assert_eq!(0, count_idempotent(config.cargo_rustc_env_map()));
432        assert_eq!(0, config.cargo_warning().len());
433        Ok(())
434    }
435
436    #[test]
437    #[serial]
438    fn rustc_all() -> Result<()> {
439        let rustc = Rustc::all_rustc();
440        let config = Emitter::default().add_instructions(&rustc)?.test_emit();
441        assert_eq!(6, config.cargo_rustc_env_map().len());
442        assert_eq!(0, count_idempotent(config.cargo_rustc_env_map()));
443        assert_eq!(0, config.cargo_warning().len());
444        Ok(())
445    }
446
447    #[test]
448    #[serial]
449    fn rustc_commit_date() -> Result<()> {
450        let rustc = Rustc::builder().commit_date(true).build();
451        let config = Emitter::default().add_instructions(&rustc)?.test_emit();
452        assert_eq!(1, config.cargo_rustc_env_map().len());
453        assert_eq!(0, count_idempotent(config.cargo_rustc_env_map()));
454        assert_eq!(0, config.cargo_warning().len());
455        Ok(())
456    }
457
458    #[test]
459    #[serial]
460    fn rustc_commit_hash() -> Result<()> {
461        let rustc = Rustc::builder().commit_hash(true).build();
462        let config = Emitter::default().add_instructions(&rustc)?.test_emit();
463        assert_eq!(1, config.cargo_rustc_env_map().len());
464        assert_eq!(0, count_idempotent(config.cargo_rustc_env_map()));
465        assert_eq!(0, config.cargo_warning().len());
466        Ok(())
467    }
468
469    #[test]
470    #[serial]
471    fn rustc_host_triple() -> Result<()> {
472        let rustc = Rustc::builder().host_triple(true).build();
473        let config = Emitter::default().add_instructions(&rustc)?.test_emit();
474        assert_eq!(1, config.cargo_rustc_env_map().len());
475        assert_eq!(0, count_idempotent(config.cargo_rustc_env_map()));
476        assert_eq!(0, config.cargo_warning().len());
477        Ok(())
478    }
479
480    #[test]
481    #[serial]
482    fn rustc_llvm_version() -> Result<()> {
483        let rustc = Rustc::builder().llvm_version(true).build();
484        let config = Emitter::default().add_instructions(&rustc)?.test_emit();
485        assert_eq!(1, config.cargo_rustc_env_map().len());
486        assert_eq!(0, count_idempotent(config.cargo_rustc_env_map()));
487        assert_eq!(0, config.cargo_warning().len());
488        Ok(())
489    }
490
491    #[test]
492    #[serial]
493    fn rustc_semver() -> Result<()> {
494        let rustc = Rustc::builder().semver(true).build();
495        let config = Emitter::default().add_instructions(&rustc)?.test_emit();
496        assert_eq!(1, config.cargo_rustc_env_map().len());
497        assert_eq!(0, count_idempotent(config.cargo_rustc_env_map()));
498        assert_eq!(0, config.cargo_warning().len());
499        Ok(())
500    }
501
502    const NO_LLVM: &str = r"rustc 1.68.0-nightly (270c94e48 2022-12-28)
503binary: rustc
504commit-hash: 270c94e484e19764a2832ef918c95224eb3f17c7
505commit-date: 2022-12-28
506host: x86_64-unknown-linux-gnu
507release: 1.68.0-nightly
508    ";
509
510    #[test]
511    #[serial]
512    fn no_llvm_in_rustc() -> Result<()> {
513        let mut rustc = Rustc::all_rustc();
514        let _ = rustc.with_rustc_str(NO_LLVM);
515        let emitter = Emitter::default()
516            .fail_on_error()
517            .add_instructions(&rustc)?
518            .test_emit();
519        assert_eq!(5, emitter.cargo_rustc_env_map().len());
520        assert_eq!(0, count_idempotent(emitter.cargo_rustc_env_map()));
521        assert_eq!(1, emitter.cargo_warning().len());
522        Ok(())
523    }
524
525    const DEV_BUILD: &str = r"rustc 1.68.0-nightly (270c94e48 2022-12-28)
526binary: rustc
527commit-hash: 270c94e484e19764a2832ef918c95224eb3f17c7
528commit-date: 2022-12-28
529host: x86_64-unknown-linux-gnu
530release: 1.68.0-dev
531LLVM version: 15.0.6
532    ";
533
534    #[test]
535    #[serial]
536    fn rustc_dev_build() -> Result<()> {
537        let mut rustc = Rustc::all_rustc();
538        let _ = rustc.with_rustc_str(DEV_BUILD);
539        let emitter = Emitter::default()
540            .fail_on_error()
541            .add_instructions(&rustc)?
542            .test_emit();
543        assert_eq!(6, emitter.cargo_rustc_env_map().len());
544        assert_eq!(0, count_idempotent(emitter.cargo_rustc_env_map()));
545        assert_eq!(0, emitter.cargo_warning().len());
546        Ok(())
547    }
548
549    const UNKNOWN_BITS: &str = r"rustc 1.68.0-nightly (270c94e48 2022-12-28)
550binary: rustc
551commit-hash: unknown
552commit-date: unknown
553host: x86_64-unknown-linux-gnu
554release: 1.68.0-dev
555LLVM version: 15.0.6
556    ";
557
558    #[test]
559    #[serial]
560    fn rustc_unknown_bits() -> Result<()> {
561        let mut rustc = Rustc::all_rustc();
562        let _ = rustc.with_rustc_str(UNKNOWN_BITS);
563        let emitter = Emitter::default()
564            .fail_on_error()
565            .add_instructions(&rustc)?
566            .test_emit();
567        assert_eq!(4, emitter.cargo_rustc_env_map().len());
568        assert_eq!(0, count_idempotent(emitter.cargo_rustc_env_map()));
569        assert_eq!(2, emitter.cargo_warning().len());
570        Ok(())
571    }
572
573    #[test]
574    #[serial]
575    fn rustc_fails_on_bad_input() -> Result<()> {
576        let mut rustc = Rustc::all_rustc();
577        let _ = rustc.with_rustc_str("a_bad_rustcvv_string");
578        assert!(
579            Emitter::default()
580                .fail_on_error()
581                .add_instructions(&rustc)
582                .is_err()
583        );
584        Ok(())
585    }
586
587    #[test]
588    #[serial]
589    fn rustc_warnings_on_bad_input() -> Result<()> {
590        let mut rustc = Rustc::all_rustc();
591        let _ = rustc.with_rustc_str("a_bad_rustcvv_string");
592        let emitter = Emitter::default().add_instructions(&rustc)?.test_emit();
593        assert_eq!(0, emitter.cargo_rustc_env_map().len());
594        assert_eq!(0, count_idempotent(emitter.cargo_rustc_env_map()));
595        assert_eq!(6, emitter.cargo_warning().len());
596        Ok(())
597    }
598
599    #[test]
600    #[serial]
601    fn rustc_channel_override_works() {
602        with_var("VERGEN_RUSTC_CHANNEL", Some("this is a bad date"), || {
603            let result = || -> Result<()> {
604                let mut stdout_buf = vec![];
605                let rustc = Rustc::all_rustc();
606                assert!(
607                    Emitter::default()
608                        .add_instructions(&rustc)?
609                        .emit_to(&mut stdout_buf)
610                        .is_ok()
611                );
612                let output = String::from_utf8_lossy(&stdout_buf);
613                assert!(output.contains("cargo:rustc-env=VERGEN_RUSTC_CHANNEL=this is a bad date"));
614                Ok(())
615            }();
616            assert!(result.is_ok());
617        });
618    }
619
620    #[test]
621    #[serial]
622    fn rustc_commit_date_override_works() {
623        with_var(
624            "VERGEN_RUSTC_COMMIT_DATE",
625            Some("this is a bad date"),
626            || {
627                let result =
628                    || -> Result<()> {
629                        let mut stdout_buf = vec![];
630                        let rustc = Rustc::all_rustc();
631                        assert!(
632                            Emitter::default()
633                                .add_instructions(&rustc)?
634                                .emit_to(&mut stdout_buf)
635                                .is_ok()
636                        );
637                        let output = String::from_utf8_lossy(&stdout_buf);
638                        assert!(output.contains(
639                            "cargo:rustc-env=VERGEN_RUSTC_COMMIT_DATE=this is a bad date"
640                        ));
641                        Ok(())
642                    }();
643                assert!(result.is_ok());
644            },
645        );
646    }
647
648    #[test]
649    #[serial]
650    fn rustc_commit_hash_override_works() {
651        with_var(
652            "VERGEN_RUSTC_COMMIT_HASH",
653            Some("this is a bad date"),
654            || {
655                let result =
656                    || -> Result<()> {
657                        let mut stdout_buf = vec![];
658                        let rustc = Rustc::all_rustc();
659                        assert!(
660                            Emitter::default()
661                                .add_instructions(&rustc)?
662                                .emit_to(&mut stdout_buf)
663                                .is_ok()
664                        );
665                        let output = String::from_utf8_lossy(&stdout_buf);
666                        assert!(output.contains(
667                            "cargo:rustc-env=VERGEN_RUSTC_COMMIT_HASH=this is a bad date"
668                        ));
669                        Ok(())
670                    }();
671                assert!(result.is_ok());
672            },
673        );
674    }
675
676    #[test]
677    #[serial]
678    fn rustc_host_triple_override_works() {
679        with_var(
680            "VERGEN_RUSTC_HOST_TRIPLE",
681            Some("this is a bad date"),
682            || {
683                let result =
684                    || -> Result<()> {
685                        let mut stdout_buf = vec![];
686                        let rustc = Rustc::all_rustc();
687                        assert!(
688                            Emitter::default()
689                                .add_instructions(&rustc)?
690                                .emit_to(&mut stdout_buf)
691                                .is_ok()
692                        );
693                        let output = String::from_utf8_lossy(&stdout_buf);
694                        assert!(output.contains(
695                            "cargo:rustc-env=VERGEN_RUSTC_HOST_TRIPLE=this is a bad date"
696                        ));
697                        Ok(())
698                    }();
699                assert!(result.is_ok());
700            },
701        );
702    }
703
704    #[test]
705    #[serial]
706    fn rustc_llvm_version_override_works() {
707        with_var(
708            "VERGEN_RUSTC_LLVM_VERSION",
709            Some("this is a bad date"),
710            || {
711                let result =
712                    || -> Result<()> {
713                        let mut stdout_buf = vec![];
714                        let rustc = Rustc::all_rustc();
715                        assert!(
716                            Emitter::default()
717                                .add_instructions(&rustc)?
718                                .emit_to(&mut stdout_buf)
719                                .is_ok()
720                        );
721                        let output = String::from_utf8_lossy(&stdout_buf);
722                        assert!(output.contains(
723                            "cargo:rustc-env=VERGEN_RUSTC_LLVM_VERSION=this is a bad date"
724                        ));
725                        Ok(())
726                    }();
727                assert!(result.is_ok());
728            },
729        );
730    }
731
732    #[test]
733    #[serial]
734    fn rustc_semver_override_works() {
735        with_var("VERGEN_RUSTC_SEMVER", Some("this is a bad date"), || {
736            let result = || -> Result<()> {
737                let mut stdout_buf = vec![];
738                let rustc = Rustc::all_rustc();
739                assert!(
740                    Emitter::default()
741                        .add_instructions(&rustc)?
742                        .emit_to(&mut stdout_buf)
743                        .is_ok()
744                );
745                let output = String::from_utf8_lossy(&stdout_buf);
746                assert!(output.contains("cargo:rustc-env=VERGEN_RUSTC_SEMVER=this is a bad date"));
747                Ok(())
748            }();
749            assert!(result.is_ok());
750        });
751    }
752}