Skip to content

Commit 8006b82

Browse files
jyn514Joshua Nelson
authored and
Joshua Nelson
committed
Handle whitespace properly in rustdoc and rustc options
- Use `cargo rustdoc` and `--config build.rustflags` to preserve whitespace - Allow passing in additional rustdoc and cargo arguments now that `RUSTDOCFLAGS` isn't dependable
1 parent 395daf7 commit 8006b82

File tree

2 files changed

+40
-20
lines changed

2 files changed

+40
-20
lines changed

crates/metadata/lib.rs

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ pub struct Metadata {
122122
targets: Option<Vec<String>>,
123123

124124
/// List of command line arguments for `rustc`.
125-
rustc_args: Option<Vec<String>>,
125+
#[serde(default)]
126+
rustc_args: Vec<String>,
126127

127128
/// List of command line arguments for `rustdoc`.
128129
#[serde(default)]
@@ -217,15 +218,22 @@ impl Metadata {
217218

218219
/// Return the arguments that should be passed to `cargo`.
219220
///
220-
// TODO: maybe it shouldn't?
221-
/// This will always include `doc --lib --no-deps`.
221+
/// This will always include `rustdoc --lib --`.
222222
/// This will never include `--target`.
223223
///
224+
/// You can pass `additional_args` to cargo, as well as `rustdoc_args` to `rustdoc`.
225+
/// Do not depend on modifying the `Vec` after it's returned; additional arguments
226+
/// appended may be passed to rustdoc instead.
227+
///
224228
/// Note that this does not necessarily reproduce the HTML _output_ of docs.rs exactly.
225229
/// For example, the links may point somewhere different than they would on docs.rs.
226230
/// However, rustdoc will see exactly the same code as it would on docs.rs, even counting `cfg`s.
227-
pub fn cargo_args(&self) -> Vec<String> {
228-
let mut cargo_args: Vec<String> = vec!["doc".into(), "--lib".into(), "--no-deps".into()];
231+
pub fn cargo_args(
232+
&self,
233+
additional_args: &[impl AsRef<str>],
234+
rustdoc_args: &[impl AsRef<str>],
235+
) -> Vec<String> {
236+
let mut cargo_args: Vec<String> = vec!["rustdoc".into(), "--lib".into()];
229237

230238
if let Some(features) = &self.features {
231239
cargo_args.push("--features".into());
@@ -240,22 +248,31 @@ impl Metadata {
240248
cargo_args.push("--no-default-features".into());
241249
}
242250

251+
// Pass `RUSTFLAGS` using `cargo --config`, which handles whitespace correctly.
252+
if !self.rustc_args.is_empty() {
253+
cargo_args.push("-Z".into());
254+
cargo_args.push("unstable-options".into());
255+
cargo_args.push("--config".into());
256+
let rustflags =
257+
toml::to_string(&self.rustc_args).expect("serializing a string should never fail");
258+
cargo_args.push(format!("build.rustflags={}", rustflags));
259+
}
260+
261+
cargo_args.extend(additional_args.iter().map(|s| s.as_ref().to_owned()));
262+
cargo_args.push("--".into());
263+
cargo_args.extend_from_slice(&self.rustdoc_args);
264+
cargo_args.extend(rustdoc_args.iter().map(|s| s.as_ref().to_owned()));
243265
cargo_args
244266
}
245267

246268
/// Return the environment variables that should be set when building this crate.
247269
///
248270
/// This will always contain at least `RUSTDOCFLAGS="-Z unstable-options"`.
249271
pub fn environment_variables(&self) -> HashMap<&'static str, String> {
250-
let joined = |v: &Option<Vec<_>>| v.as_ref().map(|args| args.join(" ")).unwrap_or_default();
251-
252272
let mut map = HashMap::new();
253-
map.insert("RUSTFLAGS", joined(&self.rustc_args));
254-
map.insert("RUSTDOCFLAGS", self.rustdoc_args.join(" "));
255273
// For docs.rs detection from build scripts:
256274
// https://github.com/rust-lang/docs.rs/issues/147
257275
map.insert("DOCS_RS", "1".into());
258-
259276
map
260277
}
261278
}

src/docbuilder/rustwide_builder.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -561,17 +561,16 @@ impl RustwideBuilder {
561561
target: &str,
562562
metadata: &Metadata,
563563
limits: &Limits,
564-
rustdoc_flags_extras: Vec<String>,
564+
mut rustdoc_flags_extras: Vec<String>,
565565
) -> Result<Command<'ws, 'pl>> {
566566
// If the explicit target is not a tier one target, we need to install it.
567567
if !docsrs_metadata::DEFAULT_TARGETS.contains(&target) {
568568
// This is a no-op if the target is already installed.
569569
self.toolchain.add_target(&self.workspace, target)?;
570570
}
571571

572-
let mut cargo_args = metadata.cargo_args();
573-
574572
// Add docs.rs specific arguments
573+
let mut cargo_args = Vec::new();
575574
if let Some(cpu_limit) = self.config.build_cpu_limit {
576575
cargo_args.push(format!("-j{}", cpu_limit));
577576
}
@@ -580,18 +579,22 @@ impl RustwideBuilder {
580579
cargo_args.push(target.into());
581580
};
582581

583-
let mut env_vars = metadata.environment_variables();
584-
let rustdoc_flags = env_vars.entry("RUSTDOCFLAGS").or_default();
585-
// WARNING: this *must* end with a space or it will cause rustdoc to give an error
586-
rustdoc_flags
587-
.push_str(" --static-root-path / --cap-lints warn --disable-per-crate-search ");
588-
rustdoc_flags.push_str(&rustdoc_flags_extras.join(" "));
582+
#[rustfmt::skip]
583+
const UNCONDITIONAL_ARGS: &[&str] = &[
584+
"--static-root-path", "/",
585+
"--cap-lints", "warn",
586+
"--disable-per-crate-search",
587+
];
588+
589+
rustdoc_flags_extras.extend(UNCONDITIONAL_ARGS.iter().map(|&s| s.to_owned()));
590+
let cargo_args = metadata.cargo_args(&cargo_args, &rustdoc_flags_extras);
589591

590592
let mut command = build
591593
.cargo()
592594
.timeout(Some(limits.timeout()))
593595
.no_output_timeout(None);
594-
for (key, val) in env_vars {
596+
597+
for (key, val) in metadata.environment_variables() {
595598
command = command.env(key, val);
596599
}
597600

0 commit comments

Comments
 (0)