mirror of
https://github.com/rust-lang/cargo
synced 2024-10-02 22:13:47 +00:00
Catch filename output collisions in rustdoc.
This commit is contained in:
parent
32cf756444
commit
69091780d1
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue