Skip to content

Commit

Permalink
Auto merge of #5628 - ehuss:metabuild, r=alexcrichton
Browse files Browse the repository at this point in the history
Metabuild (RFC 2196)
  • Loading branch information
bors committed Aug 24, 2018
2 parents 3ce6527 + ecc87b1 commit 90fc9f6
Show file tree
Hide file tree
Showing 13 changed files with 974 additions and 48 deletions.
36 changes: 36 additions & 0 deletions src/cargo/core/compiler/custom_build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoRes
let build_plan = bcx.build_config.build_plan;
let invocation_name = unit.buildkey();

if let Some(deps) = unit.pkg.manifest().metabuild() {
prepare_metabuild(cx, build_script_unit, deps)?;
}

// Building the command to execute
let to_exec = script_output.join(unit.target.name());

Expand Down Expand Up @@ -532,6 +536,38 @@ impl BuildOutput {
}
}

fn prepare_metabuild<'a, 'cfg>(
cx: &Context<'a, 'cfg>,
unit: &Unit<'a>,
deps: &[String],
) -> CargoResult<()> {
let mut output = Vec::new();
let available_deps = cx.dep_targets(unit);
// Filter out optional dependencies, and look up the actual lib name.
let meta_deps: Vec<_> = deps
.iter()
.filter_map(|name| {
available_deps
.iter()
.find(|u| u.pkg.name().as_str() == name.as_str())
.map(|dep| dep.target.crate_name())
})
.collect();
for dep in &meta_deps {
output.push(format!("extern crate {};\n", dep));
}
output.push("fn main() {\n".to_string());
for dep in &meta_deps {
output.push(format!(" {}::metabuild();\n", dep));
}
output.push("}\n".to_string());
let output = output.join("");
let path = unit.pkg.manifest().metabuild_path(cx.bcx.ws.target_dir());
fs::create_dir_all(path.parent().unwrap())?;
paths::write_if_changed(path, &output)?;
Ok(())
}

