Skip to content

Commit

Permalink
support custom targets
Browse files Browse the repository at this point in the history
  • Loading branch information
Jorge Aparicio committed Jan 20, 2017
1 parent adff982 commit 670030a
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 37 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ This project adheres to [Semantic Versioning](https://semver.org/).

## [Unreleased]

### Added

- Support for custom targets. Cross will now also try to use a docker image for
them. As with the built-in targets, one can override the image using
`[target.{}.image]` in Cross.toml.

## [v0.1.7] - 2017-01-19

### Changed
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ use std::env;

use Target;
use cargo::Subcommand;
use rustc::TargetList;

pub struct Args {
pub all: Vec<String>,
pub subcommand: Option<Subcommand>,
pub target: Option<Target>,
}

pub fn parse() -> Args {
pub fn parse(target_list: &TargetList) -> Args {
let all: Vec<_> = env::args().skip(1).collect();

let mut target = None;
Expand All @@ -23,11 +24,11 @@ pub fn parse() -> Args {
}

if arg == "--target" {
target = args.next().map(|s| Target::from(&**s))
target = args.next().map(|s| Target::from(&**s, target_list))
} else if arg.starts_with("--target=") {
target = arg.splitn(2, '=')
.nth(1)
.map(|s| Target::from(&*s))
.map(|s| Target::from(&*s, target_list))
} else if !arg.starts_with('-') && sc.is_none() {
sc = Some(Subcommand::from(&**arg));
}
Expand Down
60 changes: 45 additions & 15 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use toml::{Parser, Value};

use cargo::Root;
use errors::*;
use rustc::TargetList;

#[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq)]
Expand All @@ -40,15 +41,23 @@ impl Host {
/// Checks if this `(host, target)` pair is supported by `cross`
///
/// `target == None` means `target == host`
fn is_supported(&self, target: Option<Target>) -> bool {
fn is_supported(&self, target: Option<&Target>) -> bool {
if *self == Host::X86_64AppleDarwin {
target == Some(Target::I686AppleDarwin)
target.map(|t| *t == Target::I686AppleDarwin).unwrap_or(false)
} else if *self == Host::X86_64UnknownLinuxGnu {
target.map(|t| t.needs_docker()).unwrap_or(true)
} else {
false
}
}

fn triple(&self) -> &'static str {
match *self {
Host::X86_64AppleDarwin => "x86_64-apple-darwin",
Host::X86_64UnknownLinuxGnu => "x86_64-unknown-linux-gnu",
Host::Other => unimplemented!(),
}
}
}

impl<'a> From<&'a str> for Host {
Expand All @@ -62,8 +71,11 @@ impl<'a> From<&'a str> for Host {
}

#[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq)]
#[derive(Clone, PartialEq)]
pub enum Target {
Custom { triple: String },

// Other built-in
Other,

// OSX
Expand Down Expand Up @@ -112,6 +124,13 @@ impl Target {
}
}

fn is_builtin(&self) -> bool {
match *self {
Target::Custom { .. } => false,
_ => true,
}
}

fn is_bsd(&self) -> bool {
match *self {
Target::I686UnknownFreebsd |
Expand Down Expand Up @@ -145,7 +164,8 @@ impl Target {
}

fn needs_docker(&self) -> bool {
self.is_linux() || self.is_bare_metal() || self.is_bsd()
self.is_linux() || self.is_bare_metal() || self.is_bsd() ||
!self.is_builtin()
}

fn needs_qemu(&self) -> bool {
Expand All @@ -155,14 +175,22 @@ impl Target {
Target::I686UnknownLinuxMusl |
Target::X86_64UnknownLinuxGnu |
Target::X86_64UnknownLinuxMusl => false,
Target::Custom { ref triple } => {
!triple.starts_with("x86_64") && !triple.starts_with("x86") &&
!triple.starts_with("i586") &&
!triple.starts_with("i686")
}
_ => true,
}
}

fn triple(&self) -> &'static str {
fn triple(&self) -> &str {
use Target::*;

match *self {
Custom { ref triple } => triple,
Other => unreachable!(),

Aarch64UnknownLinuxGnu => "aarch64-unknown-linux-gnu",
ArmUnknownLinuxGnueabi => "arm-unknown-linux-gnueabi",
Armv7UnknownLinuxGnueabihf => "armv7-unknown-linux-gnueabihf",
Expand All @@ -174,7 +202,6 @@ impl Target {
Mips64elUnknownLinuxGnuabi64 => "mips64el-unknown-linux-gnuabi64",
MipsUnknownLinuxGnu => "mips-unknown-linux-gnu",
MipselUnknownLinuxGnu => "mipsel-unknown-linux-gnu",
Other => unreachable!(),
Powerpc64UnknownLinuxGnu => "powerpc64-unknown-linux-gnu",
Powerpc64leUnknownLinuxGnu => "powerpc64le-unknown-linux-gnu",
PowerpcUnknownLinuxGnu => "powerpc-unknown-linux-gnu",
Expand All @@ -194,15 +221,15 @@ impl Target {
}

fn needs_xargo(&self) -> bool {
self.is_bare_metal()
self.is_bare_metal() || !self.is_builtin()
}
}

impl<'a> From<&'a str> for Target {
fn from(s: &str) -> Target {
impl Target {
fn from(triple: &str, target_list: &TargetList) -> Target {
use Target::*;

match s {
match triple {
"aarch64-unknown-linux-gnu" => Aarch64UnknownLinuxGnu,
"arm-unknown-linux-gnueabi" => ArmUnknownLinuxGnueabi,
"armv7-unknown-linux-gnueabihf" => Armv7UnknownLinuxGnueabihf,
Expand All @@ -229,7 +256,8 @@ impl<'a> From<&'a str> for Target {
"x86_64-unknown-linux-gnu" => X86_64UnknownLinuxGnu,
"x86_64-unknown-linux-musl" => X86_64UnknownLinuxMusl,
"x86_64-unknown-netbsd" => X86_64UnknownNetbsd,
_ => Other,
_ if target_list.contains(triple) => Other,
_ => Custom { triple: triple.to_owned() },
}
}
}
Expand Down Expand Up @@ -281,7 +309,8 @@ pub fn main() {
}

fn run() -> Result<ExitStatus> {
let args = cli::parse();
let target_list = rustc::target_list(false)?;
let args = cli::parse(&target_list);

if args.all.iter().any(|a| a == "--version" || a == "-V") &&
args.subcommand.is_none() {
Expand All @@ -295,8 +324,9 @@ fn run() -> Result<ExitStatus> {
if let Some(root) = cargo::root()? {
let host = rustc::host();

if host.is_supported(args.target) {
let target = args.target.unwrap_or(Target::from(host));
if host.is_supported(args.target.as_ref()) {
let target = args.target
.unwrap_or(Target::from(host.triple(), &target_list));
let toml = toml(&root)?;
let uses_xargo = if let Some(toml) = toml.as_ref() {
toml.xargo(&target)?
Expand All @@ -307,7 +337,7 @@ fn run() -> Result<ExitStatus> {

if !uses_xargo &&
rustup::available_targets(verbose)?.contains(&target) {
rustup::install(target, verbose)?;
rustup::install(&target, verbose)?;
}

if uses_xargo && !rustup::rust_src_is_installed(verbose)? {
Expand Down
19 changes: 19 additions & 0 deletions src/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,29 @@ use Host;
use errors::*;
use extensions::CommandExt;

pub struct TargetList {
triples: Vec<String>,
}

impl TargetList {
pub fn contains(&self, triple: &str) -> bool {
self.triples.iter().any(|t| t == triple)
}
}

pub fn host() -> Host {
Host::from(&*rustc_version::version_meta().host)
}

pub fn target_list(verbose: bool) -> Result<TargetList> {
Command::new("rustc")
.args(&["--print", "target-list"])
.run_and_get_stdout(verbose)
.map(|s| {
TargetList { triples: s.lines().map(|l| l.to_owned()).collect() }
})
}

pub fn sysroot(verbose: bool) -> Result<PathBuf> {
let mut stdout = Command::new("rustc").args(&["--print", "sysroot"])
.run_and_get_stdout(verbose)?;
Expand Down
46 changes: 28 additions & 18 deletions src/rustup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,34 @@ use Target;
use errors::*;
use extensions::CommandExt;

pub fn install(target: Target, verbose: bool) -> Result<()> {
pub struct AvailableTargets {
triples: Vec<String>,
}

impl AvailableTargets {
pub fn contains(&self, target: &Target) -> bool {
let target = target.triple();
self.triples.iter().any(|t| t == target)
}
}

pub fn available_targets(verbose: bool) -> Result<AvailableTargets> {
let out = Command::new("rustup").args(&["target", "list"])
.run_and_get_stdout(verbose)?;

Ok(AvailableTargets {
triples: out.lines()
.filter_map(|line| if line.contains("installed") ||
line.contains("default") {
None
} else {
Some(line.to_owned())
})
.collect(),
})
}

pub fn install(target: &Target, verbose: bool) -> Result<()> {
let target = target.triple();

Command::new("rustup")
Expand All @@ -20,23 +47,6 @@ pub fn install_rust_src(verbose: bool) -> Result<()> {
.chain_err(|| format!("couldn't install the `rust-src` component"))
}

pub fn available_targets(verbose: bool) -> Result<Vec<Target>> {
let out = Command::new("rustup").args(&["target", "list"])
.run_and_get_stdout(verbose)?;

Ok(out.lines()
.filter_map(|line| if line.contains("installed") ||
line.contains("default") {
None
} else {
match Target::from(line) {
Target::Other => None,
t => Some(t),
}
})
.collect())
}

pub fn rust_src_is_installed(verbose: bool) -> Result<bool> {
Ok(Command::new("rustup")
.args(&["component", "list"])
Expand Down

0 comments on commit 670030a

Please sign in to comment.