@@ -20,13 +20,14 @@ use crate::core::builder::Builder;
2020use crate :: core:: metadata:: { project_metadata, workspace_members, Dependency } ;
2121
2222#[ derive( Debug , Serialize ) ]
23- /// FIXME(before-merge): doc-comment
23+ /// Represents the root object in `rust-project.json`
2424pub ( crate ) struct RustAnalyzerProject {
2525 crates : Vec < Crate > ,
2626 sysroot : String ,
2727 sysroot_src : String ,
2828}
2929
30+ /// Represents the crate object in `rust-project.json`
3031#[ derive( Debug , Default , Serialize , PartialEq ) ]
3132struct Crate {
3233 cfg : Vec < String > ,
@@ -42,13 +43,18 @@ struct Crate {
4243}
4344
4445#[ derive( Debug , Default , Serialize , PartialEq , PartialOrd , Ord , Eq ) ]
46+ /// Represents the dependency object in `rust-project.json`
4547struct Dep {
4648 #[ serde( rename = "crate" ) ]
4749 crate_index : usize ,
4850 name : String ,
4951}
5052
5153impl RustAnalyzerProject {
54+ /// Gathers data for `rust-project.json` from `cargo metadata`.
55+ ///
56+ /// Skips the indirect dependency crates since we don't need to
57+ /// run LSP on them.
5258 pub ( crate ) fn collect_ra_project_data ( builder : & Builder < ' _ > ) -> Self {
5359 let config = & builder. config ;
5460
@@ -61,6 +67,7 @@ impl RustAnalyzerProject {
6167 let packages: Vec < _ > = project_metadata ( config) . collect ( ) ;
6268 let workspace_members: Vec < _ > = workspace_members ( config) . collect ( ) ;
6369
70+ // Handle crates in the workspace
6471 for package in & packages {
6572 let is_not_indirect_dependency = packages
6673 . iter ( )
@@ -105,42 +112,56 @@ impl RustAnalyzerProject {
105112 ra_project. crates . sort_by_key ( |c| c. display_name . clone ( ) ) ;
106113 ra_project. crates . dedup_by_key ( |c| c. display_name . clone ( ) ) ;
107114
108- // Find and fill dependencies of crates.
115+ let mut info_is_printed = false ;
116+
117+ // Handle dependencies and proc-macro dylibs
109118 for package in packages {
110119 if let Some ( index) =
111120 ra_project. crates . iter ( ) . position ( |c| c. display_name == package. name )
112121 {
113- assert ! (
114- !package. manifest_path. is_empty( ) ,
115- "manifest_path must be valid for proc-macro crates."
116- ) ;
117-
118- let mut cargo = Command :: new ( & builder. initial_cargo ) ;
119- cargo
120- . env ( "RUSTC_BOOTSTRAP" , "1" )
121- . arg ( "build" )
122- . arg ( "--manifest-path" )
123- . arg ( package. manifest_path ) ;
124-
125122 if ra_project. crates [ index] . is_proc_macro {
126- // FIXME(before-merge): use `CARGO_TARGET_DIR` to place shared libraries in the build output directory.
123+ let date = & builder. config . stage0_metadata . compiler . date ;
124+
125+ let cargo_target_dir = builder
126+ . out
127+ . join ( "cache" )
128+ . join ( "proc-macro-artifacts-for-ra" )
129+ // Although it's rare (when the stage0 compiler changes while proc-macro artifacts under
130+ // `proc-macro-artifacts-for-ra` directory exist), there is a chance of ABI mismatch between
131+ // the stage0 compiler and dynamic libraries. Therefore, we want to trigger compilations
132+ // when the stage0 compiler changes.
133+ . join ( format ! ( "{date}_{}" , package. name) ) ;
134+
135+ let mut cargo = Command :: new ( & builder. initial_cargo ) ;
136+ cargo
137+ . env ( "RUSTC_BOOTSTRAP" , "1" )
138+ . env ( "CARGO_TARGET_DIR" , cargo_target_dir)
139+ . arg ( "build" )
140+ . arg ( "--manifest-path" )
141+ . arg ( package. manifest_path ) ;
142+
143+ if !info_is_printed {
144+ builder. info ( "Building proc-macro artifacts to be used for rust-analyzer" ) ;
145+ }
146+
147+ info_is_printed = true ;
148+
127149 let ok = stream_cargo ( builder, cargo. into ( ) , vec ! [ ] , & mut |msg| {
128150 let filenames = match msg {
129151 CargoMessage :: CompilerArtifact { filenames, .. } => filenames,
130152 _ => return ,
131153 } ;
132154
133155 for filename in filenames {
156+ let kebab_case = & ra_project. crates [ index] . display_name ;
134157 let snake_case_name = ra_project. crates [ index]
135158 . display_name
136159 . replace ( '-' , "_" )
137160 . to_lowercase ( ) ;
138161
139162 if filename. ends_with ( ".so" )
140- && ( filename. contains ( & format ! (
141- "lib{}" ,
142- ra_project. crates[ index] . display_name
143- ) ) || filename. contains ( & format ! ( "lib{}" , snake_case_name) ) )
163+ && ( filename. contains ( & format ! ( "lib{}" , kebab_case) )
164+ || filename. contains ( & format ! ( "lib{}" , snake_case_name) ) )
144165 {
145166 ra_project. crates [ index] . proc_macro_dylib_path =
146167 Some ( filename. to_string ( ) ) ;
@@ -173,7 +194,8 @@ impl RustAnalyzerProject {
173194 ra_project
174195 }
175196
176- pub ( crate ) fn generate_file ( & self , path : & Path ) -> io:: Result < ( ) > {
197+ /// Generates a json file on the given path.
198+ pub ( crate ) fn generate_json_file ( & self , path : & Path ) -> io:: Result < ( ) > {
177199 if path. exists ( ) {
178200 return Err ( io:: Error :: new (
179201 io:: ErrorKind :: AlreadyExists ,
0 commit comments