Skip to content

Commit

Permalink
Experiment: Wrap Unit in Rc
Browse files Browse the repository at this point in the history
  • Loading branch information
ehuss committed Mar 20, 2020
1 parent 4c7a638 commit c053288
Show file tree
Hide file tree
Showing 24 changed files with 439 additions and 524 deletions.
17 changes: 6 additions & 11 deletions src/cargo/core/compiler/build_context/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::core::compiler::unit::UnitInterner;
use crate::core::compiler::{BuildConfig, BuildOutput, CompileKind, Unit};
use crate::core::profiles::Profiles;
use crate::core::{InternedString, Workspace};
Expand All @@ -8,6 +7,7 @@ use crate::util::errors::CargoResult;
use crate::util::Rustc;
use std::collections::HashMap;
use std::path::PathBuf;
use std::rc::Rc;
use std::str;

mod target_info;
Expand All @@ -27,13 +27,10 @@ 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<Rc<Unit>, Vec<String>>,
/// Package downloader.
pub packages: &'a PackageSet<'cfg>,

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

/// Information about rustc and the target platform.
pub target_data: RustcTargetData,
}
Expand All @@ -45,8 +42,7 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> {
config: &'cfg Config,
build_config: &'a BuildConfig,
profiles: Profiles,
units: &'a UnitInterner<'a>,
extra_compiler_args: HashMap<Unit<'a>, Vec<String>>,
extra_compiler_args: HashMap<Rc<Unit>, Vec<String>>,
target_data: RustcTargetData,
) -> CargoResult<BuildContext<'a, 'cfg>> {
Ok(BuildContext {
Expand All @@ -56,7 +52,6 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> {
build_config,
profiles,
extra_compiler_args,
units,
target_data,
})
}
Expand Down Expand Up @@ -89,19 +84,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)
}

Expand Down
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<'a>(&mut self, cx: &Context<'a, '_>, unit: &Unit) -> CargoResult<()> {
let id = self.plan.invocations.len();
self.invocation_map.insert(unit.buildkey(), id);
let deps = cx
Expand Down
7 changes: 4 additions & 3 deletions src/cargo/core/compiler/compilation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::collections::{BTreeSet, HashMap, HashSet};
use std::env;
use std::ffi::{OsStr, OsString};
use std::path::PathBuf;
use std::rc::Rc;

