Skip to content

Commit b8158cf

Browse files
committed
fix dynamic library search path for build scripts
Make dynamic library search path handling for build scripts mirror the behaviour for cargo run etc. -L paths are taken and stripped of the native= and similar prefixes and added to the dynamic library search path if they are inside the target dir. Resolves #3957
1 parent a232aef commit b8158cf

File tree

6 files changed

+93
-50
lines changed

6 files changed

+93
-50
lines changed

src/cargo/ops/cargo_rustc/compilation.rs

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -100,32 +100,9 @@ impl<'cfg> Compilation<'cfg> {
100100
let mut search_path = if is_host {
101101
vec![self.plugins_dylib_path.clone()]
102102
} else {
103-
let mut search_path = vec![];
104-
105-
// Add -L arguments, after stripping off prefixes like "native="
106-
// or "framework=" and filtering out directories *not* inside our
107-
// output directory, since they are likely spurious and can cause
108-
// clashes with system shared libraries (issue #3366).
109-
for dir in self.native_dirs.iter() {
110-
let dir = match dir.to_str() {
111-
Some(s) => {
112-
let mut parts = s.splitn(2, '=');
113-
match (parts.next(), parts.next()) {
114-
(Some("native"), Some(path)) |
115-
(Some("crate"), Some(path)) |
116-
(Some("dependency"), Some(path)) |
117-
(Some("framework"), Some(path)) |
118-
(Some("all"), Some(path)) => path.into(),
119-
_ => dir.clone(),
120-
}
121-
}
122-
None => dir.clone(),
123-
};
124-
125-
if dir.starts_with(&self.root_output) {
126-
search_path.push(dir);
127-
}
128-
}
103+
let mut search_path =
104+
super::filter_dynamic_search_path(self.native_dirs.iter(),
105+
&self.root_output);
129106
search_path.push(self.root_output.clone());
130107
search_path.push(self.deps_output.clone());
131108
search_path

src/cargo/ops/cargo_rustc/context.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,11 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
336336
self.host.deps()
337337
}
338338

339+
/// Return the root of the build output tree
340+
pub fn target_root(&self) -> &Path {
341+
self.host.dest()
342+
}
343+
339344
/// Returns the appropriate output directory for the specified package and
340345
/// target.
341346
pub fn out_dir(&mut self, unit: &Unit) -> PathBuf {

src/cargo/ops/cargo_rustc/custom_build.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>)
181181
fs::create_dir_all(&script_output)?;
182182
fs::create_dir_all(&build_output)?;
183183

184+
let root_output = cx.target_root().to_path_buf();
185+
184186
// Prepare the unit of "dirty work" which will actually run the custom build
185187
// command.
186188
//
@@ -218,7 +220,8 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>)
218220
}
219221
if let Some(build_scripts) = build_scripts {
220222
super::add_plugin_deps(&mut cmd, &build_state,
221-
&build_scripts)?;
223+
&build_scripts,
224+
&root_output)?;
222225
}
223226
}
224227

src/cargo/ops/cargo_rustc/mod.rs

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,8 @@ fn rustc(cx: &mut Context, unit: &Unit, exec: Arc<Executor>) -> CargoResult<Work
297297
exec.init(cx);
298298
let exec = exec.clone();
299299

