Skip to content

Commit

Permalink
Auto merge of #8068 - ehuss:bcx-units, r=alexcrichton,ehuss
Browse files Browse the repository at this point in the history
Refactor BuildContext

This restructures the "front end" of the compile process so that the `UnitGraph` can be accessed by API users. Essentially, the `BuildContext` contains the result of generating the `UnitGraph`, and other bits of information collected along the way. This logically separates the build process into two phases: (1) generate the `UnitGraph` and `BuildContext` and (2) pass the `BuildContext` to `Context` which performs the actual compilation.

The main challenge here is dealing with the references and lifetimes. The old code kept a bunch of things on the stack with various layers of references. Beside reorganizing things, the big change is to wrap `Package` and `Target` in `Rc`. This still requires the `UnitInterner` to be passed in and kept alive. It is possible to avoid that by placing all `Unit`s in `Rc`, but that had a roughly 5% performance hit (on fresh builds) because Units are very optimized to be used as hashable keys, and `Rc` loses those optimizations.
  • Loading branch information
bors committed Apr 19, 2020
2 parents 8e8c62b + df5cb70 commit 3dcfdef
Show file tree
Hide file tree
Showing 28 changed files with 831 additions and 860 deletions.
6 changes: 3 additions & 3 deletions src/bin/cargo/commands/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,12 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
)?;