use cargo_platform::CfgExpr;
use semver::Version;
Expand All @@ -14,9 +15,9 @@ use crate::util::{self, config, join_paths, process, CargoResult, Config, Proces
/// Structure with enough information to run `rustdoc --test`.
pub struct Doctest {
/// The package being doc-tested.
pub package: Package,
pub package: Rc<Package>,
/// The target being tested (currently always the package's lib).
pub target: Target,
pub target: Rc<Target>,
/// Arguments needed to pass to rustdoc to run this test.
pub args: Vec<OsString>,
/// Whether or not -Zunstable-options is needed.
Expand All @@ -27,7 +28,7 @@ pub struct Doctest {
pub struct Compilation<'cfg> {
/// An array of all tests created during this compilation.
/// `(package, target, path_to_test_exe)`
pub tests: Vec<(Package, Target, PathBuf)>,
pub tests: Vec<(Rc<Package>, Rc<Target>, PathBuf)>,

/// An array of all binaries created.
pub binaries: Vec<PathBuf>,
Expand Down
59 changes: 30 additions & 29 deletions src/cargo/core/compiler/context/compilation_files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::env;
use std::fmt;
use std::hash::{Hash, Hasher, SipHasher};
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::sync::Arc;

use lazycell::LazyCell;
Expand Down Expand Up @@ -67,15 +68,15 @@ pub struct CompilationFiles<'a, 'cfg> {
export_dir: Option<PathBuf>,
/// The root targets requested by the user on the command line (does not
/// include dependencies).
roots: Vec<Unit<'a>>,
roots: Vec<Rc<Unit>>,
ws: &'a Workspace<'cfg>,
/// Metadata hash to use for each unit.
///
/// `None` if the unit should not use a metadata data hash (like rustdoc,
/// or some dylibs).
metas: HashMap<Unit<'a>, Option<Metadata>>,
metas: HashMap<Rc<Unit>, Option<Metadata>>,
/// For each Unit, a list all files produced.
outputs: HashMap<Unit<'a>, LazyCell<Arc<Vec<OutputFile>>>>,
outputs: HashMap<Rc<Unit>, LazyCell<Arc<Vec<OutputFile>>>>,
}

/// Info about a single file emitted by the compiler.
Expand Down Expand Up @@ -104,7 +105,7 @@ impl OutputFile {

impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
pub(super) fn new(
roots: &[Unit<'a>],
roots: &[Rc<Unit>],
host: Layout,
target: HashMap<CompileTarget, Layout>,
export_dir: Option<PathBuf>,
Expand Down Expand Up @@ -146,20 +147,20 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
///
/// Returns `None` if the unit should not use a metadata data hash (like
/// rustdoc, or some dylibs).
pub fn metadata(&self, unit: &Unit<'a>) -> Option<Metadata> {
pub fn metadata(&self, unit: &Unit) -> Option<Metadata> {
self.metas[unit]
}

/// Gets the short hash based only on the `PackageId`.
/// Used for the metadata when `metadata` returns `None`.
pub fn target_short_hash(&self, unit: &Unit<'_>) -> String {
pub fn target_short_hash(&self, unit: &Unit) -> String {
let hashable = unit.pkg.package_id().stable_hash(self.ws.root());
util::short_hash(&hashable)
}

/// Returns the appropriate output directory for the specified package and
/// target.
pub fn out_dir(&self, unit: &Unit<'a>) -> PathBuf {
pub fn out_dir(&self, unit: &Unit) -> PathBuf {
if unit.mode.is_doc() {
self.layout(unit.kind).doc().to_path_buf()
} else if unit.mode.is_doc_test() {
Expand All @@ -179,7 +180,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
}

/// Directory name to use for a package in the form `NAME-HASH`.
pub fn pkg_dir(&self, unit: &Unit<'a>) -> String {
pub fn pkg_dir(&self, unit: &Unit) -> String {
let name = unit.pkg.package_id().name();
match self.metas[unit] {
Some(ref meta) => format!("{}-{}", name, meta),
Expand All @@ -199,24 +200,24 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {

/// Returns the directories where Rust crate dependencies are found for the
/// specified unit.
pub fn deps_dir(&self, unit: &Unit<'_>) -> &Path {
pub fn deps_dir(&self, unit: &Unit) -> &Path {
self.layout(unit.kind).deps()
}

/// Directory where the fingerprint for the given unit should go.
pub fn fingerprint_dir(&self, unit: &Unit<'a>) -> PathBuf {
pub fn fingerprint_dir(&self, unit: &Unit) -> PathBuf {
let dir = self.pkg_dir(unit);
self.layout(unit.kind).fingerprint().join(dir)
}

/// Path where compiler output is cached.
pub fn message_cache_path(&self, unit: &Unit<'a>) -> PathBuf {
pub fn message_cache_path(&self, unit: &Unit) -> PathBuf {
self.fingerprint_dir(unit).join("output")
}

/// Returns the directory where a compiled build script is stored.
/// `/path/to/target/{debug,release}/build/PKG-HASH`
pub fn build_script_dir(&self, unit: &Unit<'a>) -> PathBuf {
pub fn build_script_dir(&self, unit: &Unit) -> PathBuf {
assert!(unit.target.is_custom_build());
assert!(!unit.mode.is_run_custom_build());
assert!(self.metas.contains_key(unit));
Expand All @@ -227,7 +228,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
/// Returns the directory where information about running a build script
/// is stored.
/// `/path/to/target/{debug,release}/build/PKG-HASH`
pub fn build_script_run_dir(&self, unit: &Unit<'a>) -> PathBuf {
pub fn build_script_run_dir(&self, unit: &Unit) -> PathBuf {
assert!(unit.target.is_custom_build());
assert!(unit.mode.is_run_custom_build());
let dir = self.pkg_dir(unit);
Expand All @@ -236,12 +237,12 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {

/// Returns the "OUT_DIR" directory for running a build script.
/// `/path/to/target/{debug,release}/build/PKG-HASH/out`
pub fn build_script_out_dir(&self, unit: &Unit<'a>) -> PathBuf {
pub fn build_script_out_dir(&self, unit: &Unit) -> PathBuf {
self.build_script_run_dir(unit).join("out")
}

/// Returns the file stem for a given target/profile combo (with metadata).
pub fn file_stem(&self, unit: &Unit<'a>) -> String {
pub fn file_stem(&self, unit: &Unit) -> String {
match self.metas[unit] {
Some(ref metadata) => format!("{}-{}", unit.target.crate_name(), metadata),
None => self.bin_stem(unit),
Expand Down Expand Up @@ -280,7 +281,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
/// Returns the filenames that the given unit will generate.
pub(super) fn outputs(
&self,
unit: &Unit<'a>,
unit: &Unit,
bcx: &BuildContext<'a, 'cfg>,
) -> CargoResult<Arc<Vec<OutputFile>>> {
self.outputs[unit]
Expand All @@ -289,7 +290,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
}

/// Returns the bin filename for a given target, without extension and metadata.
fn bin_stem(&self, unit: &Unit<'_>) -> String {
fn bin_stem(&self, unit: &Unit) -> String {
if unit.target.allows_underscores() {
unit.target.name().to_string()
} else {
Expand All @@ -310,7 +311,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
///
/// Returns an `Option` because in some cases we don't want to link
/// (eg a dependent lib).
fn link_stem(&self, unit: &Unit<'a>) -> Option<(PathBuf, String)> {
fn link_stem(&self, unit: &Unit) -> Option<(PathBuf, String)> {
let out_dir = self.out_dir(unit);
let bin_stem = self.bin_stem(unit); // Stem without metadata.
let file_stem = self.file_stem(unit); // Stem with metadata.
Expand All @@ -320,7 +321,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
// we don't want to link it up.
if out_dir.ends_with("deps") {
// Don't lift up library dependencies.
if unit.target.is_bin() || self.roots.contains(unit) {
if unit.target.is_bin() || self.roots.iter().any(|root| &**root == unit) {
Some((
out_dir.parent().unwrap().to_owned(),
if unit.mode.is_any_test() {
Expand All @@ -343,7 +344,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {

fn calc_outputs(
&self,
unit: &Unit<'a>,
unit: &Unit,
bcx: &BuildContext<'a, 'cfg>,
) -> CargoResult<Arc<Vec<OutputFile>>> {
let ret = match unit.mode {
Expand Down Expand Up @@ -393,7 +394,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {

fn calc_outputs_rustc(
&self,
unit: &Unit<'a>,
unit: &Unit,
bcx: &BuildContext<'a, 'cfg>,
) -> CargoResult<Vec<OutputFile>> {
let mut ret = Vec::new();
Expand Down Expand Up @@ -508,24 +509,24 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
}

fn metadata_of<'a, 'cfg>(
unit: &Unit<'a>,
unit: &Rc<Unit>,
cx: &Context<'a, 'cfg>,
metas: &mut HashMap<Unit<'a>, Option<Metadata>>,
metas: &mut HashMap<Rc<Unit>, Option<Metadata>>,
) -> Option<Metadata> {
if !metas.contains_key(unit) {
let meta = compute_metadata(unit, cx, metas);
metas.insert(*unit, meta);
for dep in cx.unit_deps(unit) {
let meta = compute_metadata(&unit, cx, metas);
metas.insert(Rc::clone(unit), meta);
for dep in cx.unit_deps(&unit) {
metadata_of(&dep.unit, cx, metas);
}
}
metas[unit]
}

fn compute_metadata<'a, 'cfg>(
unit: &Unit<'a>,
unit: &Unit,
cx: &Context<'a, 'cfg>,
metas: &mut HashMap<Unit<'a>, Option<Metadata>>,
metas: &mut HashMap<Rc<Unit>, Option<Metadata>>,
) -> Option<Metadata> {
if unit.mode.is_doc_test() {
// Doc tests do not have metadata.
Expand Down Expand Up @@ -616,7 +617,7 @@ fn compute_metadata<'a, 'cfg>(

bcx.rustc().verbose_version.hash(&mut hasher);

if cx.bcx.ws.is_member(unit.pkg) {
if cx.bcx.ws.is_member(&unit.pkg) {
// This is primarily here for clippy. This ensures that the clippy
// artifacts are separate from the `check` ones.
if let Some(path) = &cx.bcx.rustc().workspace_wrapper {
Expand Down
Loading

0 comments on commit c053288

Please sign in to comment.