@@ -58,28 +58,32 @@ impl PartialEq for BuildDataConfig {
58
58
59
59
impl Eq for BuildDataConfig { }
60
60
61
- #[ derive( Debug , Default ) ]
61
+ #[ derive( Debug ) ]
62
62
pub struct BuildDataCollector {
63
+ wrap_rustc : bool ,
63
64
configs : FxHashMap < AbsPathBuf , BuildDataConfig > ,
64
65
}
65
66
66
67
impl BuildDataCollector {
68
+ pub fn new ( wrap_rustc : bool ) -> Self {
69
+ Self { wrap_rustc, configs : FxHashMap :: default ( ) }
70
+ }
71
+
67
72
pub ( crate ) fn add_config ( & mut self , workspace_root : & AbsPath , config : BuildDataConfig ) {
68
73
self . configs . insert ( workspace_root. to_path_buf ( ) , config) ;
69
74
}
70
75
71
76
pub fn collect ( & mut self , progress : & dyn Fn ( String ) ) -> Result < BuildDataResult > {
72
77
let mut res = BuildDataResult :: default ( ) ;
73
78
for ( path, config) in self . configs . iter ( ) {
74
- res. per_workspace . insert (
75
- path. clone ( ) ,
76
- collect_from_workspace (
77
- & config. cargo_toml ,
78
- & config. cargo_features ,
79
- & config. packages ,
80
- progress,
81
- ) ?,
82
- ) ;
79
+ let workspace_build_data = WorkspaceBuildData :: collect (
80
+ & config. cargo_toml ,
81
+ & config. cargo_features ,
82
+ & config. packages ,
83
+ self . wrap_rustc ,
84
+ progress,
85
+ ) ?;
86
+ res. per_workspace . insert ( path. clone ( ) , workspace_build_data) ;
83
87
}
84
88
Ok ( res)
85
89
}
@@ -120,119 +124,137 @@ impl BuildDataConfig {
120
124
}
121
125
}
122
126
123
- fn collect_from_workspace (
124
- cargo_toml : & AbsPath ,
125
- cargo_features : & CargoConfig ,
126
- packages : & Vec < cargo_metadata:: Package > ,
127
- progress : & dyn Fn ( String ) ,
128
- ) -> Result < WorkspaceBuildData > {
129
- let mut cmd = Command :: new ( toolchain:: cargo ( ) ) ;
130
- cmd. args ( & [ "check" , "--workspace" , "--message-format=json" , "--manifest-path" ] )
131
- . arg ( cargo_toml. as_ref ( ) ) ;
132
-
133
- // --all-targets includes tests, benches and examples in addition to the
134
- // default lib and bins. This is an independent concept from the --targets
135
- // flag below.
136
- cmd. arg ( "--all-targets" ) ;
137
-
138
- if let Some ( target) = & cargo_features. target {
139
- cmd. args ( & [ "--target" , target] ) ;
140
- }
127
+ impl WorkspaceBuildData {
128
+ fn collect (
129
+ cargo_toml : & AbsPath ,
130
+ cargo_features : & CargoConfig ,
131
+ packages : & Vec < cargo_metadata:: Package > ,
132
+ wrap_rustc : bool ,
133
+ progress : & dyn Fn ( String ) ,
134
+ ) -> Result < WorkspaceBuildData > {
135
+ let mut cmd = Command :: new ( toolchain:: cargo ( ) ) ;
136
+
137
+ if wrap_rustc {
138
+ // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use
139
+ // that to compile only proc macros and build scripts during the initial
140
+ // `cargo check`.
141
+ let myself = std:: env:: current_exe ( ) ?;
142
+ cmd. env ( "RUSTC_WRAPPER" , myself) ;
143
+ cmd. env ( "RA_RUSTC_WRAPPER" , "1" ) ;
144
+ }
145
+
146
+ cmd. args ( & [ "check" , "--workspace" , "--message-format=json" , "--manifest-path" ] )
147
+ . arg ( cargo_toml. as_ref ( ) ) ;
141
148
142
- if cargo_features . all_features {
143
- cmd . arg ( "--all-features" ) ;
144
- } else {
145
- if cargo_features . no_default_features {
146
- // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
147
- // https://github.com/oli-obk/cargo_metadata/issues/79
148
- cmd. arg ( "--no-default-features" ) ;
149
+ // --all-targets includes tests, benches and examples in addition to the
150
+ // default lib and bins. This is an independent concept from the --targets
151
+ // flag below.
152
+ cmd . arg ( "--all-targets" ) ;
153
+
154
+ if let Some ( target ) = & cargo_features . target {
155
+ cmd. args ( & [ "--target" , target ] ) ;
149
156
}
150
- if !cargo_features. features . is_empty ( ) {
151
- cmd. arg ( "--features" ) ;
152
- cmd. arg ( cargo_features. features . join ( " " ) ) ;
157
+
158
+ if cargo_features. all_features {
159
+ cmd. arg ( "--all-features" ) ;
160
+ } else {
161
+ if cargo_features. no_default_features {
162
+ // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
163
+ // https://github.com/oli-obk/cargo_metadata/issues/79
164
+ cmd. arg ( "--no-default-features" ) ;
165
+ }
166
+ if !cargo_features. features . is_empty ( ) {
167
+ cmd. arg ( "--features" ) ;
168
+ cmd. arg ( cargo_features. features . join ( " " ) ) ;
169
+ }
153
170
}
154
- }
155
171
156
- cmd. stdout ( Stdio :: piped ( ) ) . stderr ( Stdio :: piped ( ) ) . stdin ( Stdio :: null ( ) ) ;
157
-
158
- let mut child = cmd. spawn ( ) . map ( JodChild ) ?;
159
- let child_stdout = child. stdout . take ( ) . unwrap ( ) ;
160
- let stdout = BufReader :: new ( child_stdout) ;
161
-
162
- let mut res = WorkspaceBuildData :: default ( ) ;
163
- for message in cargo_metadata:: Message :: parse_stream ( stdout) . flatten ( ) {
164
- match message {
165
- Message :: BuildScriptExecuted ( BuildScript {
166
- package_id, out_dir, cfgs, env, ..
167
- } ) => {
168
- let cfgs = {
169
- let mut acc = Vec :: new ( ) ;
170
- for cfg in cfgs {
171
- match cfg. parse :: < CfgFlag > ( ) {
172
- Ok ( it) => acc. push ( it) ,
173
- Err ( err) => {
174
- anyhow:: bail!( "invalid cfg from cargo-metadata: {}" , err)
175
- }
176
- } ;
172
+ cmd. stdout ( Stdio :: piped ( ) ) . stderr ( Stdio :: piped ( ) ) . stdin ( Stdio :: null ( ) ) ;
173
+
174
+ let mut child = cmd. spawn ( ) . map ( JodChild ) ?;
175
+ let child_stdout = child. stdout . take ( ) . unwrap ( ) ;
176
+ let stdout = BufReader :: new ( child_stdout) ;
177
+
178
+ let mut res = WorkspaceBuildData :: default ( ) ;
179
+ for message in cargo_metadata:: Message :: parse_stream ( stdout) . flatten ( ) {
180
+ match message {
181
+ Message :: BuildScriptExecuted ( BuildScript {
182
+ package_id,
183
+ out_dir,
184
+ cfgs,
185
+ env,
186
+ ..
187
+ } ) => {
188
+ let cfgs = {
189
+ let mut acc = Vec :: new ( ) ;
190
+ for cfg in cfgs {
191
+ match cfg. parse :: < CfgFlag > ( ) {
192
+ Ok ( it) => acc. push ( it) ,
193
+ Err ( err) => {
194
+ anyhow:: bail!( "invalid cfg from cargo-metadata: {}" , err)
195
+ }
196
+ } ;
197
+ }
198
+ acc
199
+ } ;
200
+ let package_build_data =
201
+ res. per_package . entry ( package_id. repr . clone ( ) ) . or_default ( ) ;
202
+ // cargo_metadata crate returns default (empty) path for
203
+ // older cargos, which is not absolute, so work around that.
204
+ if !out_dir. as_str ( ) . is_empty ( ) {
205
+ let out_dir = AbsPathBuf :: assert ( PathBuf :: from ( out_dir. into_os_string ( ) ) ) ;
206
+ package_build_data. out_dir = Some ( out_dir) ;
207
+ package_build_data. cfgs = cfgs;
177
208
}
178
- acc
179
- } ;
180
- let package_build_data =
181
- res. per_package . entry ( package_id. repr . clone ( ) ) . or_default ( ) ;
182
- // cargo_metadata crate returns default (empty) path for
183
- // older cargos, which is not absolute, so work around that.
184
- if !out_dir. as_str ( ) . is_empty ( ) {
185
- let out_dir = AbsPathBuf :: assert ( PathBuf :: from ( out_dir. into_os_string ( ) ) ) ;
186
- package_build_data. out_dir = Some ( out_dir) ;
187
- package_build_data. cfgs = cfgs;
188
- }
189
209
190
- package_build_data. envs = env;
191
- }
192
- Message :: CompilerArtifact ( message) => {
193
- progress ( format ! ( "metadata {}" , message. target. name) ) ;
194
-
195
- if message. target . kind . contains ( & "proc-macro" . to_string ( ) ) {
196
- let package_id = message. package_id ;
197
- // Skip rmeta file
198
- if let Some ( filename) = message. filenames . iter ( ) . find ( |name| is_dylib ( name) ) {
199
- let filename = AbsPathBuf :: assert ( PathBuf :: from ( & filename) ) ;
200
- let package_build_data =
201
- res. per_package . entry ( package_id. repr . clone ( ) ) . or_default ( ) ;
202
- package_build_data. proc_macro_dylib_path = Some ( filename) ;
210
+ package_build_data. envs = env;
211
+ }
212
+ Message :: CompilerArtifact ( message) => {
213
+ progress ( format ! ( "metadata {}" , message. target. name) ) ;
214
+
215
+ if message. target . kind . contains ( & "proc-macro" . to_string ( ) ) {
216
+ let package_id = message. package_id ;
217
+ // Skip rmeta file
218
+ if let Some ( filename) = message. filenames . iter ( ) . find ( |name| is_dylib ( name) )
219
+ {
220
+ let filename = AbsPathBuf :: assert ( PathBuf :: from ( & filename) ) ;
221
+ let package_build_data =
222
+ res. per_package . entry ( package_id. repr . clone ( ) ) . or_default ( ) ;
223
+ package_build_data. proc_macro_dylib_path = Some ( filename) ;
224
+ }
203
225
}
204
226
}
227
+ Message :: CompilerMessage ( message) => {
228
+ progress ( message. target . name . clone ( ) ) ;
229
+ }
230
+ Message :: BuildFinished ( _) => { }
231
+ Message :: TextLine ( _) => { }
232
+ _ => { }
205
233
}
206
- Message :: CompilerMessage ( message) => {
207
- progress ( message. target . name . clone ( ) ) ;
208
- }
209
- Message :: BuildFinished ( _) => { }
210
- Message :: TextLine ( _) => { }
211
- _ => { }
212
234
}
213
- }
214
235
215
- for package in packages {
216
- let package_build_data = res. per_package . entry ( package. id . repr . clone ( ) ) . or_default ( ) ;
217
- inject_cargo_env ( package, package_build_data) ;
218
- if let Some ( out_dir) = & package_build_data. out_dir {
219
- // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
220
- if let Some ( out_dir) = out_dir. to_str ( ) . map ( |s| s. to_owned ( ) ) {
221
- package_build_data. envs . push ( ( "OUT_DIR" . to_string ( ) , out_dir) ) ;
236
+ for package in packages {
237
+ let package_build_data = res. per_package . entry ( package. id . repr . clone ( ) ) . or_default ( ) ;
238
+ inject_cargo_env ( package, package_build_data) ;
239
+ if let Some ( out_dir) = & package_build_data. out_dir {
240
+ // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
241
+ if let Some ( out_dir) = out_dir. to_str ( ) . map ( |s| s. to_owned ( ) ) {
242
+ package_build_data. envs . push ( ( "OUT_DIR" . to_string ( ) , out_dir) ) ;
243
+ }
222
244
}
223
245
}
224
- }
225
246
226
- let output = child. into_inner ( ) . wait_with_output ( ) ?;
227
- if !output. status . success ( ) {
228
- let mut stderr = String :: from_utf8 ( output. stderr ) . unwrap_or_default ( ) ;
229
- if stderr. is_empty ( ) {
230
- stderr = "cargo check failed" . to_string ( ) ;
247
+ let output = child. into_inner ( ) . wait_with_output ( ) ?;
248
+ if !output. status . success ( ) {
249
+ let mut stderr = String :: from_utf8 ( output. stderr ) . unwrap_or_default ( ) ;
250
+ if stderr. is_empty ( ) {
251
+ stderr = "cargo check failed" . to_string ( ) ;
252
+ }
253
+ res. error = Some ( stderr)
231
254
}
232
- res. error = Some ( stderr)
233
- }
234
255
235
- Ok ( res)
256
+ Ok ( res)
257
+ }
236
258
}
237
259
238
260
// FIXME: File a better way to know if it is a dylib
0 commit comments