Skip to content

Commit 167a8f5

Browse files
authored
Rollup merge of rust-lang#65945 - tmiasko:long-linker-command-line, r=alexcrichton
Optimize long-linker-command-line test Replace O(n^3) text matching with inexpensive hash set lookups. On my machine this reduces the total runtime of complete run-make-fulldeps suite from roughly 75 seconds to 45 seconds.
2 parents 40f8f56 + afbb89e commit 167a8f5

File tree

1 file changed

+48
-29
lines changed
  • src/test/run-make-fulldeps/long-linker-command-lines

1 file changed

+48
-29
lines changed

src/test/run-make-fulldeps/long-linker-command-lines/foo.rs

+48-29
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,43 @@
77
// Eventually we should see an argument that looks like `@` as we switch from
88
// passing literal arguments to passing everything in the file.
99

10+
use std::collections::HashSet;
1011
use std::env;
1112
use std::fs::{self, File};
12-
use std::io::{BufWriter, Write, Read};
13-
use std::path::PathBuf;
13+
use std::io::{BufWriter, Write};
14+
use std::path::{Path, PathBuf};
1415
use std::process::Command;
1516

17+
fn write_test_case(file: &Path, n: usize) -> HashSet<String> {
18+
let mut libs = HashSet::new();
19+
let mut f = BufWriter::new(File::create(&file).unwrap());
20+
let mut prefix = String::new();
21+
for _ in 0..n {
22+
prefix.push_str("foo");
23+
}
24+
for i in 0..n {
25+
writeln!(f, "#[link(name = \"{}{}\")]", prefix, i).unwrap();
26+
libs.insert(format!("{}{}", prefix, i));
27+
}
28+
writeln!(f, "extern {{}}\nfn main() {{}}").unwrap();
29+
f.into_inner().unwrap();
30+
31+
libs
32+
}
33+
34+
fn read_linker_args(path: &Path) -> String {
35+
let contents = fs::read(path).unwrap();
36+
if cfg!(target_env = "msvc") {
37+
let mut i = contents.chunks(2).map(|c| {
38+
c[0] as u16 | ((c[1] as u16) << 8)
39+
});
40+
assert_eq!(i.next(), Some(0xfeff), "Expected UTF-16 BOM");
41+
String::from_utf16(&i.collect::<Vec<u16>>()).unwrap()
42+
} else {
43+
String::from_utf8(contents).unwrap()
44+
}
45+
}
46+
1647
fn main() {
1748
let tmpdir = PathBuf::from(env::var_os("TMPDIR").unwrap());
1849
let ok = tmpdir.join("ok");
@@ -29,16 +60,7 @@ fn main() {
2960
for i in (1..).map(|i| i * 100) {
3061
println!("attempt: {}", i);
3162
let file = tmpdir.join("bar.rs");
32-
let mut f = BufWriter::new(File::create(&file).unwrap());
33-
let mut lib_name = String::new();
34-
for _ in 0..i {
35-
lib_name.push_str("foo");
36-
}
37-
for j in 0..i {
38-
writeln!(f, "#[link(name = \"{}{}\")]", lib_name, j).unwrap();
39-
}
40-
writeln!(f, "extern {{}}\nfn main() {{}}").unwrap();
41-
f.into_inner().unwrap();
63+
let mut expected_libs = write_test_case(&file, i);
4264

4365
drop(fs::remove_file(&ok));
4466
let output = Command::new(&rustc)
@@ -67,25 +89,22 @@ fn main() {
6789
continue
6890
}
6991

70-
let mut contents = Vec::new();
71-
File::open(&ok).unwrap().read_to_end(&mut contents).unwrap();
72-
73-
for j in 0..i {
74-
let exp = format!("{}{}", lib_name, j);
75-
let exp = if cfg!(target_env = "msvc") {
76-
let mut out = Vec::with_capacity(exp.len() * 2);
77-
for c in exp.encode_utf16() {
78-
// encode in little endian
79-
out.push(c as u8);
80-
out.push((c >> 8) as u8);
81-
}
82-
out
83-
} else {
84-
exp.into_bytes()
85-
};
86-
assert!(contents.windows(exp.len()).any(|w| w == &exp[..]));
92+
for mut arg in read_linker_args(&ok).lines() {
93+
if arg.starts_with("-l") {
94+
arg = &arg["-l".len()..];
95+
}
96+
if arg.ends_with(".lib") {
97+
arg = &arg[..arg.len() - ".lib".len()];
98+
}
99+
expected_libs.remove(arg);
87100
}
88101

102+
assert!(
103+
expected_libs.is_empty(),
104+
"expected but missing libraries: {:#?}",
105+
expected_libs,
106+
);
107+
89108
break
90109
}
91110
}

0 commit comments

Comments
 (0)