1+ // ignore-tidy-filelength
2+
13//! Contains infrastructure for configuring the compiler, including parsing
24//! command-line options.
35
@@ -31,7 +33,7 @@ use std::fmt;
3133use std:: str:: { self , FromStr } ;
3234use std:: hash:: Hasher ;
3335use std:: collections:: hash_map:: DefaultHasher ;
34- use std:: iter:: FromIterator ;
36+ use std:: iter:: { self , FromIterator } ;
3537use std:: path:: { Path , PathBuf } ;
3638
3739pub struct Config {
@@ -322,10 +324,35 @@ impl OutputTypes {
322324#[ derive( Clone ) ]
323325pub struct Externs ( BTreeMap < String , ExternEntry > ) ;
324326
325- #[ derive( Clone , Debug , Default ) ]
327+ #[ derive( Clone , Debug ) ]
326328pub struct ExternEntry {
327- pub locations : BTreeSet < Option < String > > ,
328- pub is_private_dep : bool
329+ pub location : ExternLocation ,
330+ /// Indicates this is a "private" dependency for the
331+ /// `exported_private_dependencies` lint.
332+ ///
333+ /// This can be set with the `priv` option like
334+ /// `--extern priv:name=foo.rlib`.
335+ pub is_private_dep : bool ,
336+ /// Add the extern entry to the extern prelude.
337+ ///
338+ /// This can be disabled with the `noprelude` option like
339+ /// `--extern noprelude:name`.
340+ pub add_prelude : bool ,
341+ }
342+
343+ #[ derive( Clone , Debug ) ]
344+ pub enum ExternLocation {
345+ /// Indicates to look for the library in the search paths.
346+ ///
347+ /// Added via `--extern name`.
348+ FoundInLibrarySearchDirectories ,
349+ /// The locations where this extern entry must be found.
350+ ///
351+ /// The `CrateLoader` is responsible for loading these and figuring out
352+ /// which one to use.
353+ ///
354+ /// Added via `--extern prelude_name=some_file.rlib`
355+ ExactPaths ( BTreeSet < String > ) ,
329356}
330357
331358impl Externs {
@@ -342,6 +369,18 @@ impl Externs {
342369 }
343370}
344371
372+ impl ExternEntry {
373+ fn new ( location : ExternLocation ) -> ExternEntry {
374+ ExternEntry { location, is_private_dep : false , add_prelude : false }
375+ }
376+
377+ pub fn files ( & self ) -> Option < impl Iterator < Item = & String > > {
378+ match & self . location {
379+ ExternLocation :: ExactPaths ( set) => Some ( set. iter ( ) ) ,
380+ _ => None ,
381+ }
382+ }
383+ }
345384
346385macro_rules! hash_option {
347386 ( $opt_name: ident, $opt_expr: expr, $sub_hashes: expr, [ UNTRACKED ] ) => ( { } ) ;
@@ -1869,12 +1908,6 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
18691908 "Specify where an external rust library is located" ,
18701909 "NAME[=PATH]" ,
18711910 ) ,
1872- opt:: multi_s(
1873- "" ,
1874- "extern-private" ,
1875- "Specify where an extern rust library is located, marking it as a private dependency" ,
1876- "NAME=PATH" ,
1877- ) ,
18781911 opt:: opt_s( "" , "sysroot" , "Override the system root" , "PATH" ) ,
18791912 opt:: multi( "Z" , "" , "Set internal debugging options" , "FLAG" ) ,
18801913 opt:: opt_s(
@@ -2435,43 +2468,105 @@ fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType)
24352468 }
24362469}
24372470
2438- fn parse_externs (
2471+ pub fn parse_externs (
24392472 matches : & getopts:: Matches ,
24402473 debugging_opts : & DebuggingOptions ,
24412474 error_format : ErrorOutputType ,
24422475) -> Externs {
2443- if matches. opt_present ( "extern-private" ) && !debugging_opts. unstable_options {
2444- early_error (
2445- ErrorOutputType :: default ( ) ,
2446- "'--extern-private' is unstable and only \
2447- available for nightly builds of rustc."
2448- )
2449- }
2450-
2451- // We start out with a `Vec<(Option<String>, bool)>>`,
2452- // and later convert it into a `BTreeSet<(Option<String>, bool)>`
2453- // This allows to modify entries in-place to set their correct
2454- // 'public' value.
2476+ let is_unstable_enabled = debugging_opts. unstable_options ;
24552477 let mut externs: BTreeMap < String , ExternEntry > = BTreeMap :: new ( ) ;
2456- for ( arg, private) in matches. opt_strs ( "extern" ) . into_iter ( ) . map ( |v| ( v, false ) )
2457- . chain ( matches. opt_strs ( "extern-private" ) . into_iter ( ) . map ( |v| ( v, true ) ) ) {
2458-
2478+ for arg in matches. opt_strs ( "extern" ) {
24592479 let mut parts = arg. splitn ( 2 , '=' ) ;
2460- let name = parts. next ( ) . unwrap_or_else ( ||
2461- early_error ( error_format, "--extern value must not be empty" ) ) ;
2462- let location = parts. next ( ) . map ( |s| s. to_string ( ) ) ;
2480+ let name = parts
2481+ . next ( )
2482+ . unwrap_or_else ( || early_error ( error_format, "--extern value must not be empty" ) ) ;
2483+ let path = parts. next ( ) . map ( |s| s. to_string ( ) ) ;
2484+
2485+ let mut name_parts = name. splitn ( 2 , ':' ) ;
2486+ let first_part = name_parts. next ( ) ;
2487+ let second_part = name_parts. next ( ) ;
2488+ let ( options, name) = match ( first_part, second_part) {
2489+ ( Some ( opts) , Some ( name) ) => ( Some ( opts) , name) ,
2490+ ( Some ( name) , None ) => ( None , name) ,
2491+ ( None , None ) => early_error ( error_format, "--extern name must not be empty" ) ,
2492+ _ => unreachable ! ( ) ,
2493+ } ;
2494+
2495+ let entry = externs. entry ( name. to_owned ( ) ) ;
24632496
2464- let entry = externs
2465- . entry ( name. to_owned ( ) )
2466- . or_default ( ) ;
2497+ use std:: collections:: btree_map:: Entry ;
24672498
2499+ let entry = if let Some ( path) = path {
2500+ // --extern prelude_name=some_file.rlib
2501+ match entry {
2502+ Entry :: Vacant ( vacant) => {
2503+ let files = BTreeSet :: from_iter ( iter:: once ( path) ) ;
2504+ vacant. insert ( ExternEntry :: new ( ExternLocation :: ExactPaths ( files) ) )
2505+ }
2506+ Entry :: Occupied ( occupied) => {
2507+ let ext_ent = occupied. into_mut ( ) ;
2508+ match ext_ent {
2509+ ExternEntry { location : ExternLocation :: ExactPaths ( files) , .. } => {
2510+ files. insert ( path) ;
2511+ }
2512+ ExternEntry {
2513+ location : location @ ExternLocation :: FoundInLibrarySearchDirectories ,
2514+ ..
2515+ } => {
2516+ // Exact paths take precedence over search directories.
2517+ let files = BTreeSet :: from_iter ( iter:: once ( path) ) ;
2518+ * location = ExternLocation :: ExactPaths ( files) ;
2519+ }
2520+ }
2521+ ext_ent
2522+ }
2523+ }
2524+ } else {
2525+ // --extern prelude_name
2526+ match entry {
2527+ Entry :: Vacant ( vacant) => {
2528+ vacant. insert ( ExternEntry :: new ( ExternLocation :: FoundInLibrarySearchDirectories ) )
2529+ }
2530+ Entry :: Occupied ( occupied) => {
2531+ // Ignore if already specified.
2532+ occupied. into_mut ( )
2533+ }
2534+ }
2535+ } ;
24682536
2469- entry. locations . insert ( location. clone ( ) ) ;
2537+ let mut is_private_dep = false ;
2538+ let mut add_prelude = true ;
2539+ if let Some ( opts) = options {
2540+ if !is_unstable_enabled {
2541+ early_error (
2542+ error_format,
2543+ "the `-Z unstable-options` flag must also be passed to \
2544+ enable `--extern options",
2545+ ) ;
2546+ }
2547+ for opt in opts. split ( ',' ) {
2548+ match opt {
2549+ "priv" => is_private_dep = true ,
2550+ "noprelude" => {
2551+ if let ExternLocation :: ExactPaths ( _) = & entry. location {
2552+ add_prelude = false ;
2553+ } else {
2554+ early_error (
2555+ error_format,
2556+ "the `noprelude` --extern option requires a file path" ,
2557+ ) ;
2558+ }
2559+ }
2560+ _ => early_error ( error_format, & format ! ( "unknown --extern option `{}`" , opt) ) ,
2561+ }
2562+ }
2563+ }
24702564
2471- // Crates start out being not private,
2472- // and go to being private if we see an '--extern-private'
2473- // flag
2474- entry. is_private_dep |= private;
2565+ // Crates start out being not private, and go to being private `priv`
2566+ // is specified.
2567+ entry. is_private_dep |= is_private_dep;
2568+ // If any flag is missing `noprelude`, then add to the prelude.
2569+ entry. add_prelude |= add_prelude;
24752570 }
24762571 Externs ( externs)
24772572}
0 commit comments