//! metadata` or `rust-project.json`) into representation stored in the salsa
//! database -- `CrateGraph`.
-use std::{collections::VecDeque, fmt, fs, path::Path, process::Command};
+use std::{collections::VecDeque, convert::TryFrom, fmt, fs, process::Command};
use anyhow::{format_err, Context, Result};
use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro};
-use cargo_workspace::DepKind;
-use cfg::CfgOptions;
+use cfg::{CfgDiff, CfgOptions};
use paths::{AbsPath, AbsPathBuf};
-use proc_macro_api::ProcMacroClient;
use rustc_hash::{FxHashMap, FxHashSet};
+use stdx::always;
use crate::{
- build_data::{BuildDataResult, PackageBuildData, WorkspaceBuildData},
- cargo_workspace,
+ build_scripts::BuildScriptOutput,
+ cargo_workspace::{DepKind, PackageData, RustcSource},
cfg_flag::CfgFlag,
rustc_cfg,
sysroot::SysrootCrate,
- utf8_stdout, BuildDataCollector, CargoConfig, CargoWorkspace, ProjectJson, ProjectManifest,
- Sysroot, TargetKind,
+ utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath, ProjectJson, ProjectManifest, Sysroot,
+ TargetKind, WorkspaceBuildScripts,
};
+/// A set of cfg-overrides per crate.
+///
+/// `Wildcard(..)` is useful e.g. disabling `#[cfg(test)]` on all crates,
+/// without having to first obtain a list of all crates.
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub enum CfgOverrides {
+ /// A single global set of overrides matching all crates.
+ Wildcard(CfgDiff),
+ /// A set of overrides matching specific crates.
+ Selective(FxHashMap<String, CfgDiff>),
+}
+
+impl Default for CfgOverrides {
+ fn default() -> Self {
+ Self::Selective(FxHashMap::default())
+ }
+}
+
+impl CfgOverrides {
+ pub fn len(&self) -> usize {
+ match self {
+ CfgOverrides::Wildcard(_) => 1,
+ CfgOverrides::Selective(hash_map) => hash_map.len(),
+ }
+ }
+}
+
/// `PackageRoot` describes a package root folder.
/// Which may be an external dependency, or a member of
/// the current workspace.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct PackageRoot {
- /// Is a member of the current workspace
- pub is_member: bool,
+ /// Is from the local filesystem and may be edited
+ pub is_local: bool,
pub include: Vec<AbsPathBuf>,
pub exclude: Vec<AbsPathBuf>,
}
/// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
Cargo {
cargo: CargoWorkspace,
- sysroot: Sysroot,
+ build_scripts: WorkspaceBuildScripts,
+ sysroot: Option<Sysroot>,
rustc: Option<CargoWorkspace>,
/// Holds cfg flags for the current target. We get those by running
/// `rustc --print cfg`.
/// FIXME: make this a per-crate map, as, eg, build.rs might have a
/// different target.
rustc_cfg: Vec<CfgFlag>,
+ cfg_overrides: CfgOverrides,
},
/// Project workspace was manually specified using a `rust-project.json` file.
Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> },
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Make sure this isn't too verbose.
match self {
- ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => f
+ ProjectWorkspace::Cargo {
+ cargo,
+ build_scripts: _,
+ sysroot,
+ rustc,
+ rustc_cfg,
+ cfg_overrides,
+ } => f
.debug_struct("Cargo")
.field("root", &cargo.workspace_root().file_name())
.field("n_packages", &cargo.packages().len())
- .field("n_sysroot_crates", &sysroot.crates().len())
+ .field("sysroot", &sysroot.is_some())
.field(
"n_rustc_compiler_crates",
&rustc.as_ref().map_or(0, |rc| rc.packages().len()),
)
.field("n_rustc_cfg", &rustc_cfg.len())
+ .field("n_cfg_overrides", &cfg_overrides.len())
.finish(),
ProjectWorkspace::Json { project, sysroot, rustc_cfg } => {
let mut debug_struct = f.debug_struct("Json");
let data = serde_json::from_str(&file).with_context(|| {
format!("Failed to deserialize json file {}", project_json.display())
})?;
- let project_location = project_json.parent().unwrap().to_path_buf();
+ let project_location = project_json.parent().to_path_buf();
let project_json = ProjectJson::new(&project_location, data);
ProjectWorkspace::load_inline(project_json, config.target.as_deref())?
}
cmd
})?;
- let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, config, progress)
+ let meta = CargoWorkspace::fetch_metadata(&cargo_toml, config, progress)
.with_context(|| {
format!(
"Failed to read Cargo metadata from Cargo.toml file {}, {}",
cargo_version
)
})?;
+ let cargo = CargoWorkspace::new(meta);
let sysroot = if config.no_sysroot {
- Sysroot::default()
+ None
} else {
- Sysroot::discover(&cargo_toml).with_context(|| {
+ Some(Sysroot::discover(cargo_toml.parent()).with_context(|| {
format!(
"Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?",
cargo_toml.display()
)
- })?
+ })?)
};
- let rustc_dir = if let Some(rustc_source) = &config.rustc_source {
- use cargo_workspace::RustcSource;
- match rustc_source {
- RustcSource::Path(path) => Some(path.clone()),
- RustcSource::Discover => Sysroot::discover_rustc(&cargo_toml),
- }
- } else {
- None
+ let rustc_dir = match &config.rustc_source {
+ Some(RustcSource::Path(path)) => ManifestPath::try_from(path.clone()).ok(),
+ Some(RustcSource::Discover) => Sysroot::discover_rustc(&cargo_toml),
+ None => None,
};
- let rustc = if let Some(rustc_dir) = rustc_dir {
- Some(
- CargoWorkspace::from_cargo_metadata(&rustc_dir, config, progress)
+ let rustc = match rustc_dir {
+ Some(rustc_dir) => Some({
+ let meta = CargoWorkspace::fetch_metadata(&rustc_dir, config, progress)
.with_context(|| {
format!("Failed to read Cargo metadata for Rust sources")
- })?,
- )
- } else {
- None
+ })?;
+ CargoWorkspace::new(meta)
+ }),
+ None => None,
};
let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref());
- ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg }
+
+ let cfg_overrides = config.cfg_overrides();
+ ProjectWorkspace::Cargo {
+ cargo,
+ build_scripts: WorkspaceBuildScripts::default(),
+ sysroot,
+ rustc,
+ rustc_cfg,
+ cfg_overrides,
+ }
}
};
target: Option<&str>,
) -> Result<ProjectWorkspace> {
let sysroot = match &project_json.sysroot_src {
- Some(path) => Some(Sysroot::load(path)?),
+ Some(path) => Some(Sysroot::load(path.clone())?),
None => None,
};
let rustc_cfg = rustc_cfg::get(None, target);
pub fn load_detached_files(detached_files: Vec<AbsPathBuf>) -> Result<ProjectWorkspace> {
let sysroot = Sysroot::discover(
- &detached_files.first().ok_or_else(|| format_err!("No detached files to load"))?,
+ detached_files
+ .first()
+ .and_then(|it| it.parent())
+ .ok_or_else(|| format_err!("No detached files to load"))?,
)?;
let rustc_cfg = rustc_cfg::get(None, None);
Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg })
}
+ pub fn run_build_scripts(
+ &self,
+ config: &CargoConfig,
+ progress: &dyn Fn(String),
+ ) -> Result<WorkspaceBuildScripts> {
+ match self {
+ ProjectWorkspace::Cargo { cargo, .. } => {
+ WorkspaceBuildScripts::run(config, cargo, progress)
+ }
+ ProjectWorkspace::Json { .. } | ProjectWorkspace::DetachedFiles { .. } => {
+ Ok(WorkspaceBuildScripts::default())
+ }
+ }
+ }
+
+ pub fn set_build_scripts(&mut self, bs: WorkspaceBuildScripts) {
+ match self {
+ ProjectWorkspace::Cargo { build_scripts, .. } => *build_scripts = bs,
+ _ => {
+ always!(bs == WorkspaceBuildScripts::default());
+ }
+ }
+ }
+
/// Returns the roots for the current `ProjectWorkspace`
/// The return type contains the path and whether or not
/// the root is a member of the current workspace
- pub fn to_roots(&self, build_data: Option<&BuildDataResult>) -> Vec<PackageRoot> {
+ pub fn to_roots(&self) -> Vec<PackageRoot> {
match self {
ProjectWorkspace::Json { project, sysroot, rustc_cfg: _ } => project
.crates()
.map(|(_, krate)| PackageRoot {
- is_member: krate.is_workspace_member,
+ is_local: krate.is_workspace_member,
include: krate.include.clone(),
exclude: krate.exclude.clone(),
})
.into_iter()
.chain(sysroot.as_ref().into_iter().flat_map(|sysroot| {
sysroot.crates().map(move |krate| PackageRoot {
- is_member: false,
- include: vec![sysroot[krate].root_dir().to_path_buf()],
+ is_local: false,
+ include: vec![sysroot[krate].root.parent().to_path_buf()],
exclude: Vec::new(),
})
}))
.collect::<Vec<_>>(),
- ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _ } => cargo
- .packages()
- .map(|pkg| {
- let is_member = cargo[pkg].is_member;
- let pkg_root = cargo[pkg].root().to_path_buf();
-
- let mut include = vec![pkg_root.clone()];
- include.extend(
- build_data
- .and_then(|it| it.get(cargo.workspace_root()))
- .and_then(|map| map.get(&cargo[pkg].id))
- .and_then(|it| it.out_dir.clone()),
- );
+ ProjectWorkspace::Cargo {
+ cargo,
+ sysroot,
+ rustc,
+ rustc_cfg: _,
+ cfg_overrides: _,
+ build_scripts,
+ } => {
+ cargo
+ .packages()
+ .map(|pkg| {
+ let is_local = cargo[pkg].is_local;
+ let pkg_root = cargo[pkg].manifest.parent().to_path_buf();
+
+ let mut include = vec![pkg_root.clone()];
+ include.extend(
+ build_scripts.outputs.get(pkg).and_then(|it| it.out_dir.clone()),
+ );
- let mut exclude = vec![pkg_root.join(".git")];
- if is_member {
- exclude.push(pkg_root.join("target"));
- } else {
- exclude.push(pkg_root.join("tests"));
- exclude.push(pkg_root.join("examples"));
- exclude.push(pkg_root.join("benches"));
- }
- PackageRoot { is_member, include, exclude }
- })
- .chain(sysroot.crates().map(|krate| PackageRoot {
- is_member: false,
- include: vec![sysroot[krate].root_dir().to_path_buf()],
- exclude: Vec::new(),
- }))
- .chain(rustc.into_iter().flat_map(|rustc| {
- rustc.packages().map(move |krate| PackageRoot {
- is_member: false,
- include: vec![rustc[krate].root().to_path_buf()],
- exclude: Vec::new(),
+ // In case target's path is manually set in Cargo.toml to be
+ // outside the package root, add its parent as an extra include.
+ // An example of this situation would look like this:
+ //
+ // ```toml
+ // [lib]
+ // path = "../../src/lib.rs"
+ // ```
+ let extra_targets = cargo[pkg]
+ .targets
+ .iter()
+ .filter(|&&tgt| cargo[tgt].kind == TargetKind::Lib)
+ .filter_map(|&tgt| cargo[tgt].root.parent())
+ .map(|tgt| tgt.normalize().to_path_buf())
+ .filter(|path| !path.starts_with(&pkg_root));
+ include.extend(extra_targets);
+
+ let mut exclude = vec![pkg_root.join(".git")];
+ if is_local {
+ exclude.push(pkg_root.join("target"));
+ } else {
+ exclude.push(pkg_root.join("tests"));
+ exclude.push(pkg_root.join("examples"));
+ exclude.push(pkg_root.join("benches"));
+ }
+ PackageRoot { is_local, include, exclude }
})
- }))
- .collect(),
+ .chain(sysroot.into_iter().map(|sysroot| PackageRoot {
+ is_local: false,
+ include: vec![sysroot.root().to_path_buf()],
+ exclude: Vec::new(),
+ }))
+ .chain(rustc.into_iter().flat_map(|rustc| {
+ rustc.packages().map(move |krate| PackageRoot {
+ is_local: false,
+ include: vec![rustc[krate].manifest.parent().to_path_buf()],
+ exclude: Vec::new(),
+ })
+ }))
+ .collect()
+ }
ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files
.into_iter()
.map(|detached_file| PackageRoot {
- is_member: true,
+ is_local: true,
include: vec![detached_file.clone()],
exclude: Vec::new(),
})
.chain(sysroot.crates().map(|krate| PackageRoot {
- is_member: false,
- include: vec![sysroot[krate].root_dir().to_path_buf()],
+ is_local: false,
+ include: vec![sysroot[krate].root.parent().to_path_buf()],
exclude: Vec::new(),
}))
.collect(),
match self {
ProjectWorkspace::Json { project, .. } => project.n_crates(),
ProjectWorkspace::Cargo { cargo, sysroot, rustc, .. } => {
- let rustc_package_len = rustc.as_ref().map_or(0, |rc| rc.packages().len());
- cargo.packages().len() + sysroot.crates().len() + rustc_package_len
+ let rustc_package_len = rustc.as_ref().map_or(0, |it| it.packages().len());
+ let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.crates().len());
+ cargo.packages().len() + sysroot_package_len + rustc_package_len
}
ProjectWorkspace::DetachedFiles { sysroot, files, .. } => {
sysroot.crates().len() + files.len()
pub fn to_crate_graph(
&self,
- build_data: Option<&BuildDataResult>,
- proc_macro_client: Option<&ProcMacroClient>,
+ load_proc_macro: &mut dyn FnMut(&AbsPath) -> Vec<ProcMacro>,
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
) -> CrateGraph {
let _p = profile::span("ProjectWorkspace::to_crate_graph");
- let proc_macro_loader = |path: &Path| match proc_macro_client {
- Some(client) => client.by_dylib_path(path),
- None => Vec::new(),
- };
let mut crate_graph = match self {
ProjectWorkspace::Json { project, sysroot, rustc_cfg } => project_json_to_crate_graph(
rustc_cfg.clone(),
- &proc_macro_loader,
+ load_proc_macro,
load,
project,
sysroot,
),
- ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => cargo_to_crate_graph(
+ ProjectWorkspace::Cargo {
+ cargo,
+ sysroot,
+ rustc,
+ rustc_cfg,
+ cfg_overrides,
+ build_scripts,
+ } => cargo_to_crate_graph(
rustc_cfg.clone(),
- &proc_macro_loader,
+ cfg_overrides,
+ load_proc_macro,
load,
cargo,
- build_data.and_then(|it| it.get(cargo.workspace_root())),
- sysroot,
+ build_scripts,
+ sysroot.as_ref(),
rustc,
- rustc.as_ref().zip(build_data).and_then(|(it, map)| map.get(it.workspace_root())),
),
ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => {
detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot)
}
};
if crate_graph.patch_cfg_if() {
- log::debug!("Patched std to depend on cfg-if")
+ tracing::debug!("Patched std to depend on cfg-if")
} else {
- log::debug!("Did not patch std to depend on cfg-if")
+ tracing::debug!("Did not patch std to depend on cfg-if")
}
crate_graph
}
-
- pub fn collect_build_data_configs(&self, collector: &mut BuildDataCollector) {
- match self {
- ProjectWorkspace::Cargo { cargo, .. } => {
- collector.add_config(&cargo.workspace_root(), cargo.build_data_config().clone());
- }
- _ => {}
- }
- }
}
fn project_json_to_crate_graph(
rustc_cfg: Vec<CfgFlag>,
- proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
+ load_proc_macro: &mut dyn FnMut(&AbsPath) -> Vec<ProcMacro>,
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
project: &ProjectJson,
sysroot: &Option<Sysroot>,
.crates()
.filter_map(|(crate_id, krate)| {
let file_path = &krate.root_module;
- let file_id = load(&file_path)?;
+ let file_id = load(file_path)?;
Some((crate_id, krate, file_id))
})
.map(|(crate_id, krate, file_id)| {
let env = krate.env.clone().into_iter().collect();
- let proc_macro = krate.proc_macro_dylib_path.clone().map(|it| proc_macro_loader(&it));
+ let proc_macro = krate.proc_macro_dylib_path.clone().map(|it| load_proc_macro(&it));
let target_cfgs = match krate.target.as_deref() {
Some(target) => {
file_id,
krate.edition,
krate.display_name.clone(),
+ cfg_options.clone(),
cfg_options,
env,
proc_macro.unwrap_or_default(),
for (from, krate) in project.crates() {
if let Some(&from) = crates.get(&from) {
- if let Some((public_deps, _proc_macro)) = &sysroot_deps {
+ if let Some((public_deps, libproc_macro)) = &sysroot_deps {
for (name, to) in public_deps.iter() {
add_dep(&mut crate_graph, from, name.clone(), *to)
}
+ if krate.is_proc_macro {
+ if let Some(proc_macro) = libproc_macro {
+ add_dep(
+ &mut crate_graph,
+ from,
+ CrateName::new("proc_macro").unwrap(),
+ *proc_macro,
+ );
+ }
+ }
}
for dep in &krate.deps {
fn cargo_to_crate_graph(
rustc_cfg: Vec<CfgFlag>,
- proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
+ override_cfg: &CfgOverrides,
+ load_proc_macro: &mut dyn FnMut(&AbsPath) -> Vec<ProcMacro>,
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
cargo: &CargoWorkspace,
- build_data_map: Option<&WorkspaceBuildData>,
- sysroot: &Sysroot,
+ build_scripts: &WorkspaceBuildScripts,
+ sysroot: Option<&Sysroot>,
rustc: &Option<CargoWorkspace>,
- rustc_build_data_map: Option<&WorkspaceBuildData>,
) -> CrateGraph {
let _p = profile::span("cargo_to_crate_graph");
let mut crate_graph = CrateGraph::default();
- let (public_deps, libproc_macro) =
- sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load);
+ let (public_deps, libproc_macro) = match sysroot {
+ Some(sysroot) => sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load),
+ None => (Vec::new(), None),
+ };
let mut cfg_options = CfgOptions::default();
cfg_options.extend(rustc_cfg);
let mut has_private = false;
// Next, create crates for each package, target pair
for pkg in cargo.packages() {
+ let mut cfg_options = &cfg_options;
+ let mut replaced_cfg_options;
+
+ let overrides = match override_cfg {
+ CfgOverrides::Wildcard(cfg_diff) => Some(cfg_diff),
+ CfgOverrides::Selective(cfg_overrides) => cfg_overrides.get(&cargo[pkg].name),
+ };
+
+ if let Some(overrides) = overrides {
+ // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen
+ // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while
+ // working on rust-lang/rust as that's the only time it appears outside sysroot).
+ //
+ // A more ideal solution might be to reanalyze crates based on where the cursor is and
+ // figure out the set of cfgs that would have to apply to make it active.
+
+ replaced_cfg_options = cfg_options.clone();
+ replaced_cfg_options.apply_diff(overrides.clone());
+ cfg_options = &replaced_cfg_options;
+ };
+
has_private |= cargo[pkg].metadata.rustc_private;
let mut lib_tgt = None;
for &tgt in cargo[pkg].targets.iter() {
let crate_id = add_target_crate_root(
&mut crate_graph,
&cargo[pkg],
- build_data_map.and_then(|it| it.get(&cargo[pkg].id)),
+ build_scripts.outputs.get(pkg),
&cfg_options,
- proc_macro_loader,
+ load_proc_macro,
file_id,
&cargo[tgt].name,
);
lib_tgt = Some((crate_id, cargo[tgt].name.clone()));
pkg_to_lib_crate.insert(pkg, crate_id);
}
- if cargo[tgt].is_proc_macro {
- if let Some(proc_macro) = libproc_macro {
- add_dep(
- &mut crate_graph,
- crate_id,
- CrateName::new("proc_macro").unwrap(),
- proc_macro,
- );
- }
+ if let Some(proc_macro) = libproc_macro {
+ add_dep(
+ &mut crate_graph,
+ crate_id,
+ CrateName::new("proc_macro").unwrap(),
+ proc_macro,
+ );
}
pkg_crates.entry(pkg).or_insert_with(Vec::new).push((crate_id, cargo[tgt].kind));
rustc_workspace,
load,
&mut crate_graph,
- rustc_build_data_map,
&cfg_options,
- proc_macro_loader,
+ load_proc_macro,
&mut pkg_to_lib_crate,
&public_deps,
cargo,
cfg_options.extend(rustc_cfg);
for detached_file in detached_files {
- let file_id = match load(&detached_file) {
+ let file_id = match load(detached_file) {
Some(file_id) => file_id,
None => {
- log::error!("Failed to load detached file {:?}", detached_file);
+ tracing::error!("Failed to load detached file {:?}", detached_file);
continue;
}
};
.map(|file_stem| CrateDisplayName::from_canonical_name(file_stem.to_string()));
let detached_file_crate = crate_graph.add_crate_root(
file_id,
- Edition::Edition2018,
+ Edition::CURRENT,
display_name,
cfg_options.clone(),
+ cfg_options.clone(),
Env::default(),
Vec::new(),
);
rustc_workspace: &CargoWorkspace,
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
crate_graph: &mut CrateGraph,
- rustc_build_data_map: Option<&WorkspaceBuildData>,
cfg_options: &CfgOptions,
- proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
+ load_proc_macro: &mut dyn FnMut(&AbsPath) -> Vec<ProcMacro>,
pkg_to_lib_crate: &mut FxHashMap<la_arena::Idx<crate::PackageData>, CrateId>,
public_deps: &[(CrateName, CrateId)],
cargo: &CargoWorkspace,
let crate_id = add_target_crate_root(
crate_graph,
&rustc_workspace[pkg],
- rustc_build_data_map.and_then(|it| it.get(&rustc_workspace[pkg].id)),
- &cfg_options,
- proc_macro_loader,
+ None,
+ cfg_options,
+ load_proc_macro,
file_id,
&rustc_workspace[tgt].name,
);
fn add_target_crate_root(
crate_graph: &mut CrateGraph,
- pkg: &cargo_workspace::PackageData,
- build_data: Option<&PackageBuildData>,
+ pkg: &PackageData,
+ build_data: Option<&BuildScriptOutput>,
cfg_options: &CfgOptions,
- proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
+ load_proc_macro: &mut dyn FnMut(&AbsPath) -> Vec<ProcMacro>,
file_id: FileId,
cargo_name: &str,
) -> CrateId {
};
let mut env = Env::default();
+ inject_cargo_env(pkg, &mut env);
+
if let Some(envs) = build_data.map(|it| &it.envs) {
for (k, v) in envs {
env.set(k, v.clone());
let proc_macro = build_data
.as_ref()
.and_then(|it| it.proc_macro_dylib_path.as_ref())
- .map(|it| proc_macro_loader(&it))
+ .map(|it| load_proc_macro(it))
.unwrap_or_default();
let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_string());
+ let mut potential_cfg_options = cfg_options.clone();
+ potential_cfg_options.extend(
+ pkg.features
+ .iter()
+ .map(|feat| CfgFlag::KeyValue { key: "feature".into(), value: feat.0.into() }),
+ );
+
let crate_id = crate_graph.add_crate_root(
file_id,
edition,
Some(display_name),
cfg_options,
+ potential_cfg_options,
env,
proc_macro,
);
let display_name = CrateDisplayName::from_canonical_name(sysroot[krate].name.clone());
let crate_id = crate_graph.add_crate_root(
file_id,
- Edition::Edition2018,
+ Edition::CURRENT,
Some(display_name),
cfg_options.clone(),
+ cfg_options.clone(),
env,
proc_macro,
);
fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) {
if let Err(err) = graph.add_dep(from, name, to) {
- log::error!("{}", err)
+ tracing::error!("{}", err)
}
}
+
+/// 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.
+fn inject_cargo_env(package: &PackageData, env: &mut Env) {
+ // FIXME: Missing variables:
+ // CARGO_BIN_NAME, CARGO_BIN_EXE_<name>
+
+ let manifest_dir = package.manifest.parent();
+ env.set("CARGO_MANIFEST_DIR".into(), manifest_dir.as_os_str().to_string_lossy().into_owned());
+
+ // Not always right, but works for common cases.
+ env.set("CARGO".into(), "cargo".into());
+
+ env.set("CARGO_PKG_VERSION".into(), package.version.to_string());
+ env.set("CARGO_PKG_VERSION_MAJOR".into(), package.version.major.to_string());
+ env.set("CARGO_PKG_VERSION_MINOR".into(), package.version.minor.to_string());
+ env.set("CARGO_PKG_VERSION_PATCH".into(), package.version.patch.to_string());
+ env.set("CARGO_PKG_VERSION_PRE".into(), package.version.pre.to_string());
+
+ env.set("CARGO_PKG_AUTHORS".into(), String::new());
+
+ env.set("CARGO_PKG_NAME".into(), package.name.clone());
+ // FIXME: This isn't really correct (a package can have many crates with different names), but
+ // it's better than leaving the variable unset.
+ env.set("CARGO_CRATE_NAME".into(), CrateName::normalize_dashes(&package.name).to_string());
+ env.set("CARGO_PKG_DESCRIPTION".into(), String::new());
+ env.set("CARGO_PKG_HOMEPAGE".into(), String::new());
+ env.set("CARGO_PKG_REPOSITORY".into(), String::new());
+ env.set("CARGO_PKG_LICENSE".into(), String::new());
+
+ env.set("CARGO_PKG_LICENSE_FILE".into(), String::new());
+}