@@ -533,6 +533,92 @@ impl ToJson for LinkerFlavorCli {
533533 }
534534}
535535
536+ /// The different `-Clink-self-contained` options that can be specified in a target spec:
537+ /// - enabling or disabling in bulk
538+ /// - some target-specific pieces of inference to determine whether to use self-contained linking
539+ /// if `-Clink-self-contained` is not specified explicitly (e.g. on musl/mingw)
540+ /// - explicitly enabling some of the self-contained linking components, e.g. the linker component
541+ /// to use `rust-lld`
542+ #[ derive( Clone , Copy , PartialEq , Debug ) ]
543+ pub enum LinkSelfContained {
544+ /// The target spec explicitly enables self-contained linking.
545+ True ,
546+
547+ /// The target spec explicitly disables self-contained linking.
548+ False ,
549+
550+ /// The target spec requests that the self-contained mode is inferred, in the context of musl.
551+ InferredForMusl ,
552+
553+ /// The target spec requests that the self-contained mode is inferred, in the context of mingw.
554+ InferredForMingw ,
555+
556+ /// The target spec explicitly enables a list of self-contained linking components: e.g. for
557+ /// targets opting into a subset of components like the CLI's `-C link-self-contained=+linker`.
558+ WithComponents ( LinkSelfContainedComponents ) ,
559+ }
560+
561+ impl ToJson for LinkSelfContained {
562+ fn to_json ( & self ) -> Json {
563+ match * self {
564+ LinkSelfContained :: WithComponents ( components) => {
565+ // Serialize the components in a json object's `components` field, to prepare for a
566+ // future where `crt-objects-fallback` is removed from the json specs and
567+ // incorporated as a field here.
568+ let mut map = BTreeMap :: new ( ) ;
569+ map. insert ( "components" , components) ;
570+ map. to_json ( )
571+ }
572+
573+ // Stable values backwards-compatible with `LinkSelfContainedDefault`
574+ LinkSelfContained :: True => "true" . to_json ( ) ,
575+ LinkSelfContained :: False => "false" . to_json ( ) ,
576+ LinkSelfContained :: InferredForMusl => "musl" . to_json ( ) ,
577+ LinkSelfContained :: InferredForMingw => "mingw" . to_json ( ) ,
578+ }
579+ }
580+ }
581+
582+ impl LinkSelfContained {
583+ /// Returns whether the target spec has self-contained linking explicitly disabled. Used to emit
584+ /// errors if the user then enables it on the CLI.
585+ pub fn is_disabled ( self ) -> bool {
586+ self == Self :: False
587+ }
588+
589+ /// Returns whether the target spec explictly requests self-contained linking, i.e. not via
590+ /// inference.
591+ pub fn is_linker_enabled ( self ) -> bool {
592+ match self {
593+ LinkSelfContained :: True => true ,
594+ LinkSelfContained :: False => false ,
595+ LinkSelfContained :: WithComponents ( c) => c. contains ( LinkSelfContainedComponents :: LINKER ) ,
596+ _ => false ,
597+ }
598+ }
599+
600+ /// Returns the key to use when serializing the setting to json:
601+ /// - individual components in a `link-self-contained` object value
602+ /// - the other variants as a backwards-compatible `crt-objects-fallback` string
603+ fn json_key ( self ) -> & ' static str {
604+ match self {
605+ LinkSelfContained :: WithComponents ( _) => "link-self-contained" ,
606+ _ => "crt-objects-fallback" ,
607+ }
608+ }
609+ }
610+
611+ impl From < LinkSelfContainedDefault > for LinkSelfContained {
612+ fn from ( value : LinkSelfContainedDefault ) -> Self {
613+ match value {
614+ LinkSelfContainedDefault :: True => LinkSelfContained :: True ,
615+ LinkSelfContainedDefault :: False => LinkSelfContained :: False ,
616+ LinkSelfContainedDefault :: Musl => LinkSelfContained :: InferredForMusl ,
617+ LinkSelfContainedDefault :: Mingw => LinkSelfContained :: InferredForMingw ,
618+ }
619+ }
620+ }
621+
536622bitflags:: bitflags! {
537623 #[ derive( Default ) ]
538624 /// The `-C link-self-contained` components that can individually be enabled or disabled.
@@ -565,6 +651,49 @@ impl LinkSelfContainedComponents {
565651 _ => return None ,
566652 } )
567653 }
654+
655+ /// Return the component's name.
656+ ///
657+ /// Returns `None` if the bitflags aren't a singular component (but a mix of multiple flags).
658+ fn as_str ( self ) -> Option < & ' static str > {
659+ Some ( match self {
660+ LinkSelfContainedComponents :: CRT_OBJECTS => "crto" ,
661+ LinkSelfContainedComponents :: LIBC => "libc" ,
662+ LinkSelfContainedComponents :: UNWIND => "unwind" ,
663+ LinkSelfContainedComponents :: LINKER => "linker" ,
664+ LinkSelfContainedComponents :: SANITIZERS => "sanitizers" ,
665+ LinkSelfContainedComponents :: MINGW => "mingw" ,
666+ _ => return None ,
667+ } )
668+ }
669+
670+ /// Returns an array of all the components.
671+ fn all_components ( ) -> [ LinkSelfContainedComponents ; 6 ] {
672+ [
673+ LinkSelfContainedComponents :: CRT_OBJECTS ,
674+ LinkSelfContainedComponents :: LIBC ,
675+ LinkSelfContainedComponents :: UNWIND ,
676+ LinkSelfContainedComponents :: LINKER ,
677+ LinkSelfContainedComponents :: SANITIZERS ,
678+ LinkSelfContainedComponents :: MINGW ,
679+ ]
680+ }
681+ }
682+
683+ impl ToJson for LinkSelfContainedComponents {
684+ fn to_json ( & self ) -> Json {
685+ let components: Vec < _ > = Self :: all_components ( )
686+ . into_iter ( )
687+ . filter ( |c| self . contains ( * c) )
688+ . map ( |c| {
689+ // We can unwrap because we're iterating over all the known singular components,
690+ // not an actual set of flags where `as_str` can fail.
691+ c. as_str ( ) . unwrap ( ) . to_owned ( )
692+ } )
693+ . collect ( ) ;
694+
695+ components. to_json ( )
696+ }
568697}
569698
570699#[ derive( Clone , Copy , Debug , PartialEq , Hash , Encodable , Decodable , HashStable_Generic ) ]
@@ -1742,7 +1871,9 @@ pub struct TargetOptions {
17421871 /// Same as `(pre|post)_link_objects`, but when self-contained linking mode is enabled.
17431872 pub pre_link_objects_self_contained : CrtObjects ,
17441873 pub post_link_objects_self_contained : CrtObjects ,
1745- pub link_self_contained : LinkSelfContainedDefault ,
1874+ /// Behavior for the self-contained linking mode: inferred for some targets, or explicitly
1875+ /// enabled (in bulk, or with individual components).
1876+ pub link_self_contained : LinkSelfContained ,
17461877
17471878 /// Linker arguments that are passed *before* any user-defined libraries.
17481879 pub pre_link_args : LinkArgs ,
@@ -2215,7 +2346,7 @@ impl Default for TargetOptions {
22152346 post_link_objects : Default :: default ( ) ,
22162347 pre_link_objects_self_contained : Default :: default ( ) ,
22172348 post_link_objects_self_contained : Default :: default ( ) ,
2218- link_self_contained : LinkSelfContainedDefault :: False ,
2349+ link_self_contained : LinkSelfContained :: False ,
22192350 pre_link_args : LinkArgs :: new ( ) ,
22202351 pre_link_args_json : LinkArgsCli :: new ( ) ,
22212352 late_link_args : LinkArgs :: new ( ) ,
@@ -2696,12 +2827,47 @@ impl Target {
26962827 }
26972828 Ok :: <( ) , String >( ( ) )
26982829 } ) ;
2699-
2700- ( $key_name: ident = $json_name: expr, link_self_contained) => ( {
2830+ ( $key_name: ident, LinkSelfContained ) => ( {
2831+ // Skeleton of what needs to be parsed:
2832+ //
2833+ // ```
2834+ // $name: {
2835+ // "components": [
2836+ // <array of strings>
2837+ // ]
2838+ // }
2839+ // ```
2840+ let name = ( stringify!( $key_name) ) . replace( "_" , "-" ) ;
2841+ if let Some ( o) = obj. remove( & name) {
2842+ if let Some ( o) = o. as_object( ) {
2843+ let component_array = o. get( "components" )
2844+ . ok_or_else( || format!( "{name}: expected a \
2845+ JSON object with a `components` field.") ) ?;
2846+ let component_array = component_array. as_array( )
2847+ . ok_or_else( || format!( "{name}.components: expected a JSON array" ) ) ?;
2848+ let mut components = LinkSelfContainedComponents :: empty( ) ;
2849+ for s in component_array {
2850+ components |= match s. as_str( ) {
2851+ Some ( s) => {
2852+ LinkSelfContainedComponents :: from_str( s)
2853+ . ok_or_else( || format!( "unknown \
2854+ `-Clink-self-contained` component: {s}") ) ?
2855+ } ,
2856+ _ => return Err ( format!( "not a string: {:?}" , s) ) ,
2857+ } ;
2858+ }
2859+ base. $key_name = LinkSelfContained :: WithComponents ( components) ;
2860+ } else {
2861+ incorrect_type. push( name)
2862+ }
2863+ }
2864+ Ok :: <( ) , String >( ( ) )
2865+ } ) ;
2866+ ( $key_name: ident = $json_name: expr, LinkSelfContainedDefault ) => ( {
27012867 let name = $json_name;
27022868 obj. remove( name) . and_then( |o| o. as_str( ) . and_then( |s| {
27032869 match s. parse:: <LinkSelfContainedDefault >( ) {
2704- Ok ( lsc_default) => base. $key_name = lsc_default,
2870+ Ok ( lsc_default) => base. $key_name = lsc_default. into ( ) ,
27052871 _ => return Some ( Err ( format!( "'{}' is not a valid `-Clink-self-contained` default. \
27062872 Use 'false', 'true', 'musl' or 'mingw'", s) ) ) ,
27072873 }
@@ -2850,7 +3016,10 @@ impl Target {
28503016 key ! ( post_link_objects = "post-link-objects" , link_objects) ;
28513017 key ! ( pre_link_objects_self_contained = "pre-link-objects-fallback" , link_objects) ;
28523018 key ! ( post_link_objects_self_contained = "post-link-objects-fallback" , link_objects) ;
2853- key ! ( link_self_contained = "crt-objects-fallback" , link_self_contained) ?;
3019+ // Deserializes the backwards-compatible variants of `-Clink-self-contained`
3020+ key ! ( link_self_contained = "crt-objects-fallback" , LinkSelfContainedDefault ) ?;
3021+ // Deserializes the components variant of `-Clink-self-contained`
3022+ key ! ( link_self_contained, LinkSelfContained ) ?;
28543023 key ! ( pre_link_args_json = "pre-link-args" , link_args) ;
28553024 key ! ( late_link_args_json = "late-link-args" , link_args) ;
28563025 key ! ( late_link_args_dynamic_json = "late-link-args-dynamic" , link_args) ;
@@ -3106,7 +3275,6 @@ impl ToJson for Target {
31063275 target_option_val ! ( post_link_objects) ;
31073276 target_option_val ! ( pre_link_objects_self_contained, "pre-link-objects-fallback" ) ;
31083277 target_option_val ! ( post_link_objects_self_contained, "post-link-objects-fallback" ) ;
3109- target_option_val ! ( link_self_contained, "crt-objects-fallback" ) ;
31103278 target_option_val ! ( link_args - pre_link_args_json, "pre-link-args" ) ;
31113279 target_option_val ! ( link_args - late_link_args_json, "late-link-args" ) ;
31123280 target_option_val ! ( link_args - late_link_args_dynamic_json, "late-link-args-dynamic" ) ;
@@ -3203,6 +3371,10 @@ impl ToJson for Target {
32033371 d. insert ( "default-adjusted-cabi" . into ( ) , Abi :: name ( abi) . to_json ( ) ) ;
32043372 }
32053373
3374+ // Serializing `-Clink-self-contained` needs a dynamic key to support the
3375+ // backwards-compatible variants.
3376+ d. insert ( self . link_self_contained . json_key ( ) . into ( ) , self . link_self_contained . to_json ( ) ) ;
3377+
32063378 Json :: Object ( d)
32073379 }
32083380}
0 commit comments