-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of #5301 - mshal:build-plan, r=matklad
Add --build-plan for 'cargo build' With 'cargo build --build-plan', cargo does not actually run any commands, but instead prints out what it would have done in the form of a JSON data structure. Fixes #3815
- Loading branch information
Showing
11 changed files
with
548 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
//! A graph-like structure used to represent the rustc commands to build the project and the | ||
//! interdependencies between them. | ||
//! | ||
//! The BuildPlan structure is used to store the dependency graph of a dry run so that it can be | ||
//! shared with an external build system. Each Invocation in the BuildPlan comprises a single | ||
//! subprocess and defines the build environment, the outputs produced by the subprocess, and the | ||
//! dependencies on other Invocations. | ||
use std::collections::BTreeMap; | ||
|
||
use core::TargetKind; | ||
use super::{Context, Kind, Unit}; | ||
use super::context::OutputFile; | ||
use util::{internal, CargoResult, ProcessBuilder}; | ||
use std::sync::Arc; | ||
use std::path::PathBuf; | ||
use serde_json; | ||
use semver; | ||
|
||
#[derive(Debug, Serialize)] | ||
struct Invocation { | ||
package_name: String, | ||
package_version: semver::Version, | ||
target_kind: TargetKind, | ||
kind: Kind, | ||
deps: Vec<usize>, | ||
outputs: Vec<PathBuf>, | ||
links: BTreeMap<PathBuf, PathBuf>, | ||
program: String, | ||
args: Vec<String>, | ||
env: BTreeMap<String, String>, | ||
cwd: Option<PathBuf>, | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct BuildPlan { | ||
invocation_map: BTreeMap<String, usize>, | ||
plan: SerializedBuildPlan, | ||
} | ||
|
||
#[derive(Debug, Serialize)] | ||
struct SerializedBuildPlan { | ||
invocations: Vec<Invocation>, | ||
inputs: Vec<PathBuf>, | ||
} | ||
|
||
impl Invocation { | ||
pub fn new(unit: &Unit, deps: Vec<usize>) -> Invocation { | ||
let id = unit.pkg.package_id(); | ||
Invocation { | ||
package_name: id.name().to_string(), | ||
package_version: id.version().clone(), | ||
kind: unit.kind, | ||
target_kind: unit.target.kind().clone(), | ||
deps: deps, | ||
outputs: Vec::new(), | ||
links: BTreeMap::new(), | ||
program: String::new(), | ||
args: Vec::new(), | ||
env: BTreeMap::new(), | ||
cwd: None, | ||
} | ||
} | ||
|
||
pub fn add_output(&mut self, path: &PathBuf, link: &Option<PathBuf>) { | ||
self.outputs.push(path.clone()); | ||
if let Some(ref link) = *link { | ||
self.links.insert(link.clone(), path.clone()); | ||
} | ||
} | ||
|
||
pub fn update_cmd(&mut self, cmd: ProcessBuilder) -> CargoResult<()> { | ||
self.program = cmd.get_program() | ||
.to_str() | ||
.ok_or_else(|| format_err!("unicode program string required"))? | ||
.to_string(); | ||
self.cwd = Some(cmd.get_cwd().unwrap().to_path_buf()); | ||
for arg in cmd.get_args().iter() { | ||
self.args.push( | ||
arg.to_str() | ||
.ok_or_else(|| format_err!("unicode argument string required"))? | ||
.to_string(), | ||
); | ||
} | ||
for (var, value) in cmd.get_envs() { | ||
let value = match value { | ||
Some(s) => s, | ||
None => continue, | ||
}; | ||
self.env.insert( | ||
var.clone(), | ||
value | ||
.to_str() | ||
.ok_or_else(|| format_err!("unicode environment value required"))? | ||
.to_string(), | ||
); | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl BuildPlan { | ||
pub fn new() -> BuildPlan { | ||
BuildPlan { | ||
invocation_map: BTreeMap::new(), | ||
plan: SerializedBuildPlan::new(), | ||
} | ||
} | ||
|
||
pub fn add(&mut self, cx: &Context, unit: &Unit) -> CargoResult<()> { | ||
let id = self.plan.invocations.len(); | ||
self.invocation_map.insert(unit.buildkey(), id); | ||
let deps = cx.dep_targets(&unit) | ||
.iter() | ||
.map(|dep| self.invocation_map[&dep.buildkey()]) | ||
.collect(); | ||
let invocation = Invocation::new(unit, deps); | ||
self.plan.invocations.push(invocation); | ||
Ok(()) | ||
} | ||
|
||
pub fn update( | ||
&mut self, | ||
invocation_name: String, | ||
cmd: ProcessBuilder, | ||
outputs: Arc<Vec<OutputFile>>, | ||
) -> CargoResult<()> { | ||
let id = self.invocation_map[&invocation_name]; | ||
let invocation = self.plan | ||
.invocations | ||
.get_mut(id) | ||
.ok_or_else(|| internal(format!("couldn't find invocation for {}", invocation_name)))?; | ||
|
||
invocation.update_cmd(cmd)?; | ||
for output in outputs.iter() { | ||
invocation.add_output(&output.path, &output.hardlink); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
pub fn set_inputs(&mut self, inputs: Vec<PathBuf>) { | ||
self.plan.inputs = inputs; | ||
} | ||
|
||
pub fn output_plan(self) { | ||
let encoded = serde_json::to_string(&self.plan).unwrap(); | ||
println!("{}", encoded); | ||
} | ||
} | ||
|
||
impl SerializedBuildPlan { | ||
pub fn new() -> SerializedBuildPlan { | ||
SerializedBuildPlan { | ||
invocations: Vec::new(), | ||
inputs: Vec::new(), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.