Catch filename output collisions in rustdoc.

This commit is contained in:
Eric Huss 2019-05-31 12:06:07 -07:00
parent 32cf756444
commit 69091780d1
2 changed files with 166 additions and 93 deletions

View file

@ -9,7 +9,7 @@ use lazycell::LazyCell;
use log::info;
use super::{BuildContext, Context, FileFlavor, Kind, Layout};
use crate::core::compiler::Unit;
use crate::core::compiler::{CompileMode, Unit};
use crate::core::{TargetKind, Workspace};
use crate::util::{self, CargoResult};
@ -294,106 +294,137 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
bcx: &BuildContext<'a, 'cfg>,
) -> CargoResult<Arc<Vec<OutputFile>>> {
let out_dir = self.out_dir(unit);
let file_stem = self.file_stem(unit);
let ret = match unit.mode {
CompileMode::Check { .. } => {
// This may be confusing. rustc outputs a file named `lib*.rmeta`
// for both libraries and binaries.
let file_stem = self.file_stem(unit);
let path = out_dir.join(format!("lib{}.rmeta", file_stem));
vec![OutputFile {
path,
hardlink: None,
export_path: None,
flavor: FileFlavor::Linkable { rmeta: false },
}]
}
CompileMode::Doc { .. } => {
let path = out_dir.join(unit.target.crate_name()).join("index.html");
vec![OutputFile {
path,
hardlink: None,
export_path: None,
flavor: FileFlavor::Normal,
}]
}
CompileMode::RunCustomBuild => {
// At this time, this code path does not handle build script
// outputs.
vec![]
}
CompileMode::Doctest => {
// Doctests are built in a temporary directory and then
// deleted. There is the `--persist-doctests` unstable flag,
// but Cargo does not know about that.
vec![]
}
CompileMode::Test | CompileMode::Build | CompileMode::Bench => {
self.calc_outputs_rustc(unit, bcx, &out_dir)?
}
};
info!("Target filenames: {:?}", ret);
Ok(Arc::new(ret))
}
fn calc_outputs_rustc(
&self,
unit: &Unit<'a>,
bcx: &BuildContext<'a, 'cfg>,
out_dir: &Path,
) -> CargoResult<Vec<OutputFile>> {
let mut ret = Vec::new();
let mut unsupported = Vec::new();
let link_stem = self.link_stem(unit);
let info = if unit.kind == Kind::Host {
&bcx.host_info
} else {
&bcx.target_info
};
let file_stem = self.file_stem(unit);
let mut ret = Vec::new();
let mut unsupported = Vec::new();
{
if unit.mode.is_check() {
// This may be confusing. rustc outputs a file named `lib*.rmeta`
// for both libraries and binaries.
let path = out_dir.join(format!("lib{}.rmeta", file_stem));
ret.push(OutputFile {
path,
hardlink: None,
export_path: None,
flavor: FileFlavor::Linkable { rmeta: false },
});
let mut add = |crate_type: &str, flavor: FileFlavor| -> CargoResult<()> {
let crate_type = if crate_type == "lib" {
"rlib"
} else {
let mut add = |crate_type: &str, flavor: FileFlavor| -> CargoResult<()> {
let crate_type = if crate_type == "lib" {
"rlib"
} else {
crate_type
};
let file_types = info.file_types(
crate_type,
flavor,
unit.target.kind(),
bcx.target_triple(),
)?;
crate_type
};
let file_types =
info.file_types(crate_type, flavor, unit.target.kind(), bcx.target_triple())?;
match file_types {
Some(types) => {
for file_type in types {
let path = out_dir.join(file_type.filename(&file_stem));
let hardlink = link_stem
.as_ref()
.map(|&(ref ld, ref ls)| ld.join(file_type.filename(ls)));
let export_path = if unit.target.is_custom_build() {
None
} else {
self.export_dir.as_ref().and_then(|export_dir| {
hardlink.as_ref().and_then(|hardlink| {
Some(export_dir.join(hardlink.file_name().unwrap()))
})
})
};
ret.push(OutputFile {
path,
hardlink,
export_path,
flavor: file_type.flavor,
});
}
}
// Not supported; don't worry about it.
None => {
unsupported.push(crate_type.to_string());
}
}
Ok(())
};
// info!("{:?}", unit);
match *unit.target.kind() {
TargetKind::Bin
| TargetKind::CustomBuild
| TargetKind::ExampleBin
| TargetKind::Bench
| TargetKind::Test => {
add("bin", FileFlavor::Normal)?;
}
TargetKind::Lib(..) | TargetKind::ExampleLib(..) if unit.mode.is_any_test() => {
add("bin", FileFlavor::Normal)?;
}
TargetKind::ExampleLib(ref kinds) | TargetKind::Lib(ref kinds) => {
for kind in kinds {
add(
kind.crate_type(),
if kind.linkable() {
FileFlavor::Linkable { rmeta: false }
} else {
FileFlavor::Normal
},
)?;
}
let path = out_dir.join(format!("lib{}.rmeta", file_stem));
if !unit.target.requires_upstream_objects() {
ret.push(OutputFile {
path,
hardlink: None,
export_path: None,
flavor: FileFlavor::Linkable { rmeta: true },
});
}
match file_types {
Some(types) => {
for file_type in types {
let path = out_dir.join(file_type.filename(&file_stem));
let hardlink = link_stem
.as_ref()
.map(|&(ref ld, ref ls)| ld.join(file_type.filename(ls)));
let export_path = if unit.target.is_custom_build() {
None
} else {
self.export_dir.as_ref().and_then(|export_dir| {
hardlink.as_ref().and_then(|hardlink| {
Some(export_dir.join(hardlink.file_name().unwrap()))
})
})
};
ret.push(OutputFile {
path,
hardlink,
export_path,
flavor: file_type.flavor,
});
}
}
// Not supported; don't worry about it.
None => {
unsupported.push(crate_type.to_string());
}
}
Ok(())
};
match *unit.target.kind() {
TargetKind::Bin
| TargetKind::CustomBuild
| TargetKind::ExampleBin
| TargetKind::Bench
| TargetKind::Test => {
add("bin", FileFlavor::Normal)?;
}
TargetKind::Lib(..) | TargetKind::ExampleLib(..) if unit.mode.is_any_test() => {
add("bin", FileFlavor::Normal)?;
}
TargetKind::ExampleLib(ref kinds) | TargetKind::Lib(ref kinds) => {
for kind in kinds {
add(
kind.crate_type(),
if kind.linkable() {
FileFlavor::Linkable { rmeta: false }
} else {
FileFlavor::Normal
},
)?;
}
let path = out_dir.join(format!("lib{}.rmeta", file_stem));
if !unit.target.requires_upstream_objects() {
ret.push(OutputFile {
path,
hardlink: None,
export_path: None,
flavor: FileFlavor::Linkable { rmeta: true },
});
}
}
}
if ret.is_empty() {
@ -413,9 +444,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
bcx.target_triple()
);
}
info!("Target filenames: {:?}", ret);
Ok(Arc::new(ret))
Ok(ret)
}
}

View file

@ -103,3 +103,47 @@ This may become a hard error in the future; see <https://github.com/rust-lang/ca
")
.run();
}
#[test]
fn collision_doc() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
[dependencies]
foo2 = { path = "foo2" }
"#,
)
.file("src/lib.rs", "")
.file(
"foo2/Cargo.toml",
r#"
[package]
name = "foo2"
version = "0.1.0"
[lib]
name = "foo"
"#,
)
.file("foo2/src/lib.rs", "")
.build();
p.cargo("doc")
.with_stderr_contains(
"\
[WARNING] output filename collision.
The lib target `foo` in package `foo2 v0.1.0 ([..]/foo/foo2)` has the same output \
filename as the lib target `foo` in package `foo v0.1.0 ([..]/foo)`.
Colliding filename is: [..]/foo/target/doc/foo/index.html
The targets should have unique names.
Consider changing their names to be unique or compiling them separately.
This may become a hard error in the future; see <https://github.com/rust-lang/cargo/issues/6313>.
",
)
.run();
}