@@ -20,13 +20,14 @@ use crate::core::builder::Builder;
20
20
use crate :: core:: metadata:: { project_metadata, workspace_members, Dependency } ;
21
21
22
22
#[ derive( Debug , Serialize ) ]
23
- /// FIXME(before-merge): doc-comment
23
+ /// Represents the root object in `rust-project.json`
24
24
pub ( crate ) struct RustAnalyzerProject {
25
25
crates : Vec < Crate > ,
26
26
sysroot : String ,
27
27
sysroot_src : String ,
28
28
}
29
29
30
+ /// Represents the crate object in `rust-project.json`
30
31
#[ derive( Debug , Default , Serialize , PartialEq ) ]
31
32
struct Crate {
32
33
cfg : Vec < String > ,
@@ -42,13 +43,18 @@ struct Crate {
42
43
}
43
44
44
45
#[ derive( Debug , Default , Serialize , PartialEq , PartialOrd , Ord , Eq ) ]
46
+ /// Represents the dependency object in `rust-project.json`
45
47
struct Dep {
46
48
#[ serde( rename = "crate" ) ]
47
49
crate_index : usize ,
48
50
name : String ,
49
51
}
50
52
51
53
impl 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.
52
58
pub ( crate ) fn collect_ra_project_data ( builder : & Builder < ' _ > ) -> Self {
53
59
let config = & builder. config ;
54
60
@@ -61,6 +67,7 @@ impl RustAnalyzerProject {
61
67
let packages: Vec < _ > = project_metadata ( config) . collect ( ) ;
62
68
let workspace_members: Vec < _ > = workspace_members ( config) . collect ( ) ;
63
69
70
+ // Handle crates in the workspace
64
71
for package in & packages {
65
72
let is_not_indirect_dependency = packages
66
73
. iter ( )
@@ -105,42 +112,56 @@ impl RustAnalyzerProject {
105
112
ra_project. crates . sort_by_key ( |c| c. display_name . clone ( ) ) ;
106
113
ra_project. crates . dedup_by_key ( |c| c. display_name . clone ( ) ) ;
107
114
108
- // Find and fill dependencies of crates.
115
+ let mut info_is_printed = false ;
116
+
117
+ // Handle dependencies and proc-macro dylibs
109
118
for package in packages {
110
119
if let Some ( index) =
111
120
ra_project. crates . iter ( ) . position ( |c| c. display_name == package. name )
112
121
{
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
-
125
122
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
+
127
149
let ok = stream_cargo ( builder, cargo. into ( ) , vec ! [ ] , & mut |msg| {
128
150
let filenames = match msg {
129
151
CargoMessage :: CompilerArtifact { filenames, .. } => filenames,
130
152
_ => return ,
131
153
} ;
132
154
133
155
for filename in filenames {
156
+ let kebab_case = & ra_project. crates [ index] . display_name ;
134
157
let snake_case_name = ra_project. crates [ index]
135
158
. display_name
136
159
. replace ( '-' , "_" )
137
160
. to_lowercase ( ) ;
138
161
139
162
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) ) )
144
165
{
145
166
ra_project. crates [ index] . proc_macro_dylib_path =
146
167
Some ( filename. to_string ( ) ) ;
@@ -173,7 +194,8 @@ impl RustAnalyzerProject {
173
194
ra_project
174
195
}
175
196
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 < ( ) > {
177
199
if path. exists ( ) {
178
200
return Err ( io:: Error :: new (
179
201
io:: ErrorKind :: AlreadyExists ,
0 commit comments