Skip to content

Commit

Permalink
Auto merge of #71858 - petrochenkov:env, r=Mark-Simulacrum
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Jun 25, 2020
2 parents 50fc24d + 69b2179 commit 1033351
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 7 deletions.
18 changes: 11 additions & 7 deletions src/librustc_builtin_macros/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ pub fn expand_option_env<'cx>(
};

let sp = cx.with_def_site_ctxt(sp);
let e = match env::var(&var.as_str()) {
Err(..) => {
let value = env::var(&var.as_str()).ok().as_deref().map(Symbol::intern);
cx.parse_sess.env_depinfo.borrow_mut().insert((Symbol::intern(&var), value));
let e = match value {
None => {
let lt = cx.lifetime(sp, Ident::new(kw::StaticLifetime, sp));
cx.expr_path(cx.path_all(
sp,
Expand All @@ -37,10 +39,10 @@ pub fn expand_option_env<'cx>(
))],
))
}
Ok(s) => cx.expr_call_global(
Some(value) => cx.expr_call_global(
sp,
cx.std_path(&[sym::option, sym::Option, sym::Some]),
vec![cx.expr_str(sp, Symbol::intern(&s))],
vec![cx.expr_str(sp, value)],
),
};
MacEager::expr(e)
Expand Down Expand Up @@ -78,12 +80,14 @@ pub fn expand_env<'cx>(
}

let sp = cx.with_def_site_ctxt(sp);
let e = match env::var(&*var.as_str()) {
Err(_) => {
let value = env::var(&*var.as_str()).ok().as_deref().map(Symbol::intern);
cx.parse_sess.env_depinfo.borrow_mut().insert((var, value));
let e = match value {
None => {
cx.span_err(sp, &msg.as_str());
return DummyResult::any(sp);
}
Ok(s) => cx.expr_str(sp, Symbol::intern(&s)),
Some(value) => cx.expr_str(sp, value),
};
MacEager::expr(e)
}
1 change: 1 addition & 0 deletions src/librustc_builtin_macros/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(inner_deref)]
#![feature(nll)]
#![feature(or_patterns)]
#![feature(proc_macro_internals)]
Expand Down
35 changes: 35 additions & 0 deletions src/librustc_interface/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,22 @@ fn escape_dep_filename(filename: &FileName) -> String {
filename.to_string().replace(" ", "\\ ")
}

// Makefile comments only need escaping newlines and `\`.
// The result can be unescaped by anything that can unescape `escape_default` and friends.
fn escape_dep_env(symbol: Symbol) -> String {
let s = symbol.as_str();
let mut escaped = String::with_capacity(s.len());
for c in s.chars() {
match c {
'\n' => escaped.push_str(r"\n"),
'\r' => escaped.push_str(r"\r"),
'\\' => escaped.push_str(r"\\"),
_ => escaped.push(c),
}
}
escaped
}

fn write_out_deps(
sess: &Session,
boxed_resolver: &Steal<Rc<RefCell<BoxedResolver>>>,
Expand Down Expand Up @@ -604,6 +620,25 @@ fn write_out_deps(
for path in files {
writeln!(file, "{}:", path)?;
}

// Emit special comments with information about accessed environment variables.
let env_depinfo = sess.parse_sess.env_depinfo.borrow();
if !env_depinfo.is_empty() {
let mut envs: Vec<_> = env_depinfo
.iter()
.map(|(k, v)| (escape_dep_env(*k), v.map(escape_dep_env)))
.collect();
envs.sort_unstable();
writeln!(file)?;
for (k, v) in envs {
write!(file, "# env-dep:{}", k)?;
if let Some(v) = v {
write!(file, "={}", v)?;
}
writeln!(file)?;
}
}

Ok(())
})();

Expand Down
3 changes: 3 additions & 0 deletions src/librustc_session/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ pub struct ParseSess {
pub symbol_gallery: SymbolGallery,
/// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors.
pub reached_eof: Lock<bool>,
/// Environment variables accessed during the build and their values when they exist.
pub env_depinfo: Lock<FxHashSet<(Symbol, Option<Symbol>)>>,
}

impl ParseSess {
Expand All @@ -160,6 +162,7 @@ impl ParseSess {
gated_spans: GatedSpans::default(),
symbol_gallery: SymbolGallery::default(),
reached_eof: Lock::new(false),
env_depinfo: Default::default(),
}
}

Expand Down
8 changes: 8 additions & 0 deletions src/test/run-make/env-dep-info/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-include ../../run-make-fulldeps/tools.mk

all:
EXISTING_ENV=1 EXISTING_OPT_ENV=1 $(RUSTC) --emit dep-info main.rs
$(CGREP) "# env-dep:EXISTING_ENV=1" < $(TMPDIR)/main.d
$(CGREP) "# env-dep:EXISTING_OPT_ENV=1" < $(TMPDIR)/main.d
$(CGREP) "# env-dep:NONEXISTENT_OPT_ENV" < $(TMPDIR)/main.d
$(CGREP) "# env-dep:ESCAPE\nESCAPE\\" < $(TMPDIR)/main.d
6 changes: 6 additions & 0 deletions src/test/run-make/env-dep-info/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
fn main() {
env!("EXISTING_ENV");
option_env!("EXISTING_OPT_ENV");
option_env!("NONEXISTENT_OPT_ENV");
option_env!("ESCAPE\nESCAPE\\");
}

0 comments on commit 1033351

Please sign in to comment.