Skip to content

Commit 6909178

Browse files
committed
Catch filename output collisions in rustdoc.
1 parent 32cf756 commit 6909178

File tree

2 files changed

+166
-93
lines changed

2 files changed

+166
-93
lines changed

src/cargo/core/compiler/context/compilation_files.rs

Lines changed: 122 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use lazycell::LazyCell;
99
use log::info;
1010

1111
use super::{BuildContext, Context, FileFlavor, Kind, Layout};
12-
use crate::core::compiler::Unit;
12+
use crate::core::compiler::{CompileMode, Unit};
1313
use crate::core::{TargetKind, Workspace};
1414
use crate::util::{self, CargoResult};
1515

@@ -294,106 +294,137 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
294294
bcx: &BuildContext<'a, 'cfg>,
295295
) -> CargoResult<Arc<Vec<OutputFile>>> {
296296
let out_dir = self.out_dir(unit);
297-
let file_stem = self.file_stem(unit);
298-
let link_stem = self.link_stem(unit);
299-
let info = if unit.kind == Kind::Host {
300-
&bcx.host_info
301-
} else {
302-
&bcx.target_info
303-
};
304297

305-
let mut ret = Vec::new();
306-
let mut unsupported = Vec::new();
307-
{
308-
if unit.mode.is_check() {
298+
let ret = match unit.mode {
299+
CompileMode::Check { .. } => {
309300
// This may be confusing. rustc outputs a file named `lib*.rmeta`
310301
// for both libraries and binaries.
302+
let file_stem = self.file_stem(unit);
311303
let path = out_dir.join(format!("lib{}.rmeta", file_stem));
312-
ret.push(OutputFile {
304+
vec![OutputFile {
313305
path,
314306
hardlink: None,
315307
export_path: None,
316308
flavor: FileFlavor::Linkable { rmeta: false },
317-
});
318-
} else {
319-
let mut add = |crate_type: &str, flavor: FileFlavor| -> CargoResult<()> {
320-
let crate_type = if crate_type == "lib" {
321-
"rlib"
322-
} else {
323-
crate_type
324-
};
325-
let file_types = info.file_types(
326-
crate_type,
327-
flavor,
328-
unit.target.kind(),
329-
bcx.target_triple(),
330-
)?;
309+
}]
310+
}
311+
CompileMode::Doc { .. } => {
312+
let path = out_dir.join(unit.target.crate_name()).join("index.html");
313+
vec![OutputFile {
314+
path,
315+
hardlink: None,
316+
export_path: None,
317+
flavor: FileFlavor::Normal,
318+
}]
319+
}
320+
CompileMode::RunCustomBuild => {
321+
// At this time, this code path does not handle build script
322+
// outputs.
323+
vec![]
324+
}
325+
CompileMode::Doctest => {
326+
// Doctests are built in a temporary directory and then
327+
// deleted. There is the `--persist-doctests` unstable flag,
328+
// but Cargo does not know about that.
329+
vec![]
330+
}
331+
CompileMode::Test | CompileMode::Build | CompileMode::Bench => {
332+
self.calc_outputs_rustc(unit, bcx, &out_dir)?
333+
}
334+
};
335+
info!("Target filenames: {:?}", ret);
331336

332-
match file_types {
333-
Some(types) => {
334-
for file_type in types {
335-
let path = out_dir.join(file_type.filename(&file_stem));
336-
let hardlink = link_stem
337-
.as_ref()
338-
.map(|&(ref ld, ref ls)| ld.join(file_type.filename(ls)));
339-
let export_path = if unit.target.is_custom_build() {
340-
None
341-
} else {
342-
self.export_dir.as_ref().and_then(|export_dir| {
343-
hardlink.as_ref().and_then(|hardlink| {
344-
Some(export_dir.join(hardlink.file_name().unwrap()))
345-
})
346-
})
347-
};
348-
ret.push(OutputFile {
349-
path,
350-
hardlink,
351-
export_path,
352-
flavor: file_type.flavor,
353-
});
354-
}
355-
}
356-
// Not supported; don't worry about it.
357-
None => {
358-
unsupported.push(crate_type.to_string());
359-
}
360-
}
361-
Ok(())
362-
};
363-
// info!("{:?}", unit);
364-
match *unit.target.kind() {
365-
TargetKind::Bin
366-
| TargetKind::CustomBuild
367-
| TargetKind::ExampleBin
368-
| TargetKind::Bench
369-
| TargetKind::Test => {
370-
add("bin", FileFlavor::Normal)?;
371-
}
372-
TargetKind::Lib(..) | TargetKind::ExampleLib(..) if unit.mode.is_any_test() => {
373-
add("bin", FileFlavor::Normal)?;
374-
}
375-
TargetKind::ExampleLib(ref kinds) | TargetKind::Lib(ref kinds) => {
376-
for kind in kinds {
377-
add(
378-
kind.crate_type(),
379-
if kind.linkable() {
380-
FileFlavor::Linkable { rmeta: false }
381-
} else {
382-
FileFlavor::Normal
383-
},
384-
)?;
385-
}
386-
let path = out_dir.join(format!("lib{}.rmeta", file_stem));
387-
if !unit.target.requires_upstream_objects() {
388-
ret.push(OutputFile {
389-
path,
390-
hardlink: None,
391-
export_path: None,
392-
flavor: FileFlavor::Linkable { rmeta: true },
393-
});
394-
}
337+
Ok(Arc::new(ret))
338+
}
339+
340+
fn calc_outputs_rustc(
341+
&self,
342+
unit: &Unit<'a>,
343+
bcx: &BuildContext<'a, 'cfg>,
344+
out_dir: &Path,
345+
) -> CargoResult<Vec<OutputFile>> {
346+
let mut ret = Vec::new();
347+
let mut unsupported = Vec::new();
348+
349+
let link_stem = self.link_stem(unit);
350+
let info = if unit.kind == Kind::Host {
351+
&bcx.host_info
352+
} else {
353+
&bcx.target_info
354+
};
355+
let file_stem = self.file_stem(unit);
356+
357+
let mut add = |crate_type: &str, flavor: FileFlavor| -> CargoResult<()> {
358+
let crate_type = if crate_type == "lib" {
359+
"rlib"
360+
} else {
361+
crate_type
362+
};
363+
let file_types =
364+
info.file_types(crate_type, flavor, unit.target.kind(), bcx.target_triple())?;
365+
366+
match file_types {
367+
Some(types) => {
368+
for file_type in types {
369+
let path = out_dir.join(file_type.filename(&file_stem));
370+
let hardlink = link_stem
371+
.as_ref()
372+
.map(|&(ref ld, ref ls)| ld.join(file_type.filename(ls)));
373+
let export_path = if unit.target.is_custom_build() {
374+
None
375+
} else {
376+
self.export_dir.as_ref().and_then(|export_dir| {
377+
hardlink.as_ref().and_then(|hardlink| {
378+
Some(export_dir.join(hardlink.file_name().unwrap()))
379+
})
380+
})
381+
};
382+
ret.push(OutputFile {
383+
path,
384+
hardlink,
385+
export_path,
386+
flavor: file_type.flavor,
387+
});
395388
}
396389
}
390+
// Not supported; don't worry about it.
391+
None => {
392+
unsupported.push(crate_type.to_string());
393+
}
394+
}
395+
Ok(())
396+
};
397+
match *unit.target.kind() {
398+
TargetKind::Bin
399+
| TargetKind::CustomBuild
400+
| TargetKind::ExampleBin
401+
| TargetKind::Bench
402+
| TargetKind::Test => {
403+
add("bin", FileFlavor::Normal)?;
404+
}
405+
TargetKind::Lib(..) | TargetKind::ExampleLib(..) if unit.mode.is_any_test() => {
406+
add("bin", FileFlavor::Normal)?;
407+
}
408+
TargetKind::ExampleLib(ref kinds) | TargetKind::Lib(ref kinds) => {
409+
for kind in kinds {
410+
add(
411+
kind.crate_type(),
412+
if kind.linkable() {
413+
FileFlavor::Linkable { rmeta: false }
414+
} else {
415+
FileFlavor::Normal
416+
},
417+
)?;
418+
}
419+
let path = out_dir.join(format!("lib{}.rmeta", file_stem));
420+
if !unit.target.requires_upstream_objects() {
421+
ret.push(OutputFile {
422+
path,
423+
hardlink: None,
424+
export_path: None,
425+
flavor: FileFlavor::Linkable { rmeta: true },
426+
});
427+
}
397428
}
398429
}
399430
if ret.is_empty() {
@@ -413,9 +444,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
413444
bcx.target_triple()
414445
);
415446
}
416-
info!("Target filenames: {:?}", ret);
417-
418-
Ok(Arc::new(ret))
447+
Ok(ret)
419448
}
420449
}
421450

tests/testsuite/collisions.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,47 @@ This may become a hard error in the future; see <https://github.com/rust-lang/ca
103103
")
104104
.run();
105105
}
106+
107+
#[test]
108+
fn collision_doc() {
109+
let p = project()
110+
.file(
111+
"Cargo.toml",
112+
r#"
113+
[package]
114+
name = "foo"
115+
version = "0.1.0"
116+
117+
[dependencies]
118+
foo2 = { path = "foo2" }
119+
"#,
120+
)
121+
.file("src/lib.rs", "")
122+
.file(
123+
"foo2/Cargo.toml",
124+
r#"
125+
[package]
126+
name = "foo2"
127+
version = "0.1.0"
128+
129+
[lib]
130+
name = "foo"
131+
"#,
132+
)
133+
.file("foo2/src/lib.rs", "")
134+
.build();
135+
136+
p.cargo("doc")
137+
.with_stderr_contains(
138+
"\
139+
[WARNING] output filename collision.
140+
The lib target `foo` in package `foo2 v0.1.0 ([..]/foo/foo2)` has the same output \
141+
filename as the lib target `foo` in package `foo v0.1.0 ([..]/foo)`.
142+
Colliding filename is: [..]/foo/target/doc/foo/index.html
143+
The targets should have unique names.
144+
Consider changing their names to be unique or compiling them separately.
145+
This may become a hard error in the future; see <https://github.com/rust-lang/cargo/issues/6313>.
146+
",
147+
)
148+
.run();
149+
}

0 commit comments

Comments
 (0)