Skip to content

Commit 7007dc9

Browse files
committed
fix the actual bug
- only skip `--target` for proc-macros - don't try build non-host targets for proc-macros, since they're not supported anyway. - change rustwide_builder to look in the platform-specific target directory for the default target - stores all source docs in the target/{target_name} directory, rather than trying to special case anything - this also creates the `{target_name}` directory before copying, because `rename` delegates directly to the syscall and doesn't create parent directories
1 parent 8772e1a commit 7007dc9

File tree

2 files changed

+112
-17
lines changed

2 files changed

+112
-17
lines changed

crates/metadata/lib.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,15 +197,26 @@ impl Metadata {
197197
/// If `include_default_targets` is `true` and `targets` is unset, this also includes
198198
/// [`DEFAULT_TARGETS`]. Otherwise, if `include_default_targets` is `false` and `targets`
199199
/// is unset, `other_targets` will be empty.
200+
///
201+
/// All of the above is ignored for proc-macros, which are always only compiled for the host.
200202
pub fn targets(&self, include_default_targets: bool) -> BuildTargets<'_> {
203+
// Proc macros can only be compiled for the host, so just completely ignore any configured targets.
204+
// It would be nice to warn about this somehow ...
205+
if self.proc_macro {
206+
return BuildTargets {
207+
default_target: HOST_TARGET,
208+
other_targets: HashSet::default(),
209+
};
210+
}
211+
201212
let default_target = self
202213
.default_target
203214
.as_deref()
204215
// Use the first element of `targets` if `default_target` is unset and `targets` is non-empty
205216
.or_else(|| {
206217
self.targets
207218
.as_ref()
208-
.and_then(|targets| targets.iter().next().map(String::as_str))
219+
.and_then(|targets| targets.first().map(String::as_str))
209220
})
210221
.unwrap_or(HOST_TARGET);
211222

src/docbuilder/rustwide_builder.rs

Lines changed: 100 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,8 @@ impl RustwideBuilder {
210210
}
211211

212212
info!("copying essential files for {}", self.rustc_version);
213-
let source = build.host_target_dir().join("doc");
213+
assert!(!metadata.proc_macro);
214+
let source = build.host_target_dir().join(HOST_TARGET).join("doc");
214215
let dest = tempfile::Builder::new()
215216
.prefix("essential-files")
216217
.tempdir()?;
@@ -350,14 +351,23 @@ impl RustwideBuilder {
350351
if res.result.successful {
351352
if let Some(name) = res.cargo_metadata.root().library_name() {
352353
let host_target = build.host_target_dir();
353-
has_docs = host_target.join("doc").join(name).is_dir();
354+
has_docs = host_target
355+
.join(default_target)
356+
.join("doc")
357+
.join(name)
358+
.is_dir();
354359
}
355360
}
356361

357362
let mut algs = HashSet::new();
358363
if has_docs {
359364
debug!("adding documentation for the default target to the database");
360-
self.copy_docs(&build.host_target_dir(), local_storage.path(), "", true)?;
365+
self.copy_docs(
366+
&build.host_target_dir(),
367+
local_storage.path(),
368+
default_target,
369+
true,
370+
)?;
361371

362372
successful_targets.push(res.target.clone());
363373

@@ -593,17 +603,20 @@ impl RustwideBuilder {
593603
.is_ok()
594604
});
595605

596-
// If we're passed a default_target which requires a cross-compile,
597-
// cargo will put the output in `target/<target>/doc`.
598-
// However, if this is the default build, we don't want it there,
599-
// we want it in `target/doc`.
600-
// NOTE: don't rename this if the build failed, because `target/<target>/doc` won't exist.
601-
if successful && target != HOST_TARGET && is_default_target {
602-
// mv target/$target/doc target/doc
606+
// For proc-macros, cargo will put the output in `target/doc`.
607+
// Move it to the target-specific directory for consistency with other builds.
608+
// NOTE: don't rename this if the build failed, because `target/doc` won't exist.
609+
if successful && metadata.proc_macro {
610+
assert!(
611+
is_default_target && target == HOST_TARGET,
612+
"can't handle cross-compiling macros"
613+
);
614+
// mv target/doc target/$target/doc
603615
let target_dir = build.host_target_dir();
604-
let old_dir = target_dir.join(target).join("doc");
605-
let new_dir = target_dir.join("doc");
616+
let old_dir = target_dir.join("doc");
617+
let new_dir = target_dir.join(target).join("doc");
606618
debug!("rename {} to {}", old_dir.display(), new_dir.display());
619+
std::fs::create_dir(target_dir.join(target))?;
607620
std::fs::rename(old_dir, new_dir)?;
608621
}
609622

@@ -656,7 +669,16 @@ impl RustwideBuilder {
656669
if let Some(cpu_limit) = self.config.build_cpu_limit {
657670
cargo_args.push(format!("-j{}", cpu_limit));
658671
}
659-
if target != HOST_TARGET {
672+
// Cargo has a series of frightening bugs around cross-compiling proc-macros:
673+
// - Passing `--target` causes RUSTDOCFLAGS to fail to be passed 🤦
674+
// - Passing `--target` will *create* `target/{target-name}/doc` but will put the docs in `target/doc` anyway
675+
// As a result, it's not possible for us to support cross-compiling proc-macros.
676+
// However, all these caveats unfortunately still apply when `{target-name}` is the host.
677+
// So, only pass `--target` for crates that aren't proc-macros.
678+
//
679+
// Originally, this had a simpler check `target != HOST_TARGET`, but *that* was buggy when `HOST_TARGET` wasn't the same as the default target.
680+
// Rather than trying to keep track of it all, only special case proc-macros, which are what we actually care about.
681+
if !metadata.proc_macro {
660682
cargo_args.push("--target".into());
661683
cargo_args.push(target.into());
662684
};
@@ -702,7 +724,7 @@ impl RustwideBuilder {
702724
dest = dest.join(target);
703725
}
704726

705-
info!("{} {}", source.display(), dest.display());
727+
info!("copy {} to {}", source.display(), dest.display());
706728
copy_dir_all(source, dest).map_err(Into::into)
707729
}
708730

@@ -835,11 +857,11 @@ mod tests {
835857

836858
// doc archive exists
837859
let doc_archive = rustdoc_archive_path(crate_, version);
838-
assert!(storage.exists(&doc_archive)?);
860+
assert!(storage.exists(&doc_archive)?, "{}", doc_archive);
839861

840862
// source archive exists
841863
let source_archive = source_archive_path(crate_, version);
842-
assert!(storage.exists(&source_archive)?);
864+
assert!(storage.exists(&source_archive)?, "{}", source_archive);
843865

844866
// default target was built and is accessible
845867
assert!(storage.exists_in_archive(&doc_archive, &format!("{}/index.html", crate_path))?);
@@ -935,4 +957,66 @@ mod tests {
935957
Ok(())
936958
})
937959
}
960+
961+
#[test]
962+
#[ignore]
963+
fn test_proc_macro() {
964+
wrapper(|env| {
965+
let crate_ = "thiserror-impl";
966+
let version = "1.0.26";
967+
let mut builder = RustwideBuilder::init(env).unwrap();
968+
assert!(builder.build_package(crate_, version, PackageKind::CratesIo)?);
969+
970+
let storage = env.storage();
971+
972+
// doc archive exists
973+
let doc_archive = rustdoc_archive_path(crate_, version);
974+
assert!(storage.exists(&doc_archive)?);
975+
976+
// source archive exists
977+
let source_archive = source_archive_path(crate_, version);
978+
assert!(storage.exists(&source_archive)?);
979+
980+
Ok(())
981+
});
982+
}
983+
984+
#[test]
985+
#[ignore]
986+
fn test_cross_compile_non_host_default() {
987+
wrapper(|env| {
988+
let crate_ = "xingapi";
989+
let version = "0.3.3";
990+
let mut builder = RustwideBuilder::init(env).unwrap();
991+
assert!(builder.build_package(crate_, version, PackageKind::CratesIo)?);
992+
993+
let storage = env.storage();
994+
995+
// doc archive exists
996+
let doc_archive = rustdoc_archive_path(crate_, version);
997+
assert!(storage.exists(&doc_archive)?, "{}", doc_archive);
998+
999+
// source archive exists
1000+
let source_archive = source_archive_path(crate_, version);
1001+
assert!(storage.exists(&source_archive)?, "{}", source_archive);
1002+
1003+
let target = "x86_64-unknown-linux-gnu";
1004+
let crate_path = crate_.replace("-", "_");
1005+
let target_docs_present = storage.exists_in_archive(
1006+
&doc_archive,
1007+
&format!("{}/{}/index.html", target, crate_path),
1008+
)?;
1009+
1010+
let web = env.frontend();
1011+
let target_url = format!(
1012+
"/{}/{}/{}/{}/index.html",
1013+
crate_, version, target, crate_path
1014+
);
1015+
1016+
assert!(target_docs_present);
1017+
assert_success(&target_url, web)?;
1018+
1019+
Ok(())
1020+
});
1021+
}
9381022
}

0 commit comments

Comments
 (0)