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<Write>),
+ /// 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(
}
}
+ /// Create a shell from a plain writable object, with no color, and max verbosity.
pub fn from_write(out: Box<Write>) -> Shell {
Shell {
err: ShellOut::Write(out),
}
}
+ /// 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,
}
}
+ /// 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<T, U>(&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<T, U>(&mut self,
status: T,
message: U,
self.print(&status, &message, color, true)
}
+ /// Run the callback only if we are in verbose mode
pub fn verbose<F>(&mut self, mut callback: F) -> CargoResult<()>
where F: FnMut(&mut Shell) -> CargoResult<()>
{
}
}
+ /// Run the callback if we are not in verbose mode.
pub fn concise<F>(&mut self, mut callback: F) -> CargoResult<()>
where F: FnMut(&mut Shell) -> CargoResult<()>
{
}
}
+ /// Print a red 'error' message
pub fn error<T: fmt::Display>(&mut self, message: T) -> CargoResult<()> {
self.print(&"error:", &message, Red, false)
}
+ /// Print an amber 'warning' message
pub fn warn<T: fmt::Display>(&mut self, message: T) -> CargoResult<()> {
match self.verbosity {
Verbosity::Quiet => Ok(()),
}
}
+ /// 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 {
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,
}
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,
Ok(())
}
+ /// Get this object as a `io::Write`.
fn as_write(&mut self) -> &mut Write {
match *self {
ShellOut::Stream(ref mut err, _) => err,
}
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,
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,
pub used_in_plugin: HashSet<Unit<'a>>,
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<Layout>,
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<Unit<'a>, Arc<Vec<(PathBuf, Option<PathBuf>, bool)>>>,
target_metadatas: HashMap<Unit<'a>, Option<Metadata>>,
}
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<String>,
}
}
};
-
+ //info!("{:?}", unit);
match *unit.target.kind() {
TargetKind::Bin |
TargetKind::CustomBuild |
}
}
-// 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,
}
}
+/// 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,
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,
incremental: PathBuf,
fingerprint: PathBuf,
examples: PathBuf,
+ /// The lockfile for a build, will be unlocked when this struct is `drop`ped.
_lock: FileLock,
}
}
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<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<Layout> {
// 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
}
}
+ /// 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)?;
}
}
+ /// 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 }
}
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<Shell>,
+ /// Information on how to invoke the compiler (rustc)
rustc: LazyCell<Rustc>,
+ /// A collection of configuration options
values: LazyCell<HashMap<String, ConfigValue>>,
+ /// The current working directory of cargo
cwd: PathBuf,
+ /// The location of the cargo executable (path to current process)
cargo_exe: LazyCell<PathBuf>,
+ /// The location of the rustdoc executable
rustdoc: LazyCell<PathBuf>,
+ /// Whether we are printing extra verbose messages
extra_verbose: Cell<bool>,
frozen: Cell<bool>,
locked: Cell<bool>,
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<PathBuf>,
+ /// 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.
})
}
+ /// 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);