impl BuildDeps {
pub fn new(output_file: &Path, output: Option<&BuildOutput>) -> BuildDeps {
BuildDeps {
Expand Down
20 changes: 15 additions & 5 deletions src/cargo/core/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use std::sync::Arc;
use same_file::is_same_file;
use serde_json;

use core::manifest::TargetSourcePath;
use core::profiles::{Lto, Profile};
use core::shell::ColorChoice;
use core::{PackageId, Target};
Expand Down Expand Up @@ -390,7 +391,6 @@ fn link_targets<'a, 'cfg>(
let outputs = cx.outputs(unit)?;
let export_dir = cx.files().export_dir();
let package_id = unit.pkg.package_id().clone();
let target = unit.target.clone();
let profile = unit.profile;
let unit_mode = unit.mode;
let features = bcx.resolve
Expand All @@ -399,6 +399,12 @@ fn link_targets<'a, 'cfg>(
.map(|s| s.to_owned())
.collect();
let json_messages = bcx.build_config.json_messages();
let mut target = unit.target.clone();
if let TargetSourcePath::Metabuild = target.src_path() {
// Give it something to serialize.
let path = unit.pkg.manifest().metabuild_path(cx.bcx.ws.target_dir());
target.set_src_path(TargetSourcePath::Path(path));
}

Ok(Work::new(move |_| {
// If we're a "root crate", e.g. the target of this compilation, then we
Expand Down Expand Up @@ -668,12 +674,16 @@ fn rustdoc<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoResult
// second is the cwd that rustc should operate in.
fn path_args(bcx: &BuildContext, unit: &Unit) -> (PathBuf, PathBuf) {
let ws_root = bcx.ws.root();
let src = unit.target.src_path();
let src = if unit.target.is_custom_build() && unit.pkg.manifest().metabuild().is_some() {
unit.pkg.manifest().metabuild_path(bcx.ws.target_dir())
} else {
unit.target.src_path().path().to_path_buf()
};
assert!(src.is_absolute());
match src.strip_prefix(ws_root) {
Ok(path) => (path.to_path_buf(), ws_root.to_path_buf()),
Err(_) => (src.to_path_buf(), unit.pkg.root().to_path_buf()),
if let Ok(path) = src.strip_prefix(ws_root) {
return (path.to_path_buf(), ws_root.to_path_buf());
}
(src, unit.pkg.root().to_path_buf())
}

fn add_path_args(bcx: &BuildContext, unit: &Unit, cmd: &mut ProcessBuilder) {
Expand Down
3 changes: 3 additions & 0 deletions src/cargo/core/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ features! {

// "default-run" manifest option,
[unstable] default_run: bool,

// Declarative build scripts.
[unstable] metabuild: bool,
}
}

Expand Down
140 changes: 106 additions & 34 deletions src/cargo/core/manifest.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#![allow(deprecated)] // for SipHasher

use std::collections::{BTreeMap, HashMap};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::hash::{Hash, Hasher, SipHasher};
use std::path::{Path, PathBuf};
use std::rc::Rc;

Expand All @@ -15,7 +17,7 @@ use core::{Dependency, PackageId, PackageIdSpec, SourceId, Summary};
use core::{Edition, Feature, Features, WorkspaceConfig};
use util::errors::*;
use util::toml::TomlManifest;
use util::Config;
use util::{Config, Filesystem};

pub enum EitherManifest {
Real(Manifest),
Expand Down Expand Up @@ -44,6 +46,7 @@ pub struct Manifest {
edition: Edition,
im_a_teapot: Option<bool>,
default_run: Option<String>,
metabuild: Option<Vec<String>>,
}

/// When parsing `Cargo.toml`, some warnings should silenced
Expand Down Expand Up @@ -190,7 +193,7 @@ pub struct Target {
// as it's absolute currently and is otherwise a little too brittle for
// causing rebuilds. Instead the hash for the path that we send to the
// compiler is handled elsewhere.
src_path: NonHashedPathBuf,
src_path: TargetSourcePath,
required_features: Option<Vec<String>>,
tested: bool,
benched: bool,
Expand All @@ -202,19 +205,50 @@ pub struct Target {
}

#[derive(Clone, PartialEq, Eq)]
struct NonHashedPathBuf {
path: PathBuf,
pub enum TargetSourcePath {
Path(PathBuf),
Metabuild,
}

impl Hash for NonHashedPathBuf {
impl TargetSourcePath {
pub fn path(&self) -> &Path {
match self {
TargetSourcePath::Path(path) => path.as_ref(),
TargetSourcePath::Metabuild => panic!("metabuild not expected"),
}
}

pub fn is_path(&self) -> bool {
match self {
TargetSourcePath::Path(_) => true,
_ => false,
}
}
}

impl Hash for TargetSourcePath {
fn hash<H: Hasher>(&self, _: &mut H) {
// ...
}
}

impl fmt::Debug for NonHashedPathBuf {
impl fmt::Debug for TargetSourcePath {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.path.fmt(f)
match self {
TargetSourcePath::Path(path) => path.fmt(f),
TargetSourcePath::Metabuild => "metabuild".fmt(f),
}
}
}

impl From<PathBuf> for TargetSourcePath {
fn from(path: PathBuf) -> Self {
assert!(
path.is_absolute(),
"`{}` is not absolute",
path.display()
);
TargetSourcePath::Path(path)
}
}

Expand All @@ -239,7 +273,7 @@ impl ser::Serialize for Target {
kind: &self.kind,
crate_types: self.rustc_crate_types(),
name: &self.name,
src_path: &self.src_path.path,
src_path: &self.src_path.path().to_path_buf(),
edition: &self.edition.to_string(),
required_features: self
.required_features
Expand All @@ -253,34 +287,43 @@ compact_debug! {
impl fmt::Debug for Target {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (default, default_name) = {
let src = self.src_path().to_path_buf();
match &self.kind {
TargetKind::Lib(kinds) => {
(
Target::lib_target(
&self.name,
kinds.clone(),
src.clone(),
Edition::Edition2015,
self.src_path().path().to_path_buf(),
self.edition,
),
format!("lib_target({:?}, {:?}, {:?})",
self.name, kinds, src),
format!("lib_target({:?}, {:?}, {:?}, {:?})",
self.name, kinds, self.src_path, self.edition),
)
}
TargetKind::CustomBuild => {
(
Target::custom_build_target(
&self.name,
src.clone(),
Edition::Edition2015,
),
format!("custom_build_target({:?}, {:?})",
self.name, src),
)
match self.src_path {
TargetSourcePath::Path(ref path) => {
(
Target::custom_build_target(
&self.name,
path.to_path_buf(),
self.edition,
),
format!("custom_build_target({:?}, {:?}, {:?})",
self.name, path, self.edition),
)
}
TargetSourcePath::Metabuild => {
(
Target::metabuild_target(&self.name),
format!("metabuild_target({:?})", self.name),
)
}
}
}
_ => (
Target::with_path(src.clone(), Edition::Edition2015),
format!("with_path({:?})", src),
Target::new(self.src_path.clone(), self.edition),
format!("with_path({:?}, {:?})", self.src_path, self.edition),
),
}
};
Expand Down Expand Up @@ -321,6 +364,7 @@ impl Manifest {
im_a_teapot: Option<bool>,
default_run: Option<String>,
original: Rc<TomlManifest>,
metabuild: Option<Vec<String>>,
) -> Manifest {
Manifest {
summary,
Expand All @@ -342,6 +386,7 @@ impl Manifest {
im_a_teapot,
default_run,
publish_lockfile,
metabuild,
}
}

Expand Down Expand Up @@ -464,6 +509,20 @@ impl Manifest {
pub fn default_run(&self) -> Option<&str> {
self.default_run.as_ref().map(|s| &s[..])
}

pub fn metabuild(&self) -> Option<&Vec<String>> {
self.metabuild.as_ref()
}

pub fn metabuild_path(&self, target_dir: Filesystem) -> PathBuf {
let mut hasher = SipHasher::new_with_keys(0, 0);
self.package_id().hash(&mut hasher);
let hash = hasher.finish();
target_dir
.into_path_unlocked()
.join(".metabuild")
.join(format!("metabuild-{}-{:016x}.rs", self.name(), hash))
}
}

impl VirtualManifest {
Expand Down Expand Up @@ -508,16 +567,11 @@ impl VirtualManifest {
}

impl Target {
fn with_path(src_path: PathBuf, edition: Edition) -> Target {
assert!(
src_path.is_absolute(),
"`{}` is not absolute",
src_path.display()
);
fn new(src_path: TargetSourcePath, edition: Edition) -> Target {
Target {
kind: TargetKind::Bin,
name: String::new(),
src_path: NonHashedPathBuf { path: src_path },
src_path,
required_features: None,
doc: false,
doctest: false,
Expand All @@ -529,6 +583,10 @@ impl Target {
}
}

fn with_path(src_path: PathBuf, edition: Edition) -> Target {
Target::new(TargetSourcePath::from(src_path), edition)
}

pub fn lib_target(
name: &str,
crate_targets: Vec<LibKind>,
Expand Down Expand Up @@ -575,6 +633,17 @@ impl Target {
}
}

pub fn metabuild_target(name: &str) -> Target {
Target {
kind: TargetKind::CustomBuild,
name: name.to_string(),
for_host: true,
benched: false,
tested: false,
..Target::new(TargetSourcePath::Metabuild, Edition::Edition2015)
}
}

pub fn example_target(
name: &str,
crate_targets: Vec<LibKind>,
Expand Down Expand Up @@ -634,8 +703,11 @@ impl Target {
pub fn crate_name(&self) -> String {
self.name.replace("-", "_")
}
pub fn src_path(&self) -> &Path {
&self.src_path.path
pub fn src_path(&self) -> &TargetSourcePath {
&self.src_path
}
pub fn set_src_path(&mut self, src_path: TargetSourcePath) {
self.src_path = src_path;
}
pub fn required_features(&self) -> Option<&Vec<String>> {
self.required_features.as_ref()
Expand Down
Loading

0 comments on commit 90fc9f6

Please sign in to comment.