@@ -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 ( Box < [ TargetKind ] > ) ,
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,60 @@ 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 (
254
+ package. targets . iter ( ) . map ( |& target| rustc[ target] . kind ) . collect ( ) ,
255
+ )
222
256
}
223
- }
224
257
}
225
258
226
259
if tracing:: enabled!( tracing:: Level :: INFO ) {
227
260
for package in rustc. packages ( ) {
228
261
let package_build_data = & bs. outputs [ package] ;
229
262
if !package_build_data. is_empty ( ) {
230
- tracing:: info!(
231
- "{}: {package_build_data:?}" ,
232
- rustc[ package] . manifest. parent( ) ,
233
- ) ;
263
+ tracing:: info!( "{}: {package_build_data:?}" , rustc[ package] . manifest, ) ;
234
264
}
235
265
}
236
266
}
@@ -263,6 +293,8 @@ impl WorkspaceBuildScripts {
263
293
|package, cb| {
264
294
if let Some ( & package) = by_id. get ( package) {
265
295
cb ( & workspace[ package] . name , & mut outputs[ package] ) ;
296
+ } else {
297
+ never ! ( "Received compiler message for unknown package: {}" , package) ;
266
298
}
267
299
} ,
268
300
progress,
@@ -272,10 +304,7 @@ impl WorkspaceBuildScripts {
272
304
for package in workspace. packages ( ) {
273
305
let package_build_data = & outputs[ package] ;
274
306
if !package_build_data. is_empty ( ) {
275
- tracing:: info!(
276
- "{}: {package_build_data:?}" ,
277
- workspace[ package] . manifest. parent( ) ,
278
- ) ;
307
+ tracing:: info!( "{}: {package_build_data:?}" , workspace[ package] . manifest, ) ;
279
308
}
280
309
}
281
310
}
@@ -348,15 +377,33 @@ impl WorkspaceBuildScripts {
348
377
progress ( format ! (
349
378
"building compile-time-deps: proc-macro {name} built"
350
379
) ) ;
351
- if message. target . kind . contains ( & cargo_metadata:: TargetKind :: ProcMacro )
380
+ always ! (
381
+ data. proc_macro_dylib_path == ProcMacroDylibPath :: NotBuilt ,
382
+ "received multiple compiler artifacts for the same package: {message:?}"
383
+ ) ;
384
+ data. proc_macro_dylib_path = if message
385
+ . target
386
+ . kind
387
+ . contains ( & cargo_metadata:: TargetKind :: ProcMacro )
352
388
{
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 ( ) ) ;
389
+ match message. filenames . iter ( ) . find ( |file| is_dylib ( file) ) {
390
+ Some ( filename) => {
391
+ let filename = AbsPath :: assert ( filename) ;
392
+ ProcMacroDylibPath :: Path ( filename. to_owned ( ) )
393
+ }
394
+ None => ProcMacroDylibPath :: DylibNotFound (
395
+ message. filenames . clone ( ) . into_boxed_slice ( ) ,
396
+ ) ,
359
397
}
398
+ } else {
399
+ ProcMacroDylibPath :: NotProcMacro (
400
+ message
401
+ . target
402
+ . kind
403
+ . iter ( )
404
+ . map ( |target| TargetKind :: new ( std:: slice:: from_ref ( target) ) )
405
+ . collect ( ) ,
406
+ )
360
407
}
361
408
} ) ;
362
409
}
0 commit comments