-
Notifications
You must be signed in to change notification settings - Fork 13.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP]: generating rust-project file for r-a #120611
Draft
onur-ozkan
wants to merge
7
commits into
rust-lang:master
Choose a base branch
from
onur-ozkan:embedded-lsp-feed
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+335
−19
Draft
Changes from 5 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
6533515
create helper function `project_metadata` in bootstrap
onur-ozkan 8e6a409
implement new util `ra_project` for bootstrap
onur-ozkan e125924
add setup step for generating `rust-project.json`
onur-ozkan c78ef01
ignore `rust-project.json`
onur-ozkan 8bbdb07
no need for `Serialize` on ra_project types
onur-ozkan 9219a80
compile proc-macro crates and fill dylibs for ra
onur-ozkan 558bb77
set `CARGO_TARGET_DIR` on proc-macro builds
onur-ozkan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,6 +35,7 @@ Session.vim | |
config.mk | ||
config.stamp | ||
no_llvm_build | ||
rust-project.json | ||
|
||
## Build | ||
/dl/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
//! This module contains the implementation for generating rust-project.json data which can be | ||
//! utilized for LSPs (Language Server Protocols). | ||
//! | ||
//! The primary reason for relying on rust-analyzer.json instead of the default rust-analyzer | ||
//! is because rust-analyzer is not so capable of handling rust-lang/rust workspaces out of the box. | ||
//! It often encounters new issues while trying to fix current problems with some hacky workarounds. | ||
//! | ||
//! For additional context, see the [zulip thread]. | ||
//! | ||
//! [zulip thread]: https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/r-a.20support.20for.20rust-lang.2Frust.20via.20project-rust.2Ejson/near/412505824 | ||
|
||
use serde_derive::Serialize; | ||
use std::collections::{BTreeMap, BTreeSet}; | ||
use std::io; | ||
use std::path::Path; | ||
|
||
use crate::core::metadata::{project_metadata, workspace_members, Dependency}; | ||
use crate::Config; | ||
|
||
#[derive(Debug, Serialize)] | ||
/// FIXME(before-merge): doc-comment | ||
pub(crate) struct RustAnalyzerProject { | ||
crates: Vec<Crate>, | ||
sysroot: String, | ||
sysroot_src: String, | ||
} | ||
|
||
#[derive(Debug, Default, Serialize, PartialEq)] | ||
struct Crate { | ||
cfg: Vec<String>, | ||
deps: BTreeSet<Dep>, | ||
display_name: String, | ||
edition: String, | ||
env: BTreeMap<String, String>, | ||
is_proc_macro: bool, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
proc_macro_dylib_path: Option<String>, | ||
is_workspace_member: bool, | ||
root_module: String, | ||
} | ||
|
||
#[derive(Debug, Default, Serialize, PartialEq, PartialOrd, Ord, Eq)] | ||
struct Dep { | ||
#[serde(rename = "crate")] | ||
crate_index: usize, | ||
name: String, | ||
} | ||
|
||
impl RustAnalyzerProject { | ||
#[allow(dead_code)] // FIXME(before-merge): remove this | ||
pub(crate) fn collect_ra_project_data(config: &Config) -> Self { | ||
let mut ra_project = RustAnalyzerProject { | ||
crates: vec![], | ||
sysroot: format!("{}", config.out.join("host").join("stage0").display()), | ||
sysroot_src: format!("{}", config.src.join("library").display()), | ||
}; | ||
|
||
let packages: Vec<_> = project_metadata(config).collect(); | ||
let workspace_members: Vec<_> = workspace_members(config).collect(); | ||
|
||
for package in &packages { | ||
let is_not_indirect_dependency = packages | ||
.iter() | ||
.filter(|t| { | ||
let used_from_other_crates = t.dependencies.contains(&Dependency { | ||
name: package.name.clone(), | ||
source: package.source.clone(), | ||
}); | ||
|
||
let is_local = t.source.is_none(); | ||
|
||
(used_from_other_crates && is_local) || package.source.is_none() | ||
}) | ||
.next() | ||
.is_some(); | ||
|
||
if !is_not_indirect_dependency { | ||
continue; | ||
} | ||
|
||
for target in &package.targets { | ||
let mut krate = Crate::default(); | ||
krate.display_name = target.name.clone(); | ||
krate.root_module = target.src_path.clone(); | ||
krate.edition = target.edition.clone(); | ||
krate.is_workspace_member = workspace_members.iter().any(|p| p.name == target.name); | ||
krate.is_proc_macro = target.crate_types.contains(&"proc-macro".to_string()); | ||
|
||
// FIXME(before-merge): We need to figure out how to find proc-macro dylibs. | ||
// if krate.is_proc_macro { | ||
// krate.proc_macro_dylib_path = | ||
// } | ||
onur-ozkan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
krate.env.insert("RUSTC_BOOTSTRAP".into(), "1".into()); | ||
|
||
if target | ||
.src_path | ||
.starts_with(&config.src.join("library").to_string_lossy().to_string()) | ||
{ | ||
krate.cfg.push("bootstrap".into()); | ||
} | ||
|
||
ra_project.crates.push(krate); | ||
} | ||
} | ||
|
||
ra_project.crates.sort_by_key(|c| c.display_name.clone()); | ||
ra_project.crates.dedup_by_key(|c| c.display_name.clone()); | ||
|
||
// Find and fill dependencies of crates. | ||
for package in packages { | ||
if package.dependencies.is_empty() { | ||
continue; | ||
} | ||
|
||
for dependency in package.dependencies { | ||
if let Some(index) = | ||
ra_project.crates.iter().position(|c| c.display_name == package.name) | ||
{ | ||
if let Some(dependency_index) = | ||
ra_project.crates.iter().position(|c| c.display_name == dependency.name) | ||
{ | ||
// no need to find indirect dependencies of direct dependencies, just continue | ||
if ra_project.crates[index].root_module.contains(".cargo/registry") { | ||
continue; | ||
} | ||
|
||
let dependency_name = dependency.name.replace('-', "_").to_lowercase(); | ||
|
||
ra_project.crates[index] | ||
.deps | ||
.insert(Dep { crate_index: dependency_index, name: dependency_name }); | ||
} | ||
} | ||
} | ||
} | ||
|
||
ra_project | ||
} | ||
|
||
#[allow(dead_code)] // FIXME(before-merge): remove this | ||
pub(crate) fn generate_file(&self, path: &Path) -> io::Result<()> { | ||
if path.exists() { | ||
return Err(io::Error::new( | ||
io::ErrorKind::AlreadyExists, | ||
format!("File '{}' already exists.", path.display()), | ||
)); | ||
} | ||
|
||
let mut file = std::fs::File::create(path)?; | ||
serde_json::to_writer_pretty(&mut file, self)?; | ||
|
||
Ok(()) | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this isn't documented, but you probably want to include a
include_dirs
that corresponds to eachsrc/
directory. Ifrustc
keeps a Cargo-like structure, knowing the crate entrypoint is probably enough, but if it drifts,include_dirs
will ensure all rust-analyzer functionality will keep working.(it's important to note that
rust-project.json
is basically a lower-level version of what rust-analyzer already doing with Cargo, so you just need to a do a little more work via rust-project.json to ensure that everything continues to just work.)