Skip to content

Commit 1033351

Browse files
committed
Auto merge of #71858 - petrochenkov:env, r=Mark-Simulacrum
Print environment variables accessed by rustc as special comments into depinfo files So cargo (and perhaps others tools) can use them for linting (at least) or for actually rebuilding crates on env var changes. --- I've recently observed one more forgotten environment variable in a build script 8a77d1c and thought it would be nice to provide the list of accessed variables to cargo automatically as a part of depinfo. Unsurprisingly, I wasn't the first who had this idea - cc #70517 #40364 #44074. Also, there are dozens of uses of `(option_)env!` in rustc repo and, like, half of them are not registered in build scripts. --- Description: - depinfo files are extended with special comments containing info about environment variables accessed during compilation. - Comment format for environment variables with successfully retrieved value: `# env-dep:KEY=VALUE`. - Comment format for environment variables without successfully retrieved value: `# env-dep:KEY` (can happen with `option_env!`). - `KEY` and `VALUE` are minimally escaped (`\n`, `\r`, `\\`) so they don't break makefile comments and can be unescaped by anything that can unescape standard `escape_default` and friends. FCP report: #71858 (comment) Closes #70517 Closes #40364 Closes #44074 A new issue in the cargo repo will be needed to track the cargo side of this feature. r? @ehuss
2 parents 50fc24d + 69b2179 commit 1033351

File tree

6 files changed

+64
-7
lines changed

6 files changed

+64
-7
lines changed

src/librustc_builtin_macros/env.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ pub fn expand_option_env<'cx>(
2222
};
2323

2424
let sp = cx.with_def_site_ctxt(sp);
25-
let e = match env::var(&var.as_str()) {
26-
Err(..) => {
25+
let value = env::var(&var.as_str()).ok().as_deref().map(Symbol::intern);
26+
cx.parse_sess.env_depinfo.borrow_mut().insert((Symbol::intern(&var), value));
27+
let e = match value {
28+
None => {
2729
let lt = cx.lifetime(sp, Ident::new(kw::StaticLifetime, sp));
2830
cx.expr_path(cx.path_all(
2931
sp,
@@ -37,10 +39,10 @@ pub fn expand_option_env<'cx>(
3739
))],
3840
))
3941
}
40-
Ok(s) => cx.expr_call_global(
42+
Some(value) => cx.expr_call_global(
4143
sp,
4244
cx.std_path(&[sym::option, sym::Option, sym::Some]),
43-
vec![cx.expr_str(sp, Symbol::intern(&s))],
45+
vec![cx.expr_str(sp, value)],
4446
),
4547
};
4648
MacEager::expr(e)
@@ -78,12 +80,14 @@ pub fn expand_env<'cx>(
7880
}
7981

8082
let sp = cx.with_def_site_ctxt(sp);
81-
let e = match env::var(&*var.as_str()) {
82-
Err(_) => {
83+
let value = env::var(&*var.as_str()).ok().as_deref().map(Symbol::intern);
84+
cx.parse_sess.env_depinfo.borrow_mut().insert((var, value));
85+
let e = match value {
86+
None => {
8387
cx.span_err(sp, &msg.as_str());
8488
return DummyResult::any(sp);
8589
}
86-
Ok(s) => cx.expr_str(sp, Symbol::intern(&s)),
90+
Some(value) => cx.expr_str(sp, value),
8791
};
8892
MacEager::expr(e)
8993
}

src/librustc_builtin_macros/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#![feature(bool_to_option)]
66
#![feature(crate_visibility_modifier)]
77
#![feature(decl_macro)]
8+
#![feature(inner_deref)]
89
#![feature(nll)]
910
#![feature(or_patterns)]
1011
#![feature(proc_macro_internals)]

src/librustc_interface/passes.rs

+35
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,22 @@ fn escape_dep_filename(filename: &FileName) -> String {
549549
filename.to_string().replace(" ", "\\ ")
550550
}
551551

552+
// Makefile comments only need escaping newlines and `\`.
553+
// The result can be unescaped by anything that can unescape `escape_default` and friends.
554+
fn escape_dep_env(symbol: Symbol) -> String {
555+
let s = symbol.as_str();
556+
let mut escaped = String::with_capacity(s.len());
557+
for c in s.chars() {
558+
match c {
559+
'\n' => escaped.push_str(r"\n"),
560+
'\r' => escaped.push_str(r"\r"),
561+
'\\' => escaped.push_str(r"\\"),
562+
_ => escaped.push(c),
563+
}
564+
}
565+
escaped
566+
}
567+
552568
fn write_out_deps(
553569
sess: &Session,
554570
boxed_resolver: &Steal<Rc<RefCell<BoxedResolver>>>,
@@ -604,6 +620,25 @@ fn write_out_deps(
604620
for path in files {
605621
writeln!(file, "{}:", path)?;
606622
}
623+
624+
// Emit special comments with information about accessed environment variables.
625+
let env_depinfo = sess.parse_sess.env_depinfo.borrow();
626+
if !env_depinfo.is_empty() {
627+
let mut envs: Vec<_> = env_depinfo
628+
.iter()
629+
.map(|(k, v)| (escape_dep_env(*k), v.map(escape_dep_env)))
630+
.collect();
631+
envs.sort_unstable();
632+
writeln!(file)?;
633+
for (k, v) in envs {
634+
write!(file, "# env-dep:{}", k)?;
635+
if let Some(v) = v {
636+
write!(file, "={}", v)?;
637+
}
638+
writeln!(file)?;
639+
}
640+
}
641+
607642
Ok(())
608643
})();
609644

src/librustc_session/parse.rs

+3
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ pub struct ParseSess {
135135
pub symbol_gallery: SymbolGallery,
136136
/// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors.
137137
pub reached_eof: Lock<bool>,
138+
/// Environment variables accessed during the build and their values when they exist.
139+
pub env_depinfo: Lock<FxHashSet<(Symbol, Option<Symbol>)>>,
138140
}
139141

140142
impl ParseSess {
@@ -160,6 +162,7 @@ impl ParseSess {
160162
gated_spans: GatedSpans::default(),
161163
symbol_gallery: SymbolGallery::default(),
162164
reached_eof: Lock::new(false),
165+
env_depinfo: Default::default(),
163166
}
164167
}
165168

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-include ../../run-make-fulldeps/tools.mk
2+
3+
all:
4+
EXISTING_ENV=1 EXISTING_OPT_ENV=1 $(RUSTC) --emit dep-info main.rs
5+
$(CGREP) "# env-dep:EXISTING_ENV=1" < $(TMPDIR)/main.d
6+
$(CGREP) "# env-dep:EXISTING_OPT_ENV=1" < $(TMPDIR)/main.d
7+
$(CGREP) "# env-dep:NONEXISTENT_OPT_ENV" < $(TMPDIR)/main.d
8+
$(CGREP) "# env-dep:ESCAPE\nESCAPE\\" < $(TMPDIR)/main.d
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
fn main() {
2+
env!("EXISTING_ENV");
3+
option_env!("EXISTING_OPT_ENV");
4+
option_env!("NONEXISTENT_OPT_ENV");
5+
option_env!("ESCAPE\nESCAPE\\");
6+
}

0 commit comments

Comments
 (0)