use std::env;
-use std::fs::{self, File};
+use std::fs;
use std::hash::{self, Hasher};
-use std::io::prelude::*;
-use std::io::BufReader;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
}
// Parse the dep-info into a list of paths
-pub fn parse_dep_info(cx: &Context, dep_info: &Path)
+pub fn parse_dep_info(pkg: &Package, dep_info: &Path)
-> CargoResult<Option<Vec<PathBuf>>>
{
- macro_rules! fs_try {
- ($e:expr) => (match $e { Ok(e) => e, Err(..) => return Ok(None) })
- }
- let f = BufReader::new(fs_try!(File::open(dep_info)));
- let line = match f.lines().next() {
- Some(Ok(line)) => line,
- _ => return Ok(None),
+ let data = match paths::read_bytes(dep_info) {
+ Ok(data) => data,
+ Err(_) => return Ok(None),
};
- let pos = line.find(": ").ok_or_else(|| {
- internal(format!("dep-info not in an understood format: {}",
- dep_info.display()))
- })?;
- let deps = &line[pos + 2..];
-
- let mut paths = Vec::new();
- let mut deps = deps.split(' ').map(|s| s.trim()).filter(|s| !s.is_empty());
- while let Some(s) = deps.next() {
- let mut file = s.to_string();
- while file.ends_with('\\') {
- file.pop();
- file.push(' ');
- file.push_str(deps.next().ok_or_else(|| {
- internal("malformed dep-info format, trailing \\".to_string())
- })?);
- }
-
- // Note that paths emitted in dep info files may be relative, but due to
- // `path_args` in the module above this the relative paths are always
- // relative to the root of a workspace.
- paths.push(cx.ws.root().join(&file));
+ let paths = data.split(|&x| x == 0)
+ .filter(|x| !x.is_empty())
+ .map(|p| util::bytes2path(p).map(|p| pkg.root().join(p)))
+ .collect::<Result<Vec<_>, _>>()?;
+ if paths.len() == 0 {
+ Ok(None)
+ } else {
+ Ok(Some(paths))
}
- Ok(Some(paths))
}
-fn dep_info_mtime_if_fresh(cx: &Context, dep_info: &Path)
+fn dep_info_mtime_if_fresh(pkg: &Package, dep_info: &Path)
-> CargoResult<Option<FileTime>>
{
- if let Some(paths) = parse_dep_info(cx, dep_info)? {
+ if let Some(paths) = parse_dep_info(pkg, dep_info)? {
Ok(mtime_if_fresh(dep_info, paths.iter()))
} else {
Ok(None)
};
format!("{}{}-{}", flavor, kind, file_stem)
}
+
+/// Parses the dep-info file coming out of rustc into a Cargo-specific format.
+///
+/// This function will parse `rustc_dep_info` as a makefile-style dep info to
+/// learn about the all files which a crate depends on. This is then
+/// re-serialized into the `cargo_dep_info` path in a Cargo-specific format.
+///
+/// The `pkg_root` argument here is the absolute path to the directory
+/// containing `Cargo.toml` for this crate that was compiled. The paths listed
+/// in the rustc dep-info file may or may not be absolute but we'll want to
+/// consider all of them relative to the `root` specified.
+///
+/// The `rustc_cwd` argument is the absolute path to the cwd of the compiler
+/// when it was invoked.
+///
+/// The serialized Cargo format will contain a list of files, all of which are
+/// relative if they're under `root`. or absolute if they're elsewehre.
+pub fn translate_dep_info(rustc_dep_info: &Path,
+ cargo_dep_info: &Path,
+ pkg_root: &Path,
+ rustc_cwd: &Path) -> CargoResult<()> {
+ let contents = paths::read(rustc_dep_info)?;
+ let line = match contents.lines().next() {
+ Some(line) => line,
+ None => return Ok(()),
+ };
+ let pos = line.find(": ").ok_or_else(|| {
+ internal(format!("dep-info not in an understood format: {}",
+ rustc_dep_info.display()))
+ })?;
+ let deps = &line[pos + 2..];
+
+ let mut new_contents = Vec::new();
+ let mut deps = deps.split(' ').map(|s| s.trim()).filter(|s| !s.is_empty());
+ while let Some(s) = deps.next() {
+ let mut file = s.to_string();
+ while file.ends_with('\\') {
+ file.pop();
+ file.push(' ');
+ file.push_str(deps.next().ok_or_else(|| {
+ internal("malformed dep-info format, trailing \\".to_string())
+ })?);
+ }
+
+ let absolute = rustc_cwd.join(file);
+ let path = absolute.strip_prefix(pkg_root).unwrap_or(&absolute);
+ new_contents.extend(util::path2bytes(path)?);
+ new_contents.push(0);
+ }
+ paths::write(cargo_dep_info, &new_contents)?;
+ Ok(())
+}
+
let exec = exec.clone();
let root_output = cx.target_root().to_path_buf();
+ let pkg_root = unit.pkg.root().to_path_buf();
+ let cwd = rustc.get_cwd().unwrap_or(cx.config.cwd()).to_path_buf();
return Ok(Work::new(move |state| {
// Only at runtime have we discovered what the extra -L and -l
}
}
- if fs::metadata(&rustc_dep_info_loc).is_ok() {
- info!("Renaming dep_info {:?} to {:?}", rustc_dep_info_loc, dep_info_loc);
- fs::rename(&rustc_dep_info_loc, &dep_info_loc).chain_err(|| {
- internal(format!("could not rename dep info: {:?}",
- rustc_dep_info_loc))
- })?;
+ if rustc_dep_info_loc.exists() {
+ fingerprint::translate_dep_info(&rustc_dep_info_loc,
+ &dep_info_loc,
+ &pkg_root,
+ &cwd)
+ .chain_err(|| {
+ internal(format!("could not parse/generate dep info at: {}",
+ rustc_dep_info_loc.display()))
+ })?;
}
Ok(())
//
// The first returned value here is the argument to pass to rustc, and the
// second is the cwd that rustc should operate in.
-fn path_args(cx: &Context, unit: &Unit) -> (PathBuf, Option<PathBuf>) {
+fn path_args(cx: &Context, unit: &Unit) -> (PathBuf, PathBuf) {
let ws_root = cx.ws.root();
let src = unit.target.src_path();
assert!(src.is_absolute());
match src.strip_prefix(ws_root) {
- Ok(path) => (path.to_path_buf(), Some(ws_root.to_path_buf())),
- Err(_) => (src.to_path_buf(), None),
+ Ok(path) => (path.to_path_buf(), ws_root.to_path_buf()),
+ Err(_) => (src.to_path_buf(), unit.pkg.root().to_path_buf()),
}
}
fn add_path_args(cx: &Context, unit: &Unit, cmd: &mut ProcessBuilder) {
let (arg, cwd) = path_args(cx, unit);
cmd.arg(arg);
- if let Some(cwd) = cwd {
- cmd.cwd(cwd);
- }
+ cmd.cwd(cwd);
}
fn build_base_args<'a, 'cfg>(cx: &mut Context<'a, 'cfg>,