@@ -30,6 +30,7 @@ extern crate time;
30
30
use std:: io;
31
31
use std:: io:: { File , MemWriter } ;
32
32
use std:: gc:: Gc ;
33
+ use std:: collections:: HashMap ;
33
34
use serialize:: { json, Decodable , Encodable } ;
34
35
use externalfiles:: ExternalHtml ;
35
36
@@ -104,6 +105,7 @@ pub fn opts() -> Vec<getopts::OptGroup> {
104
105
optmulti( "L" , "library-path" , "directory to add to crate search path" ,
105
106
"DIR" ) ,
106
107
optmulti( "" , "cfg" , "pass a --cfg to rustc" , "" ) ,
108
+ optmulti( "" , "extern" , "pass an --extern to rustc" , "NAME=PATH" ) ,
107
109
optmulti( "" , "plugin-path" , "directory to load plugins from" , "DIR" ) ,
108
110
optmulti( "" , "passes" , "space separated list of passes to also run, a \
109
111
value of `list` will print available passes",
@@ -170,6 +172,13 @@ pub fn main_args(args: &[String]) -> int {
170
172
let input = matches. free [ 0 ] . as_slice ( ) ;
171
173
172
174
let libs = matches. opt_strs ( "L" ) . iter ( ) . map ( |s| Path :: new ( s. as_slice ( ) ) ) . collect ( ) ;
175
+ let externs = match parse_externs ( & matches) {
176
+ Ok ( ex) => ex,
177
+ Err ( err) => {
178
+ println ! ( "{}" , err) ;
179
+ return 1 ;
180
+ }
181
+ } ;
173
182
174
183
let test_args = matches. opt_strs ( "test-args" ) ;
175
184
let test_args: Vec < String > = test_args. iter ( )
@@ -193,10 +202,10 @@ pub fn main_args(args: &[String]) -> int {
193
202
194
203
match ( should_test, markdown_input) {
195
204
( true , true ) => {
196
- return markdown:: test ( input, libs, test_args)
205
+ return markdown:: test ( input, libs, externs , test_args)
197
206
}
198
207
( true , false ) => {
199
- return test:: run ( input, cfgs, libs, test_args)
208
+ return test:: run ( input, cfgs, libs, externs , test_args)
200
209
}
201
210
( false , true ) => return markdown:: render ( input, output. unwrap_or ( Path :: new ( "doc" ) ) ,
202
211
& matches, & external_html) ,
@@ -215,7 +224,7 @@ pub fn main_args(args: &[String]) -> int {
215
224
return 0 ;
216
225
}
217
226
218
- let ( krate, res) = match acquire_input ( input, & matches) {
227
+ let ( krate, res) = match acquire_input ( input, externs , & matches) {
219
228
Ok ( pair) => pair,
220
229
Err ( s) => {
221
230
println ! ( "input error: {}" , s) ;
@@ -252,27 +261,53 @@ pub fn main_args(args: &[String]) -> int {
252
261
/// Looks inside the command line arguments to extract the relevant input format
253
262
/// and files and then generates the necessary rustdoc output for formatting.
254
263
fn acquire_input ( input : & str ,
264
+ externs : core:: Externs ,
255
265
matches : & getopts:: Matches ) -> Result < Output , String > {
256
266
match matches. opt_str ( "r" ) . as_ref ( ) . map ( |s| s. as_slice ( ) ) {
257
- Some ( "rust" ) => Ok ( rust_input ( input, matches) ) ,
267
+ Some ( "rust" ) => Ok ( rust_input ( input, externs , matches) ) ,
258
268
Some ( "json" ) => json_input ( input) ,
259
269
Some ( s) => Err ( format ! ( "unknown input format: {}" , s) ) ,
260
270
None => {
261
271
if input. ends_with ( ".json" ) {
262
272
json_input ( input)
263
273
} else {
264
- Ok ( rust_input ( input, matches) )
274
+ Ok ( rust_input ( input, externs , matches) )
265
275
}
266
276
}
267
277
}
268
278
}
269
279
280
+ /// Extracts `--extern CRATE=PATH` arguments from `matches` and
281
+ /// returns a `HashMap` mapping crate names to their paths or else an
282
+ /// error message.
283
+ fn parse_externs ( matches : & getopts:: Matches ) -> Result < core:: Externs , String > {
284
+ let mut externs = HashMap :: new ( ) ;
285
+ for arg in matches. opt_strs ( "extern" ) . iter ( ) {
286
+ let mut parts = arg. as_slice ( ) . splitn ( '=' , 1 ) ;
287
+ let name = match parts. next ( ) {
288
+ Some ( s) => s,
289
+ None => {
290
+ return Err ( "--extern value must not be empty" . to_string ( ) ) ;
291
+ }
292
+ } ;
293
+ let location = match parts. next ( ) {
294
+ Some ( s) => s,
295
+ None => {
296
+ return Err ( "--extern value must be of the format `foo=bar`" . to_string ( ) ) ;
297
+ }
298
+ } ;
299
+ let locs = externs. find_or_insert ( name. to_string ( ) , Vec :: new ( ) ) ;
300
+ locs. push ( location. to_string ( ) ) ;
301
+ }
302
+ Ok ( externs)
303
+ }
304
+
270
305
/// Interprets the input file as a rust source file, passing it through the
271
306
/// compiler all the way through the analysis passes. The rustdoc output is then
272
307
/// generated from the cleaned AST of the crate.
273
308
///
274
309
/// This form of input will run all of the plug/cleaning passes
275
- fn rust_input ( cratefile : & str , matches : & getopts:: Matches ) -> Output {
310
+ fn rust_input ( cratefile : & str , externs : core :: Externs , matches : & getopts:: Matches ) -> Output {
276
311
let mut default_passes = !matches. opt_present ( "no-defaults" ) ;
277
312
let mut passes = matches. opt_strs ( "passes" ) ;
278
313
let mut plugins = matches. opt_strs ( "plugins" ) ;
@@ -283,12 +318,14 @@ fn rust_input(cratefile: &str, matches: &getopts::Matches) -> Output {
283
318
. map ( |s| Path :: new ( s. as_slice ( ) ) )
284
319
. collect ( ) ;
285
320
let cfgs = matches. opt_strs ( "cfg" ) ;
321
+
286
322
let cr = Path :: new ( cratefile) ;
287
323
info ! ( "starting to run rustc" ) ;
288
324
let ( krate, analysis) = std:: task:: try ( proc ( ) {
289
325
let cr = cr;
290
- core:: run_core ( libs. move_iter ( ) . map ( |x| x . clone ( ) ) . collect ( ) ,
326
+ core:: run_core ( libs. move_iter ( ) . collect ( ) ,
291
327
cfgs,
328
+ externs,
292
329
& cr)
293
330
} ) . map_err ( |boxed_any|format ! ( "{:?}" , boxed_any) ) . unwrap ( ) ;
294
331
info ! ( "finished with rustc" ) ;
0 commit comments