@@ -22,7 +22,9 @@ use rustc_session::utils::NativeLibKind;
2222/// need out of the shared crate context before we get rid of it.
2323use rustc_session:: { filesearch, Session } ;
2424use rustc_span:: symbol:: Symbol ;
25- use rustc_target:: spec:: crt_objects:: { CrtObjects , LinkSelfContainedDefault } ;
25+ use rustc_target:: spec:: crt_objects:: CrtObjects ;
26+ use rustc_target:: spec:: LinkSelfContainedComponents ;
27+ use rustc_target:: spec:: LinkSelfContainedDefault ;
2628use rustc_target:: spec:: { Cc , LinkOutputKind , LinkerFlavor , Lld , PanicStrategy } ;
2729use rustc_target:: spec:: { RelocModel , RelroLevel , SanitizerSet , SplitDebuginfo } ;
2830
@@ -728,6 +730,7 @@ fn link_natively<'a>(
728730) -> Result < ( ) , ErrorGuaranteed > {
729731 info ! ( "preparing {:?} to {:?}" , crate_type, out_filename) ;
730732 let ( linker_path, flavor) = linker_and_flavor ( sess) ;
733+ let self_contained_components = self_contained_components ( sess, crate_type) ;
731734 let mut cmd = linker_with_args (
732735 & linker_path,
733736 flavor,
@@ -737,6 +740,7 @@ fn link_natively<'a>(
737740 tmpdir,
738741 out_filename,
739742 codegen_results,
743+ self_contained_components,
740744 ) ?;
741745
742746 linker:: disable_localization ( & mut cmd) ;
@@ -812,14 +816,14 @@ fn link_natively<'a>(
812816 "Linker does not support -static-pie command line option. Retrying with -static instead."
813817 ) ;
814818 // Mirror `add_(pre,post)_link_objects` to replace CRT objects.
815- let self_contained = self_contained ( sess , crate_type ) ;
819+ let self_contained_crt_objects = self_contained_components . is_crt_objects_enabled ( ) ;
816820 let opts = & sess. target ;
817- let pre_objects = if self_contained {
821+ let pre_objects = if self_contained_crt_objects {
818822 & opts. pre_link_objects_self_contained
819823 } else {
820824 & opts. pre_link_objects
821825 } ;
822- let post_objects = if self_contained {
826+ let post_objects = if self_contained_crt_objects {
823827 & opts. post_link_objects_self_contained
824828 } else {
825829 & opts. post_link_objects
@@ -830,7 +834,9 @@ fn link_natively<'a>(
830834 . iter ( )
831835 . copied ( )
832836 . flatten ( )
833- . map ( |obj| get_object_file_path ( sess, obj, self_contained) . into_os_string ( ) )
837+ . map ( |obj| {
838+ get_object_file_path ( sess, obj, self_contained_crt_objects) . into_os_string ( )
839+ } )
834840 . collect :: < Vec < _ > > ( )
835841 } ;
836842 let pre_objects_static_pie = get_objects ( pre_objects, LinkOutputKind :: StaticPicExe ) ;
@@ -1710,26 +1716,43 @@ fn detect_self_contained_mingw(sess: &Session) -> bool {
17101716/// Various toolchain components used during linking are used from rustc distribution
17111717/// instead of being found somewhere on the host system.
17121718/// We only provide such support for a very limited number of targets.
1713- fn self_contained ( sess : & Session , crate_type : CrateType ) -> bool {
1714- if let Some ( self_contained) = sess. opts . cg . link_self_contained . explicitly_set {
1715- if sess. target . link_self_contained == LinkSelfContainedDefault :: False {
1716- sess. emit_err ( errors:: UnsupportedLinkSelfContained ) ;
1717- }
1718- return self_contained;
1719- }
1719+ fn self_contained_components ( sess : & Session , crate_type : CrateType ) -> LinkSelfContainedComponents {
1720+ // Turn the backwards compatible bool values for `self_contained` into fully inferred
1721+ // `LinkSelfContainedComponents`.
1722+ let self_contained =
1723+ if let Some ( self_contained) = sess. opts . cg . link_self_contained . explicitly_set {
1724+ // Emit an error if the user requested self-contained mode on the CLI but the target
1725+ // explicitly refuses it.
1726+ if sess. target . link_self_contained . is_disabled ( ) {
1727+ sess. emit_err ( errors:: UnsupportedLinkSelfContained ) ;
1728+ }
1729+ self_contained
1730+ } else {
1731+ match sess. target . link_self_contained {
1732+ LinkSelfContainedDefault :: False => false ,
1733+ LinkSelfContainedDefault :: True => true ,
1734+
1735+ LinkSelfContainedDefault :: WithComponents ( components) => {
1736+ // For target specs with explicitly enabled components, we can return them
1737+ // directly.
1738+ return components;
1739+ }
17201740
1721- match sess. target . link_self_contained {
1722- LinkSelfContainedDefault :: False => false ,
1723- LinkSelfContainedDefault :: True => true ,
1724- // FIXME: Find a better heuristic for "native musl toolchain is available",
1725- // based on host and linker path, for example.
1726- // (https://github.com/rust-lang/rust/pull/71769#issuecomment-626330237).
1727- LinkSelfContainedDefault :: Musl => sess. crt_static ( Some ( crate_type) ) ,
1728- LinkSelfContainedDefault :: Mingw => {
1729- sess. host == sess. target
1730- && sess. target . vendor != "uwp"
1731- && detect_self_contained_mingw ( & sess)
1732- }
1741+ // FIXME: Find a better heuristic for "native musl toolchain is available",
1742+ // based on host and linker path, for example.
1743+ // (https://github.com/rust-lang/rust/pull/71769#issuecomment-626330237).
1744+ LinkSelfContainedDefault :: InferredForMusl => sess. crt_static ( Some ( crate_type) ) ,
1745+ LinkSelfContainedDefault :: InferredForMingw => {
1746+ sess. host == sess. target
1747+ && sess. target . vendor != "uwp"
1748+ && detect_self_contained_mingw ( & sess)
1749+ }
1750+ }
1751+ } ;
1752+ if self_contained {
1753+ LinkSelfContainedComponents :: all ( )
1754+ } else {
1755+ LinkSelfContainedComponents :: empty ( )
17331756 }
17341757}
17351758
@@ -2030,13 +2053,14 @@ fn linker_with_args<'a>(
20302053 tmpdir : & Path ,
20312054 out_filename : & Path ,
20322055 codegen_results : & CodegenResults ,
2056+ self_contained_components : LinkSelfContainedComponents ,
20332057) -> Result < Command , ErrorGuaranteed > {
2034- let self_contained = self_contained ( sess , crate_type ) ;
2058+ let self_contained_crt_objects = self_contained_components . is_crt_objects_enabled ( ) ;
20352059 let cmd = & mut * super :: linker:: get_linker (
20362060 sess,
20372061 path,
20382062 flavor,
2039- self_contained ,
2063+ self_contained_components . are_any_components_enabled ( ) ,
20402064 & codegen_results. crate_info . target_cpu ,
20412065 ) ;
20422066 let link_output_kind = link_output_kind ( sess, crate_type) ;
@@ -2063,7 +2087,7 @@ fn linker_with_args<'a>(
20632087 // ------------ Object code and libraries, order-dependent ------------
20642088
20652089 // Pre-link CRT objects.
2066- add_pre_link_objects ( cmd, sess, flavor, link_output_kind, self_contained ) ;
2090+ add_pre_link_objects ( cmd, sess, flavor, link_output_kind, self_contained_crt_objects ) ;
20672091
20682092 add_linked_symbol_object (
20692093 cmd,
@@ -2206,7 +2230,7 @@ fn linker_with_args<'a>(
22062230 cmd,
22072231 sess,
22082232 link_output_kind,
2209- self_contained ,
2233+ self_contained_components ,
22102234 flavor,
22112235 crate_type,
22122236 codegen_results,
@@ -2222,7 +2246,7 @@ fn linker_with_args<'a>(
22222246 // ------------ Object code and libraries, order-dependent ------------
22232247
22242248 // Post-link CRT objects.
2225- add_post_link_objects ( cmd, sess, link_output_kind, self_contained ) ;
2249+ add_post_link_objects ( cmd, sess, link_output_kind, self_contained_crt_objects ) ;
22262250
22272251 // ------------ Late order-dependent options ------------
22282252
@@ -2239,15 +2263,15 @@ fn add_order_independent_options(
22392263 cmd : & mut dyn Linker ,
22402264 sess : & Session ,
22412265 link_output_kind : LinkOutputKind ,
2242- self_contained : bool ,
2266+ self_contained_components : LinkSelfContainedComponents ,
22432267 flavor : LinkerFlavor ,
22442268 crate_type : CrateType ,
22452269 codegen_results : & CodegenResults ,
22462270 out_filename : & Path ,
22472271 tmpdir : & Path ,
22482272) {
22492273 // Take care of the flavors and CLI options requesting the `lld` linker.
2250- add_lld_args ( cmd, sess, flavor) ;
2274+ add_lld_args ( cmd, sess, flavor, self_contained_components ) ;
22512275
22522276 add_apple_sdk ( cmd, sess, flavor) ;
22532277
@@ -2272,7 +2296,7 @@ fn add_order_independent_options(
22722296 // Make the binary compatible with data execution prevention schemes.
22732297 cmd. add_no_exec ( ) ;
22742298
2275- if self_contained {
2299+ if self_contained_components . is_crt_objects_enabled ( ) {
22762300 cmd. no_crt_objects ( ) ;
22772301 }
22782302
@@ -2303,7 +2327,7 @@ fn add_order_independent_options(
23032327
23042328 cmd. linker_plugin_lto ( ) ;
23052329
2306- add_library_search_dirs ( cmd, sess, self_contained ) ;
2330+ add_library_search_dirs ( cmd, sess, self_contained_components . are_any_components_enabled ( ) ) ;
23072331
23082332 cmd. output_filename ( out_filename) ;
23092333
@@ -2953,8 +2977,16 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result<String, errors::AppleSdkRootErro
29532977/// invoke it:
29542978/// - when the self-contained linker flag is active: the build of `lld` distributed with rustc,
29552979/// - or any `lld` available to `cc`.
2956- fn add_lld_args ( cmd : & mut dyn Linker , sess : & Session , flavor : LinkerFlavor ) {
2957- debug ! ( "add_lld_args requested, flavor: '{flavor:?}'" ) ;
2980+ fn add_lld_args (
2981+ cmd : & mut dyn Linker ,
2982+ sess : & Session ,
2983+ flavor : LinkerFlavor ,
2984+ self_contained_components : LinkSelfContainedComponents ,
2985+ ) {
2986+ debug ! (
2987+ "add_lld_args requested, flavor: '{:?}', target self-contained components: {:?}" ,
2988+ flavor, self_contained_components,
2989+ ) ;
29582990
29592991 // If the flavor doesn't use a C/C++ compiler to invoke the linker, or doesn't opt in to `lld`,
29602992 // we don't need to do anything.
@@ -2963,9 +2995,32 @@ fn add_lld_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
29632995 }
29642996
29652997 // 1. Implement the "self-contained" part of this feature by adding rustc distribution
2966- // directories to the tool's search path:
2967- // - if the self-contained linker is enabled on the CLI.
2968- if sess. opts . cg . link_self_contained . is_linker_enabled ( ) {
2998+ // directories to the tool's search path, depending on a mix between what users can specify on
2999+ // the CLI, and what the target spec enables (as it can't disable components):
3000+ // - if the self-contained linker is enabled on the CLI or by the target spec,
3001+ // - and if the self-contained linker is not disabled on the CLI.
3002+ let self_contained_cli = sess. opts . cg . link_self_contained . is_linker_enabled ( ) ;
3003+ let self_contained_target = self_contained_components. is_linker_enabled ( ) ;
3004+
3005+ // FIXME: in the future, codegen backends may need to have more control over this process: they
3006+ // don't always support all the features the linker expects here, and vice versa. For example,
3007+ // at the time of writing this, lld expects a newer style of aarch64 TLS relocations that
3008+ // cranelift doesn't implement yet. That in turn can impact whether linking would succeed on
3009+ // such a target when using the `cg_clif` backend and lld.
3010+ //
3011+ // Until interactions between backends and linker features are expressible, we limit target
3012+ // specs to opt-in to lld only when we're on the llvm backend, where it's expected to work and
3013+ // tested on CI. As usual, the CLI still has precedence over this, so that users and developers
3014+ // can still override this default when needed (e.g. for tests).
3015+ let uses_llvm_backend =
3016+ matches ! ( sess. opts. unstable_opts. codegen_backend. as_deref( ) , None | Some ( "llvm" ) ) ;
3017+ if !uses_llvm_backend && !self_contained_cli && sess. opts . cg . linker_flavor . is_none ( ) {
3018+ // We bail if we're not using llvm and lld was not explicitly requested on the CLI.
3019+ return ;
3020+ }
3021+
3022+ let self_contained_linker = self_contained_cli || self_contained_target;
3023+ if self_contained_linker && !sess. opts . cg . link_self_contained . is_linker_disabled ( ) {
29693024 for path in sess. get_tools_search_paths ( false ) {
29703025 cmd. arg ( {
29713026 let mut arg = OsString :: from ( "-B" ) ;
0 commit comments