From 72899f5bf85399b5d36cb5b5d0df891613cd8cad Mon Sep 17 00:00:00 2001 From: Richard Dodd Date: Sun, 1 Oct 2017 14:47:53 +0100 Subject: [PATCH] Add some more docs --- src/cargo/core/shell.rs | 50 ++++++++++++++++++-- src/cargo/ops/cargo_rustc/context.rs | 70 ++++++++++++++++++++++++++-- src/cargo/ops/cargo_rustc/layout.rs | 21 +++++++++ src/cargo/util/config.rs | 12 +++++ src/cargo/util/rustc.rs | 9 +++- 5 files changed, 155 insertions(+), 7 deletions(-) diff --git a/src/cargo/core/shell.rs b/src/cargo/core/shell.rs index 8c330a05dc2..6911339d819 100644 --- a/src/cargo/core/shell.rs +++ b/src/cargo/core/shell.rs @@ -7,37 +7,60 @@ use termcolor::{self, StandardStream, Color, ColorSpec, WriteColor}; use util::errors::CargoResult; -#[derive(Clone, Copy, PartialEq)] +/// The requested verbosity of output +#[derive(Debug, Clone, Copy, PartialEq)] pub enum Verbosity { Verbose, Normal, Quiet } +/// An abstraction around a `Write`able object that remembers preferences for output verbosity and +/// color. pub struct Shell { + /// the `Write`able object, either with or without color support (represented by different enum + /// variants) err: ShellOut, + /// How verbose messages should be verbosity: Verbosity, } impl fmt::Debug for Shell { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Shell") + match &self.err { + &ShellOut::Write(_) => f.debug_struct("Shell") + .field("verbosity", &self.verbosity) + .finish(), + &ShellOut::Stream(_, color_choice) => f.debug_struct("Shell") + .field("verbosity", &self.verbosity) + .field("color_choice", &color_choice) + .finish() + } } } +/// A `Write`able object, either with or without color support enum ShellOut { + /// A plain write object without color support Write(Box), + /// Color-enabled stdio, with information on whether color should be used Stream(StandardStream, ColorChoice), } -#[derive(PartialEq, Clone, Copy)] +/// Whether messages should use color output +#[derive(Debug, PartialEq, Clone, Copy)] pub enum ColorChoice { + /// Force color output Always, + /// Force disable color output Never, + /// Intelligently guess whether to use color output CargoAuto, } impl Shell { + /// Create a new shell (color choice and verbosity), defaulting to 'auto' color and verbose + /// output. pub fn new() -> Shell { Shell { err: ShellOut::Stream( @@ -48,6 +71,7 @@ impl Shell { } } + /// Create a shell from a plain writable object, with no color, and max verbosity. pub fn from_write(out: Box) -> Shell { Shell { err: ShellOut::Write(out), @@ -55,6 +79,8 @@ impl Shell { } } + /// Print a message, where the status will have `color` color, and can be justified. The + /// messages follows without color. fn print(&mut self, status: &fmt::Display, message: &fmt::Display, @@ -68,16 +94,19 @@ impl Shell { } } + /// Get a reference to the underlying writer pub fn err(&mut self) -> &mut Write { self.err.as_write() } + /// Shortcut to right-align and color green a status message. pub fn status(&mut self, status: T, message: U) -> CargoResult<()> where T: fmt::Display, U: fmt::Display { self.print(&status, &message, Green, true) } + /// Shortcut to right-align a status message. pub fn status_with_color(&mut self, status: T, message: U, @@ -87,6 +116,7 @@ impl Shell { self.print(&status, &message, color, true) } + /// Run the callback only if we are in verbose mode pub fn verbose(&mut self, mut callback: F) -> CargoResult<()> where F: FnMut(&mut Shell) -> CargoResult<()> { @@ -96,6 +126,7 @@ impl Shell { } } + /// Run the callback if we are not in verbose mode. pub fn concise(&mut self, mut callback: F) -> CargoResult<()> where F: FnMut(&mut Shell) -> CargoResult<()> { @@ -105,10 +136,12 @@ impl Shell { } } + /// Print a red 'error' message pub fn error(&mut self, message: T) -> CargoResult<()> { self.print(&"error:", &message, Red, false) } + /// Print an amber 'warning' message pub fn warn(&mut self, message: T) -> CargoResult<()> { match self.verbosity { Verbosity::Quiet => Ok(()), @@ -116,14 +149,17 @@ impl Shell { } } + /// Update the verbosity of the shell pub fn set_verbosity(&mut self, verbosity: Verbosity) { self.verbosity = verbosity; } + /// Get the verbosity of the shell pub fn verbosity(&self) -> Verbosity { self.verbosity } + /// Update the color choice (always, never, or auto) from a string. pub fn set_color_choice(&mut self, color: Option<&str>) -> CargoResult<()> { if let ShellOut::Stream(ref mut err, ref mut cc) = self.err { let cfg = match color { @@ -142,6 +178,10 @@ impl Shell { Ok(()) } + /// Get the current color choice + /// + /// If we are not using a color stream, this will always return Never, even if the color choice + /// has been set to something else. pub fn color_choice(&self) -> ColorChoice { match self.err { ShellOut::Stream(_, cc) => cc, @@ -151,6 +191,8 @@ impl Shell { } impl ShellOut { + /// Print out a message with a status. The status comes first and is bold + the given color. + /// The status can be justified, in which case the max width that will right align is 12 chars. fn print(&mut self, status: &fmt::Display, message: &fmt::Display, @@ -182,6 +224,7 @@ impl ShellOut { Ok(()) } + /// Get this object as a `io::Write`. fn as_write(&mut self) -> &mut Write { match *self { ShellOut::Stream(ref mut err, _) => err, @@ -191,6 +234,7 @@ impl ShellOut { } impl ColorChoice { + /// Convert our color choice to termcolor's version fn to_termcolor_color_choice(&self) -> termcolor::ColorChoice { match *self { ColorChoice::Always => termcolor::ColorChoice::Always, diff --git a/src/cargo/ops/cargo_rustc/context.rs b/src/cargo/ops/cargo_rustc/context.rs index b4435f213b2..192badff278 100755 --- a/src/cargo/ops/cargo_rustc/context.rs +++ b/src/cargo/ops/cargo_rustc/context.rs @@ -25,15 +25,44 @@ use super::layout::Layout; use super::links::Links; use super::{Kind, Compilation, BuildConfig}; +/// All information needed to define a Unit. +/// +/// A unit is an object that has enough information so that cargo knows how to build it. +/// For example, if your project has dependencies, then every dependency will be built as a library +/// unit. If your project is a library, then it will be built as a library unit as well, or if it +/// is a binary with `main.rs`, then a binary will be output. There are also separate unit types +/// for `test`ing and `check`ing, amongst others. +/// +/// The unit also holds information about all possible metadata about the package in `pkg`. +/// +/// A unit needs to know extra information in addition to the type and root source file. For +/// example, it needs to know the target architecture (OS, chip arch etc.) and it needs to know +/// whether you want a debug or release build. There is enough information in this struct to figure +/// all that out. #[derive(Clone, Copy, Eq, PartialEq, Hash)] pub struct Unit<'a> { + /// Information about avaiable targets, which files to include/exclude, etc. Basically stuff in + /// `Cargo.toml`. pub pkg: &'a Package, + /// Information about the specific target to build, out of the possible targets in `pkg`. Not + /// to be confused with *target-triple* (or *target architecture* ...), the target arch for a + /// build. pub target: &'a Target, + /// The profile contains information about *how* the build should be run, including debug + /// level, extra args to pass to rustc, etc. pub profile: &'a Profile, + /// Whether this compilation unit is for the host or target architecture. + /// + /// For example, when + /// cross compiling and using a custom build script, the build script needs to be compiled for + /// the host architecture so the host rustc can use it (when compiling to the target + /// architecture). pub kind: Kind, } +/// The build context, containing all information about a build task pub struct Context<'a, 'cfg: 'a> { + /// The workspace the build is for pub ws: &'a Workspace<'cfg>, pub config: &'cfg Config, pub resolve: &'a Resolve, @@ -50,13 +79,21 @@ pub struct Context<'a, 'cfg: 'a> { pub used_in_plugin: HashSet>, pub jobserver: Client, + /// The target directory layout for the host (and target if it is the same as host) host: Layout, + /// The target directory layout for the target (if different from then host) target: Option, target_info: TargetInfo, host_info: TargetInfo, profiles: &'a Profiles, incremental_enabled: bool, + /// For each Unit, a list all files produced as a triple of + /// + /// - File name that will be produced by the build process (in `deps`) + /// - If it should be linked into `target`, and what it should be called (e.g. without + /// metadata). + /// - Whether it is something you can link against (e.g. a library) target_filenames: HashMap, Arc, bool)>>>, target_metadatas: HashMap, Option>, } @@ -210,6 +247,10 @@ impl<'a, 'cfg> Context<'a, 'cfg> { Ok(()) } + /// A recursive function that checks all crate types (`rlib`, ...) are in `crate_types` + /// for this unit and its dependencies. + /// + /// Tracks visited units to avoid unnecessary work. fn visit_crate_type(&self, unit: &Unit<'a>, crate_types: &mut BTreeSet, @@ -660,7 +701,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> { } } }; - + //info!("{:?}", unit); match *unit.target.kind() { TargetKind::Bin | TargetKind::CustomBuild | @@ -1038,8 +1079,23 @@ impl<'a, 'cfg> Context<'a, 'cfg> { } } -// Acquire extra flags to pass to the compiler from the -// RUSTFLAGS environment variable and similar config values +/// Acquire extra flags to pass to the compiler from various locations. +/// +/// The locations are: +/// +/// - the `RUSTFLAGS` environment variable +/// +/// then if this was not found +/// +/// - `target.*.rustflags` from the manifest (Cargo.toml) +/// - `target.cfg(..).rustflags` from the manifest +/// +/// then if neither of these were found +/// +/// - `build.rustflags` from the manifest +/// +/// Note that if a `target` is specified, no args will be passed to host code (plugins, build +/// scripts, ...), even if it is the same as the target. fn env_args(config: &Config, build_config: &BuildConfig, target_info: &TargetInfo, @@ -1136,6 +1192,14 @@ impl fmt::Display for Metadata { } } +/// Takes rustc output (using specialized command line args), and calculates the file prefix and +/// suffix for the given crate type, or returns None if the type is not supported. (e.g. for a +/// rust library like libcargo.rlib, prefix = "lib", suffix = "rlib"). +/// +/// The caller needs to ensure that the lines object is at the correct line for the given crate +/// type: this is not checked. +// This function can not handle more than 1 file per type (with wasm32-unknown-emscripten, there +// are 2 files for bin (.wasm and .js)) fn parse_crate_type( crate_type: &str, error: &str, diff --git a/src/cargo/ops/cargo_rustc/layout.rs b/src/cargo/ops/cargo_rustc/layout.rs index 426188b288d..b28e1bb9d93 100644 --- a/src/cargo/ops/cargo_rustc/layout.rs +++ b/src/cargo/ops/cargo_rustc/layout.rs @@ -56,6 +56,9 @@ use std::path::{PathBuf, Path}; use core::Workspace; use util::{Config, FileLock, CargoResult, Filesystem}; +/// Contains the paths of all target output locations. +/// +/// See module docs for more information. pub struct Layout { root: PathBuf, deps: PathBuf, @@ -64,6 +67,7 @@ pub struct Layout { incremental: PathBuf, fingerprint: PathBuf, examples: PathBuf, + /// The lockfile for a build, will be unlocked when this struct is `drop`ped. _lock: FileLock, } @@ -74,6 +78,12 @@ pub fn is_bad_artifact_name(name: &str) -> bool { } impl Layout { + /// Calcuate the paths for build output, lock the build directory, and return as a Layout. + /// + /// This function will block if the directory is already locked. + /// + /// Differs from `at` in that it calculates the root path from the workspace target directory, + /// adding the target triple and the profile (debug, release, ...). pub fn new(ws: &Workspace, triple: Option<&str>, dest: &str) -> CargoResult { @@ -88,6 +98,9 @@ impl Layout { Layout::at(ws.config(), path) } + /// Calcuate the paths for build output, lock the build directory, and return as a Layout. + /// + /// This function will block if the directory is already locked. pub fn at(config: &Config, root: Filesystem) -> CargoResult { // For now we don't do any more finer-grained locking on the artifact // directory, so just lock the entire thing for the duration of this @@ -136,6 +149,7 @@ impl Layout { } } + /// Make sure all directories stored in the Layout exist on the filesystem. pub fn prepare(&mut self) -> io::Result<()> { if fs::metadata(&self.root).is_err() { fs::create_dir_all(&self.root)?; @@ -160,11 +174,18 @@ impl Layout { } } + /// Fetch the root path. pub fn dest(&self) -> &Path { &self.root } + /// Fetch the deps path. pub fn deps(&self) -> &Path { &self.deps } + /// Fetch the examples path. pub fn examples(&self) -> &Path { &self.examples } + /// Fetch the root path. pub fn root(&self) -> &Path { &self.root } + /// Fetch the incremental path. pub fn incremental(&self) -> &Path { &self.incremental } + /// Fetch the fingerprint path. pub fn fingerprint(&self) -> &Path { &self.fingerprint } + /// Fetch the build path. pub fn build(&self) -> &Path { &self.build } } diff --git a/src/cargo/util/config.rs b/src/cargo/util/config.rs index 7feb4e1e939..38e2e303fab 100644 --- a/src/cargo/util/config.rs +++ b/src/cargo/util/config.rs @@ -28,15 +28,27 @@ use util::{Filesystem, LazyCell}; use self::ConfigValue as CV; +/// Configuration information for cargo. This is not specific to a build, it is information +/// relating to cargo itself. +/// +/// This struct implements `Default`: all fields can be inferred. #[derive(Debug)] pub struct Config { + /// The location of the users's 'home' directory. OS-dependent. home_path: Filesystem, + /// Information about how to write messages to the shell shell: RefCell, + /// Information on how to invoke the compiler (rustc) rustc: LazyCell, + /// A collection of configuration options values: LazyCell>, + /// The current working directory of cargo cwd: PathBuf, + /// The location of the cargo executable (path to current process) cargo_exe: LazyCell, + /// The location of the rustdoc executable rustdoc: LazyCell, + /// Whether we are printing extra verbose messages extra_verbose: Cell, frozen: Cell, locked: Cell, diff --git a/src/cargo/util/rustc.rs b/src/cargo/util/rustc.rs index d1ba345d5c0..a9b65c959ca 100644 --- a/src/cargo/util/rustc.rs +++ b/src/cargo/util/rustc.rs @@ -2,17 +2,23 @@ use std::path::PathBuf; use util::{self, CargoResult, internal, ProcessBuilder}; +/// Information on the `rustc` executable #[derive(Debug)] pub struct Rustc { + /// The location of the exe pub path: PathBuf, + /// An optional program that will be passed the path of the rust exe as its first argument, and + /// rustc args following this. pub wrapper: Option, + /// Verbose version information (the output of `rustc -vV`) pub verbose_version: String, + /// The host triple (arch-platform-OS), this comes from verbose_version. pub host: String, } impl Rustc { /// Run the compiler at `path` to learn various pieces of information about - /// it. + /// it, with an optional wrapper. /// /// If successful this function returns a description of the compiler along /// with a list of its capabilities. @@ -41,6 +47,7 @@ impl Rustc { }) } + /// Get a process builder set up to use the found rustc version, with a wrapper if Some pub fn process(&self) -> ProcessBuilder { if let Some(ref wrapper) = self.wrapper { let mut cmd = util::process(wrapper);