300+
let root_output = cx.target_root().to_path_buf();
301+
300302
return Ok(Work::new(move |state| {
301303
// Only at runtime have we discovered what the extra -L and -l
302304
// arguments are for native libraries, so we process those here. We
@@ -307,7 +309,8 @@ fn rustc(cx: &mut Context, unit: &Unit, exec: Arc<Executor>) -> CargoResult<Work
307309
let build_state = build_state.outputs.lock().unwrap();
308310
add_native_deps(&mut rustc, &build_state, &build_deps,
309311
pass_l_flag, &current_id)?;
310-
add_plugin_deps(&mut rustc, &build_state, &build_deps)?;
312+
add_plugin_deps(&mut rustc, &build_state, &build_deps,
313+
&root_output)?;
311314
}
312315

313316
// FIXME(rust-lang/rust#18913): we probably shouldn't have to do
@@ -492,7 +495,8 @@ fn load_build_deps(cx: &Context, unit: &Unit) -> Option<Arc<BuildScripts>> {
492495
// execute.
493496
fn add_plugin_deps(rustc: &mut ProcessBuilder,
494497
build_state: &BuildMap,
495-
build_scripts: &BuildScripts)
498+
build_scripts: &BuildScripts,
499+
root_output: &PathBuf)
496500
-> CargoResult<()> {
497501
let var = util::dylib_path_envvar();
498502
let search_path = rustc.get_env(var).unwrap_or(OsString::new());
@@ -502,15 +506,47 @@ fn add_plugin_deps(rustc: &mut ProcessBuilder,
502506
let output = build_state.get(&key).chain_error(|| {
503507
internal(format!("couldn't find libs for plugin dep {}", id))
504508
})?;
505-
for path in output.library_paths.iter() {
506-
search_path.push(path.clone());
507-
}
509+
search_path.append(&mut filter_dynamic_search_path(output.library_paths.iter(),
510+
root_output));
508511
}
509512
let search_path = join_paths(&search_path, var)?;
510513
rustc.env(var, &search_path);
511514
Ok(())
512515
}
513516

517+
// Determine paths to add to the dynamic search path from -L entries
518+
//
519+
// Strip off prefixes like "native=" or "framework=" and filter out directories
520+
// *not* inside our output directory since they are likely spurious and can cause
521+
// clashes with system shared libraries (issue #3366).
522+
fn filter_dynamic_search_path<'a, I>(paths :I, root_output: &PathBuf) -> Vec<PathBuf>
523+
where I: Iterator<Item=&'a PathBuf> {
524+
let mut search_path = vec![];
525+
for dir in paths {
526+
let dir = match dir.to_str() {
527+
Some(s) => {
528+
let mut parts = s.splitn(2, '=');
529+
match (parts.next(), parts.next()) {
530+
(Some("native"), Some(path)) |
531+
(Some("crate"), Some(path)) |
532+
(Some("dependency"), Some(path)) |
533+
(Some("framework"), Some(path)) |
534+
(Some("all"), Some(path)) => path.into(),
535+
_ => dir.clone(),
536+
}
537+
}
538+
None => dir.clone(),
539+
};
540+
if dir.starts_with(&root_output) {
541+
search_path.push(dir);
542+
} else {
543+
debug!("Not including path {} in runtime library search path because it is \
544+
outside target root {}", dir.display(), root_output.display());
545+
}
546+
}
547+
search_path
548+
}
549+
514550
fn prepare_rustc(cx: &mut Context,
515551
crate_types: Vec<&str>,
516552
unit: &Unit) -> CargoResult<ProcessBuilder> {

tests/build-script.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,7 +1131,15 @@ fn test_dev_dep_build_script() {
11311131

11321132
#[test]
11331133
fn build_script_with_dynamic_native_dependency() {
1134-
let build = project("builder")
1134+
1135+
let workspace = project("ws")
1136+
.file("Cargo.toml", r#"
1137+
[workspace]
1138+
members = ["builder", "foo"]
1139+
"#);
1140+
workspace.build();
1141+
1142+
let build = project("ws/builder")
11351143
.file("Cargo.toml", r#"
11361144
[package]
11371145
name = "builder"
@@ -1147,11 +1155,9 @@ fn build_script_with_dynamic_native_dependency() {
11471155
#[no_mangle]
11481156
pub extern fn foo() {}
11491157
"#);
1150-
assert_that(build.cargo_process("build").arg("-v")
1151-
.env("RUST_LOG", "cargo::ops::cargo_rustc"),
1152-
execs().with_status(0));
1158+
build.build();
11531159

1154-
let foo = project("foo")
1160+
let foo = project("ws/foo")
11551161
.file("Cargo.toml", r#"
11561162
[package]
11571163
name = "foo"
@@ -1180,7 +1186,7 @@ fn build_script_with_dynamic_native_dependency() {
11801186
11811187
fn main() {
11821188
let src = PathBuf::from(env::var("SRC").unwrap());
1183-
println!("cargo:rustc-link-search={}/target/debug/deps",
1189+
println!("cargo:rustc-link-search=native={}/target/debug/deps",
11841190
src.display());
11851191
}
11861192
"#)
@@ -1192,8 +1198,13 @@ fn build_script_with_dynamic_native_dependency() {
11921198
unsafe { foo() }
11931199
}
11941200
"#);
1201+
foo.build();
1202+
1203+
assert_that(build.cargo("build").arg("-v")
1204+
.env("RUST_LOG", "cargo::ops::cargo_rustc"),
1205+
execs().with_status(0));
11951206

1196-
assert_that(foo.cargo_process("build").arg("-v").env("SRC", build.root())
1207+
assert_that(foo.cargo("build").arg("-v").env("SRC", build.root())
11971208
.env("RUST_LOG", "cargo::ops::cargo_rustc"),
11981209
execs().with_status(0));
11991210
}

tests/plugins.rs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,14 @@ fn plugin_to_the_max() {
9090
fn plugin_with_dynamic_native_dependency() {
9191
if !is_nightly() { return }
9292

93-
let build = project("builder")
93+
let workspace = project("ws")
94+
.file("Cargo.toml", r#"
95+
[workspace]
96+
members = ["builder", "foo"]
97+
"#);
98+
workspace.build();
99+
100+
let build = project("ws/builder")
94101
.file("Cargo.toml", r#"
95102
[package]
96103
name = "builder"
@@ -105,16 +112,9 @@ fn plugin_with_dynamic_native_dependency() {
105112
#[no_mangle]
106113
pub extern fn foo() {}
107114
"#);
108-
assert_that(build.cargo_process("build"),
109-
execs().with_status(0));
110-
let src = build.root().join("target/debug");
111-
let lib = fs::read_dir(&src).unwrap().map(|s| s.unwrap().path()).find(|lib| {
112-
let lib = lib.file_name().unwrap().to_str().unwrap();
113-
lib.starts_with(env::consts::DLL_PREFIX) &&
114-
lib.ends_with(env::consts::DLL_SUFFIX)
115-
}).unwrap();
115+
build.build();
116116

117-
let foo = project("foo")
117+
let foo = project("ws/foo")
118118
.file("Cargo.toml", r#"
119119
[package]
120120
name = "foo"
@@ -165,8 +165,19 @@ fn plugin_with_dynamic_native_dependency() {
165165
unsafe { foo() }
166166
}
167167
"#);
168+
foo.build();
169+
170+
assert_that(build.cargo("build"),
171+
execs().with_status(0));
172+
173+
let src = workspace.root().join("target/debug");
174+
let lib = fs::read_dir(&src).unwrap().map(|s| s.unwrap().path()).find(|lib| {
175+
let lib = lib.file_name().unwrap().to_str().unwrap();
176+
lib.starts_with(env::consts::DLL_PREFIX) &&
177+
lib.ends_with(env::consts::DLL_SUFFIX)
178+
}).unwrap();
168179

169-
assert_that(foo.cargo_process("build").env("SRC", &lib).arg("-v"),
180+
assert_that(foo.cargo("build").env("SRC", &lib).arg("-v"),
170181
execs().with_status(0));
171182
}
172183

0 commit comments

Comments
 (0)