2
2
#![ feature( once_cell) ]
3
3
#![ feature( try_blocks) ]
4
4
5
+ // Some `extern crate`s are needed to ensure that UI test dependencies
6
+ // show up in the depinfo file.
7
+ extern crate clippy_utils;
8
+ extern crate derive_new;
9
+ extern crate if_chain;
10
+ extern crate itertools;
11
+ extern crate quote;
12
+ extern crate syn;
13
+
5
14
use compiletest_rs as compiletest;
6
15
use compiletest_rs:: common:: Mode as TestMode ;
7
16
@@ -38,6 +47,7 @@ fn third_party_crates() -> String {
38
47
static CRATES : & [ & str ] = & [
39
48
"clippy_lints" ,
40
49
"clippy_utils" ,
50
+ "derive_new" ,
41
51
"if_chain" ,
42
52
"itertools" ,
43
53
"quote" ,
@@ -46,50 +56,38 @@ fn third_party_crates() -> String {
46
56
"serde_derive" ,
47
57
"syn" ,
48
58
] ;
49
- let dep_dir = cargo:: TARGET_LIB . join ( "deps" ) ;
50
- let mut crates: HashMap < & str , Vec < PathBuf > > = HashMap :: with_capacity ( CRATES . len ( ) ) ;
51
- let mut flags = String :: new ( ) ;
52
- for entry in fs:: read_dir ( dep_dir) . unwrap ( ) . flatten ( ) {
53
- let path = entry. path ( ) ;
54
- if let Some ( name) = try {
55
- let name = path. file_name ( ) ?. to_str ( ) ?;
56
- let ( name, _) = name. strip_suffix ( ".rlib" ) ?. strip_prefix ( "lib" ) ?. split_once ( '-' ) ?;
57
- CRATES . iter ( ) . copied ( ) . find ( |& c| c == name) ?
58
- } {
59
- flags += & format ! ( " --extern {}={}" , name, path. display( ) ) ;
60
- crates. entry ( name) . or_default ( ) . push ( path. clone ( ) ) ;
61
- }
62
- }
63
- crates. retain ( |_, paths| paths. len ( ) > 1 ) ;
64
- if !crates. is_empty ( ) {
65
- let crate_names = crates. keys ( ) . map ( |s| format ! ( "`{}`" , s) ) . collect :: < Vec < _ > > ( ) . join ( ", " ) ;
66
- // add backslashes for an easy copy-paste `rm` command
67
- let paths = crates
68
- . into_values ( )
69
- . flatten ( )
70
- . map ( |p| strip_current_dir ( & p) . display ( ) . to_string ( ) )
71
- . collect :: < Vec < _ > > ( )
72
- . join ( " \\ \n " ) ;
73
- // Check which action should be done in order to remove compiled deps.
74
- // If pre-installed version of compiler is used, `cargo clean` will do.
75
- // Otherwise (for bootstrapped compiler), the dependencies directory
76
- // must be removed manually.
77
- let suggested_action = if std:: env:: var_os ( "RUSTC_BOOTSTRAP" ) . is_some ( ) {
78
- "removing the stageN-tools directory"
79
- } else {
80
- "running `cargo clean`"
81
- } ;
82
59
83
- panic ! (
84
- "\n ----------------------------------------------------------------------\n \
85
- ERROR: Found multiple rlibs for crates: {}\n \
86
- Try {} or remove the following files:\n \n {}\n \n \
87
- For details on this error see https://github.com/rust-lang/rust-clippy/issues/7343\n \
88
- ----------------------------------------------------------------------\n ",
89
- crate_names, suggested_action, paths
90
- ) ;
60
+ let depinfo = {
61
+ let exe_path = env:: current_exe ( ) . unwrap ( ) ;
62
+ let depinfo_filename = format ! ( "{}.d" , exe_path. file_stem( ) . unwrap( ) . to_str( ) . unwrap( ) ) ;
63
+ let mut dep_info_path = exe_path;
64
+ dep_info_path. set_file_name ( depinfo_filename) ;
65
+ std:: fs:: read_to_string ( dep_info_path) . unwrap ( )
66
+ } ;
67
+ let mut crates: HashMap < & str , & str > = HashMap :: with_capacity ( CRATES . len ( ) ) ;
68
+ for line in depinfo. lines ( ) {
69
+ let path = try {
70
+ let path = line. strip_suffix ( ':' ) ?;
71
+ let part = path
72
+ . strip_suffix ( ".rlib" )
73
+ . or_else ( || path. strip_suffix ( ".so" ) )
74
+ . or_else ( || path. strip_suffix ( ".dylib" ) )
75
+ . or_else ( || path. strip_suffix ( ".dll" ) ) ?;
76
+ let part = part. rsplit_once ( '-' ) ?. 0 ;
77
+ let name = part. rsplit_once ( |c| matches ! ( c, '/' | '\\' ) ) ?. 1 . strip_prefix ( "lib" ) ?;
78
+ CRATES . contains ( & name) . then ( || ( name, path) ) ?
79
+ } ;
80
+ if let Some ( ( name, path) ) = path {
81
+ // A dependency may be listed twice if it is available in sysroot,
82
+ // and the sysroot dependencies are listed first. As of the writing,
83
+ // this only seems to apply to if_chain.
84
+ crates. insert ( name, path) ;
85
+ }
91
86
}
92
- flags
87
+ crates
88
+ . into_iter ( )
89
+ . map ( |( name, path) | format ! ( "--extern {}={} " , name, path) )
90
+ . collect ( )
93
91
}
94
92
95
93
fn default_config ( ) -> compiletest:: Config {
@@ -105,8 +103,11 @@ fn default_config() -> compiletest::Config {
105
103
config. compile_lib_path = path;
106
104
}
107
105
106
+ // Using `-L dependency={}` enforces that external dependencies are added with `--extern`.
107
+ // This is valuable because a) it allows us to monitor what external dependencies are used
108
+ // and b) it ensures that conflicting rlibs are resolved properly.
108
109
config. target_rustcflags = Some ( format ! (
109
- "--emit=metadata -L {0 } -L {1 } -Dwarnings -Zui-testing {2 }" ,
110
+ "--emit=metadata -L dependency={ } -L dependency={ } -Dwarnings -Zui-testing {}" ,
110
111
host_lib( ) . join( "deps" ) . display( ) ,
111
112
cargo:: TARGET_LIB . join( "deps" ) . display( ) ,
112
113
third_party_crates( ) ,
@@ -316,12 +317,3 @@ impl Drop for VarGuard {
316
317
}
317
318
}
318
319
}
319
-
320
- fn strip_current_dir ( path : & Path ) -> & Path {
321
- if let Ok ( curr) = env:: current_dir ( ) {
322
- if let Ok ( stripped) = path. strip_prefix ( curr) {
323
- return stripped;
324
- }
325
- }
326
- path
327
- }
0 commit comments