rustdoc: Add an --extern flag analagous to rustc's
This adds an `--extern` flag to `rustdoc` much like the compiler's to specify the path where a given crate can be found.
This commit is contained in:
parent
97ca98f5cc
commit
ec70f2bb6e
5 changed files with 66 additions and 17 deletions
|
@ -582,7 +582,7 @@ pub fn optgroups() -> Vec<getopts::OptGroup> {
|
||||||
always = always colorize output;
|
always = always colorize output;
|
||||||
never = never colorize output", "auto|always|never"),
|
never = never colorize output", "auto|always|never"),
|
||||||
optmulti("", "extern", "Specify where an external rust library is located",
|
optmulti("", "extern", "Specify where an external rust library is located",
|
||||||
"PATH"),
|
"NAME=PATH"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,8 +77,10 @@ pub struct CrateAnalysis {
|
||||||
pub inlined: RefCell<Option<HashSet<ast::DefId>>>,
|
pub inlined: RefCell<Option<HashSet<ast::DefId>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type Externs = HashMap<String, Vec<String>>;
|
||||||
|
|
||||||
/// Parses, resolves, and typechecks the given crate
|
/// Parses, resolves, and typechecks the given crate
|
||||||
fn get_ast_and_resolve(cpath: &Path, libs: HashSet<Path>, cfgs: Vec<String>)
|
fn get_ast_and_resolve(cpath: &Path, libs: HashSet<Path>, cfgs: Vec<String>, externs: Externs)
|
||||||
-> (DocContext, CrateAnalysis) {
|
-> (DocContext, CrateAnalysis) {
|
||||||
use syntax::codemap::dummy_spanned;
|
use syntax::codemap::dummy_spanned;
|
||||||
use rustc::driver::driver::{FileInput,
|
use rustc::driver::driver::{FileInput,
|
||||||
|
@ -96,6 +98,7 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet<Path>, cfgs: Vec<String>)
|
||||||
addl_lib_search_paths: RefCell::new(libs),
|
addl_lib_search_paths: RefCell::new(libs),
|
||||||
crate_types: vec!(driver::config::CrateTypeRlib),
|
crate_types: vec!(driver::config::CrateTypeRlib),
|
||||||
lint_opts: vec!((warning_lint, lint::Allow)),
|
lint_opts: vec!((warning_lint, lint::Allow)),
|
||||||
|
externs: externs,
|
||||||
..rustc::driver::config::basic_options().clone()
|
..rustc::driver::config::basic_options().clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -148,9 +151,9 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet<Path>, cfgs: Vec<String>)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_core(libs: HashSet<Path>, cfgs: Vec<String>, path: &Path)
|
pub fn run_core(libs: HashSet<Path>, cfgs: Vec<String>, externs: Externs, path: &Path)
|
||||||
-> (clean::Crate, CrateAnalysis) {
|
-> (clean::Crate, CrateAnalysis) {
|
||||||
let (ctxt, analysis) = get_ast_and_resolve(path, libs, cfgs);
|
let (ctxt, analysis) = get_ast_and_resolve(path, libs, cfgs, externs);
|
||||||
let ctxt = box(GC) ctxt;
|
let ctxt = box(GC) ctxt;
|
||||||
super::ctxtkey.replace(Some(ctxt));
|
super::ctxtkey.replace(Some(ctxt));
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ extern crate time;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::{File, MemWriter};
|
use std::io::{File, MemWriter};
|
||||||
use std::gc::Gc;
|
use std::gc::Gc;
|
||||||
|
use std::collections::HashMap;
|
||||||
use serialize::{json, Decodable, Encodable};
|
use serialize::{json, Decodable, Encodable};
|
||||||
use externalfiles::ExternalHtml;
|
use externalfiles::ExternalHtml;
|
||||||
|
|
||||||
|
@ -104,6 +105,7 @@ pub fn opts() -> Vec<getopts::OptGroup> {
|
||||||
optmulti("L", "library-path", "directory to add to crate search path",
|
optmulti("L", "library-path", "directory to add to crate search path",
|
||||||
"DIR"),
|
"DIR"),
|
||||||
optmulti("", "cfg", "pass a --cfg to rustc", ""),
|
optmulti("", "cfg", "pass a --cfg to rustc", ""),
|
||||||
|
optmulti("", "extern", "pass an --extern to rustc", "NAME=PATH"),
|
||||||
optmulti("", "plugin-path", "directory to load plugins from", "DIR"),
|
optmulti("", "plugin-path", "directory to load plugins from", "DIR"),
|
||||||
optmulti("", "passes", "space separated list of passes to also run, a \
|
optmulti("", "passes", "space separated list of passes to also run, a \
|
||||||
value of `list` will print available passes",
|
value of `list` will print available passes",
|
||||||
|
@ -170,6 +172,13 @@ pub fn main_args(args: &[String]) -> int {
|
||||||
let input = matches.free[0].as_slice();
|
let input = matches.free[0].as_slice();
|
||||||
|
|
||||||
let libs = matches.opt_strs("L").iter().map(|s| Path::new(s.as_slice())).collect();
|
let libs = matches.opt_strs("L").iter().map(|s| Path::new(s.as_slice())).collect();
|
||||||
|
let externs = match parse_externs(&matches) {
|
||||||
|
Ok(ex) => ex,
|
||||||
|
Err(err) => {
|
||||||
|
println!("{}", err);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let test_args = matches.opt_strs("test-args");
|
let test_args = matches.opt_strs("test-args");
|
||||||
let test_args: Vec<String> = test_args.iter()
|
let test_args: Vec<String> = test_args.iter()
|
||||||
|
@ -193,10 +202,10 @@ pub fn main_args(args: &[String]) -> int {
|
||||||
|
|
||||||
match (should_test, markdown_input) {
|
match (should_test, markdown_input) {
|
||||||
(true, true) => {
|
(true, true) => {
|
||||||
return markdown::test(input, libs, test_args)
|
return markdown::test(input, libs, externs, test_args)
|
||||||
}
|
}
|
||||||
(true, false) => {
|
(true, false) => {
|
||||||
return test::run(input, cfgs, libs, test_args)
|
return test::run(input, cfgs, libs, externs, test_args)
|
||||||
}
|
}
|
||||||
(false, true) => return markdown::render(input, output.unwrap_or(Path::new("doc")),
|
(false, true) => return markdown::render(input, output.unwrap_or(Path::new("doc")),
|
||||||
&matches, &external_html),
|
&matches, &external_html),
|
||||||
|
@ -215,7 +224,7 @@ pub fn main_args(args: &[String]) -> int {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (krate, res) = match acquire_input(input, &matches) {
|
let (krate, res) = match acquire_input(input, externs, &matches) {
|
||||||
Ok(pair) => pair,
|
Ok(pair) => pair,
|
||||||
Err(s) => {
|
Err(s) => {
|
||||||
println!("input error: {}", s);
|
println!("input error: {}", s);
|
||||||
|
@ -252,27 +261,53 @@ pub fn main_args(args: &[String]) -> int {
|
||||||
/// Looks inside the command line arguments to extract the relevant input format
|
/// Looks inside the command line arguments to extract the relevant input format
|
||||||
/// and files and then generates the necessary rustdoc output for formatting.
|
/// and files and then generates the necessary rustdoc output for formatting.
|
||||||
fn acquire_input(input: &str,
|
fn acquire_input(input: &str,
|
||||||
|
externs: core::Externs,
|
||||||
matches: &getopts::Matches) -> Result<Output, String> {
|
matches: &getopts::Matches) -> Result<Output, String> {
|
||||||
match matches.opt_str("r").as_ref().map(|s| s.as_slice()) {
|
match matches.opt_str("r").as_ref().map(|s| s.as_slice()) {
|
||||||
Some("rust") => Ok(rust_input(input, matches)),
|
Some("rust") => Ok(rust_input(input, externs, matches)),
|
||||||
Some("json") => json_input(input),
|
Some("json") => json_input(input),
|
||||||
Some(s) => Err(format!("unknown input format: {}", s)),
|
Some(s) => Err(format!("unknown input format: {}", s)),
|
||||||
None => {
|
None => {
|
||||||
if input.ends_with(".json") {
|
if input.ends_with(".json") {
|
||||||
json_input(input)
|
json_input(input)
|
||||||
} else {
|
} else {
|
||||||
Ok(rust_input(input, matches))
|
Ok(rust_input(input, externs, matches))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extracts `--extern CRATE=PATH` arguments from `matches` and
|
||||||
|
/// returns a `HashMap` mapping crate names to their paths or else an
|
||||||
|
/// error message.
|
||||||
|
fn parse_externs(matches: &getopts::Matches) -> Result<core::Externs, String> {
|
||||||
|
let mut externs = HashMap::new();
|
||||||
|
for arg in matches.opt_strs("extern").iter() {
|
||||||
|
let mut parts = arg.as_slice().splitn('=', 1);
|
||||||
|
let name = match parts.next() {
|
||||||
|
Some(s) => s,
|
||||||
|
None => {
|
||||||
|
return Err("--extern value must not be empty".to_string());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let location = match parts.next() {
|
||||||
|
Some(s) => s,
|
||||||
|
None => {
|
||||||
|
return Err("--extern value must be of the format `foo=bar`".to_string());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let locs = externs.find_or_insert(name.to_string(), Vec::new());
|
||||||
|
locs.push(location.to_string());
|
||||||
|
}
|
||||||
|
Ok(externs)
|
||||||
|
}
|
||||||
|
|
||||||
/// Interprets the input file as a rust source file, passing it through the
|
/// Interprets the input file as a rust source file, passing it through the
|
||||||
/// compiler all the way through the analysis passes. The rustdoc output is then
|
/// compiler all the way through the analysis passes. The rustdoc output is then
|
||||||
/// generated from the cleaned AST of the crate.
|
/// generated from the cleaned AST of the crate.
|
||||||
///
|
///
|
||||||
/// This form of input will run all of the plug/cleaning passes
|
/// This form of input will run all of the plug/cleaning passes
|
||||||
fn rust_input(cratefile: &str, matches: &getopts::Matches) -> Output {
|
fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matches) -> Output {
|
||||||
let mut default_passes = !matches.opt_present("no-defaults");
|
let mut default_passes = !matches.opt_present("no-defaults");
|
||||||
let mut passes = matches.opt_strs("passes");
|
let mut passes = matches.opt_strs("passes");
|
||||||
let mut plugins = matches.opt_strs("plugins");
|
let mut plugins = matches.opt_strs("plugins");
|
||||||
|
@ -283,12 +318,14 @@ fn rust_input(cratefile: &str, matches: &getopts::Matches) -> Output {
|
||||||
.map(|s| Path::new(s.as_slice()))
|
.map(|s| Path::new(s.as_slice()))
|
||||||
.collect();
|
.collect();
|
||||||
let cfgs = matches.opt_strs("cfg");
|
let cfgs = matches.opt_strs("cfg");
|
||||||
|
|
||||||
let cr = Path::new(cratefile);
|
let cr = Path::new(cratefile);
|
||||||
info!("starting to run rustc");
|
info!("starting to run rustc");
|
||||||
let (krate, analysis) = std::task::try(proc() {
|
let (krate, analysis) = std::task::try(proc() {
|
||||||
let cr = cr;
|
let cr = cr;
|
||||||
core::run_core(libs.move_iter().map(|x| x.clone()).collect(),
|
core::run_core(libs.move_iter().collect(),
|
||||||
cfgs,
|
cfgs,
|
||||||
|
externs,
|
||||||
&cr)
|
&cr)
|
||||||
}).map_err(|boxed_any|format!("{:?}", boxed_any)).unwrap();
|
}).map_err(|boxed_any|format!("{:?}", boxed_any)).unwrap();
|
||||||
info!("finished with rustc");
|
info!("finished with rustc");
|
||||||
|
|
|
@ -12,6 +12,7 @@ use std::collections::HashSet;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
|
|
||||||
|
use core;
|
||||||
use getopts;
|
use getopts;
|
||||||
use testing;
|
use testing;
|
||||||
|
|
||||||
|
@ -129,10 +130,11 @@ pub fn render(input: &str, mut output: Path, matches: &getopts::Matches,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run any tests/code examples in the markdown file `input`.
|
/// Run any tests/code examples in the markdown file `input`.
|
||||||
pub fn test(input: &str, libs: HashSet<Path>, mut test_args: Vec<String>) -> int {
|
pub fn test(input: &str, libs: HashSet<Path>, externs: core::Externs,
|
||||||
|
mut test_args: Vec<String>) -> int {
|
||||||
let input_str = load_or_return!(input, 1, 2);
|
let input_str = load_or_return!(input, 1, 2);
|
||||||
|
|
||||||
let mut collector = Collector::new(input.to_string(), libs, true);
|
let mut collector = Collector::new(input.to_string(), libs, externs, true);
|
||||||
find_testable_code(input_str.as_slice(), &mut collector);
|
find_testable_code(input_str.as_slice(), &mut collector);
|
||||||
test_args.unshift("rustdoctest".to_string());
|
test_args.unshift("rustdoctest".to_string());
|
||||||
testing::test_main(test_args.as_slice(), collector.tests);
|
testing::test_main(test_args.as_slice(), collector.tests);
|
||||||
|
|
|
@ -40,6 +40,7 @@ use visit_ast::RustdocVisitor;
|
||||||
pub fn run(input: &str,
|
pub fn run(input: &str,
|
||||||
cfgs: Vec<String>,
|
cfgs: Vec<String>,
|
||||||
libs: HashSet<Path>,
|
libs: HashSet<Path>,
|
||||||
|
externs: core::Externs,
|
||||||
mut test_args: Vec<String>)
|
mut test_args: Vec<String>)
|
||||||
-> int {
|
-> int {
|
||||||
let input_path = Path::new(input);
|
let input_path = Path::new(input);
|
||||||
|
@ -49,10 +50,10 @@ pub fn run(input: &str,
|
||||||
maybe_sysroot: Some(os::self_exe_path().unwrap().dir_path()),
|
maybe_sysroot: Some(os::self_exe_path().unwrap().dir_path()),
|
||||||
addl_lib_search_paths: RefCell::new(libs.clone()),
|
addl_lib_search_paths: RefCell::new(libs.clone()),
|
||||||
crate_types: vec!(config::CrateTypeDylib),
|
crate_types: vec!(config::CrateTypeDylib),
|
||||||
|
externs: externs.clone(),
|
||||||
..config::basic_options().clone()
|
..config::basic_options().clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let codemap = CodeMap::new();
|
let codemap = CodeMap::new();
|
||||||
let diagnostic_handler = diagnostic::default_handler(diagnostic::Auto, None);
|
let diagnostic_handler = diagnostic::default_handler(diagnostic::Auto, None);
|
||||||
let span_diagnostic_handler =
|
let span_diagnostic_handler =
|
||||||
|
@ -92,6 +93,7 @@ pub fn run(input: &str,
|
||||||
|
|
||||||
let mut collector = Collector::new(krate.name.to_string(),
|
let mut collector = Collector::new(krate.name.to_string(),
|
||||||
libs,
|
libs,
|
||||||
|
externs,
|
||||||
false);
|
false);
|
||||||
collector.fold_crate(krate);
|
collector.fold_crate(krate);
|
||||||
|
|
||||||
|
@ -102,8 +104,8 @@ pub fn run(input: &str,
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, should_fail: bool,
|
fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, externs: core::Externs,
|
||||||
no_run: bool, as_test_harness: bool) {
|
should_fail: bool, no_run: bool, as_test_harness: bool) {
|
||||||
// the test harness wants its own `main` & top level functions, so
|
// the test harness wants its own `main` & top level functions, so
|
||||||
// never wrap the test in `fn main() { ... }`
|
// never wrap the test in `fn main() { ... }`
|
||||||
let test = maketest(test, Some(cratename), true, as_test_harness);
|
let test = maketest(test, Some(cratename), true, as_test_harness);
|
||||||
|
@ -115,6 +117,7 @@ fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, should_fail: bool,
|
||||||
crate_types: vec!(config::CrateTypeExecutable),
|
crate_types: vec!(config::CrateTypeExecutable),
|
||||||
output_types: vec!(link::OutputTypeExe),
|
output_types: vec!(link::OutputTypeExe),
|
||||||
no_trans: no_run,
|
no_trans: no_run,
|
||||||
|
externs: externs,
|
||||||
cg: config::CodegenOptions {
|
cg: config::CodegenOptions {
|
||||||
prefer_dynamic: true,
|
prefer_dynamic: true,
|
||||||
.. config::basic_codegen_options()
|
.. config::basic_codegen_options()
|
||||||
|
@ -237,6 +240,7 @@ pub struct Collector {
|
||||||
pub tests: Vec<testing::TestDescAndFn>,
|
pub tests: Vec<testing::TestDescAndFn>,
|
||||||
names: Vec<String>,
|
names: Vec<String>,
|
||||||
libs: HashSet<Path>,
|
libs: HashSet<Path>,
|
||||||
|
externs: core::Externs,
|
||||||
cnt: uint,
|
cnt: uint,
|
||||||
use_headers: bool,
|
use_headers: bool,
|
||||||
current_header: Option<String>,
|
current_header: Option<String>,
|
||||||
|
@ -244,12 +248,13 @@ pub struct Collector {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Collector {
|
impl Collector {
|
||||||
pub fn new(cratename: String, libs: HashSet<Path>,
|
pub fn new(cratename: String, libs: HashSet<Path>, externs: core::Externs,
|
||||||
use_headers: bool) -> Collector {
|
use_headers: bool) -> Collector {
|
||||||
Collector {
|
Collector {
|
||||||
tests: Vec::new(),
|
tests: Vec::new(),
|
||||||
names: Vec::new(),
|
names: Vec::new(),
|
||||||
libs: libs,
|
libs: libs,
|
||||||
|
externs: externs,
|
||||||
cnt: 0,
|
cnt: 0,
|
||||||
use_headers: use_headers,
|
use_headers: use_headers,
|
||||||
current_header: None,
|
current_header: None,
|
||||||
|
@ -267,6 +272,7 @@ impl Collector {
|
||||||
};
|
};
|
||||||
self.cnt += 1;
|
self.cnt += 1;
|
||||||
let libs = self.libs.clone();
|
let libs = self.libs.clone();
|
||||||
|
let externs = self.externs.clone();
|
||||||
let cratename = self.cratename.to_string();
|
let cratename = self.cratename.to_string();
|
||||||
debug!("Creating test {}: {}", name, test);
|
debug!("Creating test {}: {}", name, test);
|
||||||
self.tests.push(testing::TestDescAndFn {
|
self.tests.push(testing::TestDescAndFn {
|
||||||
|
@ -279,6 +285,7 @@ impl Collector {
|
||||||
runtest(test.as_slice(),
|
runtest(test.as_slice(),
|
||||||
cratename.as_slice(),
|
cratename.as_slice(),
|
||||||
libs,
|
libs,
|
||||||
|
externs,
|
||||||
should_fail,
|
should_fail,
|
||||||
no_run,
|
no_run,
|
||||||
as_test_harness);
|
as_test_harness);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue