Skip to content

Commit faaba55

Browse files
committed
Allow rust-project.json to specify sysroot workspace
1 parent 444ce09 commit faaba55

4 files changed

Lines changed: 135 additions & 61 deletions

File tree

‎src/tools/rust-analyzer/crates/project-model/src/lib.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ fn parse_cfg(s: &str) -> Result<cfg::CfgAtom, String> {
262262
#[derive(Clone,Debug,PartialEq,Eq)]
263263
pubenumRustSourceWorkspaceConfig{
264264
CargoMetadata(CargoMetadataConfig),
265+
Json(ProjectJson),
265266
Stitched,
266267
}
267268

‎src/tools/rust-analyzer/crates/project-model/src/project_json.rs‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ pub struct ProjectJson {
6565
pub(crate)sysroot:Option<AbsPathBuf>,
6666
/// e.g. `path/to/sysroot/lib/rustlib/src/rust/library`
6767
pub(crate)sysroot_src:Option<AbsPathBuf>,
68+
/// A nested project describing the layout of the sysroot
69+
pub(crate)sysroot_project:Option<Box<ProjectJson>>,
6870
project_root:AbsPathBuf,
6971
/// The path to the rust-project.json file. May be None if this
7072
/// data was generated by the discoverConfig command.
@@ -91,9 +93,16 @@ impl ProjectJson {
9193
data:ProjectJsonData,
9294
) -> ProjectJson{
9395
let absolutize_on_base = |p| base.absolutize(p);
96+
let sysroot_src = data.sysroot_src.map(absolutize_on_base);
97+
let sysroot_project =
98+
data.sysroot_project.zip(sysroot_src.clone()).map(|(sysroot_data, sysroot_src)| {
99+
Box::new(ProjectJson::new(None,&sysroot_src,*sysroot_data))
100+
});
101+
94102
ProjectJson{
95103
sysroot: data.sysroot.map(absolutize_on_base),
96-
sysroot_src: data.sysroot_src.map(absolutize_on_base),
104+
sysroot_src,
105+
sysroot_project,
97106
project_root: base.to_path_buf(),
98107
manifest,
99108
runnables: data.runnables.into_iter().map(Runnable::from).collect(),
@@ -330,6 +339,7 @@ pub enum RunnableKind {
330339
pubstructProjectJsonData{
331340
sysroot:Option<Utf8PathBuf>,
332341
sysroot_src:Option<Utf8PathBuf>,
342+
sysroot_project:Option<Box<ProjectJsonData>>,
333343
#[serde(default)]
334344
cfg_groups:FxHashMap<String,CfgList>,
335345
crates:Vec<CrateData>,

‎src/tools/rust-analyzer/crates/project-model/src/sysroot.rs‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use stdx::format_to;
2121
use toolchain::{probe_for_binary,Tool};
2222

2323
usecrate::{
24-
cargo_workspace::CargoMetadataConfig, utf8_stdout,CargoWorkspace,ManifestPath,
24+
cargo_workspace::CargoMetadataConfig, utf8_stdout,CargoWorkspace,ManifestPath,ProjectJson,
2525
RustSourceWorkspaceConfig,
2626
};
2727

@@ -36,6 +36,7 @@ pub struct Sysroot {
3636
#[derive(Debug,Clone,Eq,PartialEq)]
3737
pubenumRustLibSrcWorkspace{
3838
Workspace(CargoWorkspace),
39+
Json(ProjectJson),
3940
Stitched(Stitched),
4041
Empty,
4142
}
@@ -114,6 +115,7 @@ impl Sysroot {
114115
pubfnis_rust_lib_src_empty(&self) -> bool{
115116
match&self.workspace{
116117
RustLibSrcWorkspace::Workspace(ws) => ws.packages().next().is_none(),
118+
RustLibSrcWorkspace::Json(project_json) => project_json.n_crates() == 0,
117119
RustLibSrcWorkspace::Stitched(stitched) => stitched.crates.is_empty(),
118120
RustLibSrcWorkspace::Empty => true,
119121
}
@@ -126,6 +128,7 @@ impl Sysroot {
126128
pubfnnum_packages(&self) -> usize{
127129
match&self.workspace{
128130
RustLibSrcWorkspace::Workspace(ws) => ws.packages().count(),
131+
RustLibSrcWorkspace::Json(project_json) => project_json.n_crates(),
129132
RustLibSrcWorkspace::Stitched(c) => c.crates().count(),
130133
RustLibSrcWorkspace::Empty => 0,
131134
}
@@ -252,6 +255,8 @@ impl Sysroot {
252255
returnSome(loaded);
253256
}
254257
}
258+
}elseifletRustSourceWorkspaceConfig::Json(project_json) = sysroot_source_config {
259+
returnSome(RustLibSrcWorkspace::Json(project_json.clone()));
255260
}
256261
tracing::debug!("Stitching sysroot library: {src_root}");
257262

@@ -308,6 +313,10 @@ impl Sysroot {
308313
RustLibSrcWorkspace::Workspace(ws) => {
309314
ws.packages().any(|p| ws[p].name == "core")
310315
}
316+
RustLibSrcWorkspace::Json(project_json) => project_json
317+
.crates()
318+
.filter_map(|(_, krate)| krate.display_name.clone())
319+
.any(|name| name.canonical_name().as_str() == "core"),
311320
RustLibSrcWorkspace::Stitched(stitched) => stitched.by_name("core").is_some(),
312321
RustLibSrcWorkspace::Empty => true,
313322
};

‎src/tools/rust-analyzer/crates/project-model/src/workspace.rs‎

Lines changed: 113 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ pub struct ProjectWorkspace {
6969
}
7070

7171
#[derive(Clone)]
72+
#[allow(clippy::large_enum_variant)]
7273
pubenumProjectWorkspaceKind{
7374
/// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
7475
Cargo{
@@ -400,20 +401,17 @@ impl ProjectWorkspace {
400401
}
401402

402403
pubfnload_inline(
403-
project_json:ProjectJson,
404+
mutproject_json:ProjectJson,
404405
config:&CargoConfig,
405406
progress:&dynFn(String),
406407
) -> ProjectWorkspace{
407408
progress("Discovering sysroot".to_owned());
408409
letmut sysroot =
409410
Sysroot::new(project_json.sysroot.clone(), project_json.sysroot_src.clone());
410-
let loaded_sysroot = sysroot.load_workspace(&RustSourceWorkspaceConfig::Stitched);
411-
ifletSome(loaded_sysroot) = loaded_sysroot {
412-
sysroot.set_workspace(loaded_sysroot);
413-
}
414411

415412
tracing::info!(workspace = %project_json.manifest_or_root(), src_root = ?sysroot.rust_lib_src_root(), root = ?sysroot.root(),"Using sysroot");
416413
progress("Querying project metadata".to_owned());
414+
let sysroot_project = project_json.sysroot_project.take();
417415
let query_config = QueryConfig::Rustc(&sysroot, project_json.path().as_ref());
418416
let targets = target_tuple::get(query_config, config.target.as_deref(),&config.extra_env)
419417
.unwrap_or_default();
@@ -435,14 +433,31 @@ impl ProjectWorkspace {
435433
&config.extra_env,
436434
)
437435
});
438-
thread::Result::Ok((toolchain.join()?, rustc_cfg.join()?, data_layout.join()?))
436+
let loaded_sysroot = s.spawn(|| {
437+
ifletSome(sysroot_project) = sysroot_project {
438+
sysroot.load_workspace(&RustSourceWorkspaceConfig::Json(*sysroot_project))
439+
}else{
440+
sysroot.load_workspace(&RustSourceWorkspaceConfig::Stitched)
441+
}
442+
});
443+
444+
thread::Result::Ok((
445+
toolchain.join()?,
446+
rustc_cfg.join()?,
447+
data_layout.join()?,
448+
loaded_sysroot.join()?,
449+
))
439450
});
440451

441-
let(toolchain, rustc_cfg, target_layout) = match join {
452+
let(toolchain, rustc_cfg, target_layout, loaded_sysroot) = match join {
442453
Ok(it) => it,
443454
Err(e) => std::panic::resume_unwind(e),
444455
};
445456

457+
ifletSome(loaded_sysroot) = loaded_sysroot {
458+
sysroot.set_workspace(loaded_sysroot);
459+
}
460+
446461
ProjectWorkspace{
447462
kind:ProjectWorkspaceKind::Json(project_json),
448463
sysroot,
@@ -667,6 +682,14 @@ impl ProjectWorkspace {
667682
Some(PackageRoot{is_local:false, include, exclude })
668683
})
669684
.collect(),
685+
RustLibSrcWorkspace::Json(project_json) => project_json
686+
.crates()
687+
.map(|(_, krate)| PackageRoot{
688+
is_local:false,
689+
include: krate.include.clone(),
690+
exclude: krate.exclude.clone(),
691+
})
692+
.collect(),
670693
RustLibSrcWorkspace::Stitched(_) | RustLibSrcWorkspace::Empty => vec![],
671694
};
672695

@@ -1490,6 +1513,65 @@ impl SysrootPublicDeps {
14901513
}
14911514
}
14921515

1516+
fnextend_crate_graph_with_sysroot(
1517+
crate_graph:&mutCrateGraph,
1518+
mutsysroot_crate_graph:CrateGraph,
1519+
mutsysroot_proc_macros:ProcMacroPaths,
1520+
) -> (SysrootPublicDeps,Option<CrateId>){
1521+
letmut pub_deps = vec![];
1522+
letmut libproc_macro = None;
1523+
let diff = CfgDiff::new(vec![],vec![CfgAtom::Flag(sym::test.clone())]).unwrap();
1524+
for(cid, c)in sysroot_crate_graph.iter_mut(){
1525+
// uninject `test` flag so `core` keeps working.
1526+
Arc::make_mut(&mut c.cfg_options).apply_diff(diff.clone());
1527+
// patch the origin
1528+
if c.origin.is_local(){
1529+
let lang_crate = LangCrateOrigin::from(
1530+
c.display_name.as_ref().map_or("", |it| it.canonical_name().as_str()),
1531+
);
1532+
c.origin = CrateOrigin::Lang(lang_crate);
1533+
match lang_crate {
1534+
LangCrateOrigin::Test
1535+
| LangCrateOrigin::Alloc
1536+
| LangCrateOrigin::Core
1537+
| LangCrateOrigin::Std => pub_deps.push((
1538+
CrateName::normalize_dashes(&lang_crate.to_string()),
1539+
cid,
1540+
!matches!(lang_crate,LangCrateOrigin::Test | LangCrateOrigin::Alloc),
1541+
)),
1542+
LangCrateOrigin::ProcMacro => libproc_macro = Some(cid),
1543+
LangCrateOrigin::Other => (),
1544+
}
1545+
}
1546+
}
1547+
1548+
letmut marker_set = vec![];
1549+
for&(_, cid, _)in pub_deps.iter(){
1550+
marker_set.extend(sysroot_crate_graph.transitive_deps(cid));
1551+
}
1552+
ifletSome(cid) = libproc_macro {
1553+
marker_set.extend(sysroot_crate_graph.transitive_deps(cid));
1554+
}
1555+
1556+
marker_set.sort();
1557+
marker_set.dedup();
1558+
1559+
// Remove all crates except the ones we are interested in to keep the sysroot graph small.
1560+
let removed_mapping = sysroot_crate_graph.remove_crates_except(&marker_set);
1561+
let mapping = crate_graph.extend(sysroot_crate_graph,&mut sysroot_proc_macros);
1562+
1563+
// Map the id through the removal mapping first, then through the crate graph extension mapping.
1564+
pub_deps.iter_mut().for_each(|(_, cid, _)| {
1565+
*cid = mapping[&removed_mapping[cid.into_raw().into_u32()asusize].unwrap()]
1566+
});
1567+
ifletSome(libproc_macro) = &mut libproc_macro {
1568+
*libproc_macro =
1569+
mapping[&removed_mapping[libproc_macro.into_raw().into_u32()asusize].unwrap()];
1570+
}
1571+
1572+
(SysrootPublicDeps{deps: pub_deps }, libproc_macro)
1573+
}
1574+
14931575
fnsysroot_to_crate_graph(
14941576
crate_graph:&mutCrateGraph,
14951577
sysroot:&Sysroot,
@@ -1499,7 +1581,7 @@ fn sysroot_to_crate_graph(
14991581
let _p = tracing::info_span!("sysroot_to_crate_graph").entered();
15001582
match sysroot.workspace(){
15011583
RustLibSrcWorkspace::Workspace(cargo) => {
1502-
let(mutcg,mut pm) = cargo_to_crate_graph(
1584+
let(cg, pm) = cargo_to_crate_graph(
15031585
load,
15041586
None,
15051587
cargo,
@@ -1520,58 +1602,30 @@ fn sysroot_to_crate_graph(
15201602
false,
15211603
);
15221604

1523-
letmut pub_deps = vec![];
1524-
letmut libproc_macro = None;
1525-
let diff = CfgDiff::new(vec![],vec![CfgAtom::Flag(sym::test.clone())]).unwrap();
1526-
for(cid, c)in cg.iter_mut(){
1527-
// uninject `test` flag so `core` keeps working.
1528-
Arc::make_mut(&mut c.cfg_options).apply_diff(diff.clone());
1529-
// patch the origin
1530-
if c.origin.is_local(){
1531-
let lang_crate = LangCrateOrigin::from(
1532-
c.display_name.as_ref().map_or("", |it| it.canonical_name().as_str()),
1533-
);
1534-
c.origin = CrateOrigin::Lang(lang_crate);
1535-
match lang_crate {
1536-
LangCrateOrigin::Test
1537-
| LangCrateOrigin::Alloc
1538-
| LangCrateOrigin::Core
1539-
| LangCrateOrigin::Std => pub_deps.push((
1540-
CrateName::normalize_dashes(&lang_crate.to_string()),
1541-
cid,
1542-
!matches!(lang_crate,LangCrateOrigin::Test | LangCrateOrigin::Alloc),
1543-
)),
1544-
LangCrateOrigin::ProcMacro => libproc_macro = Some(cid),
1545-
LangCrateOrigin::Other => (),
1546-
}
1547-
}
1548-
}
1549-
1550-
letmut marker_set = vec![];
1551-
for&(_, cid, _)in pub_deps.iter(){
1552-
marker_set.extend(cg.transitive_deps(cid));
1553-
}
1554-
ifletSome(cid) = libproc_macro {
1555-
marker_set.extend(cg.transitive_deps(cid));
1556-
}
1557-
1558-
marker_set.sort();
1559-
marker_set.dedup();
1560-
1561-
// Remove all crates except the ones we are interested in to keep the sysroot graph small.
1562-
let removed_mapping = cg.remove_crates_except(&marker_set);
1563-
let mapping = crate_graph.extend(cg,&mut pm);
1564-
1565-
// Map the id through the removal mapping first, then through the crate graph extension mapping.
1566-
pub_deps.iter_mut().for_each(|(_, cid, _)| {
1567-
*cid = mapping[&removed_mapping[cid.into_raw().into_u32()asusize].unwrap()]
1568-
});
1569-
ifletSome(libproc_macro) = &mut libproc_macro {
1570-
*libproc_macro = mapping
1571-
[&removed_mapping[libproc_macro.into_raw().into_u32()asusize].unwrap()];
1572-
}
1605+
extend_crate_graph_with_sysroot(crate_graph, cg, pm)
1606+
}
1607+
RustLibSrcWorkspace::Json(project_json) => {
1608+
let(cg, pm) = project_json_to_crate_graph(
1609+
rustc_cfg,
1610+
load,
1611+
project_json,
1612+
&Sysroot::empty(),
1613+
&FxHashMap::default(),
1614+
&CfgOverrides{
1615+
global:CfgDiff::new(
1616+
vec![
1617+
CfgAtom::Flag(sym::debug_assertions.clone()),
1618+
CfgAtom::Flag(sym::miri.clone()),
1619+
],
1620+
vec![],
1621+
)
1622+
.unwrap(),
1623+
..Default::default()
1624+
},
1625+
false,
1626+
);
15731627

1574-
(SysrootPublicDeps{deps: pub_deps }, libproc_macro)
1628+
extend_crate_graph_with_sysroot(crate_graph, cg, pm)
15751629
}
15761630
RustLibSrcWorkspace::Stitched(stitched) => {
15771631
let cfg_options = Arc::new({

0 commit comments

Comments
 (0)