mirror of
https://github.com/rust-lang/cargo
synced 2024-09-13 04:51:31 +00:00
Auto merge of #9525 - willcrichton:example-analyzer, r=alexcrichton
Scrape code examples from examples/ directory for Rustdoc Adds support for the functionality described in rust-lang/rfcs#3123 Matching changes to rustdoc are here: https://github.com/rust-lang/rust/pull/85833
This commit is contained in:
commit
0a98b1de5c
|
@ -1,6 +1,7 @@
|
||||||
use crate::command_prelude::*;
|
use crate::command_prelude::*;
|
||||||
|
|
||||||
use cargo::ops::{self, DocOptions};
|
use anyhow::anyhow;
|
||||||
|
use cargo::ops::{self, CompileFilter, DocOptions, FilterRule, LibRule};
|
||||||
|
|
||||||
pub fn cli() -> App {
|
pub fn cli() -> App {
|
||||||
subcommand("doc")
|
subcommand("doc")
|
||||||
|
@ -19,6 +20,13 @@ pub fn cli() -> App {
|
||||||
)
|
)
|
||||||
.arg(opt("no-deps", "Don't build documentation for dependencies"))
|
.arg(opt("no-deps", "Don't build documentation for dependencies"))
|
||||||
.arg(opt("document-private-items", "Document private items"))
|
.arg(opt("document-private-items", "Document private items"))
|
||||||
|
.arg(
|
||||||
|
opt(
|
||||||
|
"scrape-examples",
|
||||||
|
"Scrape examples to include as function documentation",
|
||||||
|
)
|
||||||
|
.value_name("FLAGS"),
|
||||||
|
)
|
||||||
.arg_jobs()
|
.arg_jobs()
|
||||||
.arg_targets_lib_bin_example(
|
.arg_targets_lib_bin_example(
|
||||||
"Document only this package's library",
|
"Document only this package's library",
|
||||||
|
@ -48,6 +56,33 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
|
||||||
args.compile_options(config, mode, Some(&ws), ProfileChecking::Custom)?;
|
args.compile_options(config, mode, Some(&ws), ProfileChecking::Custom)?;
|
||||||
compile_opts.rustdoc_document_private_items = args.is_present("document-private-items");
|
compile_opts.rustdoc_document_private_items = args.is_present("document-private-items");
|
||||||
|
|
||||||
|
// TODO(wcrichto): move scrape example configuration into Cargo.toml before stabilization
|
||||||
|
// See: https://github.com/rust-lang/cargo/pull/9525#discussion_r728470927
|
||||||
|
compile_opts.rustdoc_scrape_examples = match args.value_of("scrape-examples") {
|
||||||
|
Some(s) => Some(match s {
|
||||||
|
"all" => CompileFilter::new_all_targets(),
|
||||||
|
"examples" => CompileFilter::new(
|
||||||
|
LibRule::False,
|
||||||
|
FilterRule::none(),
|
||||||
|
FilterRule::none(),
|
||||||
|
FilterRule::All,
|
||||||
|
FilterRule::none(),
|
||||||
|
),
|
||||||
|
_ => {
|
||||||
|
return Err(CliError::from(anyhow!(
|
||||||
|
r#"--scrape-examples must take "all" or "examples" as an argument"#
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if compile_opts.rustdoc_scrape_examples.is_some() {
|
||||||
|
config
|
||||||
|
.cli_unstable()
|
||||||
|
.fail_if_stable_opt("--scrape-examples", 9910)?;
|
||||||
|
}
|
||||||
|
|
||||||
let doc_opts = DocOptions {
|
let doc_opts = DocOptions {
|
||||||
open_result: args.is_present("open"),
|
open_result: args.is_present("open"),
|
||||||
compile_opts,
|
compile_opts,
|
||||||
|
|
|
@ -149,6 +149,8 @@ pub enum CompileMode {
|
||||||
Doc { deps: bool },
|
Doc { deps: bool },
|
||||||
/// A target that will be tested with `rustdoc`.
|
/// A target that will be tested with `rustdoc`.
|
||||||
Doctest,
|
Doctest,
|
||||||
|
/// An example or library that will be scraped for function calls by `rustdoc`.
|
||||||
|
Docscrape,
|
||||||
/// A marker for Units that represent the execution of a `build.rs` script.
|
/// A marker for Units that represent the execution of a `build.rs` script.
|
||||||
RunCustomBuild,
|
RunCustomBuild,
|
||||||
}
|
}
|
||||||
|
@ -166,6 +168,7 @@ impl ser::Serialize for CompileMode {
|
||||||
Bench => "bench".serialize(s),
|
Bench => "bench".serialize(s),
|
||||||
Doc { .. } => "doc".serialize(s),
|
Doc { .. } => "doc".serialize(s),
|
||||||
Doctest => "doctest".serialize(s),
|
Doctest => "doctest".serialize(s),
|
||||||
|
Docscrape => "docscrape".serialize(s),
|
||||||
RunCustomBuild => "run-custom-build".serialize(s),
|
RunCustomBuild => "run-custom-build".serialize(s),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,6 +190,11 @@ impl CompileMode {
|
||||||
self == CompileMode::Doctest
|
self == CompileMode::Doctest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if this is scraping examples for documentation.
|
||||||
|
pub fn is_doc_scrape(self) -> bool {
|
||||||
|
self == CompileMode::Docscrape
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `true` if this is any type of test (test, benchmark, doc test, or
|
/// Returns `true` if this is any type of test (test, benchmark, doc test, or
|
||||||
/// check test).
|
/// check test).
|
||||||
pub fn is_any_test(self) -> bool {
|
pub fn is_any_test(self) -> bool {
|
||||||
|
|
|
@ -47,6 +47,9 @@ pub struct BuildContext<'a, 'cfg> {
|
||||||
/// The dependency graph of units to compile.
|
/// The dependency graph of units to compile.
|
||||||
pub unit_graph: UnitGraph,
|
pub unit_graph: UnitGraph,
|
||||||
|
|
||||||
|
/// Reverse-dependencies of documented units, used by the rustdoc --scrape-examples flag.
|
||||||
|
pub scrape_units: Vec<Unit>,
|
||||||
|
|
||||||
/// The list of all kinds that are involved in this build
|
/// The list of all kinds that are involved in this build
|
||||||
pub all_kinds: HashSet<CompileKind>,
|
pub all_kinds: HashSet<CompileKind>,
|
||||||
}
|
}
|
||||||
|
@ -61,6 +64,7 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> {
|
||||||
target_data: RustcTargetData<'cfg>,
|
target_data: RustcTargetData<'cfg>,
|
||||||
roots: Vec<Unit>,
|
roots: Vec<Unit>,
|
||||||
unit_graph: UnitGraph,
|
unit_graph: UnitGraph,
|
||||||
|
scrape_units: Vec<Unit>,
|
||||||
) -> CargoResult<BuildContext<'a, 'cfg>> {
|
) -> CargoResult<BuildContext<'a, 'cfg>> {
|
||||||
let all_kinds = unit_graph
|
let all_kinds = unit_graph
|
||||||
.keys()
|
.keys()
|
||||||
|
@ -79,6 +83,7 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> {
|
||||||
target_data,
|
target_data,
|
||||||
roots,
|
roots,
|
||||||
unit_graph,
|
unit_graph,
|
||||||
|
scrape_units,
|
||||||
all_kinds,
|
all_kinds,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -452,7 +452,10 @@ impl TargetInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CompileMode::Check { .. } => Ok((vec![FileType::new_rmeta()], Vec::new())),
|
CompileMode::Check { .. } => Ok((vec![FileType::new_rmeta()], Vec::new())),
|
||||||
CompileMode::Doc { .. } | CompileMode::Doctest | CompileMode::RunCustomBuild => {
|
CompileMode::Doc { .. }
|
||||||
|
| CompileMode::Doctest
|
||||||
|
| CompileMode::Docscrape
|
||||||
|
| CompileMode::RunCustomBuild => {
|
||||||
panic!("asked for rustc output for non-rustc mode")
|
panic!("asked for rustc output for non-rustc mode")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,7 +191,9 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
|
||||||
/// Returns the directory where the artifacts for the given unit are
|
/// Returns the directory where the artifacts for the given unit are
|
||||||
/// initially created.
|
/// initially created.
|
||||||
pub fn out_dir(&self, unit: &Unit) -> PathBuf {
|
pub fn out_dir(&self, unit: &Unit) -> PathBuf {
|
||||||
if unit.mode.is_doc() {
|
// Docscrape units need to have doc/ set as the out_dir so sources for reverse-dependencies
|
||||||
|
// will be put into doc/ and not into deps/ where the *.examples files are stored.
|
||||||
|
if unit.mode.is_doc() || unit.mode.is_doc_scrape() {
|
||||||
self.layout(unit.kind).doc().to_path_buf()
|
self.layout(unit.kind).doc().to_path_buf()
|
||||||
} else if unit.mode.is_doc_test() {
|
} else if unit.mode.is_doc_test() {
|
||||||
panic!("doc tests do not have an out dir");
|
panic!("doc tests do not have an out dir");
|
||||||
|
@ -417,6 +419,17 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
|
||||||
// but Cargo does not know about that.
|
// but Cargo does not know about that.
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
|
CompileMode::Docscrape => {
|
||||||
|
let path = self
|
||||||
|
.deps_dir(unit)
|
||||||
|
.join(format!("{}.examples", unit.buildkey()));
|
||||||
|
vec![OutputFile {
|
||||||
|
path,
|
||||||
|
hardlink: None,
|
||||||
|
export_path: None,
|
||||||
|
flavor: FileFlavor::Normal,
|
||||||
|
}]
|
||||||
|
}
|
||||||
CompileMode::Test
|
CompileMode::Test
|
||||||
| CompileMode::Build
|
| CompileMode::Build
|
||||||
| CompileMode::Bench
|
| CompileMode::Bench
|
||||||
|
|
|
@ -80,6 +80,10 @@ pub struct Context<'a, 'cfg> {
|
||||||
/// compilation is happening (only object, only bitcode, both, etc), and is
|
/// compilation is happening (only object, only bitcode, both, etc), and is
|
||||||
/// precalculated early on.
|
/// precalculated early on.
|
||||||
pub lto: HashMap<Unit, Lto>,
|
pub lto: HashMap<Unit, Lto>,
|
||||||
|
|
||||||
|
/// Map of Doc/Docscrape units to metadata for their -Cmetadata flag.
|
||||||
|
/// See Context::find_metadata_units for more details.
|
||||||
|
pub metadata_for_doc_units: HashMap<Unit, Metadata>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'cfg> Context<'a, 'cfg> {
|
impl<'a, 'cfg> Context<'a, 'cfg> {
|
||||||
|
@ -120,6 +124,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
|
||||||
rustc_clients: HashMap::new(),
|
rustc_clients: HashMap::new(),
|
||||||
pipelining,
|
pipelining,
|
||||||
lto: HashMap::new(),
|
lto: HashMap::new(),
|
||||||
|
metadata_for_doc_units: HashMap::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,6 +139,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
|
||||||
self.prepare()?;
|
self.prepare()?;
|
||||||
custom_build::build_map(&mut self)?;
|
custom_build::build_map(&mut self)?;
|
||||||
self.check_collisions()?;
|
self.check_collisions()?;
|
||||||
|
self.compute_metadata_for_doc_units();
|
||||||
|
|
||||||
// We need to make sure that if there were any previous docs
|
// We need to make sure that if there were any previous docs
|
||||||
// already compiled, they were compiled with the same Rustc version that we're currently
|
// already compiled, they were compiled with the same Rustc version that we're currently
|
||||||
|
@ -620,4 +626,40 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
|
||||||
|
|
||||||
Ok(client)
|
Ok(client)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Finds metadata for Doc/Docscrape units.
|
||||||
|
///
|
||||||
|
/// rustdoc needs a -Cmetadata flag in order to recognize StableCrateIds that refer to
|
||||||
|
/// items in the crate being documented. The -Cmetadata flag used by reverse-dependencies
|
||||||
|
/// will be the metadata of the Cargo unit that generated the current library's rmeta file,
|
||||||
|
/// which should be a Check unit.
|
||||||
|
///
|
||||||
|
/// If the current crate has reverse-dependencies, such a Check unit should exist, and so
|
||||||
|
/// we use that crate's metadata. If not, we use the crate's Doc unit so at least examples
|
||||||
|
/// scraped from the current crate can be used when documenting the current crate.
|
||||||
|
pub fn compute_metadata_for_doc_units(&mut self) {
|
||||||
|
for unit in self.bcx.unit_graph.keys() {
|
||||||
|
if !unit.mode.is_doc() && !unit.mode.is_doc_scrape() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let matching_units = self
|
||||||
|
.bcx
|
||||||
|
.unit_graph
|
||||||
|
.keys()
|
||||||
|
.filter(|other| {
|
||||||
|
unit.pkg == other.pkg
|
||||||
|
&& unit.target == other.target
|
||||||
|
&& !other.mode.is_doc_scrape()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let metadata_unit = matching_units
|
||||||
|
.iter()
|
||||||
|
.find(|other| other.mode.is_check())
|
||||||
|
.or_else(|| matching_units.iter().find(|other| other.mode.is_doc()))
|
||||||
|
.unwrap_or(&unit);
|
||||||
|
self.metadata_for_doc_units
|
||||||
|
.insert(unit.clone(), self.files().metadata(metadata_unit));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,7 +165,7 @@ fn compile<'cfg>(
|
||||||
let force = exec.force_rebuild(unit) || force_rebuild;
|
let force = exec.force_rebuild(unit) || force_rebuild;
|
||||||
let mut job = fingerprint::prepare_target(cx, unit, force)?;
|
let mut job = fingerprint::prepare_target(cx, unit, force)?;
|
||||||
job.before(if job.freshness() == Freshness::Dirty {
|
job.before(if job.freshness() == Freshness::Dirty {
|
||||||
let work = if unit.mode.is_doc() {
|
let work = if unit.mode.is_doc() || unit.mode.is_doc_scrape() {
|
||||||
rustdoc(cx, unit)?
|
rustdoc(cx, unit)?
|
||||||
} else {
|
} else {
|
||||||
rustc(cx, unit, exec)?
|
rustc(cx, unit, exec)?
|
||||||
|
@ -647,6 +647,42 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> {
|
||||||
rustdoc.args(args);
|
rustdoc.args(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let metadata = cx.metadata_for_doc_units[&unit];
|
||||||
|
rustdoc.arg("-C").arg(format!("metadata={}", metadata));
|
||||||
|
|
||||||
|
let scrape_output_path = |unit: &Unit| -> CargoResult<PathBuf> {
|
||||||
|
let output_dir = cx.files().deps_dir(unit);
|
||||||
|
Ok(output_dir.join(format!("{}.examples", unit.buildkey())))
|
||||||
|
};
|
||||||
|
|
||||||
|
if unit.mode.is_doc_scrape() {
|
||||||
|
debug_assert!(cx.bcx.scrape_units.contains(unit));
|
||||||
|
|
||||||
|
rustdoc.arg("-Zunstable-options");
|
||||||
|
|
||||||
|
rustdoc
|
||||||
|
.arg("--scrape-examples-output-path")
|
||||||
|
.arg(scrape_output_path(unit)?);
|
||||||
|
|
||||||
|
// Only scrape example for items from crates in the workspace, to reduce generated file size
|
||||||
|
for pkg in cx.bcx.ws.members() {
|
||||||
|
rustdoc
|
||||||
|
.arg("--scrape-examples-target-crate")
|
||||||
|
.arg(pkg.name());
|
||||||
|
}
|
||||||
|
} else if cx.bcx.scrape_units.len() > 0 && cx.bcx.ws.is_member(&unit.pkg) {
|
||||||
|
// We only pass scraped examples to packages in the workspace
|
||||||
|
// since examples are only coming from reverse-dependencies of workspace packages
|
||||||
|
|
||||||
|
rustdoc.arg("-Zunstable-options");
|
||||||
|
|
||||||
|
for scrape_unit in &cx.bcx.scrape_units {
|
||||||
|
rustdoc
|
||||||
|
.arg("--with-examples")
|
||||||
|
.arg(scrape_output_path(scrape_unit)?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
build_deps_args(&mut rustdoc, cx, unit)?;
|
build_deps_args(&mut rustdoc, cx, unit)?;
|
||||||
rustdoc::add_root_urls(cx, unit, &mut rustdoc)?;
|
rustdoc::add_root_urls(cx, unit, &mut rustdoc)?;
|
||||||
|
|
||||||
|
|
|
@ -176,6 +176,7 @@ impl<'cfg> Timings<'cfg> {
|
||||||
CompileMode::Bench => target.push_str(" (bench)"),
|
CompileMode::Bench => target.push_str(" (bench)"),
|
||||||
CompileMode::Doc { .. } => target.push_str(" (doc)"),
|
CompileMode::Doc { .. } => target.push_str(" (doc)"),
|
||||||
CompileMode::Doctest => target.push_str(" (doc test)"),
|
CompileMode::Doctest => target.push_str(" (doc test)"),
|
||||||
|
CompileMode::Docscrape => target.push_str(" (doc scrape)"),
|
||||||
CompileMode::RunCustomBuild => target.push_str(" (run)"),
|
CompileMode::RunCustomBuild => target.push_str(" (run)"),
|
||||||
}
|
}
|
||||||
let unit_time = UnitTime {
|
let unit_time = UnitTime {
|
||||||
|
|
|
@ -47,6 +47,7 @@ struct State<'a, 'cfg> {
|
||||||
target_data: &'a RustcTargetData<'cfg>,
|
target_data: &'a RustcTargetData<'cfg>,
|
||||||
profiles: &'a Profiles,
|
profiles: &'a Profiles,
|
||||||
interner: &'a UnitInterner,
|
interner: &'a UnitInterner,
|
||||||
|
scrape_units: &'a [Unit],
|
||||||
|
|
||||||
/// A set of edges in `unit_dependencies` where (a, b) means that the
|
/// A set of edges in `unit_dependencies` where (a, b) means that the
|
||||||
/// dependency from a to b was added purely because it was a dev-dependency.
|
/// dependency from a to b was added purely because it was a dev-dependency.
|
||||||
|
@ -61,6 +62,7 @@ pub fn build_unit_dependencies<'a, 'cfg>(
|
||||||
features: &'a ResolvedFeatures,
|
features: &'a ResolvedFeatures,
|
||||||
std_resolve: Option<&'a (Resolve, ResolvedFeatures)>,
|
std_resolve: Option<&'a (Resolve, ResolvedFeatures)>,
|
||||||
roots: &[Unit],
|
roots: &[Unit],
|
||||||
|
scrape_units: &[Unit],
|
||||||
std_roots: &HashMap<CompileKind, Vec<Unit>>,
|
std_roots: &HashMap<CompileKind, Vec<Unit>>,
|
||||||
global_mode: CompileMode,
|
global_mode: CompileMode,
|
||||||
target_data: &'a RustcTargetData<'cfg>,
|
target_data: &'a RustcTargetData<'cfg>,
|
||||||
|
@ -91,6 +93,7 @@ pub fn build_unit_dependencies<'a, 'cfg>(
|
||||||
target_data,
|
target_data,
|
||||||
profiles,
|
profiles,
|
||||||
interner,
|
interner,
|
||||||
|
scrape_units,
|
||||||
dev_dependency_edges: HashSet::new(),
|
dev_dependency_edges: HashSet::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -253,6 +256,7 @@ fn compute_deps(
|
||||||
if !dep.is_transitive()
|
if !dep.is_transitive()
|
||||||
&& !unit.target.is_test()
|
&& !unit.target.is_test()
|
||||||
&& !unit.target.is_example()
|
&& !unit.target.is_example()
|
||||||
|
&& !unit.mode.is_doc_scrape()
|
||||||
&& !unit.mode.is_any_test()
|
&& !unit.mode.is_any_test()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -467,6 +471,25 @@ fn compute_deps_doc(
|
||||||
if unit.target.is_bin() || unit.target.is_example() {
|
if unit.target.is_bin() || unit.target.is_example() {
|
||||||
ret.extend(maybe_lib(unit, state, unit_for)?);
|
ret.extend(maybe_lib(unit, state, unit_for)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add all units being scraped for examples as a dependency of Doc units.
|
||||||
|
if state.ws.is_member(&unit.pkg) {
|
||||||
|
for scrape_unit in state.scrape_units.iter() {
|
||||||
|
// This needs to match the FeaturesFor used in cargo_compile::generate_targets.
|
||||||
|
let unit_for = UnitFor::new_host(scrape_unit.target.proc_macro());
|
||||||
|
deps_of(scrape_unit, state, unit_for)?;
|
||||||
|
ret.push(new_unit_dep(
|
||||||
|
state,
|
||||||
|
scrape_unit,
|
||||||
|
&scrape_unit.pkg,
|
||||||
|
&scrape_unit.target,
|
||||||
|
unit_for,
|
||||||
|
scrape_unit.kind,
|
||||||
|
scrape_unit.mode,
|
||||||
|
)?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,7 +581,7 @@ fn dep_build_script(
|
||||||
/// Choose the correct mode for dependencies.
|
/// Choose the correct mode for dependencies.
|
||||||
fn check_or_build_mode(mode: CompileMode, target: &Target) -> CompileMode {
|
fn check_or_build_mode(mode: CompileMode, target: &Target) -> CompileMode {
|
||||||
match mode {
|
match mode {
|
||||||
CompileMode::Check { .. } | CompileMode::Doc { .. } => {
|
CompileMode::Check { .. } | CompileMode::Doc { .. } | CompileMode::Docscrape => {
|
||||||
if target.for_host() {
|
if target.for_host() {
|
||||||
// Plugin and proc macro targets should be compiled like
|
// Plugin and proc macro targets should be compiled like
|
||||||
// normal.
|
// normal.
|
||||||
|
@ -695,6 +718,14 @@ fn connect_run_custom_build_deps(state: &mut State<'_, '_>) {
|
||||||
&& other.unit.target.is_linkable()
|
&& other.unit.target.is_linkable()
|
||||||
&& other.unit.pkg.manifest().links().is_some()
|
&& other.unit.pkg.manifest().links().is_some()
|
||||||
})
|
})
|
||||||
|
// Avoid cycles when using the doc --scrape-examples feature:
|
||||||
|
// Say a workspace has crates A and B where A has a build-dependency on B.
|
||||||
|
// The Doc units for A and B will have a dependency on the Docscrape for both A and B.
|
||||||
|
// So this would add a dependency from B-build to A-build, causing a cycle:
|
||||||
|
// B (build) -> A (build) -> B(build)
|
||||||
|
// See the test scrape_examples_avoid_build_script_cycle for a concrete example.
|
||||||
|
// To avoid this cycle, we filter out the B -> A (docscrape) dependency.
|
||||||
|
.filter(|(_parent, other)| !other.unit.mode.is_doc_scrape())
|
||||||
// Skip dependencies induced via dev-dependencies since
|
// Skip dependencies induced via dev-dependencies since
|
||||||
// connections between `links` and build scripts only happens
|
// connections between `links` and build scripts only happens
|
||||||
// via normal dependencies. Otherwise since dev-dependencies can
|
// via normal dependencies. Otherwise since dev-dependencies can
|
||||||
|
|
|
@ -323,7 +323,9 @@ impl Profiles {
|
||||||
(InternedString::new("dev"), None)
|
(InternedString::new("dev"), None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CompileMode::Doc { .. } => (InternedString::new("doc"), None),
|
CompileMode::Doc { .. } | CompileMode::Docscrape => {
|
||||||
|
(InternedString::new("doc"), None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(self.requested_profile, None)
|
(self.requested_profile, None)
|
||||||
|
|
|
@ -76,6 +76,9 @@ pub struct CompileOptions {
|
||||||
/// Whether the `--document-private-items` flags was specified and should
|
/// Whether the `--document-private-items` flags was specified and should
|
||||||
/// be forwarded to `rustdoc`.
|
/// be forwarded to `rustdoc`.
|
||||||
pub rustdoc_document_private_items: bool,
|
pub rustdoc_document_private_items: bool,
|
||||||
|
/// Whether the `--scrape-examples` flag was specified and build flags for
|
||||||
|
/// examples should be forwarded to `rustdoc`.
|
||||||
|
pub rustdoc_scrape_examples: Option<CompileFilter>,
|
||||||
/// Whether the build process should check the minimum Rust version
|
/// Whether the build process should check the minimum Rust version
|
||||||
/// defined in the cargo metadata for a crate.
|
/// defined in the cargo metadata for a crate.
|
||||||
pub honor_rust_version: bool,
|
pub honor_rust_version: bool,
|
||||||
|
@ -94,12 +97,13 @@ impl<'a> CompileOptions {
|
||||||
target_rustc_args: None,
|
target_rustc_args: None,
|
||||||
local_rustdoc_args: None,
|
local_rustdoc_args: None,
|
||||||
rustdoc_document_private_items: false,
|
rustdoc_document_private_items: false,
|
||||||
|
rustdoc_scrape_examples: None,
|
||||||
honor_rust_version: true,
|
honor_rust_version: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
pub enum Packages {
|
pub enum Packages {
|
||||||
Default,
|
Default,
|
||||||
All,
|
All,
|
||||||
|
@ -334,6 +338,7 @@ pub fn create_bcx<'a, 'cfg>(
|
||||||
ref target_rustc_args,
|
ref target_rustc_args,
|
||||||
ref local_rustdoc_args,
|
ref local_rustdoc_args,
|
||||||
rustdoc_document_private_items,
|
rustdoc_document_private_items,
|
||||||
|
ref rustdoc_scrape_examples,
|
||||||
honor_rust_version,
|
honor_rust_version,
|
||||||
} = *options;
|
} = *options;
|
||||||
let config = ws.config();
|
let config = ws.config();
|
||||||
|
@ -351,7 +356,7 @@ pub fn create_bcx<'a, 'cfg>(
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CompileMode::Doc { .. } | CompileMode::Doctest => {
|
CompileMode::Doc { .. } | CompileMode::Doctest | CompileMode::Docscrape => {
|
||||||
if std::env::var("RUSTDOC_FLAGS").is_ok() {
|
if std::env::var("RUSTDOC_FLAGS").is_ok() {
|
||||||
config.shell().warn(
|
config.shell().warn(
|
||||||
"Cargo does not read `RUSTDOC_FLAGS` environment variable. Did you mean `RUSTDOCFLAGS`?"
|
"Cargo does not read `RUSTDOC_FLAGS` environment variable. Did you mean `RUSTDOCFLAGS`?"
|
||||||
|
@ -363,8 +368,16 @@ pub fn create_bcx<'a, 'cfg>(
|
||||||
|
|
||||||
let target_data = RustcTargetData::new(ws, &build_config.requested_kinds)?;
|
let target_data = RustcTargetData::new(ws, &build_config.requested_kinds)?;
|
||||||
|
|
||||||
let specs = spec.to_package_id_specs(ws)?;
|
let all_packages = &Packages::All;
|
||||||
let has_dev_units = if filter.need_dev_deps(build_config.mode) {
|
let need_reverse_dependencies = rustdoc_scrape_examples.is_some();
|
||||||
|
let full_specs = if need_reverse_dependencies {
|
||||||
|
all_packages
|
||||||
|
} else {
|
||||||
|
spec
|
||||||
|
};
|
||||||
|
|
||||||
|
let resolve_specs = full_specs.to_package_id_specs(ws)?;
|
||||||
|
let has_dev_units = if filter.need_dev_deps(build_config.mode) || need_reverse_dependencies {
|
||||||
HasDevUnits::Yes
|
HasDevUnits::Yes
|
||||||
} else {
|
} else {
|
||||||
HasDevUnits::No
|
HasDevUnits::No
|
||||||
|
@ -374,7 +387,7 @@ pub fn create_bcx<'a, 'cfg>(
|
||||||
&target_data,
|
&target_data,
|
||||||
&build_config.requested_kinds,
|
&build_config.requested_kinds,
|
||||||
cli_features,
|
cli_features,
|
||||||
&specs,
|
&resolve_specs,
|
||||||
has_dev_units,
|
has_dev_units,
|
||||||
crate::core::resolver::features::ForceAllTargets::No,
|
crate::core::resolver::features::ForceAllTargets::No,
|
||||||
)?;
|
)?;
|
||||||
|
@ -408,6 +421,11 @@ pub fn create_bcx<'a, 'cfg>(
|
||||||
// Find the packages in the resolver that the user wants to build (those
|
// Find the packages in the resolver that the user wants to build (those
|
||||||
// passed in with `-p` or the defaults from the workspace), and convert
|
// passed in with `-p` or the defaults from the workspace), and convert
|
||||||
// Vec<PackageIdSpec> to a Vec<PackageId>.
|
// Vec<PackageIdSpec> to a Vec<PackageId>.
|
||||||
|
let specs = if need_reverse_dependencies {
|
||||||
|
spec.to_package_id_specs(ws)?
|
||||||
|
} else {
|
||||||
|
resolve_specs.clone()
|
||||||
|
};
|
||||||
let to_build_ids = resolve.specs_to_ids(&specs)?;
|
let to_build_ids = resolve.specs_to_ids(&specs)?;
|
||||||
// Now get the `Package` for each `PackageId`. This may trigger a download
|
// Now get the `Package` for each `PackageId`. This may trigger a download
|
||||||
// if the user specified `-p` for a dependency that is not downloaded.
|
// if the user specified `-p` for a dependency that is not downloaded.
|
||||||
|
@ -487,6 +505,30 @@ pub fn create_bcx<'a, 'cfg>(
|
||||||
interner,
|
interner,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
let mut scrape_units = match rustdoc_scrape_examples {
|
||||||
|
Some(scrape_filter) => {
|
||||||
|
let to_build_ids = resolve.specs_to_ids(&resolve_specs)?;
|
||||||
|
let to_builds = pkg_set.get_many(to_build_ids)?;
|
||||||
|
let mode = CompileMode::Docscrape;
|
||||||
|
|
||||||
|
generate_targets(
|
||||||
|
ws,
|
||||||
|
&to_builds,
|
||||||
|
scrape_filter,
|
||||||
|
&build_config.requested_kinds,
|
||||||
|
explicit_host_kind,
|
||||||
|
mode,
|
||||||
|
&resolve,
|
||||||
|
&workspace_resolve,
|
||||||
|
&resolved_features,
|
||||||
|
&pkg_set,
|
||||||
|
&profiles,
|
||||||
|
interner,
|
||||||
|
)?
|
||||||
|
}
|
||||||
|
None => Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
let std_roots = if let Some(crates) = &config.cli_unstable().build_std {
|
let std_roots = if let Some(crates) = &config.cli_unstable().build_std {
|
||||||
// Only build libtest if it looks like it is needed.
|
// Only build libtest if it looks like it is needed.
|
||||||
let mut crates = crates.clone();
|
let mut crates = crates.clone();
|
||||||
|
@ -521,6 +563,7 @@ pub fn create_bcx<'a, 'cfg>(
|
||||||
&resolved_features,
|
&resolved_features,
|
||||||
std_resolve_features.as_ref(),
|
std_resolve_features.as_ref(),
|
||||||
&units,
|
&units,
|
||||||
|
&scrape_units,
|
||||||
&std_roots,
|
&std_roots,
|
||||||
build_config.mode,
|
build_config.mode,
|
||||||
&target_data,
|
&target_data,
|
||||||
|
@ -542,10 +585,17 @@ pub fn create_bcx<'a, 'cfg>(
|
||||||
// Rebuild the unit graph, replacing the explicit host targets with
|
// Rebuild the unit graph, replacing the explicit host targets with
|
||||||
// CompileKind::Host, merging any dependencies shared with build
|
// CompileKind::Host, merging any dependencies shared with build
|
||||||
// dependencies.
|
// dependencies.
|
||||||
let new_graph = rebuild_unit_graph_shared(interner, unit_graph, &units, explicit_host_kind);
|
let new_graph = rebuild_unit_graph_shared(
|
||||||
|
interner,
|
||||||
|
unit_graph,
|
||||||
|
&units,
|
||||||
|
&scrape_units,
|
||||||
|
explicit_host_kind,
|
||||||
|
);
|
||||||
// This would be nicer with destructuring assignment.
|
// This would be nicer with destructuring assignment.
|
||||||
units = new_graph.0;
|
units = new_graph.0;
|
||||||
unit_graph = new_graph.1;
|
scrape_units = new_graph.1;
|
||||||
|
unit_graph = new_graph.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut extra_compiler_args = HashMap::new();
|
let mut extra_compiler_args = HashMap::new();
|
||||||
|
@ -560,6 +610,7 @@ pub fn create_bcx<'a, 'cfg>(
|
||||||
}
|
}
|
||||||
extra_compiler_args.insert(units[0].clone(), args);
|
extra_compiler_args.insert(units[0].clone(), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
for unit in &units {
|
for unit in &units {
|
||||||
if unit.mode.is_doc() || unit.mode.is_doc_test() {
|
if unit.mode.is_doc() || unit.mode.is_doc_test() {
|
||||||
let mut extra_args = local_rustdoc_args.clone();
|
let mut extra_args = local_rustdoc_args.clone();
|
||||||
|
@ -621,6 +672,7 @@ pub fn create_bcx<'a, 'cfg>(
|
||||||
target_data,
|
target_data,
|
||||||
units,
|
units,
|
||||||
unit_graph,
|
unit_graph,
|
||||||
|
scrape_units,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(bcx)
|
Ok(bcx)
|
||||||
|
@ -742,17 +794,18 @@ impl CompileFilter {
|
||||||
match mode {
|
match mode {
|
||||||
CompileMode::Test | CompileMode::Doctest | CompileMode::Bench => true,
|
CompileMode::Test | CompileMode::Doctest | CompileMode::Bench => true,
|
||||||
CompileMode::Check { test: true } => true,
|
CompileMode::Check { test: true } => true,
|
||||||
CompileMode::Build | CompileMode::Doc { .. } | CompileMode::Check { test: false } => {
|
CompileMode::Build
|
||||||
match *self {
|
| CompileMode::Doc { .. }
|
||||||
CompileFilter::Default { .. } => false,
|
| CompileMode::Docscrape
|
||||||
CompileFilter::Only {
|
| CompileMode::Check { test: false } => match *self {
|
||||||
ref examples,
|
CompileFilter::Default { .. } => false,
|
||||||
ref tests,
|
CompileFilter::Only {
|
||||||
ref benches,
|
ref examples,
|
||||||
..
|
ref tests,
|
||||||
} => examples.is_specific() || tests.is_specific() || benches.is_specific(),
|
ref benches,
|
||||||
}
|
..
|
||||||
}
|
} => examples.is_specific() || tests.is_specific() || benches.is_specific(),
|
||||||
|
},
|
||||||
CompileMode::RunCustomBuild => panic!("Invalid mode"),
|
CompileMode::RunCustomBuild => panic!("Invalid mode"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1342,7 +1395,9 @@ fn filter_default_targets(targets: &[Target], mode: CompileMode) -> Vec<&Target>
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
CompileMode::Doctest | CompileMode::RunCustomBuild => panic!("Invalid mode {:?}", mode),
|
CompileMode::Doctest | CompileMode::Docscrape | CompileMode::RunCustomBuild => {
|
||||||
|
panic!("Invalid mode {:?}", mode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1454,8 +1509,9 @@ fn rebuild_unit_graph_shared(
|
||||||
interner: &UnitInterner,
|
interner: &UnitInterner,
|
||||||
unit_graph: UnitGraph,
|
unit_graph: UnitGraph,
|
||||||
roots: &[Unit],
|
roots: &[Unit],
|
||||||
|
scrape_units: &[Unit],
|
||||||
to_host: CompileKind,
|
to_host: CompileKind,
|
||||||
) -> (Vec<Unit>, UnitGraph) {
|
) -> (Vec<Unit>, Vec<Unit>, UnitGraph) {
|
||||||
let mut result = UnitGraph::new();
|
let mut result = UnitGraph::new();
|
||||||
// Map of the old unit to the new unit, used to avoid recursing into units
|
// Map of the old unit to the new unit, used to avoid recursing into units
|
||||||
// that have already been computed to improve performance.
|
// that have already been computed to improve performance.
|
||||||
|
@ -1466,7 +1522,11 @@ fn rebuild_unit_graph_shared(
|
||||||
traverse_and_share(interner, &mut memo, &mut result, &unit_graph, root, to_host)
|
traverse_and_share(interner, &mut memo, &mut result, &unit_graph, root, to_host)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
(new_roots, result)
|
let new_scrape_units = scrape_units
|
||||||
|
.iter()
|
||||||
|
.map(|unit| memo.get(unit).unwrap().clone())
|
||||||
|
.collect();
|
||||||
|
(new_roots, new_scrape_units, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recursive function for rebuilding the graph.
|
/// Recursive function for rebuilding the graph.
|
||||||
|
|
|
@ -765,6 +765,7 @@ fn run_verify(
|
||||||
target_rustc_args: rustc_args,
|
target_rustc_args: rustc_args,
|
||||||
local_rustdoc_args: None,
|
local_rustdoc_args: None,
|
||||||
rustdoc_document_private_items: false,
|
rustdoc_document_private_items: false,
|
||||||
|
rustdoc_scrape_examples: None,
|
||||||
honor_rust_version: true,
|
honor_rust_version: true,
|
||||||
},
|
},
|
||||||
&exec,
|
&exec,
|
||||||
|
|
|
@ -544,6 +544,7 @@ pub trait ArgMatchesExt {
|
||||||
target_rustc_args: None,
|
target_rustc_args: None,
|
||||||
local_rustdoc_args: None,
|
local_rustdoc_args: None,
|
||||||
rustdoc_document_private_items: false,
|
rustdoc_document_private_items: false,
|
||||||
|
rustdoc_scrape_examples: None,
|
||||||
honor_rust_version: !self._is_present("ignore-rust-version"),
|
honor_rust_version: !self._is_present("ignore-rust-version"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1207,7 +1207,7 @@ for the appropriate target and influenced by any other RUSTFLAGS.
|
||||||
* Tracking Issue: [#9778](https://github.com/rust-lang/cargo/issues/9778)
|
* Tracking Issue: [#9778](https://github.com/rust-lang/cargo/issues/9778)
|
||||||
* PR: [#9627](https://github.com/rust-lang/cargo/pull/9627)
|
* PR: [#9627](https://github.com/rust-lang/cargo/pull/9627)
|
||||||
|
|
||||||
The `different-binary-name` feature allows setting the filename of the binary without having to obey the
|
The `different-binary-name` feature allows setting the filename of the binary without having to obey the
|
||||||
restrictions placed on crate names. For example, the crate name must use only `alphanumeric` characters
|
restrictions placed on crate names. For example, the crate name must use only `alphanumeric` characters
|
||||||
or `-` or `_`, and cannot be empty.
|
or `-` or `_`, and cannot be empty.
|
||||||
|
|
||||||
|
@ -1378,7 +1378,23 @@ The 2021 edition has been stabilized in the 1.56 release.
|
||||||
See the [`edition` field](manifest.md#the-edition-field) for more information on setting the edition.
|
See the [`edition` field](manifest.md#the-edition-field) for more information on setting the edition.
|
||||||
See [`cargo fix --edition`](../commands/cargo-fix.md) and [The Edition Guide](../../edition-guide/index.html) for more information on migrating existing projects.
|
See [`cargo fix --edition`](../commands/cargo-fix.md) and [The Edition Guide](../../edition-guide/index.html) for more information on migrating existing projects.
|
||||||
|
|
||||||
|
|
||||||
### Custom named profiles
|
### Custom named profiles
|
||||||
|
|
||||||
Custom named profiles have been stabilized in the 1.57 release. See the
|
Custom named profiles have been stabilized in the 1.57 release. See the
|
||||||
[profiles chapter](profiles.md#custom-profiles) for more information.
|
[profiles chapter](profiles.md#custom-profiles) for more information.
|
||||||
|
|
||||||
|
|
||||||
|
### scrape-examples
|
||||||
|
|
||||||
|
* RFC: [#3123](https://github.com/rust-lang/rfcs/pull/3123)
|
||||||
|
* Tracking Issue: [#9910](https://github.com/rust-lang/cargo/issues/9910)
|
||||||
|
|
||||||
|
The `--scrape-examples` argument to the `doc` command tells Rustdoc to search
|
||||||
|
crates in the current workspace for calls to functions. Those call-sites are then
|
||||||
|
included as documentation. The flag can take an argument of `all` or `examples`
|
||||||
|
which configures which crate in the workspace to analyze for examples. For instance:
|
||||||
|
|
||||||
|
```
|
||||||
|
cargo doc -Z unstable-options --scrape-examples examples
|
||||||
|
```
|
||||||
|
|
|
@ -2148,3 +2148,152 @@ fn doc_fingerprint_unusual_behavior() {
|
||||||
assert!(build_doc.join("somefile").exists());
|
assert!(build_doc.join("somefile").exists());
|
||||||
assert!(real_doc.join("somefile").exists());
|
assert!(real_doc.join("somefile").exists());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cargo_test]
|
||||||
|
fn scrape_examples_basic() {
|
||||||
|
if !is_nightly() {
|
||||||
|
// --scrape-examples is unstable
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let p = project()
|
||||||
|
.file(
|
||||||
|
"Cargo.toml",
|
||||||
|
r#"
|
||||||
|
[package]
|
||||||
|
name = "foo"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = []
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file("examples/ex.rs", "fn main() { foo::foo(); }")
|
||||||
|
.file("src/lib.rs", "pub fn foo() {}\npub fn bar() { foo(); }")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
p.cargo("doc -Zunstable-options --scrape-examples all")
|
||||||
|
.masquerade_as_nightly_cargo()
|
||||||
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
[..] foo v0.0.1 ([CWD])
|
||||||
|
[..] foo v0.0.1 ([CWD])
|
||||||
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
|
||||||
|
let doc_html = p.read_file("target/doc/foo/fn.foo.html");
|
||||||
|
assert!(doc_html.contains("Examples found in repository"));
|
||||||
|
assert!(doc_html.contains("More examples"));
|
||||||
|
|
||||||
|
// Ensure that the reverse-dependency has its sources generated
|
||||||
|
assert!(p.build_dir().join("doc/src/ex/ex.rs.html").exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cargo_test]
|
||||||
|
fn scrape_examples_avoid_build_script_cycle() {
|
||||||
|
if !is_nightly() {
|
||||||
|
// --scrape-examples is unstable
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let p = project()
|
||||||
|
// package with build dependency
|
||||||
|
.file(
|
||||||
|
"Cargo.toml",
|
||||||
|
r#"
|
||||||
|
[package]
|
||||||
|
name = "foo"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = []
|
||||||
|
links = "foo"
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
members = ["bar"]
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
bar = {path = "bar"}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file("src/lib.rs", "")
|
||||||
|
.file("build.rs", "fn main(){}")
|
||||||
|
// dependency
|
||||||
|
.file(
|
||||||
|
"bar/Cargo.toml",
|
||||||
|
r#"
|
||||||
|
[package]
|
||||||
|
name = "bar"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = []
|
||||||
|
links = "bar"
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file("bar/src/lib.rs", "")
|
||||||
|
.file("bar/build.rs", "fn main(){}")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
p.cargo("doc --all -Zunstable-options --scrape-examples all")
|
||||||
|
.masquerade_as_nightly_cargo()
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cargo_test]
|
||||||
|
fn scrape_examples_complex_reverse_dependencies() {
|
||||||
|
if !is_nightly() {
|
||||||
|
// --scrape-examples is unstable
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let p = project()
|
||||||
|
.file(
|
||||||
|
"Cargo.toml",
|
||||||
|
r#"
|
||||||
|
[package]
|
||||||
|
name = "foo"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = []
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
a = {path = "a", features = ["feature"]}
|
||||||
|
b = {path = "b"}
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
members = ["b"]
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file("src/lib.rs", "")
|
||||||
|
.file("examples/ex.rs", "fn main() { a::f(); }")
|
||||||
|
.file(
|
||||||
|
"a/Cargo.toml",
|
||||||
|
r#"
|
||||||
|
[package]
|
||||||
|
name = "a"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = []
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
b = {path = "../b"}
|
||||||
|
|
||||||
|
[features]
|
||||||
|
feature = []
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file("a/src/lib.rs", "#[cfg(feature)] pub fn f();")
|
||||||
|
.file(
|
||||||
|
"b/Cargo.toml",
|
||||||
|
r#"
|
||||||
|
[package]
|
||||||
|
name = "b"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = []
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file("b/src/lib.rs", "")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
p.cargo("doc -Zunstable-options --scrape-examples all")
|
||||||
|
.masquerade_as_nightly_cargo()
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ fn rustdoc_args() {
|
||||||
-o [CWD]/target/doc \
|
-o [CWD]/target/doc \
|
||||||
[..] \
|
[..] \
|
||||||
--cfg=foo \
|
--cfg=foo \
|
||||||
|
-C metadata=[..] \
|
||||||
-L dependency=[CWD]/target/debug/deps [..]`
|
-L dependency=[CWD]/target/debug/deps [..]`
|
||||||
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
||||||
",
|
",
|
||||||
|
@ -83,6 +84,7 @@ fn rustdoc_foo_with_bar_dependency() {
|
||||||
-o [CWD]/target/doc \
|
-o [CWD]/target/doc \
|
||||||
[..] \
|
[..] \
|
||||||
--cfg=foo \
|
--cfg=foo \
|
||||||
|
-C metadata=[..] \
|
||||||
-L dependency=[CWD]/target/debug/deps \
|
-L dependency=[CWD]/target/debug/deps \
|
||||||
--extern [..]`
|
--extern [..]`
|
||||||
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
||||||
|
@ -122,6 +124,7 @@ fn rustdoc_only_bar_dependency() {
|
||||||
-o [CWD]/target/doc \
|
-o [CWD]/target/doc \
|
||||||
[..] \
|
[..] \
|
||||||
--cfg=foo \
|
--cfg=foo \
|
||||||
|
-C metadata=[..] \
|
||||||
-L dependency=[CWD]/target/debug/deps [..]`
|
-L dependency=[CWD]/target/debug/deps [..]`
|
||||||
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
||||||
",
|
",
|
||||||
|
@ -144,6 +147,7 @@ fn rustdoc_same_name_documents_lib() {
|
||||||
-o [CWD]/target/doc \
|
-o [CWD]/target/doc \
|
||||||
[..] \
|
[..] \
|
||||||
--cfg=foo \
|
--cfg=foo \
|
||||||
|
-C metadata=[..] \
|
||||||
-L dependency=[CWD]/target/debug/deps [..]`
|
-L dependency=[CWD]/target/debug/deps [..]`
|
||||||
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
||||||
",
|
",
|
||||||
|
|
Loading…
Reference in a new issue