if let Some(out_dir) = args.value_of_path("out-dir", config) {
compile_opts.export_dir = Some(out_dir);
compile_opts.build_config.export_dir = Some(out_dir);
} else if let Some(out_dir) = config.build_config()?.out_dir.as_ref() {
let out_dir = out_dir.resolve_path(config);
compile_opts.export_dir = Some(out_dir);
compile_opts.build_config.export_dir = Some(out_dir);
}
if compile_opts.export_dir.is_some() {
if compile_opts.build_config.export_dir.is_some() {
config
.cli_unstable()
.fail_if_stable_opt("--out-dir", 6790)?;
Expand Down
10 changes: 10 additions & 0 deletions src/cargo/core/compiler/build_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::util::ProcessBuilder;
use crate::util::{CargoResult, Config, RustfixDiagnosticServer};
use serde::ser;
use std::cell::RefCell;
use std::path::PathBuf;

/// Configuration information for a rustc build.
#[derive(Debug)]
Expand All @@ -26,7 +27,15 @@ pub struct BuildConfig {
pub unit_graph: bool,
/// An optional override of the rustc process for primary units
pub primary_unit_rustc: Option<ProcessBuilder>,
/// A thread used by `cargo fix` to receive messages on a socket regarding
/// the success/failure of applying fixes.
pub rustfix_diagnostic_server: RefCell<Option<RustfixDiagnosticServer>>,
/// The directory to copy final artifacts to. Note that even if `out_dir` is
/// set, a copy of artifacts still could be found a `target/(debug\release)`
/// as usual.
// Note that, although the cmd-line flag name is `out-dir`, in code we use
// `export_dir`, to avoid confusion with out dir at `target/debug/deps`.
pub export_dir: Option<PathBuf>,
}

impl BuildConfig {
Expand Down Expand Up @@ -70,6 +79,7 @@ impl BuildConfig {
unit_graph: false,
primary_unit_rustc: None,
rustfix_diagnostic_server: RefCell::new(None),
export_dir: None,
})
}

Expand Down
49 changes: 20 additions & 29 deletions src/cargo/core/compiler/build_context/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::core::compiler::unit::UnitInterner;
use crate::core::compiler::{BuildConfig, BuildOutput, CompileKind, Unit};
use crate::core::compiler::unit_graph::UnitGraph;
use crate::core::compiler::{BuildConfig, CompileKind, Unit};
use crate::core::profiles::Profiles;
use crate::core::{InternedString, Workspace};
use crate::core::{PackageId, PackageSet};
Expand All @@ -8,7 +8,6 @@ use crate::util::errors::CargoResult;
use crate::util::Rustc;
use std::collections::HashMap;
use std::path::PathBuf;
use std::str;

mod target_info;
pub use self::target_info::{FileFlavor, RustcTargetData, TargetInfo};
Expand All @@ -27,37 +26,40 @@ pub struct BuildContext<'a, 'cfg> {
pub profiles: Profiles,
pub build_config: &'a BuildConfig,
/// Extra compiler args for either `rustc` or `rustdoc`.
pub extra_compiler_args: HashMap<Unit<'a>, Vec<String>>,
pub extra_compiler_args: HashMap<Unit, Vec<String>>,
/// Package downloader.
pub packages: &'a PackageSet<'cfg>,

/// Source of interning new units as they're created.
pub units: &'a UnitInterner<'a>,

///
/// This holds ownership of the `Package` objects.
pub packages: PackageSet<'cfg>,
/// Information about rustc and the target platform.
pub target_data: RustcTargetData,
/// The root units of `unit_graph` (units requested on the command-line).
pub roots: Vec<Unit>,
/// The dependency graph of units to compile.
pub unit_graph: UnitGraph,
}

impl<'a, 'cfg> BuildContext<'a, 'cfg> {
pub fn new(
ws: &'a Workspace<'cfg>,
packages: &'a PackageSet<'cfg>,
config: &'cfg Config,
packages: PackageSet<'cfg>,
build_config: &'a BuildConfig,
profiles: Profiles,
units: &'a UnitInterner<'a>,
extra_compiler_args: HashMap<Unit<'a>, Vec<String>>,
extra_compiler_args: HashMap<Unit, Vec<String>>,
target_data: RustcTargetData,
roots: Vec<Unit>,
unit_graph: UnitGraph,
) -> CargoResult<BuildContext<'a, 'cfg>> {
Ok(BuildContext {
ws,
config: ws.config(),
packages,
config,
build_config,
profiles,
extra_compiler_args,
units,
target_data,
roots,
unit_graph,
})
}

Expand Down Expand Up @@ -89,30 +91,19 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> {
self.build_config.jobs
}

pub fn rustflags_args(&self, unit: &Unit<'_>) -> &[String] {
pub fn rustflags_args(&self, unit: &Unit) -> &[String] {
&self.target_data.info(unit.kind).rustflags
}

pub fn rustdocflags_args(&self, unit: &Unit<'_>) -> &[String] {
pub fn rustdocflags_args(&self, unit: &Unit) -> &[String] {
&self.target_data.info(unit.kind).rustdocflags
}

pub fn show_warnings(&self, pkg: PackageId) -> bool {
pkg.source_id().is_path() || self.config.extra_verbose()
}

pub fn extra_args_for(&self, unit: &Unit<'a>) -> Option<&Vec<String>> {
pub fn extra_args_for(&self, unit: &Unit) -> Option<&Vec<String>> {
self.extra_compiler_args.get(unit)
}

/// If a build script is overridden, this returns the `BuildOutput` to use.
///
/// `lib_name` is the `links` library name and `kind` is whether it is for
/// Host or Target.
pub fn script_override(&self, lib_name: &str, kind: CompileKind) -> Option<&BuildOutput> {
self.target_data
.target_config(kind)
.links_overrides
.get(lib_name)
}
}
11 changes: 9 additions & 2 deletions src/cargo/core/compiler/build_context/target_info.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::core::compiler::CompileKind;
use crate::core::compiler::CompileTarget;
use crate::core::compiler::{BuildOutput, CompileKind, CompileTarget};
use crate::core::{Dependency, TargetKind, Workspace};
use crate::util::config::{Config, StringList, TargetConfig};
use crate::util::{CargoResult, CargoResultExt, ProcessBuilder, Rustc};
Expand Down Expand Up @@ -583,4 +582,12 @@ impl RustcTargetData {
CompileKind::Target(s) => &self.target_config[&s],
}
}

/// If a build script is overridden, this returns the `BuildOutput` to use.
///
/// `lib_name` is the `links` library name and `kind` is whether it is for
/// Host or Target.
pub fn script_override(&self, lib_name: &str, kind: CompileKind) -> Option<&BuildOutput> {
self.target_config(kind).links_overrides.get(lib_name)
}
}
4 changes: 2 additions & 2 deletions src/cargo/core/compiler/build_plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ struct SerializedBuildPlan {
}

impl Invocation {
pub fn new(unit: &Unit<'_>, deps: Vec<usize>) -> Invocation {
pub fn new(unit: &Unit, deps: Vec<usize>) -> Invocation {
let id = unit.pkg.package_id();
Invocation {
package_name: id.name().to_string(),
Expand Down Expand Up @@ -109,7 +109,7 @@ impl BuildPlan {
}
}

pub fn add<'a>(&mut self, cx: &Context<'a, '_>, unit: &Unit<'a>) -> CargoResult<()> {
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
Expand Down
6 changes: 2 additions & 4 deletions src/cargo/core/compiler/compilation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,7 @@ pub struct Compilation<'cfg> {
}

impl<'cfg> Compilation<'cfg> {
pub fn new<'a>(
bcx: &BuildContext<'a, 'cfg>,
default_kind: CompileKind,
) -> CargoResult<Compilation<'cfg>> {
pub fn new<'a>(bcx: &BuildContext<'a, 'cfg>) -> CargoResult<Compilation<'cfg>> {
let mut rustc = bcx.rustc().process();
let mut primary_rustc_process = bcx.build_config.primary_unit_rustc.clone();
let mut rustc_workspace_wrapper_process = bcx.rustc().workspace_process();
Expand All @@ -103,6 +100,7 @@ impl<'cfg> Compilation<'cfg> {
}
}

let default_kind = bcx.build_config.requested_kind;
Ok(Compilation {
// TODO: deprecated; remove.
native_dirs: BTreeSet::new(),
Expand Down
Loading

0 comments on commit 3dcfdef

Please sign in to comment.