Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support cross compiling to triples without dylibs #469

Merged
merged 1 commit into from
Sep 3, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 33 additions & 17 deletions src/cargo/ops/cargo_rustc/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::str;

use core::{SourceMap, Package, PackageId, PackageSet, Resolve, Target};
use util::{mod, CargoResult, ChainError, internal, Config, profile, Require};
use util::human;

use super::{Kind, KindPlugin, KindTarget, Compilation};
use super::layout::{Layout, LayoutProxy};
Expand All @@ -26,9 +27,10 @@ pub struct Context<'a, 'b> {
host: Layout,
target: Option<Layout>,
target_triple: String,
host_dylib: (String, String),
host_triple: String,
host_dylib: Option<(String, String)>,
package_set: &'a PackageSet,
target_dylib: (String, String),
target_dylib: Option<(String, String)>,
target_exe: String,
requirements: HashMap<(&'a PackageId, &'a str), PlatformRequirement>,
}
Expand All @@ -48,10 +50,11 @@ impl<'a, 'b> Context<'a, 'b> {
};
let (rustc_version, rustc_host) = try!(Context::rustc_version());
let target_triple = config.target().map(|s| s.to_string());
let target_triple = target_triple.unwrap_or(rustc_host);
let target_triple = target_triple.unwrap_or(rustc_host.clone());
Ok(Context {
rustc_version: rustc_version,
target_triple: target_triple,
host_triple: rustc_host,
env: env,
host: host,
target: target,
Expand Down Expand Up @@ -93,7 +96,7 @@ impl<'a, 'b> Context<'a, 'b> {
/// Run `rustc` to discover the dylib prefix/suffix for the target
/// specified as well as the exe suffix
fn filename_parts(target: Option<&str>)
-> CargoResult<((String, String), String)> {
-> CargoResult<(Option<(String, String)>, String)> {
let process = util::process("rustc")
.arg("-")
.arg("--crate-name").arg("-")
Expand All @@ -106,17 +109,22 @@ impl<'a, 'b> Context<'a, 'b> {
};
let output = try!(process.exec_with_output());

let error = str::from_utf8(output.error.as_slice()).unwrap();
let output = str::from_utf8(output.output.as_slice()).unwrap();
let mut lines = output.lines();
let dylib_parts: Vec<&str> = lines.next().unwrap().trim()
.split('-').collect();
assert!(dylib_parts.len() == 2,
"rustc --print-file-name output has changed");
let dylib = if error.contains("dropping unsupported crate type `dylib`") {
None
} else {
let dylib_parts: Vec<&str> = lines.next().unwrap().trim()
.split('-').collect();
assert!(dylib_parts.len() == 2,
"rustc --print-file-name output has changed");
Some((dylib_parts[0].to_string(), dylib_parts[1].to_string()))
};

let exe_suffix = lines.next().unwrap().trim()
.split('-').skip(1).next().unwrap().to_string();

Ok(((dylib_parts[0].to_string(), dylib_parts[1].to_string()),
exe_suffix.to_string()))
Ok((dylib, exe_suffix.to_string()))
}

/// Prepare this context, ensuring that all filesystem directories are in
Expand Down Expand Up @@ -193,9 +201,17 @@ impl<'a, 'b> Context<'a, 'b> {
///
/// If `plugin` is true, the pair corresponds to the host platform,
/// otherwise it corresponds to the target platform.
fn dylib(&self, kind: Kind) -> (&str, &str) {
let pair = if kind == KindPlugin {&self.host_dylib} else {&self.target_dylib};
(pair.ref0().as_slice(), pair.ref1().as_slice())
fn dylib(&self, kind: Kind) -> CargoResult<(&str, &str)> {
let (triple, pair) = if kind == KindPlugin {
(&self.host_triple, &self.host_dylib)
} else {
(&self.target_triple, &self.target_dylib)
};
match *pair {
None => return Err(human(format!("dylib outputs are not supported \
for {}", triple))),
Some((ref s1, ref s2)) => Ok((s1.as_slice(), s2.as_slice())),
}
}

/// Return the target triple which this context is targeting.
Expand All @@ -204,7 +220,7 @@ impl<'a, 'b> Context<'a, 'b> {
}

/// Return the exact filename of the target.
pub fn target_filenames(&self, target: &Target) -> Vec<String> {
pub fn target_filenames(&self, target: &Target) -> CargoResult<Vec<String>> {
let stem = target.file_stem();

let mut ret = Vec::new();
Expand All @@ -214,7 +230,7 @@ impl<'a, 'b> Context<'a, 'b> {
if target.is_dylib() {
let plugin = target.get_profile().is_plugin();
let kind = if plugin {KindPlugin} else {KindTarget};
let (prefix, suffix) = self.dylib(kind);
let (prefix, suffix) = try!(self.dylib(kind));
ret.push(format!("{}{}{}", prefix, stem, suffix));
}
if target.is_rlib() {
Expand All @@ -225,7 +241,7 @@ impl<'a, 'b> Context<'a, 'b> {
}
}
assert!(ret.len() > 0);
return ret;
return Ok(ret);
}

/// For a package, return all targets which are registered as dependencies
Expand Down
2 changes: 1 addition & 1 deletion src/cargo/ops/cargo_rustc/fingerprint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ pub fn prepare_target(cx: &mut Context, pkg: &Package, target: &Target,
if !target.get_profile().is_doc() {
pairs.push((old_dep_info, new_dep_info));

for filename in cx.target_filenames(target).iter() {
for filename in try!(cx.target_filenames(target)).iter() {
let filename = filename.as_slice();
let dst = root.join(filename);
pairs.push((old_root.join(filename), root.join(filename)));
Expand Down
50 changes: 28 additions & 22 deletions src/cargo/ops/cargo_rustc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,10 @@ fn compile<'a, 'b>(targets: &[&'a Target], pkg: &'a Package,
let (mut libs, mut bins) = (Vec::new(), Vec::new());
for &target in targets.iter() {
let work = if target.get_profile().is_doc() {
vec![(rustdoc(pkg, target, cx), KindTarget)]
vec![(try!(rustdoc(pkg, target, cx)), KindTarget)]
} else {
let req = cx.get_requirement(pkg, target);
rustc(pkg, target, cx, req)
try!(rustc(pkg, target, cx, req))
};

let dst = if target.is_lib() {&mut libs} else {&mut bins};
Expand Down Expand Up @@ -188,15 +188,16 @@ fn compile_custom(pkg: &Package, cmd: &str,
}

fn rustc(package: &Package, target: &Target,
cx: &mut Context, req: PlatformRequirement) -> Vec<(Work, Kind)> {
cx: &mut Context, req: PlatformRequirement)
-> CargoResult<Vec<(Work, Kind)> >{
let crate_types = target.rustc_crate_types();
let root = package.get_root();

log!(5, "root={}; target={}; crate_types={}; verbose={}; req={}",
root.display(), target, crate_types, cx.primary, req);

let primary = cx.primary;
let rustcs = prepare_rustc(package, target, crate_types, cx, req);
let rustcs = try!(prepare_rustc(package, target, crate_types, cx, req));

let _ = cx.config.shell().verbose(|shell| {
for &(ref rustc, _) in rustcs.iter() {
Expand All @@ -205,7 +206,7 @@ fn rustc(package: &Package, target: &Target,
Ok(())
});

rustcs.move_iter().map(|(rustc, kind)| {
Ok(rustcs.move_iter().map(|(rustc, kind)| {
let name = package.get_name().to_string();

(proc() {
Expand All @@ -223,40 +224,43 @@ fn rustc(package: &Package, target: &Target,
}
Ok(())
}, kind)
}).collect()
}).collect())
}

fn prepare_rustc(package: &Package, target: &Target, crate_types: Vec<&str>,
cx: &Context, req: PlatformRequirement)
-> Vec<(ProcessBuilder, Kind)> {
-> CargoResult<Vec<(ProcessBuilder, Kind)>> {
let base = process("rustc", package, cx);
let base = build_base_args(base, target, crate_types.as_slice());

let target_cmd = build_plugin_args(base.clone(), cx, package, target, KindTarget);
let plugin_cmd = build_plugin_args(base, cx, package, target, KindPlugin);
let target_cmd = build_deps_args(target_cmd, target, package, cx, KindTarget);
let plugin_cmd = build_deps_args(plugin_cmd, target, package, cx, KindPlugin);
let target_cmd = try!(build_deps_args(target_cmd, target, package, cx,
KindTarget));
let plugin_cmd = try!(build_deps_args(plugin_cmd, target, package, cx,
KindPlugin));

match req {
Ok(match req {
Target => vec![(target_cmd, KindTarget)],
Plugin => vec![(plugin_cmd, KindPlugin)],
PluginAndTarget if cx.config.target().is_none() =>
vec![(target_cmd, KindTarget)],
PluginAndTarget => vec![(target_cmd, KindTarget),
(plugin_cmd, KindPlugin)],
}
})
}


fn rustdoc(package: &Package, target: &Target, cx: &mut Context) -> Work {
fn rustdoc(package: &Package, target: &Target,
cx: &mut Context) -> CargoResult<Work> {
let kind = KindTarget;
let pkg_root = package.get_root();
let cx_root = cx.layout(kind).proxy().dest().join("doc");
let rustdoc = process("rustdoc", package, cx).cwd(pkg_root.clone());
let rustdoc = rustdoc.arg(target.get_src_path())
.arg("-o").arg(cx_root)
.arg("--crate-name").arg(target.get_name());
let rustdoc = build_deps_args(rustdoc, target, package, cx, kind);
let rustdoc = try!(build_deps_args(rustdoc, target, package, cx, kind));

log!(5, "commands={}", rustdoc);

Expand All @@ -266,7 +270,7 @@ fn rustdoc(package: &Package, target: &Target, cx: &mut Context) -> Work {

let primary = cx.primary;
let name = package.get_name().to_string();
proc() {
Ok(proc() {
if primary {
try!(rustdoc.exec().chain_error(|| {
human(format!("Could not document `{}`.", name))
Expand All @@ -278,7 +282,7 @@ fn rustdoc(package: &Package, target: &Target, cx: &mut Context) -> Work {
}))
}
Ok(())
}
})
}

fn build_base_args(mut cmd: ProcessBuilder,
Expand Down Expand Up @@ -355,7 +359,8 @@ fn build_plugin_args(mut cmd: ProcessBuilder, cx: &Context, pkg: &Package,
}

fn build_deps_args(mut cmd: ProcessBuilder, target: &Target, package: &Package,
cx: &Context, kind: Kind) -> ProcessBuilder {
cx: &Context,
kind: Kind) -> CargoResult<ProcessBuilder> {
enum LinkReason { Dependency, LocalLib }

let layout = cx.layout(kind);
Expand All @@ -367,7 +372,7 @@ fn build_deps_args(mut cmd: ProcessBuilder, target: &Target, package: &Package,
cmd = push_native_dirs(cmd, &layout, package, cx, &mut HashSet::new());

for &(_, target) in cx.dep_targets(package).iter() {
cmd = link_to(cmd, target, cx, kind, Dependency);
cmd = try!(link_to(cmd, target, cx, kind, Dependency));
}

let mut targets = package.get_targets().iter().filter(|target| {
Expand All @@ -376,14 +381,15 @@ fn build_deps_args(mut cmd: ProcessBuilder, target: &Target, package: &Package,

if target.is_bin() {
for target in targets {
cmd = link_to(cmd, target, cx, kind, LocalLib);
cmd = try!(link_to(cmd, target, cx, kind, LocalLib));
}
}

return cmd;
return Ok(cmd);

fn link_to(mut cmd: ProcessBuilder, target: &Target,
cx: &Context, kind: Kind, reason: LinkReason) -> ProcessBuilder {
cx: &Context, kind: Kind,
reason: LinkReason) -> CargoResult<ProcessBuilder> {
// If this target is itself a plugin *or* if it's being linked to a
// plugin, then we want the plugin directory. Otherwise we want the
// target directory (hence the || here).
Expand All @@ -393,7 +399,7 @@ fn build_deps_args(mut cmd: ProcessBuilder, target: &Target, package: &Package,
KindTarget => KindTarget,
});

for filename in cx.target_filenames(target).iter() {
for filename in try!(cx.target_filenames(target)).iter() {
let mut v = Vec::new();
v.push_all(target.get_name().as_bytes());
v.push(b'=');
Expand All @@ -405,7 +411,7 @@ fn build_deps_args(mut cmd: ProcessBuilder, target: &Target, package: &Package,
v.push_all(filename.as_bytes());
cmd = cmd.arg("--extern").arg(v.as_slice());
}
return cmd;
return Ok(cmd);
}

fn push_native_dirs(mut cmd: ProcessBuilder, layout: &layout::LayoutProxy,
Expand Down
19 changes: 19 additions & 0 deletions tests/test_cargo_cross_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,3 +456,22 @@ test!(simple_cargo_run {
assert_that(p.cargo_process("run").arg("--target").arg(target),
execs().with_status(0));
})

test!(cross_but_no_dylibs {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.0"
authors = []

[lib]
name = "foo"
crate-type = ["dylib"]
"#)
.file("src/lib.rs", "");
assert_that(p.cargo_process("build").arg("--target").arg("arm-apple-ios"),
execs().with_status(101)
.with_stderr("dylib outputs are not supported for \
arm-apple-ios"));
})