@@ -16,6 +16,7 @@ use la_arena::ArenaMap;
16
16
use paths:: { AbsPath , AbsPathBuf , Utf8PathBuf } ;
17
17
use rustc_hash:: { FxHashMap , FxHashSet } ;
18
18
use serde:: Deserialize as _;
19
+ use stdx:: { always, never} ;
19
20
use toolchain:: Tool ;
20
21
21
22
use crate :: {
@@ -30,6 +31,15 @@ pub struct WorkspaceBuildScripts {
30
31
error : Option < String > ,
31
32
}
32
33
34
+ #[ derive( Debug , Clone , Default , PartialEq , Eq ) ]
35
+ pub enum ProcMacroDylibPath {
36
+ Path ( AbsPathBuf ) ,
37
+ DylibNotFound ( Box < [ Utf8PathBuf ] > ) ,
38
+ NotProcMacro ,
39
+ #[ default]
40
+ NotBuilt ,
41
+ }
42
+
33
43
/// Output of the build script and proc-macro building step for a concrete package.
34
44
#[ derive( Debug , Clone , Default , PartialEq , Eq ) ]
35
45
pub ( crate ) struct BuildScriptOutput {
@@ -43,15 +53,15 @@ pub(crate) struct BuildScriptOutput {
43
53
/// Directory where a build script might place its output.
44
54
pub ( crate ) out_dir : Option < AbsPathBuf > ,
45
55
/// Path to the proc-macro library file if this package exposes proc-macros.
46
- pub ( crate ) proc_macro_dylib_path : Option < AbsPathBuf > ,
56
+ pub ( crate ) proc_macro_dylib_path : ProcMacroDylibPath ,
47
57
}
48
58
49
59
impl BuildScriptOutput {
50
60
fn is_empty ( & self ) -> bool {
51
61
self . cfgs . is_empty ( )
52
62
&& self . envs . is_empty ( )
53
63
&& self . out_dir . is_none ( )
54
- && self . proc_macro_dylib_path . is_none ( )
64
+ && self . proc_macro_dylib_path == ProcMacroDylibPath :: NotBuilt
55
65
}
56
66
}
57
67
@@ -126,6 +136,8 @@ impl WorkspaceBuildScripts {
126
136
|package, cb| {
127
137
if let Some ( & ( package, workspace) ) = by_id. get ( package) {
128
138
cb ( & workspaces[ workspace] [ package] . name , & mut res[ workspace] . outputs [ package] ) ;
139
+ } else {
140
+ never ! ( "Received compiler message for unknown package: {}" , package) ;
129
141
}
130
142
} ,
131
143
progress,
@@ -140,12 +152,9 @@ impl WorkspaceBuildScripts {
140
152
if tracing:: enabled!( tracing:: Level :: INFO ) {
141
153
for ( idx, workspace) in workspaces. iter ( ) . enumerate ( ) {
142
154
for package in workspace. packages ( ) {
143
- let package_build_data = & mut res[ idx] . outputs [ package] ;
155
+ let package_build_data: & mut BuildScriptOutput = & mut res[ idx] . outputs [ package] ;
144
156
if !package_build_data. is_empty ( ) {
145
- tracing:: info!(
146
- "{}: {package_build_data:?}" ,
147
- workspace[ package] . manifest. parent( ) ,
148
- ) ;
157
+ tracing:: info!( "{}: {package_build_data:?}" , workspace[ package] . manifest, ) ;
149
158
}
150
159
}
151
160
}
@@ -198,39 +207,58 @@ impl WorkspaceBuildScripts {
198
207
let path = dir_entry. path ( ) ;
199
208
let extension = path. extension ( ) ?;
200
209
if extension == std:: env:: consts:: DLL_EXTENSION {
201
- let name = path. file_stem ( ) ?. to_str ( ) ?. split_once ( '-' ) ?. 0 . to_owned ( ) ;
202
- let path = AbsPathBuf :: try_from ( Utf8PathBuf :: from_path_buf ( path) . ok ( ) ?)
203
- . ok ( ) ?;
204
- return Some ( ( name, path) ) ;
210
+ let name = path
211
+ . file_stem ( ) ?
212
+ . to_str ( ) ?
213
+ . split_once ( '-' ) ?
214
+ . 0
215
+ . trim_start_matches ( "lib" )
216
+ . to_owned ( ) ;
217
+ let path = match Utf8PathBuf :: from_path_buf ( path) {
218
+ Ok ( path) => path,
219
+ Err ( path) => {
220
+ tracing:: warn!(
221
+ "Proc-macro dylib path contains non-UTF8 characters: {:?}" ,
222
+ path. display( )
223
+ ) ;
224
+ return None ;
225
+ }
226
+ } ;
227
+ return match AbsPathBuf :: try_from ( path) {
228
+ Ok ( path) => Some ( ( name, path) ) ,
229
+ Err ( path) => {
230
+ tracing:: error!(
231
+ "proc-macro dylib path is not absolute: {:?}" ,
232
+ path
233
+ ) ;
234
+ None
235
+ }
236
+ } ;
205
237
}
206
238
}
207
239
None
208
240
} )
209
241
. collect ( ) ;
210
242
for p in rustc. packages ( ) {
211
243
let package = & rustc[ p] ;
212
- if package
213
- . targets
214
- . iter ( )
215
- . any ( | & it| matches ! ( rustc [ it ] . kind , TargetKind :: Lib { is_proc_macro : true } ) )
216
- {
217
- if let Some ( ( _, path) ) = proc_macro_dylibs
218
- . iter ( )
219
- . find ( | ( name , _ ) | * name . trim_start_matches ( "lib" ) == package . name )
220
- {
221
- bs . outputs [ p ] . proc_macro_dylib_path = Some ( path . clone ( ) ) ;
244
+ bs . outputs [ p ] . proc_macro_dylib_path =
245
+ if package . targets . iter ( ) . any ( | & it| {
246
+ matches ! ( rustc [ it ] . kind , TargetKind :: Lib { is_proc_macro : true } )
247
+ } ) {
248
+ match proc_macro_dylibs . iter ( ) . find ( | ( name , _ ) | * name == package . name ) {
249
+ Some ( ( _, path) ) => ProcMacroDylibPath :: Path ( path . clone ( ) ) ,
250
+ _ => ProcMacroDylibPath :: DylibNotFound ( Box :: default ( ) ) ,
251
+ }
252
+ } else {
253
+ ProcMacroDylibPath :: NotProcMacro
222
254
}
223
- }
224
255
}
225
256
226
257
if tracing:: enabled!( tracing:: Level :: INFO ) {
227
258
for package in rustc. packages ( ) {
228
259
let package_build_data = & bs. outputs [ package] ;
229
260
if !package_build_data. is_empty ( ) {
230
- tracing:: info!(
231
- "{}: {package_build_data:?}" ,
232
- rustc[ package] . manifest. parent( ) ,
233
- ) ;
261
+ tracing:: info!( "{}: {package_build_data:?}" , rustc[ package] . manifest, ) ;
234
262
}
235
263
}
236
264
}
@@ -263,6 +291,12 @@ impl WorkspaceBuildScripts {
263
291
|package, cb| {
264
292
if let Some ( & package) = by_id. get ( package) {
265
293
cb ( & workspace[ package] . name , & mut outputs[ package] ) ;
294
+ } else {
295
+ never ! (
296
+ "Received compiler message for unknown package: {}\n {}" ,
297
+ package,
298
+ by_id. keys( ) . join( ", " )
299
+ ) ;
266
300
}
267
301
} ,
268
302
progress,
@@ -272,10 +306,7 @@ impl WorkspaceBuildScripts {
272
306
for package in workspace. packages ( ) {
273
307
let package_build_data = & outputs[ package] ;
274
308
if !package_build_data. is_empty ( ) {
275
- tracing:: info!(
276
- "{}: {package_build_data:?}" ,
277
- workspace[ package] . manifest. parent( ) ,
278
- ) ;
309
+ tracing:: info!( "{}: {package_build_data:?}" , workspace[ package] . manifest, ) ;
279
310
}
280
311
}
281
312
}
@@ -348,15 +379,25 @@ impl WorkspaceBuildScripts {
348
379
progress ( format ! (
349
380
"building compile-time-deps: proc-macro {name} built"
350
381
) ) ;
382
+ always ! (
383
+ data. proc_macro_dylib_path == ProcMacroDylibPath :: NotBuilt ,
384
+ "received multiple compiler artifacts for the same package: {message:?}"
385
+ ) ;
386
+ if data. proc_macro_dylib_path == ProcMacroDylibPath :: NotBuilt {
387
+ data. proc_macro_dylib_path = ProcMacroDylibPath :: NotProcMacro ;
388
+ }
351
389
if message. target . kind . contains ( & cargo_metadata:: TargetKind :: ProcMacro )
352
390
{
353
- // Skip rmeta file
354
- if let Some ( filename) =
355
- message. filenames . iter ( ) . find ( |file| is_dylib ( file) )
356
- {
357
- let filename = AbsPath :: assert ( filename) ;
358
- data. proc_macro_dylib_path = Some ( filename. to_owned ( ) ) ;
359
- }
391
+ data. proc_macro_dylib_path =
392
+ match message. filenames . iter ( ) . find ( |file| is_dylib ( file) ) {
393
+ Some ( filename) => {
394
+ let filename = AbsPath :: assert ( filename) ;
395
+ ProcMacroDylibPath :: Path ( filename. to_owned ( ) )
396
+ }
397
+ None => ProcMacroDylibPath :: DylibNotFound (
398
+ message. filenames . clone ( ) . into_boxed_slice ( ) ,
399
+ ) ,
400
+ } ;
360
401
}
361
402
} ) ;
362
403
}
0 commit comments