Skip to content

Commit

Permalink
Make serde optional with a feature;
Browse files Browse the repository at this point in the history
Host target is determined through a lookup from the host's name, or a
JSON target's descriptor path passed to the TARGET environment variable.
Make the second part of this feature optional by hiding it behind a
feature, on by default, but that can be disabled.
  • Loading branch information
bnjbvr committed Oct 22, 2019
1 parent dacf0ee commit fb10c91
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 64 deletions.
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ failure = { version = "0.1.3", default-features = false, features = ["derive"] }
failure_derive = { version = "0.1.3", default-features = false }

[build-dependencies]
serde_json = "1.0"
serde_json = { version = "1.0", optional = true }

[features]
default = ["enable-serde"]
enable-serde = ["serde_json"]

[badges]
maintenance = { status = "passively-maintained" }
Expand Down
146 changes: 83 additions & 63 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
// Allow dead code in triple.rs and targets.rs for our purposes here.
#![allow(dead_code)]

use serde_json::Value;
use std::env;
use std::ffi::OsString;
use std::fs::{self, File};
use std::fs::File;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::path::PathBuf;
use std::str::FromStr;

extern crate alloc;

#[cfg(feature = "enable-serde")]
extern crate serde_json;

// Include triple.rs and targets.rs so we can parse the TARGET environment variable.
Expand All @@ -36,64 +36,89 @@ mod parse_error {
}
}

use self::triple::{Endianness, PointerWidth, Triple};

/// Assuming `target` is a path to a custom target json config file, open it
/// and build a `Triple` using its contents.
fn read_target_from_file(path: &Path) -> Triple {
let json = fs::read_to_string(path).expect("error reading target file");

let v: Value = serde_json::from_str(&json).expect("error parsing target file as json");
let target = v["llvm-target"]
.as_str()
.expect("error parsing \"llvm-target\" as a string");
let triple = Triple::from_str(target).expect("error parsing host target");

// Check that the JSON describes a known target configuration.
//
// Unfortunately, none of Rust's "arch", "os", "env", nor "vendor"
// fields directly correspond to triple fields, so we can't easily
// check them.
if let Some(endian) = v["target-endian"].as_str() {
assert_eq!(
endian,
match triple.endianness().unwrap() {
Endianness::Little => "little",
Endianness::Big => "big",
},
"\"target-endian\" field disagrees with the target triple"
);
use self::triple::Triple;

#[cfg(feature = "enable-serde")]
fn triple_from_target(target: &str) -> Triple {
use self::triple::{Endianness, PointerWidth};
use serde_json::Value;
use std::ffi::OsString;
use std::fs;
use std::path::Path;

/// Assuming `target` is a path to a custom target json config file, open it
/// and build a `Triple` using its contents.
fn read_target_from_file(path: &Path) -> Triple {
let json = fs::read_to_string(path).expect("error reading target file");

let v: Value = serde_json::from_str(&json).expect("error parsing target file as json");
let target = v["llvm-target"]
.as_str()
.expect("error parsing \"llvm-target\" as a string");
let triple = Triple::from_str(target).expect("error parsing host target");

// Check that the JSON describes a known target configuration.
//
// Unfortunately, none of Rust's "arch", "os", "env", nor "vendor"
// fields directly correspond to triple fields, so we can't easily
// check them.
if let Some(endian) = v["target-endian"].as_str() {
assert_eq!(
endian,
match triple.endianness().unwrap() {
Endianness::Little => "little",
Endianness::Big => "big",
},
"\"target-endian\" field disagrees with the target triple"
);
}
if let Some(pointer_width) = v["target-pointer-width"].as_str() {
assert_eq!(
pointer_width,
match triple.pointer_width().unwrap() {
PointerWidth::U16 => "16",
PointerWidth::U32 => "32",
PointerWidth::U64 => "64",
},
"\"target-pointer-width\" field disagrees with the target triple"
);
}

triple
}
if let Some(pointer_width) = v["target-pointer-width"].as_str() {
assert_eq!(
pointer_width,
match triple.pointer_width().unwrap() {
PointerWidth::U16 => "16",
PointerWidth::U32 => "32",
PointerWidth::U64 => "64",
},
"\"target-pointer-width\" field disagrees with the target triple"
);

/// Assuming `target` is a target identifier, search for an appropriate custom
/// target json config file in the way that rustc does, and then call
/// `read_target_from_file` on that.
fn read_target_from_file_in_path(target: &str) -> Triple {
let mut target_filename = target.to_owned();
target_filename.push_str(".json");
let target_basename = PathBuf::from(target_filename);
let target_path = env::var_os("RUST_TARGET_PATH").unwrap_or_else(|| OsString::new());
for dir in env::split_paths(&target_path) {
let p = dir.join(&target_basename);
if p.is_file() {
return read_target_from_file(&p);
}
}
panic!("can't find custom target {}", target);
}

triple
// The following intends to match the logic in rustc.
if target.ends_with(".json") {
read_target_from_file(Path::new(&target))
} else {
Triple::from_str(&target).unwrap_or_else(|_| read_target_from_file_in_path(&target))
}
}

/// Assuming `target` is a target identifier, search for an appropriate custom
/// target json config file in the way that rustc does, and then call
/// `read_target_from_file` on that.
fn read_target_from_file_in_path(target: &str) -> Triple {
let mut target_filename = target.to_owned();
target_filename.push_str(".json");
let target_basename = PathBuf::from(target_filename);
let target_path = env::var_os("RUST_TARGET_PATH").unwrap_or_else(|| OsString::new());
for dir in env::split_paths(&target_path) {
let p = dir.join(&target_basename);
if p.is_file() {
return read_target_from_file(&p);
}
}
panic!("can't find custom target {}", target);
#[cfg(not(feature = "enable-serde"))]
fn triple_from_target(target: &str) -> Triple {
Triple::from_str(&target).expect(&format!(
"Invalid target name: '{}'. Use the
enable-serde feature to fallback on JSON Rust targets descriptors.",
target
))
}

fn main() {
Expand All @@ -102,12 +127,7 @@ fn main() {

let target = env::var("TARGET").expect("The TARGET environment variable must be set");

// The following intends to match the logic in rustc.
let triple = if target.ends_with(".json") {
read_target_from_file(Path::new(&target))
} else {
Triple::from_str(&target).unwrap_or_else(|_| read_target_from_file_in_path(&target))
};
let triple = triple_from_target(&target);

let out = File::create(out_dir.join("host.rs")).expect("error creating host.rs");
write_host_rs(out, triple).expect("error writing host.rs");
Expand Down

0 comments on commit fb10c91

Please sign in to comment.