in src/compiler/rust.rs [1991:2181]
fn write_inputs(self: Box<Self>, wtr: &mut dyn io::Write) -> Result<dist::PathTransformer> {
debug!("Packaging compile inputs for compile");
let RustInputsPackager {
crate_link_paths,
crate_types,
inputs,
mut path_transformer,
rlib_dep_reader,
env_vars,
} = *{ self };
// If this is a cargo build, we can assume all immediate `extern crate` dependencies
// have been passed on the command line, allowing us to scan them all and find the
// complete list of crates we might need.
// If it's not a cargo build, we can't to extract the `extern crate` statements and
// so have no way to build a list of necessary crates - send all rlibs.
let is_cargo = env_vars.iter().any(|(k, _)| k == "CARGO_PKG_NAME");
let mut rlib_dep_reader_and_names = if is_cargo {
rlib_dep_reader.map(|r| (r, HashSet::new()))
} else {
None
};
let mut tar_inputs = vec![];
for input_path in inputs.into_iter() {
let input_path = pkg::simplify_path(&input_path)?;
if let Some(ext) = input_path.extension() {
if !super::CAN_DIST_DYLIBS && ext == DLL_EXTENSION {
bail!(
"Cannot distribute dylib input {} on this platform",
input_path.display()
)
} else if ext == RLIB_EXTENSION || ext == RMETA_EXTENSION {
if let Some((ref rlib_dep_reader, ref mut dep_crate_names)) =
rlib_dep_reader_and_names
{
dep_crate_names.extend(
rlib_dep_reader
.discover_rlib_deps(&env_vars, &input_path)
.with_context(|| {
format!("Failed to read deps of {}", input_path.display())
})?,
)
}
}
}
if let Some(cargo_toml_path) = maybe_add_cargo_toml(&input_path, true) {
let dist_cargo_toml_path = path_transformer
.as_dist(&cargo_toml_path)
.with_context(|| {
format!(
"unable to transform input path {}",
cargo_toml_path.display()
)
})?;
tar_inputs.push((cargo_toml_path, dist_cargo_toml_path));
}
let dist_input_path = path_transformer.as_dist(&input_path).with_context(|| {
format!("unable to transform input path {}", input_path.display())
})?;
tar_inputs.push((input_path, dist_input_path))
}
if log_enabled!(Trace) {
if let Some((_, ref dep_crate_names)) = rlib_dep_reader_and_names {
trace!("Identified dependency crate names: {:?}", dep_crate_names)
}
}
// Given the link paths, find the things we need to send over the wire to the remote machine. If
// we've been able to use a dependency searcher then we can filter down just candidates for that
// crate, otherwise we need to send everything.
let mut tar_crate_libs = vec![];
for crate_link_path in crate_link_paths.into_iter() {
let crate_link_path = pkg::simplify_path(&crate_link_path)?;
let dir_entries = match fs::read_dir(crate_link_path) {
Ok(iter) => iter,
Err(e) if e.kind() == io::ErrorKind::NotFound => continue,
Err(e) => return Err(e).context("Failed to read dir entries in crate link path"),
};
for entry in dir_entries {
let entry = match entry {
Ok(entry) => entry,
Err(e) => return Err(e).context("Error during iteration over crate link path"),
};
let path = entry.path();
{
// Take a look at the path and see if it's something we care about
let libname: &str = match path.file_name().and_then(|s| s.to_str()) {
Some(name) => {
let mut rev_name_split = name.rsplitn(2, '-');
let _extra_filename_and_ext = rev_name_split.next();
let libname = if let Some(libname) = rev_name_split.next() {
libname
} else {
continue;
};
assert!(rev_name_split.next().is_none());
libname
}
None => continue,
};
let (crate_name, ext): (&str, _) = match path.extension() {
Some(ext) if libname.starts_with(DLL_PREFIX) && ext == DLL_EXTENSION => {
(&libname[DLL_PREFIX.len()..], ext)
}
Some(ext) if libname.starts_with(RLIB_PREFIX) && ext == RLIB_EXTENSION => {
(&libname[RLIB_PREFIX.len()..], ext)
}
Some(ext) if libname.starts_with(RLIB_PREFIX) && ext == RMETA_EXTENSION => {
(&libname[RLIB_PREFIX.len()..], ext)
}
_ => continue,
};
if let Some((_, ref dep_crate_names)) = rlib_dep_reader_and_names {
// We have a list of crate names we care about, see if this lib is a candidate
if !dep_crate_names.contains(crate_name) {
continue;
}
}
if !path.is_file() {
continue;
} else if !super::CAN_DIST_DYLIBS && ext == DLL_EXTENSION {
bail!(
"Cannot distribute dylib input {} on this platform",
path.display()
)
}
}
// This is a lib that may be of interest during compilation
let dist_path = path_transformer
.as_dist(&path)
.with_context(|| format!("unable to transform lib path {}", path.display()))?;
tar_crate_libs.push((path, dist_path))
}
}
let mut all_tar_inputs: Vec<_> = tar_inputs.into_iter().chain(tar_crate_libs).collect();
all_tar_inputs.sort();
// There are almost certainly duplicates from explicit externs also within the lib search paths
all_tar_inputs.dedup();
// If we're just creating an rlib then the only thing inspected inside dependency rlibs is the
// metadata, in which case we can create a trimmed rlib (which is actually a .a) with the metadata
let can_trim_rlibs = matches!(
crate_types,
CrateTypes {
rlib: true,
staticlib: false,
}
);
let mut builder = tar::Builder::new(wtr);
for (input_path, dist_input_path) in all_tar_inputs.iter() {
let mut file_header = pkg::make_tar_header(input_path, dist_input_path)?;
let file = fs::File::open(input_path)?;
if can_trim_rlibs && can_trim_this(input_path) {
let mut archive = ar::Archive::new(file);
while let Some(entry_result) = archive.next_entry() {
let mut entry = entry_result?;
if entry.header().identifier() != b"rust.metadata.bin" {
continue;
}
let mut metadata_ar = vec![];
{
let mut ar_builder = ar::Builder::new(&mut metadata_ar);
let header = entry.header().clone();
ar_builder.append(&header, &mut entry)?
}
file_header.set_size(metadata_ar.len() as u64);
file_header.set_cksum();
builder.append(&file_header, metadata_ar.as_slice())?;
break;
}
} else {
file_header.set_cksum();
builder.append(&file_header, file)?
}
}
// Finish archive
let _ = builder.into_inner()?;
Ok(path_transformer)
}