Skip to content

Commit

Permalink
Fix panic=abort when compiling with plugins
Browse files Browse the repository at this point in the history
Closes #2738
  • Loading branch information
alexcrichton committed Aug 4, 2016
1 parent f4a23e7 commit e9c6b0a
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 1 deletion.
37 changes: 37 additions & 0 deletions src/cargo/ops/cargo_rustc/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub struct Context<'a, 'cfg: 'a> {
pub build_config: BuildConfig,
pub build_scripts: HashMap<Unit<'a>, Arc<BuildScripts>>,
pub links: Links<'a>,
pub used_in_plugin: HashSet<Unit<'a>>,

host: Layout,
target: Option<Layout>,
Expand Down Expand Up @@ -91,6 +92,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
build_scripts: HashMap::new(),
build_explicit_deps: HashMap::new(),
links: Links::new(),
used_in_plugin: HashSet::new(),
})
}

Expand Down Expand Up @@ -235,6 +237,41 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
Ok(())
}

/// Builds up the `used_in_plugin` internal to this context from the list of
/// top-level units.
///
/// This will recursively walk `units` and all of their dependencies to
/// determine which crate are going to be used in plugins or not.
pub fn build_used_in_plugin_map(&mut self, units: &[Unit<'a>])
-> CargoResult<()> {
let mut visited = HashSet::new();
for unit in units {
try!(self.walk_used_in_plugin_map(unit,
unit.target.for_host(),
&mut visited));
}
Ok(())
}

fn walk_used_in_plugin_map(&mut self,
unit: &Unit<'a>,
is_plugin: bool,
visited: &mut HashSet<(Unit<'a>, bool)>)
-> CargoResult<()> {
if !visited.insert((*unit, is_plugin)) {
return Ok(())
}
if is_plugin {
self.used_in_plugin.insert(*unit);
}
for unit in try!(self.dep_targets(unit)) {
try!(self.walk_used_in_plugin_map(&unit,
is_plugin || unit.target.for_host(),
visited));
}
Ok(())
}

/// Returns the appropriate directory layout for either a plugin or not.
pub fn layout(&self, unit: &Unit) -> LayoutProxy {
let primary = unit.pkg.package_id() == self.resolve.root();
Expand Down
15 changes: 14 additions & 1 deletion src/cargo/ops/cargo_rustc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ pub fn compile_targets<'a, 'cfg: 'a>(ws: &Workspace<'cfg>,

try!(cx.prepare());
try!(cx.probe_target_info(&units));
try!(cx.build_used_in_plugin_map(&units));
try!(custom_build::build_map(&mut cx, &units));

for unit in units.iter() {
Expand Down Expand Up @@ -512,8 +513,20 @@ fn build_base_args(cx: &Context,
cmd.arg("-C").arg(&format!("opt-level={}", opt_level));
}

// If a panic mode was configured *and* we're not ever going to be used in a
// plugin, then we can compile with that panic mode.
//
// If we're used in a plugin then we'll eventually be linked to libsyntax
// most likely which isn't compiled with a custom panic mode, so we'll just
// get an error if we actually compile with that. This fixes `panic=abort`
// crates which have plugin dependencies, but unfortunately means that
// dependencies shared between the main application and plugins must be
// compiled without `panic=abort`. This isn't so bad, though, as the main
// application will still be compiled with `panic=abort`.
if let Some(panic) = panic.as_ref() {
cmd.arg("-C").arg(format!("panic={}", panic));
if !cx.used_in_plugin.contains(unit) {
cmd.arg("-C").arg(format!("panic={}", panic));
}
}

// Disable LTO for host builds as prefer_dynamic and it are mutually
Expand Down
90 changes: 90 additions & 0 deletions tests/plugins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,3 +274,93 @@ fn native_plugin_dependency_with_custom_ar_linker() {
[ERROR] could not exec the linker [..]
"));
}

#[test]
fn panic_abort_plugins() {
if !is_nightly() {
return
}

let bar = project("bar")
.file("Cargo.toml", r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[profile.dev]
panic = 'abort'
[dependencies]
foo = { path = "foo" }
"#)
.file("src/lib.rs", "")
.file("foo/Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[lib]
plugin = true
"#)
.file("foo/src/lib.rs", r#"
#![feature(rustc_private)]
extern crate syntax;
"#);

assert_that(bar.cargo_process("build"),
execs().with_status(0));
}

#[test]
fn shared_panic_abort_plugins() {
if !is_nightly() {
return
}

let bar = project("top")
.file("Cargo.toml", r#"
[package]
name = "top"
version = "0.0.1"
authors = []
[profile.dev]
panic = 'abort'
[dependencies]
foo = { path = "foo" }
bar = { path = "bar" }
"#)
.file("src/lib.rs", "
extern crate bar;
")
.file("foo/Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[lib]
plugin = true
[dependencies]
bar = { path = "../bar" }
"#)
.file("foo/src/lib.rs", r#"
#![feature(rustc_private)]
extern crate syntax;
extern crate bar;
"#)
.file("bar/Cargo.toml", r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
"#)
.file("bar/src/lib.rs", "");

assert_that(bar.cargo_process("build"),
execs().with_status(0));
}

0 comments on commit e9c6b0a

Please sign in to comment.