Merge commit 'aa9bc86125' into sync-from-ra

This commit is contained in:
Laurențiu Nicola 2023-06-05 12:04:23 +03:00
parent 1570299af4
commit c48062fe2a
598 changed files with 57696 additions and 17615 deletions

View file

@ -14,9 +14,10 @@ use std::{
};
use cargo_metadata::{camino::Utf8Path, Message};
use itertools::Itertools;
use la_arena::ArenaMap;
use paths::{AbsPath, AbsPathBuf};
use rustc_hash::FxHashMap;
use rustc_hash::{FxHashMap, FxHashSet};
use semver::Version;
use serde::Deserialize;
@ -56,7 +57,10 @@ impl BuildScriptOutput {
}
impl WorkspaceBuildScripts {
fn build_command(config: &CargoConfig) -> io::Result<Command> {
fn build_command(
config: &CargoConfig,
allowed_features: &FxHashSet<String>,
) -> io::Result<Command> {
let mut cmd = match config.run_build_script_command.as_deref() {
Some([program, args @ ..]) => {
let mut cmd = Command::new(program);
@ -88,7 +92,12 @@ impl WorkspaceBuildScripts {
}
if !features.is_empty() {
cmd.arg("--features");
cmd.arg(features.join(" "));
cmd.arg(
features
.iter()
.filter(|&feat| allowed_features.contains(feat))
.join(","),
);
}
}
}
@ -127,13 +136,20 @@ impl WorkspaceBuildScripts {
}
.as_ref();
match Self::run_per_ws(Self::build_command(config)?, workspace, current_dir, progress) {
let allowed_features = workspace.workspace_features();
match Self::run_per_ws(
Self::build_command(config, &allowed_features)?,
workspace,
current_dir,
progress,
) {
Ok(WorkspaceBuildScripts { error: Some(error), .. })
if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_62) =>
{
// building build scripts failed, attempt to build with --keep-going so
// that we potentially get more build data
let mut cmd = Self::build_command(config)?;
let mut cmd = Self::build_command(config, &allowed_features)?;
cmd.args(["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1");
let mut res = Self::run_per_ws(cmd, workspace, current_dir, progress)?;
res.error = Some(error);
@ -161,7 +177,7 @@ impl WorkspaceBuildScripts {
))
}
};
let cmd = Self::build_command(config)?;
let cmd = Self::build_command(config, &Default::default())?;
// NB: Cargo.toml could have been modified between `cargo metadata` and
// `cargo check`. We shouldn't assume that package ids we see here are
// exactly those from `config`.
@ -415,7 +431,6 @@ impl WorkspaceBuildScripts {
let dir_entry = entry.ok()?;
if dir_entry.file_type().ok()?.is_file() {
let path = dir_entry.path();
tracing::info!("p{:?}", path);
let extension = path.extension()?;
if extension == std::env::consts::DLL_EXTENSION {
let name = path.file_stem()?.to_str()?.split_once('-')?.0.to_owned();

View file

@ -1,6 +1,5 @@
//! See [`CargoWorkspace`].
use std::iter;
use std::path::PathBuf;
use std::str::from_utf8;
use std::{ops, process::Command};
@ -10,7 +9,7 @@ use base_db::Edition;
use cargo_metadata::{CargoOpt, MetadataCommand};
use la_arena::{Arena, Idx};
use paths::{AbsPath, AbsPathBuf};
use rustc_hash::FxHashMap;
use rustc_hash::{FxHashMap, FxHashSet};
use serde::Deserialize;
use serde_json::from_value;
@ -32,6 +31,7 @@ pub struct CargoWorkspace {
packages: Arena<PackageData>,
targets: Arena<TargetData>,
workspace_root: AbsPathBuf,
target_directory: AbsPathBuf,
}
impl ops::Index<Package> for CargoWorkspace {
@ -57,20 +57,6 @@ pub enum RustLibSource {
Discover,
}
/// Crates to disable `#[cfg(test)]` on.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum UnsetTestCrates {
None,
Only(Vec<String>),
All,
}
impl Default for UnsetTestCrates {
fn default() -> Self {
Self::None
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CargoFeatures {
All,
@ -99,8 +85,7 @@ pub struct CargoConfig {
pub sysroot_src: Option<AbsPathBuf>,
/// rustc private crate source
pub rustc_source: Option<RustLibSource>,
/// crates to disable `#[cfg(test)]` on
pub unset_test_crates: UnsetTestCrates,
pub cfg_overrides: CfgOverrides,
/// Invoke `cargo check` through the RUSTC_WRAPPER.
pub wrap_rustc_in_build_scripts: bool,
/// The command to run instead of `cargo check` for building build scripts.
@ -113,27 +98,6 @@ pub struct CargoConfig {
pub invocation_location: InvocationLocation,
}
impl CargoConfig {
pub fn cfg_overrides(&self) -> CfgOverrides {
match &self.unset_test_crates {
UnsetTestCrates::None => CfgOverrides::Selective(iter::empty().collect()),
UnsetTestCrates::Only(unset_test_crates) => CfgOverrides::Selective(
unset_test_crates
.iter()
.cloned()
.zip(iter::repeat_with(|| {
cfg::CfgDiff::new(Vec::new(), vec![cfg::CfgAtom::Flag("test".into())])
.unwrap()
}))
.collect(),
),
UnsetTestCrates::All => CfgOverrides::Wildcard(
cfg::CfgDiff::new(Vec::new(), vec![cfg::CfgAtom::Flag("test".into())]).unwrap(),
),
}
}
}
pub type Package = Idx<PackageData>;
pub type Target = Idx<TargetData>;
@ -293,14 +257,30 @@ impl CargoWorkspace {
}
meta.current_dir(current_dir.as_os_str());
if !targets.is_empty() {
let other_options: Vec<_> = targets
.into_iter()
.flat_map(|target| ["--filter-platform".to_string(), target])
.collect();
meta.other_options(other_options);
let mut other_options = vec![];
// cargo metadata only supports a subset of flags of what cargo usually accepts, and usually
// the only relevant flags for metadata here are unstable ones, so we pass those along
// but nothing else
let mut extra_args = config.extra_args.iter();
while let Some(arg) = extra_args.next() {
if arg == "-Z" {
if let Some(arg) = extra_args.next() {
other_options.push("-Z".to_owned());
other_options.push(arg.to_owned());
}
}
}
if !targets.is_empty() {
other_options.append(
&mut targets
.into_iter()
.flat_map(|target| ["--filter-platform".to_owned().to_string(), target])
.collect(),
);
}
meta.other_options(other_options);
// FIXME: Fetching metadata is a slow process, as it might require
// calling crates.io. We should be reporting progress here, but it's
// unclear whether cargo itself supports it.
@ -411,7 +391,10 @@ impl CargoWorkspace {
let workspace_root =
AbsPathBuf::assert(PathBuf::from(meta.workspace_root.into_os_string()));
CargoWorkspace { packages, targets, workspace_root }
let target_directory =
AbsPathBuf::assert(PathBuf::from(meta.target_directory.into_os_string()));
CargoWorkspace { packages, targets, workspace_root, target_directory }
}
pub fn packages(&self) -> impl Iterator<Item = Package> + ExactSizeIterator + '_ {
@ -429,6 +412,10 @@ impl CargoWorkspace {
&self.workspace_root
}
pub fn target_directory(&self) -> &AbsPath {
&self.target_directory
}
pub fn package_flag(&self, package: &PackageData) -> String {
if self.is_unique(&package.name) {
package.name.clone()
@ -467,6 +454,21 @@ impl CargoWorkspace {
None
}
/// Returns the union of the features of all member crates in this workspace.
pub fn workspace_features(&self) -> FxHashSet<String> {
self.packages()
.filter_map(|package| {
let package = &self[package];
if package.is_member {
Some(package.features.keys().cloned())
} else {
None
}
})
.flatten()
.collect()
}
fn is_unique(&self, name: &str) -> bool {
self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
}

View file

@ -49,6 +49,14 @@ impl Extend<CfgFlag> for CfgOptions {
}
}
impl FromIterator<CfgFlag> for CfgOptions {
fn from_iter<T: IntoIterator<Item = CfgFlag>>(iter: T) -> Self {
let mut this = CfgOptions::default();
this.extend(iter);
this
}
}
impl fmt::Display for CfgFlag {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {

View file

@ -44,7 +44,7 @@ pub use crate::{
build_scripts::WorkspaceBuildScripts,
cargo_workspace::{
CargoConfig, CargoFeatures, CargoWorkspace, Package, PackageData, PackageDependency,
RustLibSource, Target, TargetData, TargetKind, UnsetTestCrates,
RustLibSource, Target, TargetData, TargetKind,
},
manifest_path::ManifestPath,
project_json::{ProjectJson, ProjectJsonData},

View file

@ -34,6 +34,10 @@ impl ManifestPath {
pub fn parent(&self) -> &AbsPath {
self.file.parent().unwrap()
}
pub fn canonicalize(&self) -> ! {
(&**self).canonicalize()
}
}
impl ops::Deref for ManifestPath {

View file

@ -49,12 +49,12 @@
//! user explores them belongs to that extension (it's totally valid to change
//! rust-project.json over time via configuration request!)
use std::path::PathBuf;
use base_db::{CrateDisplayName, CrateId, CrateName, Dependency, Edition};
use la_arena::RawIdx;
use paths::{AbsPath, AbsPathBuf};
use rustc_hash::FxHashMap;
use serde::{de, Deserialize};
use std::path::PathBuf;
use crate::cfg_flag::CfgFlag;
@ -98,26 +98,23 @@ impl ProjectJson {
/// * `data` - The parsed contents of `rust-project.json`, or project json that's passed via
/// configuration.
pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson {
let absolutize_on_base = |p| base.absolutize(p);
ProjectJson {
sysroot: data.sysroot.map(|it| base.join(it)),
sysroot_src: data.sysroot_src.map(|it| base.join(it)),
sysroot: data.sysroot.map(absolutize_on_base),
sysroot_src: data.sysroot_src.map(absolutize_on_base),
project_root: base.to_path_buf(),
crates: data
.crates
.into_iter()
.map(|crate_data| {
let is_workspace_member = crate_data.is_workspace_member.unwrap_or_else(|| {
crate_data.root_module.is_relative()
&& !crate_data.root_module.starts_with("..")
|| crate_data.root_module.starts_with(base)
});
let root_module = base.join(crate_data.root_module).normalize();
let root_module = absolutize_on_base(crate_data.root_module);
let is_workspace_member = crate_data
.is_workspace_member
.unwrap_or_else(|| root_module.starts_with(base));
let (include, exclude) = match crate_data.source {
Some(src) => {
let absolutize = |dirs: Vec<PathBuf>| {
dirs.into_iter()
.map(|it| base.join(it).normalize())
.collect::<Vec<_>>()
dirs.into_iter().map(absolutize_on_base).collect::<Vec<_>>()
};
(absolutize(src.include_dirs), absolutize(src.exclude_dirs))
}
@ -135,7 +132,10 @@ impl ProjectJson {
.deps
.into_iter()
.map(|dep_data| {
Dependency::new(dep_data.name, CrateId(dep_data.krate as u32))
Dependency::new(
dep_data.name,
CrateId::from_raw(RawIdx::from(dep_data.krate as u32)),
)
})
.collect::<Vec<_>>(),
cfg: crate_data.cfg,
@ -143,7 +143,7 @@ impl ProjectJson {
env: crate_data.env,
proc_macro_dylib_path: crate_data
.proc_macro_dylib_path
.map(|it| base.join(it)),
.map(absolutize_on_base),
is_workspace_member,
include,
exclude,
@ -151,7 +151,7 @@ impl ProjectJson {
repository: crate_data.repository,
}
})
.collect::<Vec<_>>(),
.collect(),
}
}
@ -162,7 +162,10 @@ impl ProjectJson {
/// Returns an iterator over the crates in the project.
pub fn crates(&self) -> impl Iterator<Item = (CrateId, &Crate)> + '_ {
self.crates.iter().enumerate().map(|(idx, krate)| (CrateId(idx as u32), krate))
self.crates
.iter()
.enumerate()
.map(|(idx, krate)| (CrateId::from_raw(RawIdx::from(idx as u32)), krate))
}
/// Returns the path to the project's root folder.
@ -236,7 +239,7 @@ struct CrateSource {
exclude_dirs: Vec<PathBuf>,
}
fn deserialize_crate_name<'de, D>(de: D) -> Result<CrateName, D::Error>
fn deserialize_crate_name<'de, D>(de: D) -> std::result::Result<CrateName, D::Error>
where
D: de::Deserializer<'de>,
{

View file

@ -12,13 +12,15 @@ use la_arena::{Arena, Idx};
use paths::{AbsPath, AbsPathBuf};
use rustc_hash::FxHashMap;
use crate::{utf8_stdout, ManifestPath};
use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath};
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Sysroot {
root: AbsPathBuf,
src_root: AbsPathBuf,
crates: Arena<SysrootCrateData>,
/// Stores the result of `cargo metadata` of the `RA_UNSTABLE_SYSROOT_HACK` workspace.
pub hack_cargo_workspace: Option<CargoWorkspace>,
}
pub(crate) type SysrootCrate = Idx<SysrootCrateData>;
@ -74,6 +76,23 @@ impl Sysroot {
pub fn is_empty(&self) -> bool {
self.crates.is_empty()
}
pub fn loading_warning(&self) -> Option<String> {
if self.by_name("core").is_none() {
let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
" (`RUST_SRC_PATH` might be incorrect, try unsetting it)"
} else {
" try running `rustup component add rust-src` to possible fix this"
};
Some(format!(
"could not find libcore in loaded sysroot at `{}`{}",
self.src_root.as_path().display(),
var_note,
))
} else {
None
}
}
}
// FIXME: Expose a builder api as loading the sysroot got way too modular and complicated.
@ -103,14 +122,36 @@ impl Sysroot {
pub fn with_sysroot_dir(sysroot_dir: AbsPathBuf) -> Result<Sysroot> {
let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir).ok_or_else(|| {
format_err!("can't load standard library from sysroot {}", sysroot_dir.display())
format_err!("can't load standard library from sysroot path {}", sysroot_dir.display())
})?;
Ok(Sysroot::load(sysroot_dir, sysroot_src_dir))
}
pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Sysroot {
let mut sysroot =
Sysroot { root: sysroot_dir, src_root: sysroot_src_dir, crates: Arena::default() };
pub fn load(sysroot_dir: AbsPathBuf, mut sysroot_src_dir: AbsPathBuf) -> Sysroot {
// FIXME: Remove this `hack_cargo_workspace` field completely once we support sysroot dependencies
let hack_cargo_workspace = if let Ok(path) = std::env::var("RA_UNSTABLE_SYSROOT_HACK") {
let cargo_toml = ManifestPath::try_from(
AbsPathBuf::try_from(&*format!("{path}/Cargo.toml")).unwrap(),
)
.unwrap();
sysroot_src_dir = AbsPathBuf::try_from(&*path).unwrap().join("library");
CargoWorkspace::fetch_metadata(
&cargo_toml,
&AbsPathBuf::try_from("/").unwrap(),
&CargoConfig::default(),
&|_| (),
)
.map(CargoWorkspace::new)
.ok()
} else {
None
};
let mut sysroot = Sysroot {
root: sysroot_dir,
src_root: sysroot_src_dir,
crates: Arena::default(),
hack_cargo_workspace,
};
for path in SYSROOT_CRATES.trim().lines() {
let name = path.split('/').last().unwrap();
@ -153,19 +194,6 @@ impl Sysroot {
}
}
if sysroot.by_name("core").is_none() {
let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
" (`RUST_SRC_PATH` might be incorrect, try unsetting it)"
} else {
""
};
tracing::error!(
"could not find libcore in sysroot path `{}`{}",
sysroot.src_root.as_path().display(),
var_note,
);
}
sysroot
}

View file

@ -16,7 +16,7 @@ pub fn get(
let mut cmd = Command::new(toolchain::rustc());
cmd.envs(extra_env);
cmd.current_dir(cargo_toml.parent())
.args(["-Z", "unstable-options", "rustc", "--print", "target-spec-json"])
.args(["-Z", "unstable-options", "--print", "target-spec-json"])
.env("RUSTC_BOOTSTRAP", "1");
if let Some(target) = target {
cmd.args(["--target", target]);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff