Skip to content

Commit

Permalink
Auto merge of #17108 - Veykril:rustc-ws-hacks, r=Veykril
Browse files Browse the repository at this point in the history
internal: Cleanup cfg and env handling in project-model

Fixes #16122 (comment)

`miri` and `debug_assertions` are now enabled via the `cargo.cfgs` config by default, allowing them to be disabled by overwriting the config.
  • Loading branch information
bors committed Apr 19, 2024
2 parents 05428c5 + cdb8c3a commit 50bdeaa
Show file tree
Hide file tree
Showing 23 changed files with 504 additions and 311 deletions.
40 changes: 34 additions & 6 deletions crates/base-db/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,11 +295,30 @@ pub struct CrateData {
pub is_proc_macro: bool,
}

#[derive(Default, Debug, Clone, PartialEq, Eq)]
#[derive(Default, Clone, PartialEq, Eq)]
pub struct Env {
entries: FxHashMap<String, String>,
}

impl fmt::Debug for Env {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
struct EnvDebug<'s>(Vec<(&'s String, &'s String)>);

impl fmt::Debug for EnvDebug<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map().entries(self.0.iter().copied()).finish()
}
}
f.debug_struct("Env")
.field("entries", &{
let mut entries: Vec<_> = self.entries.iter().collect();
entries.sort();
EnvDebug(entries)
})
.finish()
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Dependency {
pub crate_id: CrateId,
Expand Down Expand Up @@ -331,10 +350,11 @@ impl CrateGraph {
version: Option<String>,
cfg_options: Arc<CfgOptions>,
potential_cfg_options: Option<Arc<CfgOptions>>,
env: Env,
mut env: Env,
is_proc_macro: bool,
origin: CrateOrigin,
) -> CrateId {
env.entries.shrink_to_fit();
let data = CrateData {
root_file_id,
edition,
Expand Down Expand Up @@ -651,16 +671,24 @@ impl FromIterator<(String, String)> for Env {
}

impl Env {
pub fn set(&mut self, env: &str, value: String) {
self.entries.insert(env.to_owned(), value);
pub fn set(&mut self, env: &str, value: impl Into<String>) {
self.entries.insert(env.to_owned(), value.into());
}

pub fn get(&self, env: &str) -> Option<String> {
self.entries.get(env).cloned()
}

pub fn iter(&self) -> impl Iterator<Item = (&str, &str)> {
self.entries.iter().map(|(k, v)| (k.as_str(), v.as_str()))
pub fn extend_from_other(&mut self, other: &Env) {
self.entries.extend(other.entries.iter().map(|(x, y)| (x.to_owned(), y.to_owned())));
}
}

impl From<Env> for Vec<(String, String)> {
fn from(env: Env) -> Vec<(String, String)> {
let mut entries: Vec<_> = env.entries.into_iter().collect();
entries.sort();
entries
}
}

Expand Down
7 changes: 0 additions & 7 deletions crates/cfg/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,6 @@ impl CfgOptions {
self.enabled.insert(CfgAtom::KeyValue { key, value });
}

pub fn difference<'a>(
&'a self,
other: &'a CfgOptions,
) -> impl Iterator<Item = &'a CfgAtom> + 'a {
self.enabled.difference(&other.enabled)
}

pub fn apply_diff(&mut self, diff: CfgDiff) {
for atom in diff.enable {
self.enabled.insert(atom);
Expand Down
3 changes: 1 addition & 2 deletions crates/load-cargo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,8 +407,7 @@ impl ProcMacroExpander for Expander {
call_site: Span,
mixed_site: Span,
) -> Result<tt::Subtree<Span>, ProcMacroExpansionError> {
let env = env.iter().map(|(k, v)| (k.to_owned(), v.to_owned())).collect();
match self.0.expand(subtree, attrs, env, def_site, call_site, mixed_site) {
match self.0.expand(subtree, attrs, env.clone(), def_site, call_site, mixed_site) {
Ok(Ok(subtree)) => Ok(subtree),
Ok(Err(err)) => Err(ProcMacroExpansionError::Panic(err.0)),
Err(err) => Err(ProcMacroExpansionError::System(err.to_string())),
Expand Down
10 changes: 4 additions & 6 deletions crates/proc-macro-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub mod msg;
mod process;
mod version;

use base_db::Env;
use indexmap::IndexSet;
use paths::AbsPathBuf;
use rustc_hash::FxHashMap;
Expand Down Expand Up @@ -152,16 +153,13 @@ impl ProcMacro {
&self,
subtree: &tt::Subtree<Span>,
attr: Option<&tt::Subtree<Span>>,
env: Vec<(String, String)>,
env: Env,
def_site: Span,
call_site: Span,
mixed_site: Span,
) -> Result<Result<tt::Subtree<Span>, PanicMessage>, ServerError> {
let version = self.process.lock().unwrap_or_else(|e| e.into_inner()).version();
let current_dir = env
.iter()
.find(|(name, _)| name == "CARGO_MANIFEST_DIR")
.map(|(_, value)| value.clone());
let current_dir = env.get("CARGO_MANIFEST_DIR");

let mut span_data_table = IndexSet::default();
let def_site = span_data_table.insert_full(def_site).0;
Expand All @@ -172,7 +170,7 @@ impl ProcMacro {
macro_name: self.name.to_string(),
attributes: attr.map(|subtree| FlatTree::new(subtree, version, &mut span_data_table)),
lib: self.dylib_path.to_path_buf().into(),
env,
env: env.into(),
current_dir,
has_global_spans: ExpnGlobals {
serialize: version >= HAS_GLOBAL_SPANS,
Expand Down
4 changes: 3 additions & 1 deletion crates/project-model/src/build_scripts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,18 @@ use serde::Deserialize;
use toolchain::Tool;

use crate::{
cfg_flag::CfgFlag, utf8_stdout, CargoConfig, CargoFeatures, CargoWorkspace, InvocationLocation,
cfg::CfgFlag, utf8_stdout, CargoConfig, CargoFeatures, CargoWorkspace, InvocationLocation,
InvocationStrategy, Package, Sysroot, TargetKind,
};

/// Output of the build script and proc-macro building steps for a workspace.
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct WorkspaceBuildScripts {
outputs: ArenaMap<Package, BuildScriptOutput>,
error: Option<String>,
}

/// Output of the build script and proc-macro building step for a concrete package.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub(crate) struct BuildScriptOutput {
/// List of config flags defined by this package's build script.
Expand Down
32 changes: 32 additions & 0 deletions crates/project-model/src/cargo_workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,20 @@ pub struct PackageData {
pub active_features: Vec<String>,
/// String representation of package id
pub id: String,
/// Authors as given in the `Cargo.toml`
pub authors: Vec<String>,
/// Description as given in the `Cargo.toml`
pub description: Option<String>,
/// Homepage as given in the `Cargo.toml`
pub homepage: Option<String>,
/// License as given in the `Cargo.toml`
pub license: Option<String>,
/// License file as given in the `Cargo.toml`
pub license_file: Option<Utf8PathBuf>,
/// Readme file as given in the `Cargo.toml`
pub readme: Option<Utf8PathBuf>,
/// Rust version as given in the `Cargo.toml`
pub rust_version: Option<semver::Version>,
/// The contents of [package.metadata.rust-analyzer]
pub metadata: RustAnalyzerPackageMetaData,
}
Expand Down Expand Up @@ -225,6 +239,10 @@ impl TargetKind {
}
TargetKind::Other
}

pub fn is_executable(self) -> bool {
matches!(self, TargetKind::Bin | TargetKind::Example)
}
}

// Deserialize helper for the cargo metadata
Expand Down Expand Up @@ -330,6 +348,13 @@ impl CargoWorkspace {
repository,
edition,
metadata,
authors,
description,
homepage,
license,
license_file,
readme,
rust_version,
..
} = meta_pkg;
let meta = from_value::<PackageMetadata>(metadata).unwrap_or_default();
Expand Down Expand Up @@ -358,6 +383,13 @@ impl CargoWorkspace {
is_member,
edition,
repository,
authors,
description,
homepage,
license,
license_file,
readme,
rust_version,
dependencies: Vec::new(),
features: features.into_iter().collect(),
active_features: Vec::new(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
//! rustc main.rs --cfg foo --cfg 'feature="bar"'
use std::{fmt, str::FromStr};

use cfg::CfgOptions;
use cfg::{CfgDiff, CfgOptions};
use rustc_hash::FxHashMap;
use serde::Serialize;

#[derive(Clone, Eq, PartialEq, Debug, Serialize)]
Expand Down Expand Up @@ -70,3 +71,27 @@ impl fmt::Display for CfgFlag {
}
}
}

/// A set of cfg-overrides per crate.
#[derive(Default, Debug, Clone, Eq, PartialEq)]
pub struct CfgOverrides {
/// A global set of overrides matching all crates.
pub global: CfgDiff,
/// A set of overrides matching specific crates.
pub selective: FxHashMap<String, CfgDiff>,
}

impl CfgOverrides {
pub fn len(&self) -> usize {
self.global.len() + self.selective.values().map(|it| it.len()).sum::<usize>()
}

pub fn apply(&self, cfg_options: &mut CfgOptions, name: &str) {
if !self.global.is_empty() {
cfg_options.apply_diff(self.global.clone());
};
if let Some(diff) = self.selective.get(name) {
cfg_options.apply_diff(diff.clone());
};
}
}
85 changes: 85 additions & 0 deletions crates/project-model/src/env.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//! Cargo-like environment variables injection.
use base_db::Env;
use rustc_hash::FxHashMap;
use toolchain::Tool;

use crate::{utf8_stdout, ManifestPath, PackageData, Sysroot, TargetKind};

/// Recreates the compile-time environment variables that Cargo sets.
///
/// Should be synced with
/// <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates>
///
/// FIXME: ask Cargo to provide this data instead of re-deriving.
pub(crate) fn inject_cargo_package_env(env: &mut Env, package: &PackageData) {
// FIXME: Missing variables:
// CARGO_BIN_NAME, CARGO_BIN_EXE_<name>

let manifest_dir = package.manifest.parent();
env.set("CARGO_MANIFEST_DIR", manifest_dir.as_str());

env.set("CARGO_PKG_VERSION", package.version.to_string());
env.set("CARGO_PKG_VERSION_MAJOR", package.version.major.to_string());
env.set("CARGO_PKG_VERSION_MINOR", package.version.minor.to_string());
env.set("CARGO_PKG_VERSION_PATCH", package.version.patch.to_string());
env.set("CARGO_PKG_VERSION_PRE", package.version.pre.to_string());

env.set("CARGO_PKG_AUTHORS", package.authors.join(":").clone());

env.set("CARGO_PKG_NAME", package.name.clone());
env.set("CARGO_PKG_DESCRIPTION", package.description.as_deref().unwrap_or_default());
env.set("CARGO_PKG_HOMEPAGE", package.homepage.as_deref().unwrap_or_default());
env.set("CARGO_PKG_REPOSITORY", package.repository.as_deref().unwrap_or_default());
env.set("CARGO_PKG_LICENSE", package.license.as_deref().unwrap_or_default());
env.set(
"CARGO_PKG_LICENSE_FILE",
package.license_file.as_ref().map(ToString::to_string).unwrap_or_default(),
);
env.set(
"CARGO_PKG_README",
package.readme.as_ref().map(ToString::to_string).unwrap_or_default(),
);

env.set(
"CARGO_PKG_RUST_VERSION",
package.rust_version.as_ref().map(ToString::to_string).unwrap_or_default(),
);
}

pub(crate) fn inject_cargo_env(env: &mut Env) {
env.set("CARGO", Tool::Cargo.path().to_string());
}

pub(crate) fn inject_rustc_tool_env(env: &mut Env, cargo_name: &str, kind: TargetKind) {
_ = kind;
// FIXME
// if kind.is_executable() {
// env.set("CARGO_BIN_NAME", cargo_name);
// }
env.set("CARGO_CRATE_NAME", cargo_name.replace('-', "_"));
}

pub(crate) fn cargo_config_env(
cargo_toml: &ManifestPath,
extra_env: &FxHashMap<String, String>,
sysroot: Option<&Sysroot>,
) -> FxHashMap<String, String> {
let mut cargo_config = Sysroot::tool(sysroot, Tool::Cargo);
cargo_config.envs(extra_env);
cargo_config
.current_dir(cargo_toml.parent())
.args(["-Z", "unstable-options", "config", "get", "env"])
.env("RUSTC_BOOTSTRAP", "1");
// if successful we receive `env.key.value = "value" per entry
tracing::debug!("Discovering cargo config env by {:?}", cargo_config);
utf8_stdout(cargo_config).map(parse_output_cargo_config_env).unwrap_or_default()
}

fn parse_output_cargo_config_env(stdout: String) -> FxHashMap<String, String> {
stdout
.lines()
.filter_map(|l| l.strip_prefix("env."))
.filter_map(|l| l.split_once(".value = "))
.map(|(key, value)| (key.to_owned(), value.trim_matches('"').to_owned()))
.collect()
}
6 changes: 4 additions & 2 deletions crates/project-model/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@

mod build_scripts;
mod cargo_workspace;
mod cfg_flag;
mod cfg;
mod env;
mod manifest_path;
mod project_json;
mod rustc_cfg;
Expand Down Expand Up @@ -47,10 +48,11 @@ pub use crate::{
CargoConfig, CargoFeatures, CargoWorkspace, Package, PackageData, PackageDependency,
RustLibSource, Target, TargetData, TargetKind,
},
cfg::CfgOverrides,
manifest_path::ManifestPath,
project_json::{ProjectJson, ProjectJsonData},
sysroot::Sysroot,
workspace::{CfgOverrides, PackageRoot, ProjectWorkspace},
workspace::{FileLoader, PackageRoot, ProjectWorkspace},
};

#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
Expand Down
2 changes: 1 addition & 1 deletion crates/project-model/src/project_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ use rustc_hash::FxHashMap;
use serde::{de, Deserialize, Serialize};
use span::Edition;

use crate::cfg_flag::CfgFlag;
use crate::cfg::CfgFlag;

/// Roots and crates that compose this Rust project.
#[derive(Clone, Debug, Eq, PartialEq)]
Expand Down
5 changes: 1 addition & 4 deletions crates/project-model/src/rustc_cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use anyhow::Context;
use rustc_hash::FxHashMap;
use toolchain::Tool;

use crate::{cfg_flag::CfgFlag, utf8_stdout, ManifestPath, Sysroot};
use crate::{cfg::CfgFlag, utf8_stdout, ManifestPath, Sysroot};

/// Determines how `rustc --print cfg` is discovered and invoked.
pub(crate) enum RustcCfgConfig<'a> {
Expand Down Expand Up @@ -32,9 +32,6 @@ pub(crate) fn get(
}
}

// Add miri cfg, which is useful for mir eval in stdlib
res.push(CfgFlag::Atom("miri".into()));

let rustc_cfgs = get_rust_cfgs(target, extra_env, config);

let rustc_cfgs = match rustc_cfgs {
Expand Down
Loading

0 comments on commit 50bdeaa

Please sign in to comment.