diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index f612785e5a416..59061acaff5ae 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -77,7 +77,7 @@ fn prepare_lto( // with either fat or thin LTO let mut upstream_modules = Vec::new(); if cgcx.lto != Lto::ThinLocal { - if cgcx.opts.cg.prefer_dynamic { + if cgcx.opts.cg.prefer_dynamic.is_non_empty() { diag_handler .struct_err("cannot prefer dynamic linking when performing LTO") .note( diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 3ca295f4a7e89..7a755a2a03c86 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -256,7 +256,7 @@ impl CodegenCx<'ll, 'tcx> { debug_assert!( !(self.tcx.sess.opts.cg.linker_plugin_lto.enabled() && self.tcx.sess.target.is_like_windows - && self.tcx.sess.opts.cg.prefer_dynamic) + && self.tcx.sess.opts.cg.prefer_dynamic.is_non_empty()) ); if needs_dll_storage_attr { diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 41823f7d80d69..a966e5c22d56d 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1950,7 +1950,7 @@ fn msvc_imps_needed(tcx: TyCtxt<'_>) -> bool { assert!( !(tcx.sess.opts.cg.linker_plugin_lto.enabled() && tcx.sess.target.is_like_windows - && tcx.sess.opts.cg.prefer_dynamic) + && tcx.sess.opts.cg.prefer_dynamic.is_non_empty()) ); tcx.sess.target.is_like_windows && diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index b896143400698..bd0adbc102eed 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -8,7 +8,7 @@ use rustc_session::config::{build_configuration, build_session_options, to_crate use rustc_session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes}; use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath}; use rustc_session::config::{ - Externs, OutputType, OutputTypes, SymbolManglingVersion, WasiExecModel, + Externs, OutputType, OutputTypes, PreferDynamicSet, SymbolManglingVersion, WasiExecModel, }; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; @@ -582,7 +582,7 @@ fn test_codegen_options_tracking_hash() { tracked!(overflow_checks, Some(true)); tracked!(panic, Some(PanicStrategy::Abort)); tracked!(passes, vec![String::from("1"), String::from("2")]); - tracked!(prefer_dynamic, true); + tracked!(prefer_dynamic, PreferDynamicSet::every_crate()); tracked!(profile_generate, SwitchWithOptPath::Enabled(None)); tracked!(profile_use, Some(PathBuf::from("abc"))); tracked!(relocation_model, Some(RelocModel::Pic)); @@ -590,6 +590,16 @@ fn test_codegen_options_tracking_hash() { tracked!(split_debuginfo, Some(SplitDebuginfo::Packed)); tracked!(target_cpu, Some(String::from("abc"))); tracked!(target_feature, String::from("all the features, all of them")); + + // Check that changes to the ordering of input to `-C prefer-dynamic=crate,...` + // does not cause the dependency tracking hash to change. + { + let mut v1 = Options::default(); + let mut v2 = Options::default(); + v1.cg.prefer_dynamic = PreferDynamicSet::subset(["a", "b"].iter()); + v2.cg.prefer_dynamic = PreferDynamicSet::subset(["b", "a"].iter()); + assert_same_hash(&v1, &v2); + } } #[test] diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index 2d4deb1d8d5da..a911aab994c5e 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -46,22 +46,26 @@ //! all dynamic. This isn't currently very well battle tested, so it will likely //! fall short in some use cases. //! -//! Currently, there is no way to specify the preference of linkage with a -//! particular library (other than a global dynamic/static switch). -//! Additionally, the algorithm is geared towards finding *any* solution rather -//! than finding a number of solutions (there are normally quite a few). +//! The algorithm is geared towards finding *any* solution rather than finding a +//! number of solutions (there are normally quite a few). One can specify the +//! preference of linkage for a particular list of crates by specifying that +//! list via `-C prefer-dynamic=crate1,crate2,...`. use crate::creader::CStore; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::def_id::CrateNum; -use rustc_middle::middle::cstore::CrateDepKind; +use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_middle::middle::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic}; +use rustc_middle::middle::cstore::{CrateDepKind, CrateSource}; use rustc_middle::middle::dependency_format::{Dependencies, DependencyList, Linkage}; use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; use rustc_target::spec::PanicStrategy; +type RevDeps = FxHashMap<(CrateNum, LinkagePreference), Vec>; + +use rustc_data_structures::sync::Lrc; + crate fn calculate(tcx: TyCtxt<'_>) -> Dependencies { tcx.sess .crate_types() @@ -81,23 +85,43 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { return Vec::new(); } + let prefer_dynamic = &sess.opts.cg.prefer_dynamic; + + // traverses all crates to see if any are in the prefer-dynamic set. + let prefer_dynamic_for_any_crate = || { + if prefer_dynamic.is_empty() { + // skip traversal if we know it cannot ever bear fruit. + false + } else { + tcx.crates(()).iter().any(|cnum| prefer_dynamic.contains_crate(tcx.crate_name(*cnum))) + } + }; + let preferred_linkage = match ty { - // Generating a dylib without `-C prefer-dynamic` means that we're going - // to try to eagerly statically link all dependencies. This is normally - // done for end-product dylibs, not intermediate products. + // If `-C prefer-dynamic` is not set for any crate, then means that we're + // going to try to eagerly statically link all dependencies into the dylib. + // This is normally done for end-product dylibs, not intermediate products. // - // Treat cdylibs similarly. If `-C prefer-dynamic` is set, the caller may - // be code-size conscious, but without it, it makes sense to statically - // link a cdylib. - CrateType::Dylib | CrateType::Cdylib if !sess.opts.cg.prefer_dynamic => Linkage::Static, - CrateType::Dylib | CrateType::Cdylib => Linkage::Dynamic, + // Treat cdylibs similarly. If `-C prefer-dynamic` is set for any given + // crate, the caller may be code-size conscious, but without it, it + // makes sense to statically link a cdylib. + CrateType::Dylib | CrateType::Cdylib => { + if prefer_dynamic_for_any_crate() { + Linkage::Dynamic + } else { + Linkage::Static + } + } - // If the global prefer_dynamic switch is turned off, or the final + // If `prefer_dynamic` is not set for any crate, or the final // executable will be statically linked, prefer static crate linkage. - CrateType::Executable if !sess.opts.cg.prefer_dynamic || sess.crt_static(Some(ty)) => { - Linkage::Static + CrateType::Executable => { + if !prefer_dynamic_for_any_crate() || sess.crt_static(Some(ty)) { + Linkage::Static + } else { + Linkage::Dynamic + } } - CrateType::Executable => Linkage::Dynamic, // proc-macro crates are mostly cdylibs, but we also need metadata. CrateType::ProcMacro => Linkage::Static, @@ -133,7 +157,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { if tcx.dep_kind(cnum).macros_only() { continue; } - let src = tcx.used_crate_source(cnum); + let src: Lrc = tcx.used_crate_source(cnum); if src.rlib.is_some() { continue; } @@ -144,10 +168,16 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { )); } return Vec::new(); + } else { + tracing::info!( + "calculate_type {} attempt_static failed; falling through to dynamic linkage", + tcx.crate_name(LOCAL_CRATE) + ); } } let mut formats = FxHashMap::default(); + let mut rev_deps: RevDeps = FxHashMap::default(); // Sweep all crates for found dylibs. Add all dylibs, as well as their // dependencies, ensuring there are no conflicts. The only valid case for a @@ -157,14 +187,27 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { continue; } let name = tcx.crate_name(cnum); - let src = tcx.used_crate_source(cnum); - if src.dylib.is_some() { - tracing::info!("adding dylib: {}", name); - add_library(tcx, cnum, RequireDynamic, &mut formats); + let src: Lrc = tcx.used_crate_source(cnum); + // We should prefer the dylib, when available, if either: + // 1. the user has requested that dylib (or all dylibs) via `-C prefer-dynamic`, or + // 2. for backwards compatibility: if the prefer-dynamic subset is unset, then we *still* + // favor dylibs here. This way, if static linking fails above, we might still hope to + // succeed at linking here. + let prefer_dylib = + |name| -> bool { prefer_dynamic.is_unset() || prefer_dynamic.contains_crate(name) }; + if src.dylib.is_some() && prefer_dylib(name) { + tracing::info!("calculate_type {} adding dylib: {}", tcx.crate_name(LOCAL_CRATE), name); + add_library(tcx, cnum, RequireDynamic, &mut formats, &mut rev_deps, LOCAL_CRATE); let deps = tcx.dylib_dependency_formats(cnum); for &(depnum, style) in deps.iter() { - tracing::info!("adding {:?}: {}", style, tcx.crate_name(depnum)); - add_library(tcx, depnum, style, &mut formats); + tracing::info!( + "calculate_type {} adding dep of {}, {:?}: {}", + tcx.crate_name(LOCAL_CRATE), + name, + style, + tcx.crate_name(depnum) + ); + add_library(tcx, depnum, style, &mut formats, &mut rev_deps, cnum); } } } @@ -185,14 +228,17 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { // If the crate hasn't been included yet and it's not actually required // (e.g., it's an allocator) then we skip it here as well. for &cnum in tcx.crates(()).iter() { - let src = tcx.used_crate_source(cnum); - if src.dylib.is_none() - && !formats.contains_key(&cnum) - && tcx.dep_kind(cnum) == CrateDepKind::Explicit - { + let name = tcx.crate_name(cnum); + let src: Lrc = tcx.used_crate_source(cnum); + let static_available = src.rlib.is_some() || src.rmeta.is_some(); + let prefer_static = + src.dylib.is_none() || (static_available && !prefer_dynamic.contains_crate(name)); + let missing = !formats.contains_key(&cnum); + let actually_required = tcx.dep_kind(cnum) == CrateDepKind::Explicit; + if prefer_static && missing && actually_required { assert!(src.rlib.is_some() || src.rmeta.is_some()); - tracing::info!("adding staticlib: {}", tcx.crate_name(cnum)); - add_library(tcx, cnum, RequireStatic, &mut formats); + tracing::info!("adding staticlib: {}", name); + add_library(tcx, cnum, RequireStatic, &mut formats, &mut rev_deps, LOCAL_CRATE); ret[cnum.as_usize() - 1] = Linkage::Static; } } @@ -215,7 +261,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { // making sure that everything is available in the requested format. for (cnum, kind) in ret.iter().enumerate() { let cnum = CrateNum::new(cnum + 1); - let src = tcx.used_crate_source(cnum); + let src: Lrc = tcx.used_crate_source(cnum); match *kind { Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static if src.rlib.is_some() => continue, @@ -243,7 +289,10 @@ fn add_library( cnum: CrateNum, link: LinkagePreference, m: &mut FxHashMap, + rev_deps: &mut RevDeps, + parent_cnum: CrateNum, ) { + rev_deps.entry((cnum, link)).or_insert(Vec::new()).push(parent_cnum); match m.get(&cnum) { Some(&link2) => { // If the linkages differ, then we'd have two copies of the library @@ -254,11 +303,44 @@ fn add_library( // This error is probably a little obscure, but I imagine that it // can be refined over time. if link2 != link || link == RequireStatic { + let parent_names = |link| { + let mut names = String::new(); + let mut saw_one = false; + for name in rev_deps[&(cnum, link)].iter().map(|pcnum| tcx.crate_name(*pcnum)) { + if saw_one { + names.push_str(", "); + } + names.push_str(&format!("`{}`", name)); + saw_one = true; + } + names + }; + let link_parent_names = parent_names(link); + let link2_parent_names = parent_names(link2); + + let details = match (link2, link) { + (RequireDynamic, RequireStatic) => format!( + "previously required dynamic, via [{}], \ + and now also requires static, via [{}]", + link2_parent_names, link_parent_names + ), + (RequireStatic, RequireDynamic) => format!( + "previously required static, via [{}], \ + and now also requires dynamic, via [{}]", + link2_parent_names, link_parent_names + ), + (RequireStatic, RequireStatic) => format!( + "two static copies from multiple different locations, via [{}]", + link_parent_names + ), + (RequireDynamic, RequireDynamic) => unreachable!("not a problem"), + }; tcx.sess .struct_err(&format!( "cannot satisfy dependencies so `{}` only \ - shows up once", - tcx.crate_name(cnum) + shows up once ({})", + tcx.crate_name(cnum), + details, )) .help( "having upstream crates all available in one format \ diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs index 8150e67929509..5f82cdb06e514 100644 --- a/compiler/rustc_middle/src/middle/cstore.rs +++ b/compiler/rustc_middle/src/middle/cstore.rs @@ -58,7 +58,7 @@ impl CrateDepKind { } } -#[derive(Copy, Debug, PartialEq, Clone, Encodable, Decodable, HashStable)] +#[derive(Copy, Debug, PartialEq, Eq, Clone, Encodable, Decodable, Hash, HashStable)] pub enum LinkagePreference { RequireDynamic, RequireStatic, diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 123f47b430a17..35a9fa11f9ae8 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -63,6 +63,68 @@ pub enum CFGuard { Checks, } +/// Handle `-C prefer-dynamic` flag: either its all, or its some explicit +/// subset (potentially the empty set). +#[derive(Clone, PartialEq, Hash, Debug)] +pub enum PreferDynamicSet { + /// Specified by the absence of `-C prefer-dynamic`, or via an explicit `-C prefer-dynamic=...` + /// with value `n`, `no`, or `off`. + /// + /// Under this (default) behavior, the compiler first optimistically attempts to statically + /// link everything, but if that fails, then attempts to dynamically link *everything* with a + /// dylib path available. + Unset, + + /// Specified via `-C prefer-dynamic` with no value. For backwards-compatibility, also + /// specified via `-C prefer-dynamic=...` with value `y`, `yes`, or `on`. + All, + + /// Specified via `-C prefer-dynamic=crate,...`. + Set(BTreeSet), +} + +impl PreferDynamicSet { + pub fn unset() -> Self { + PreferDynamicSet::Unset + } + + pub fn every_crate() -> Self { + PreferDynamicSet::All + } + + pub fn subset(crates: impl Iterator) -> Self { + PreferDynamicSet::Set(crates.map(|x| x.to_string()).collect()) + } + + pub fn is_unset(&self) -> bool { + if let PreferDynamicSet::Unset = *self { true } else { false } + } + + pub fn is_empty(&self) -> bool { + match self { + PreferDynamicSet::Unset => true, + PreferDynamicSet::All => false, + PreferDynamicSet::Set(s) => s.len() == 0, + } + } + + pub fn is_non_empty(&self) -> bool { + match self { + PreferDynamicSet::Unset => false, + PreferDynamicSet::All => true, + PreferDynamicSet::Set(s) => s.len() > 0, + } + } + + pub fn contains_crate(&self, crate_name: Symbol) -> bool { + match self { + PreferDynamicSet::Unset => false, + PreferDynamicSet::All => true, + PreferDynamicSet::Set(s) => s.iter().any(|s| s == &*crate_name.as_str()), + } + } +} + #[derive(Clone, Copy, Debug, PartialEq, Hash)] pub enum OptLevel { No, // -O0 @@ -2106,6 +2168,36 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { } } + if !debugging_opts.unstable_options { + // if the user hasn't specified `-Z unstable-options`, then they need to have opted into + // certain unstable variants of `-C prefer-dynamic` explicitly + if let PreferDynamicSet::Set(s) = &cg.prefer_dynamic { + if s.len() == 1 && s.iter().next().map(|s| s.as_str()) == Some("std") { + // as a special case, `-C prefer-dynamic=std` gets its own `-Z` flag (because it is + // on a shorter-term stabilization path). + if debugging_opts.prefer_dynamic_std { + // okay, user opted-into `-C prefer-dynamic=std` via `-Z prefer-dynamic-std` + } else if debugging_opts.prefer_dynamic_subset { + // okay, user opted-into arbitrary `-C prefer-dynamic=...` via `-Z prefer-dynamic-subset` + } else { + early_error( + error_format, + "`-C prefer-dynamic=std` is unstable: set `-Z prefer-dynamic-std`", + ); + } + } else { + if debugging_opts.prefer_dynamic_subset { + // okay, user opted-into arbitrary `-C prefer-dynamic=...` via `-Z prefer-dynamic-subset` + } else { + early_error( + error_format, + "`-C prefer-dynamic=crate,...` is unstable: set `-Z prefer-dynamic-subset`", + ); + } + } + } + } + // Try to find a directory containing the Rust `src`, for more details see // the doc comment on the `real_rust_source_base_dir` field. let tmp_buf; @@ -2420,8 +2512,8 @@ crate mod dep_tracking { use super::LdImpl; use super::{ CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto, - LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, - SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths, + LtoCli, OptLevel, OutputType, OutputTypes, Passes, PreferDynamicSet, + SourceFileHashAlgorithm, SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths, }; use crate::lint; use crate::options::WasiExecModel; @@ -2510,6 +2602,7 @@ crate mod dep_tracking { TrimmedDefPaths, Option, OutputType, + PreferDynamicSet, RealFileName, ); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 481520122d25d..dc81dc6ba1a5d 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -376,6 +376,8 @@ mod desc { "one of supported relocation models (`rustc --print relocation-models`)"; pub const parse_code_model: &str = "one of supported code models (`rustc --print code-models`)"; pub const parse_tls_model: &str = "one of supported TLS models (`rustc --print tls-models`)"; + pub const parse_prefer_dynamic: &str = + "one of `y`, `yes`, `on`, `n`, `no`, `off`, or a comma separated list of crates"; pub const parse_target_feature: &str = parse_string; pub const parse_wasi_exec_model: &str = "either `command` or `reactor`"; pub const parse_split_debuginfo: &str = @@ -835,6 +837,38 @@ mod parse { true } + crate fn parse_prefer_dynamic(slot: &mut PreferDynamicSet, v: Option<&str>) -> bool { + let s = match v { + // Note: n/no/off do *not* map to an empty-set of crates. + // + // This is to continue supporting rustc's historical behavior where it attempts to + // link everything statically, but failing that, then greedily link as many crates + // dynamically as it can. + // + // If these options mapped to an empty set, then that would denote that no dynamic + // linkage should be given preference over static, which would not correspond to + // historical meaning of `-C prefer-dynamic=no`. + // + // (One requests an empty set by writing `-C prefer-dynamic=`, with an empty string + // as the value.) + Some("n") | Some("no") | Some("off") => PreferDynamicSet::unset(), + + // `-C prefer-dynamic` gives all crates preferred dynamic linkage. + // `-C prefer-dynamic=...` with `y`/`yes`/`on` is a synonym, for backwards + // compatibility. + Some("y") | Some("yes") | Some("on") | None => PreferDynamicSet::every_crate(), + + // `-C prefer-dynamic=crate1,crate2,...` gives *just* crate1, crate2, ... preferred + // dynamic linkage. + Some(s) => { + let v = s.split(',').map(|s| s.to_string()).collect(); + PreferDynamicSet::Set(v) + } + }; + *slot = s; + return true; + } + crate fn parse_src_file_hash( slot: &mut Option, v: Option<&str>, @@ -962,7 +996,7 @@ options! { "panic strategy to compile crate with"), passes: Vec = (Vec::new(), parse_list, [TRACKED], "a list of extra LLVM passes to run (space separated)"), - prefer_dynamic: bool = (false, parse_bool, [TRACKED], + prefer_dynamic: PreferDynamicSet = (PreferDynamicSet::unset(), parse_prefer_dynamic, [TRACKED], "prefer dynamic linking to static linking (default: no)"), profile_generate: SwitchWithOptPath = (SwitchWithOptPath::Disabled, parse_switch_with_opt_path, [TRACKED], @@ -1204,6 +1238,10 @@ options! { "use a more precise version of drop elaboration for matches on enums (default: yes). \ This results in better codegen, but has caused miscompilations on some tier 2 platforms. \ See #77382 and #74551."), + prefer_dynamic_std: bool = (false, parse_bool, [UNTRACKED], + "enable use of unstable `-C prefer-dynamic=std` variant"), + prefer_dynamic_subset: bool = (false, parse_bool, [UNTRACKED], + "enable use of unstable `-C prefer-dynamic=crate1,crate2,...` variant"), print_fuel: Option = (None, parse_opt_string, [TRACKED], "make rustc print the total optimization fuel used by a crate"), print_link_args: bool = (false, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 5b163603d5ffb..a35420eefe6d0 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1379,7 +1379,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { // when compiling for LLD ThinLTO. This way we can validly just not generate // the `dllimport` attributes and `__imp_` symbols in that case. if sess.opts.cg.linker_plugin_lto.enabled() - && sess.opts.cg.prefer_dynamic + && sess.opts.cg.prefer_dynamic.is_non_empty() && sess.target.is_like_windows { sess.err( diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 05384117ac175..14e5ae6f5a3a9 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -402,6 +402,13 @@ linkage. This flag takes one of the following values: * `y`, `yes`, `on`, or no value: use dynamic linking. * `n`, `no`, or `off`: use static linking (the default). +* A comma-separated list of crate names `crate1,crate2,...`: prefer dynamic + linking, but solely for the indicated crates. For example, to statically link + everything except `std`, use `-C prefer-dynamic=std`. + +Note that the explicit list of crate names variant of this flag is gated behind +`-Zprefer-dynamic-subset`; as a special case, one can enable the handling of +the single crate `std` as shown in the example above via `-Zprefer-dynamic-std`. ## profile-generate diff --git a/src/test/run-make-fulldeps/dylib-subset/Makefile b/src/test/run-make-fulldeps/dylib-subset/Makefile new file mode 100644 index 0000000000000..1dd3d5c0be33a --- /dev/null +++ b/src/test/run-make-fulldeps/dylib-subset/Makefile @@ -0,0 +1,176 @@ +-include ../tools.mk + +# Here's the basic overview: the crates all form a chain of dependencies, +# +# m6 -> m5 -> m4 -> m3 -> m2 -> m1 +# +# but: some crates have both rlibs and dylibs available, and others have only +# rlib, or only dylib. +# +# m6 (app) -> m5 (rlib) -> m4 (dylib) -> m3 (rlib,dylib) -> m2 (lib) -> m1 (dylib,rlib) +# +# So the question we explore in this test is: What is the effect of `-C +# prefer-dynamic` at different points in the chain. +# +# For example, if you try to build the above without *any* use of `-C +# prefer-dynamic`, build of `m6` fails, because the compilation of dylib for +# `m4` prefers the rlib for `m3` (which itself statically links the rlib for +# `m1`). This is illustrated in v1 below. + +RLIB_TYPE=--crate-type rlib --cfg rlib_type +DYLIB_TYPE=--crate-type dylib --cfg dylib_type +LIB_TYPE=--crate-type lib --cfg lib_type +BIN_TYPE=--crate-type bin --cfg bin_type +PREFER_DYNAMIC_INPUT=-Zprefer-dynamic-subset -Cprefer-dynamic=std,m2,m3,$(1) + +# How to read this command sequence, for people unversed in shell scripting: +# +# I have tried to write useful comments as `echo` statements. Their text is usually +# delimited by single quotes ('') rathern than double quotes ("") so that I can use +# backticks (``) in the notes without it being interpreted as a shell invocation. +# +# `COMMAND && exit 1 && exit 0` is how we run a command and say that we're +# expecting it to fail. +# +# `>&2 echo "stuff"` emits "stuff" to stderr; that's useful for humans reviewing +# the error output on expected errors. +# +# (I'm not going so far as to programmatically verify the error output actually +# matches our expectations here; that is a bridge too far. Instead, I'm just +# trusting that if an error arises, its for the reason stated in the comment +# emitted to stderr.) +# +# Note: you can add a `false` to the end of the recipe if you want to forcibly +# see the stderr and stdout output captured in `compiletest`. + +all: + echo 'v1: no extra flags, just see what default behavior is for this strange chain of crates.' + >&2 echo '`m1` build as dylib and rlib, v1' + $(RUSTC) m1.rs $(DYLIB_TYPE) + $(RUSTC) m1.rs $(RLIB_TYPE) + >&2 echo '`m2` build as lib, v1' + $(RUSTC) m2.rs $(LIB_TYPE) + >&2 echo '`m3` build as dylib, v1; no prefer-dynamic: expected to select rlib for `m1`' + $(RUSTC) m3.rs $(DYLIB_TYPE) + >&2 echo '`m3` build as rlib, v1' + $(RUSTC) m3.rs $(RLIB_TYPE) + >&2 echo '`m4` build as dylib, v1; no prefer-dynamic: expected to select rlib for `m3`' + $(RUSTC) m4.rs $(DYLIB_TYPE) + >&2 echo '`m5` build as rlib, v1' + $(RUSTC) m5.rs $(RLIB_TYPE) + >&2 echo '`m6` build binary, v1: selects dylib for `m4`, because no rlib available' + $(RUSTC) m6.rs $(BIN_TYPE) && exit 1 || exit 0 + >&2 echo 'above expected to fail: `m1`, `m3` and `std` linked dynamically via `m6` and statically via `m4`.' + + echo 'v2: most immediate fix for problem from previous version: prefer-dynamic on `m4`.' + >&2 echo '`m4` build as dylib v2: prefer-dynamic (selects dylibs for `std` and `m3`)' + $(RUSTC) m4.rs $(DYLIB_TYPE) -C prefer-dynamic + >&2 echo '`m5` build as rlib v2' + $(RUSTC) m5.rs $(RLIB_TYPE) + >&2 echo '`m6` build binary, v2: selects dylib for `m4`, because no rlib available' + $(RUSTC) m6.rs $(BIN_TYPE) + echo 'run `m6` v2' + $(call RUN,m6) > $(TMPDIR)/v2.output + echo 'expectation: prefer-dynamic on `m4` selected dylib for `m3`, while latter linked rlib for `m1`.' + echo 'linkage: m6:bin m5:rlib m4:dylib m3:dylib m2:lib m1:rlib' > $(TMPDIR)/v2.expect + diff -u $(TMPDIR)/v2.output $(TMPDIR)/v2.expect + echo 'expectation: removing m4 dylib will cause run attempt to fail.' + >&2 echo 'remove m4 dylib' + $(call REMOVE_DYLIBS,m4) + $(call FAIL,m6) + >&2 echo 'rebuild m4 and check that recovered state.' + $(RUSTC) m4.rs $(DYLIB_TYPE) -C prefer-dynamic + $(call RUN,m6) + echo 'expectation: removing m3 dylib alone will cause run attempt to fail.' + >&2 echo 'remove m3 dylib' + $(call REMOVE_DYLIBS,m3) + $(call FAIL,m6) + >&2 echo 'rebuild m3 and check that recovered state.' + $(RUSTC) m3.rs $(DYLIB_TYPE) + $(call RUN,m6) + echo 'expectation: removing m1 dylib and rlib will not perturb run v2 attempt.' + >&2 echo 'remove `m1` rlib and dylib' + $(call REMOVE_DYLIBS,m1) + $(call REMOVE_RLIBS,m1) + $(call RUN,m6) + >&2 echo 'rebuild `m1` rlib and dylib' + $(RUSTC) m1.rs $(RLIB_TYPE) + $(RUSTC) m1.rs $(DYLIB_TYPE) + + echo 'v3: try `-C prefer-dynamic` when compiling `m2` now.' + >&2 echo 'rebuild m1 dylib' + $(RUSTC) m1.rs $(RLIB_TYPE) + $(RUSTC) m1.rs $(DYLIB_TYPE) + >&2 echo '`m2` build as lib, v3: prefer-dynamic (overall, still selects m1.rlib)' + $(RUSTC) m2.rs $(LIB_TYPE) -C prefer-dynamic + >&2 echo '`m3` build as dylib, v3' + $(RUSTC) m3.rs $(DYLIB_TYPE) + >&2 echo '`m3` build as rlib, v3' + $(RUSTC) m3.rs $(RLIB_TYPE) + >&2 echo '`m4` build as dylib v3: prefer-dynamic (to avoid duplicate static linkage)' + $(RUSTC) m4.rs $(DYLIB_TYPE) -C prefer-dynamic + >&2 echo '`m5` build as rlib v3' + $(RUSTC) m5.rs $(RLIB_TYPE) + >&2 echo '`m6` build bin v3' + $(RUSTC) m6.rs $(BIN_TYPE) + $(call RUN,m6) > $(TMPDIR)/v3.output + echo 'expectation: prefer-dynamic on `m2` had no effect on which m1 got linked compared to previous.' + echo 'linkage: m6:bin m5:rlib m4:dylib m3:dylib m2:lib m1:rlib' > $(TMPDIR)/v3.expect + diff -u $(TMPDIR)/v3.output $(TMPDIR)/v3.expect + + echo 'v4: try `-C prefer-dynamic` when compiling `m3` now.' + >&2 echo 'rebuild m1 dylib' + $(RUSTC) m1.rs $(RLIB_TYPE) + $(RUSTC) m1.rs $(DYLIB_TYPE) + >&2 echo '`m2` build as lib, v4' + $(RUSTC) m2.rs $(LIB_TYPE) + >&2 echo '`m3` build as dylib, v4; prefer-dynamic, and now selects m1.dylib' + $(RUSTC) m3.rs $(DYLIB_TYPE) -C prefer-dynamic + >&2 echo '`m3` build as rlib, v4: prefer-dynamic' + $(RUSTC) m3.rs $(RLIB_TYPE) -C prefer-dynamic + >&2 echo '`m4` build as dylib v4' + $(RUSTC) m4.rs $(DYLIB_TYPE) + >&2 echo '`m5` build as rlib v4' + $(RUSTC) m5.rs $(RLIB_TYPE) + >&2 echo '`m6` build bin v4: selects dylib for `m4`, because no rlib available' + $(RUSTC) m6.rs $(BIN_TYPE) && exit 1 || exit 0 + >&2 echo 'above expected to fail: `std` linked dynamically via `m6` and statically via `m4`.' + + echo 'v5: try `-C prefer-dynamic` when compiling `m3` now.' + >&2 echo 'rebuild m1 dylib' + $(RUSTC) m1.rs $(RLIB_TYPE) + $(RUSTC) m1.rs $(DYLIB_TYPE) + >&2 echo '`m2` build as lib, v5' + $(RUSTC) m2.rs $(LIB_TYPE) + >&2 echo '`m3` build as dylib, v5; prefer-dynamic, and now selects dylib for `m1`.' + $(RUSTC) m3.rs $(DYLIB_TYPE) -C prefer-dynamic + >&2 echo '`m3` build as rlib, v5: prefer-dynamic; it nonetheless resolves to rlib for `m1`' + $(RUSTC) m3.rs $(RLIB_TYPE) -C prefer-dynamic + >&2 echo '`m4` build as dylib v5; prefer-dynamic just for std, not m3' + $(RUSTC) m4.rs $(DYLIB_TYPE) -C prefer-dynamic=std -Z prefer-dynamic-std + >&2 echo '`m5` build as rlib v5' + $(RUSTC) m5.rs $(RLIB_TYPE) + >&2 echo '`m6` build bin v5; prefer-dynamic just for `m4` and `std`, not `m3`' + $(RUSTC) m6.rs $(BIN_TYPE) -C prefer-dynamic=std,m4 -Z prefer-dynamic-subset + $(call RUN,m6) > $(TMPDIR)/v5.output + echo 'expectation: prefer-dynamic=std,m4 on `m4`/`m6` meant m3 rlib gets linked, and m3 rlib links m1 rlib.' + echo 'linkage: m6:bin m5:rlib m4:dylib m3:rlib m2:lib m1:rlib' > $(TMPDIR)/v5.expect + diff -u $(TMPDIR)/v5.output $(TMPDIR)/v5.expect + + echo 'v6: try `-C prefer-dynamic` when `m3` and `m4` now.' + >&2 echo '`m4` build as dylib v6; prefer-dynamic for everything; selects dylib for `m3`.' + $(RUSTC) m4.rs $(DYLIB_TYPE) -C prefer-dynamic + >&2 echo '`m5` build as rlib v6' + $(RUSTC) m5.rs $(RLIB_TYPE) + >&2 echo '`m6` build bin v6: selects dylib for `m4` and thus for `m3` and `m1`.' + $(RUSTC) m6.rs $(BIN_TYPE) + $(call RUN,m6) > $(TMPDIR)/v6.output + echo 'expectation: prefer-dynamic on `m3`/`m4` meant m3 dylib gets linked, and m3 dylib links m1 dylib.' + echo 'linkage: m6:bin m5:rlib m4:dylib m3:dylib m2:lib m1:dylib' > $(TMPDIR)/v6.expect + diff -u $(TMPDIR)/v6.output $(TMPDIR)/v6.expect + +# >&2 echo 'reached final false' +# false + +# Note: you can add a `false` to the end of the recipe if you want to forcibly +# see the stderr and stdout output captured in `compiletest`. diff --git a/src/test/run-make-fulldeps/dylib-subset/common_body.rs b/src/test/run-make-fulldeps/dylib-subset/common_body.rs new file mode 100644 index 0000000000000..ac4b12127e1ec --- /dev/null +++ b/src/test/run-make-fulldeps/dylib-subset/common_body.rs @@ -0,0 +1,20 @@ +#[cfg(bin_type)] +pub fn crate_type() -> &'static str { "bin" } + +#[cfg(lib_type)] +pub fn crate_type() -> &'static str { "lib" } + +#[cfg(dylib_type)] +pub fn crate_type() -> &'static str { "dylib" } + +#[cfg(rlib_type)] +pub fn crate_type() -> &'static str { "rlib" } + +// (The cases below are not used in any of these tests yet. But it might be good +// to think about adding them.) + +#[cfg(staticlib_type)] +pub extern "C" fn crate_type() -> *const u8 { "staticlib\0".as_ptr() } + +#[cfg(cdylib_type)] +pub extern "C" fn crate_type() -> *const u8 { "cdylib\0".as_ptr() } diff --git a/src/test/run-make-fulldeps/dylib-subset/m1.rs b/src/test/run-make-fulldeps/dylib-subset/m1.rs new file mode 100644 index 0000000000000..02b4cf59efcf4 --- /dev/null +++ b/src/test/run-make-fulldeps/dylib-subset/m1.rs @@ -0,0 +1,5 @@ +mod common_body; + +pub fn linkage_chain() -> String { + format!("m1:{}", ::common_body::crate_type()) +} diff --git a/src/test/run-make-fulldeps/dylib-subset/m2.rs b/src/test/run-make-fulldeps/dylib-subset/m2.rs new file mode 100644 index 0000000000000..618683663cef1 --- /dev/null +++ b/src/test/run-make-fulldeps/dylib-subset/m2.rs @@ -0,0 +1,7 @@ +extern crate m1 as next; + +mod common_body; + +pub fn linkage_chain() -> String { + format!("m2:{} {}", crate::common_body::crate_type(), next::linkage_chain()) +} diff --git a/src/test/run-make-fulldeps/dylib-subset/m3.rs b/src/test/run-make-fulldeps/dylib-subset/m3.rs new file mode 100644 index 0000000000000..875d2649e39db --- /dev/null +++ b/src/test/run-make-fulldeps/dylib-subset/m3.rs @@ -0,0 +1,7 @@ +extern crate m2 as next; + +mod common_body; + +pub fn linkage_chain() -> String { + format!("m3:{} {}", crate::common_body::crate_type(), next::linkage_chain()) +} diff --git a/src/test/run-make-fulldeps/dylib-subset/m4.rs b/src/test/run-make-fulldeps/dylib-subset/m4.rs new file mode 100644 index 0000000000000..9a7536c2a3900 --- /dev/null +++ b/src/test/run-make-fulldeps/dylib-subset/m4.rs @@ -0,0 +1,7 @@ +extern crate m3 as next; + +mod common_body; + +pub fn linkage_chain() -> String { + format!("m4:{} {}", ::common_body::crate_type(), next::linkage_chain()) +} diff --git a/src/test/run-make-fulldeps/dylib-subset/m5.rs b/src/test/run-make-fulldeps/dylib-subset/m5.rs new file mode 100644 index 0000000000000..de3b2bf167040 --- /dev/null +++ b/src/test/run-make-fulldeps/dylib-subset/m5.rs @@ -0,0 +1,7 @@ +extern crate m4 as next; + +mod common_body; + +pub fn linkage_chain() -> String { + format!("m5:{} {}", crate::common_body::crate_type(), next::linkage_chain()) +} diff --git a/src/test/run-make-fulldeps/dylib-subset/m6.rs b/src/test/run-make-fulldeps/dylib-subset/m6.rs new file mode 100644 index 0000000000000..7bda77c85ba23 --- /dev/null +++ b/src/test/run-make-fulldeps/dylib-subset/m6.rs @@ -0,0 +1,11 @@ +extern crate m5 as next; + +mod common_body; + +pub fn linkage_chain() -> String { + format!("m6:{} {}", ::common_body::crate_type(), next::linkage_chain()) +} + +fn main() { + println!("linkage: {}", linkage_chain()); +} diff --git a/src/test/ui/dylibs/README.md b/src/test/ui/dylibs/README.md new file mode 100644 index 0000000000000..4b984db553a26 --- /dev/null +++ b/src/test/ui/dylibs/README.md @@ -0,0 +1,30 @@ +This directory is a collection of tests of how dylibs and rlibs are compiled and loaded. + +It is mostly an exploration checkpointing the current state of Rust. + +We tend to advise people to try make at least one format available all the way + up: e.g. all rlibs or all dylibs. But it is good to keep track of how we are + handling other combinations. + +There are seven auxiliary crates: `a`,`i`,`j`,`m`,`s`,`t`,`z`. Each top-level +test in this directory varies which of the auxiliary crates are compiled to +dylibs and which are compiled to rlibs. + +The seven auxiliary form a dependence graph that looks like this (a pair of +diamonds): + +```graphviz + z -> s; s -> m; m -> i; i -> a + z -> t; t -> m; m -> j; j -> a +// ~ ~~~~ ~~~~ ~~~~ ~ +// | | | | | +// | | | | +- basement +// | | | | +// | | | +- ground +// | | | +// | | +- middle +// | | +// | +- upper +// | +// +- roof +``` diff --git a/src/test/ui/dylibs/auxiliary/a_basement_both.rs b/src/test/ui/dylibs/auxiliary/a_basement_both.rs new file mode 100644 index 0000000000000..5fc5f0ed34351 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/a_basement_both.rs @@ -0,0 +1,8 @@ +#![crate_name="a_basement"] +#![crate_type="dylib"] +#![crate_type="rlib"] + +// no-prefer-dynamic + +mod a_basement_core; +pub use a_basement_core::*; diff --git a/src/test/ui/dylibs/auxiliary/a_basement_core.rs b/src/test/ui/dylibs/auxiliary/a_basement_core.rs new file mode 100644 index 0000000000000..9eee52c7f1197 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/a_basement_core.rs @@ -0,0 +1,5 @@ +pub fn a() -> String { + format!("a_basement_core") +} + +pub fn a_addr() -> usize { a as fn() -> String as *const u8 as usize } diff --git a/src/test/ui/dylibs/auxiliary/a_basement_dynamic.rs b/src/test/ui/dylibs/auxiliary/a_basement_dynamic.rs new file mode 100644 index 0000000000000..27a2d449418f1 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/a_basement_dynamic.rs @@ -0,0 +1,5 @@ +#![crate_name="a_basement"] +#![crate_type="dylib"] + +mod a_basement_core; +pub use a_basement_core::*; diff --git a/src/test/ui/dylibs/auxiliary/a_basement_rlib.rs b/src/test/ui/dylibs/auxiliary/a_basement_rlib.rs new file mode 100644 index 0000000000000..7fe7ad2623e0d --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/a_basement_rlib.rs @@ -0,0 +1,8 @@ +#![crate_name="a_basement"] +#![crate_type="rlib"] + +// no-prefer-dynamic : flag controls both `-C prefer-dynamic` *and* overrides the +// output crate type for this file. + +mod a_basement_core; +pub use a_basement_core::*; diff --git a/src/test/ui/dylibs/auxiliary/aaa_issue_82151_bar.rs b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_bar.rs new file mode 100644 index 0000000000000..75d8fe7b6759d --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_bar.rs @@ -0,0 +1,9 @@ +#![crate_name="bar"] +#![crate_type="rlib"] +#![crate_type="cdylib"] + +pub struct Bar; + +pub fn bar() -> Bar { + Bar +} diff --git a/src/test/ui/dylibs/auxiliary/aaa_issue_82151_bar_noprefdyn.rs b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_bar_noprefdyn.rs new file mode 100644 index 0000000000000..3832aea87df1b --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_bar_noprefdyn.rs @@ -0,0 +1,11 @@ +#![crate_name="bar"] +#![crate_type="rlib"] +#![crate_type="cdylib"] + +// no-prefer-dynamic + +pub struct Bar; + +pub fn bar() -> Bar { + Bar +} diff --git a/src/test/ui/dylibs/auxiliary/aaa_issue_82151_bar_prefdyn.rs b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_bar_prefdyn.rs new file mode 100644 index 0000000000000..b8003a945f986 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_bar_prefdyn.rs @@ -0,0 +1,12 @@ +#![crate_name="bar"] +#![crate_type="rlib"] +#![crate_type="cdylib"] + +// no-prefer-dynamic +// compile-flags: -C prefer-dynamic + +pub struct Bar; + +pub fn bar() -> Bar { + Bar +} diff --git a/src/test/ui/dylibs/auxiliary/aaa_issue_82151_bar_prefdynstd.rs b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_bar_prefdynstd.rs new file mode 100644 index 0000000000000..04a4c82b90645 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_bar_prefdynstd.rs @@ -0,0 +1,12 @@ +#![crate_name="bar"] +#![crate_type="rlib"] +#![crate_type="cdylib"] + +// no-prefer-dynamic +// compile-flags: -C prefer-dynamic=std -Z prefer-dynamic-std + +pub struct Bar; + +pub fn bar() -> Bar { + Bar +} diff --git a/src/test/ui/dylibs/auxiliary/aaa_issue_82151_bar_prefdynsubset.rs b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_bar_prefdynsubset.rs new file mode 100644 index 0000000000000..51bf92e5d7bb9 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_bar_prefdynsubset.rs @@ -0,0 +1,12 @@ +#![crate_name="bar"] +#![crate_type="rlib"] +#![crate_type="cdylib"] + +// no-prefer-dynamic +// compile-flags: -C prefer-dynamic=shared,std -Z prefer-dynamic-subset + +pub struct Bar; + +pub fn bar() -> Bar { + Bar +} diff --git a/src/test/ui/dylibs/auxiliary/aaa_issue_82151_foo_noprefdyn.rs b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_foo_noprefdyn.rs new file mode 100644 index 0000000000000..83dbcfa7a06aa --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_foo_noprefdyn.rs @@ -0,0 +1,13 @@ +#![crate_name="foo"] +#![crate_type="rlib"] + +// no-prefer-dynamic + +extern crate bar; + +pub struct Foo; +pub use bar::bar; + +pub fn foo() -> Foo { + Foo +} diff --git a/src/test/ui/dylibs/auxiliary/aaa_issue_82151_foo_prefdyn.rs b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_foo_prefdyn.rs new file mode 100644 index 0000000000000..9ddae0b718323 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_foo_prefdyn.rs @@ -0,0 +1,14 @@ +#![crate_name="foo"] +#![crate_type="rlib"] + +// no-prefer-dynamic +// compile-flags: -C prefer-dynamic + +extern crate bar; + +pub struct Foo; +pub use bar::bar; + +pub fn foo() -> Foo { + Foo +} diff --git a/src/test/ui/dylibs/auxiliary/aaa_issue_82151_foo_prefdynstd.rs b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_foo_prefdynstd.rs new file mode 100644 index 0000000000000..a2e458890355c --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_foo_prefdynstd.rs @@ -0,0 +1,14 @@ +#![crate_name="foo"] +#![crate_type="rlib"] + +// no-prefer-dynamic +// compile-flags: -C prefer-dynamic=std -Z prefer-dynamic-std + +extern crate bar; + +pub struct Foo; +pub use bar::bar; + +pub fn foo() -> Foo { + Foo +} diff --git a/src/test/ui/dylibs/auxiliary/aaa_issue_82151_foo_prefdynsubset.rs b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_foo_prefdynsubset.rs new file mode 100644 index 0000000000000..853ceca625b5f --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_foo_prefdynsubset.rs @@ -0,0 +1,14 @@ +#![crate_name="foo"] +#![crate_type="rlib"] + +// no-prefer-dynamic +// compile-flags: -C prefer-dynamic=shared,std -Z prefer-dynamic-subset + +extern crate bar; + +pub struct Foo; +pub use bar::bar; + +pub fn foo() -> Foo { + Foo +} diff --git a/src/test/ui/dylibs/auxiliary/aaa_issue_82151_shared_noprefdyn.rs b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_shared_noprefdyn.rs new file mode 100644 index 0000000000000..540a7279c3c31 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_shared_noprefdyn.rs @@ -0,0 +1,17 @@ +#![crate_name="shared"] +#![crate_type="dylib"] + +// no-prefer-dynamic + +extern crate foo; + +pub struct Test; + +impl Test { + pub fn new() -> Self { + let _ = foo::foo(); + let _ = foo::bar(); + // let _ = bar::bar(); + Self + } +} diff --git a/src/test/ui/dylibs/auxiliary/aaa_issue_82151_shared_prefdyn.rs b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_shared_prefdyn.rs new file mode 100644 index 0000000000000..c17ed4f4f7a73 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_shared_prefdyn.rs @@ -0,0 +1,18 @@ +#![crate_name="shared"] +#![crate_type="dylib"] + +// no-prefer-dynamic +// compile-flags: -C prefer-dynamic + +extern crate foo; + +pub struct Test; + +impl Test { + pub fn new() -> Self { + let _ = foo::foo(); + let _ = foo::bar(); + // let _ = bar::bar(); + Self + } +} diff --git a/src/test/ui/dylibs/auxiliary/aaa_issue_82151_shared_prefdynstd.rs b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_shared_prefdynstd.rs new file mode 100644 index 0000000000000..f70a70dcca8d2 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_shared_prefdynstd.rs @@ -0,0 +1,18 @@ +#![crate_name="shared"] +#![crate_type="dylib"] + +// no-prefer-dynamic +// compile-flags: -C prefer-dynamic=std -Z prefer-dynamic-std + +extern crate foo; + +pub struct Test; + +impl Test { + pub fn new() -> Self { + let _ = foo::foo(); + let _ = foo::bar(); + // let _ = bar::bar(); + Self + } +} diff --git a/src/test/ui/dylibs/auxiliary/aaa_issue_82151_shared_prefdynsubset.rs b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_shared_prefdynsubset.rs new file mode 100644 index 0000000000000..debfb0dc3b051 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/aaa_issue_82151_shared_prefdynsubset.rs @@ -0,0 +1,18 @@ +#![crate_name="shared"] +#![crate_type="dylib"] + +// no-prefer-dynamic +// compile-flags: -C prefer-dynamic=shared,std -Z prefer-dynamic-subset + +extern crate foo; + +pub struct Test; + +impl Test { + pub fn new() -> Self { + let _ = foo::foo(); + let _ = foo::bar(); + // let _ = bar::bar(); + Self + } +} diff --git a/src/test/ui/dylibs/auxiliary/i_ground_both.rs b/src/test/ui/dylibs/auxiliary/i_ground_both.rs new file mode 100644 index 0000000000000..aa873297e2def --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/i_ground_both.rs @@ -0,0 +1,10 @@ +#![crate_name="i_ground"] +#![crate_type="dylib"] +#![crate_type="rlib"] + +// no-prefer-dynamic + +pub extern crate a_basement as a; + +mod i_ground_core; +pub use i_ground_core::*; diff --git a/src/test/ui/dylibs/auxiliary/i_ground_core.rs b/src/test/ui/dylibs/auxiliary/i_ground_core.rs new file mode 100644 index 0000000000000..272701883917c --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/i_ground_core.rs @@ -0,0 +1,7 @@ +pub fn i() -> String { + format!("i_ground_core -> ({})", a::a()) +} + +pub fn i_addr() -> usize { i as fn() -> String as *const u8 as usize } + +pub fn a_addr() -> usize { a::a_addr() } diff --git a/src/test/ui/dylibs/auxiliary/i_ground_dynamic.rs b/src/test/ui/dylibs/auxiliary/i_ground_dynamic.rs new file mode 100644 index 0000000000000..f3f17c0cf900b --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/i_ground_dynamic.rs @@ -0,0 +1,7 @@ +#![crate_name="i_ground"] +#![crate_type="dylib"] + +pub extern crate a_basement as a; + +mod i_ground_core; +pub use i_ground_core::*; diff --git a/src/test/ui/dylibs/auxiliary/i_ground_rlib.rs b/src/test/ui/dylibs/auxiliary/i_ground_rlib.rs new file mode 100644 index 0000000000000..853606dbe5ff1 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/i_ground_rlib.rs @@ -0,0 +1,10 @@ +#![crate_name="i_ground"] +#![crate_type="rlib"] + +// no-prefer-dynamic : flag controls both `-C prefer-dynamic` *and* overrides the +// output crate type for this file. + +pub extern crate a_basement as a; + +mod i_ground_core; +pub use i_ground_core::*; diff --git a/src/test/ui/dylibs/auxiliary/j_ground_both.rs b/src/test/ui/dylibs/auxiliary/j_ground_both.rs new file mode 100644 index 0000000000000..dcfc50870fd3f --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/j_ground_both.rs @@ -0,0 +1,10 @@ +#![crate_name="j_ground"] +#![crate_type="dylib"] +#![crate_type="rlib"] + +// no-prefer-dynamic + +pub extern crate a_basement as a; + +mod j_ground_core; +pub use j_ground_core::*; diff --git a/src/test/ui/dylibs/auxiliary/j_ground_core.rs b/src/test/ui/dylibs/auxiliary/j_ground_core.rs new file mode 100644 index 0000000000000..e51f3a6276c84 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/j_ground_core.rs @@ -0,0 +1,7 @@ +pub fn j() -> String { + format!("j_ground_core -> ({})", a::a()) +} + +pub fn j_addr() -> usize { j as fn() -> String as *const u8 as usize } + +pub fn a_addr() -> usize { a::a_addr() } diff --git a/src/test/ui/dylibs/auxiliary/j_ground_dynamic.rs b/src/test/ui/dylibs/auxiliary/j_ground_dynamic.rs new file mode 100644 index 0000000000000..ef5e931a833e3 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/j_ground_dynamic.rs @@ -0,0 +1,7 @@ +#![crate_name="j_ground"] +#![crate_type="dylib"] + +pub extern crate a_basement as a; + +mod j_ground_core; +pub use j_ground_core::*; diff --git a/src/test/ui/dylibs/auxiliary/j_ground_rlib.rs b/src/test/ui/dylibs/auxiliary/j_ground_rlib.rs new file mode 100644 index 0000000000000..e417878714c28 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/j_ground_rlib.rs @@ -0,0 +1,10 @@ +#![crate_name="j_ground"] +#![crate_type="rlib"] + +// no-prefer-dynamic : flag controls both `-C prefer-dynamic` *and* overrides the +// output crate type for this file. + +pub extern crate a_basement as a; + +mod j_ground_core; +pub use j_ground_core::*; diff --git a/src/test/ui/dylibs/auxiliary/m_middle_both.rs b/src/test/ui/dylibs/auxiliary/m_middle_both.rs new file mode 100644 index 0000000000000..ab3a71a5cfac1 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/m_middle_both.rs @@ -0,0 +1,11 @@ +#![crate_name="m_middle"] +#![crate_type="dylib"] +#![crate_type="rlib"] + +// no-prefer-dynamic + +pub extern crate i_ground as i; +pub extern crate j_ground as j; + +mod m_middle_core; +pub use m_middle_core::*; diff --git a/src/test/ui/dylibs/auxiliary/m_middle_core.rs b/src/test/ui/dylibs/auxiliary/m_middle_core.rs new file mode 100644 index 0000000000000..6b054a746e440 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/m_middle_core.rs @@ -0,0 +1,13 @@ +pub fn m() -> String { + format!("m_middle_core -> ({}), -> ({})", i::i(), j::j()) +} + +pub fn m_addr() -> usize { m as fn() -> String as *const u8 as usize } + +pub fn i_addr() -> usize { i::i_addr() } + +pub fn j_addr() -> usize { j::j_addr() } + +pub fn i_a_addr() -> usize { i::a_addr() } + +pub fn j_a_addr() -> usize { j::a_addr() } diff --git a/src/test/ui/dylibs/auxiliary/m_middle_dynamic.rs b/src/test/ui/dylibs/auxiliary/m_middle_dynamic.rs new file mode 100644 index 0000000000000..fa843f19e8435 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/m_middle_dynamic.rs @@ -0,0 +1,8 @@ +#![crate_name="m_middle"] +#![crate_type="dylib"] + +pub extern crate i_ground as i; +pub extern crate j_ground as j; + +mod m_middle_core; +pub use m_middle_core::*; diff --git a/src/test/ui/dylibs/auxiliary/m_middle_rlib.rs b/src/test/ui/dylibs/auxiliary/m_middle_rlib.rs new file mode 100644 index 0000000000000..4d1b39a346a9a --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/m_middle_rlib.rs @@ -0,0 +1,11 @@ +#![crate_name="m_middle"] +#![crate_type="rlib"] + +// no-prefer-dynamic : flag controls both `-C prefer-dynamic` *and* overrides the +// output crate type for this file. + +pub extern crate i_ground as i; +pub extern crate j_ground as j; + +mod m_middle_core; +pub use m_middle_core::*; diff --git a/src/test/ui/dylibs/auxiliary/s_upper_both.rs b/src/test/ui/dylibs/auxiliary/s_upper_both.rs new file mode 100644 index 0000000000000..b0d63df5b644a --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/s_upper_both.rs @@ -0,0 +1,10 @@ +#![crate_name="s_upper"] +#![crate_type="dylib"] +#![crate_type="rlib"] + +// no-prefer-dynamic + +pub extern crate m_middle as m; + +mod s_upper_core; +pub use s_upper_core::*; diff --git a/src/test/ui/dylibs/auxiliary/s_upper_core.rs b/src/test/ui/dylibs/auxiliary/s_upper_core.rs new file mode 100644 index 0000000000000..e019ed2540f1a --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/s_upper_core.rs @@ -0,0 +1,15 @@ +pub fn s() -> String { + format!("s_upper_core -> ({})", m::m()) +} + +pub fn s_addr() -> usize { s as fn() -> String as *const u8 as usize } + +pub fn m_addr() -> usize { m::m_addr() } + +pub fn m_i_addr() -> usize { m::i_addr() } + +pub fn m_j_addr() -> usize { m::j_addr() } + +pub fn m_i_a_addr() -> usize { m::i_a_addr() } + +pub fn m_j_a_addr() -> usize { m::j_a_addr() } diff --git a/src/test/ui/dylibs/auxiliary/s_upper_dynamic.rs b/src/test/ui/dylibs/auxiliary/s_upper_dynamic.rs new file mode 100644 index 0000000000000..b338845feff35 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/s_upper_dynamic.rs @@ -0,0 +1,7 @@ +#![crate_name="s_upper"] +#![crate_type="dylib"] + +pub extern crate m_middle as m; + +mod s_upper_core; +pub use s_upper_core::*; diff --git a/src/test/ui/dylibs/auxiliary/s_upper_rlib.rs b/src/test/ui/dylibs/auxiliary/s_upper_rlib.rs new file mode 100644 index 0000000000000..72981f9a9b6a3 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/s_upper_rlib.rs @@ -0,0 +1,10 @@ +#![crate_name="s_upper"] +#![crate_type="rlib"] + +// no-prefer-dynamic : flag controls both `-C prefer-dynamic` *and* overrides the +// output crate type for this file. + +pub extern crate m_middle as m; + +mod s_upper_core; +pub use s_upper_core::*; diff --git a/src/test/ui/dylibs/auxiliary/t_upper_both.rs b/src/test/ui/dylibs/auxiliary/t_upper_both.rs new file mode 100644 index 0000000000000..fcf69bb44aaad --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/t_upper_both.rs @@ -0,0 +1,10 @@ +#![crate_name="t_upper"] +#![crate_type="dylib"] +#![crate_type="rlib"] + +// no-prefer-dynamic + +pub extern crate m_middle as m; + +mod t_upper_core; +pub use t_upper_core::*; diff --git a/src/test/ui/dylibs/auxiliary/t_upper_core.rs b/src/test/ui/dylibs/auxiliary/t_upper_core.rs new file mode 100644 index 0000000000000..7692884ac1fb2 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/t_upper_core.rs @@ -0,0 +1,15 @@ +pub fn t() -> String { + format!("t_upper_core -> {}", m::m()) +} + +pub fn t_addr() -> usize { t as fn() -> String as *const u8 as usize } + +pub fn m_addr() -> usize { m::m_addr() } + +pub fn m_i_addr() -> usize { m::i_addr() } + +pub fn m_j_addr() -> usize { m::j_addr() } + +pub fn m_i_a_addr() -> usize { m::i_a_addr() } + +pub fn m_j_a_addr() -> usize { m::j_a_addr() } diff --git a/src/test/ui/dylibs/auxiliary/t_upper_dynamic.rs b/src/test/ui/dylibs/auxiliary/t_upper_dynamic.rs new file mode 100644 index 0000000000000..04524ff5ee37f --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/t_upper_dynamic.rs @@ -0,0 +1,7 @@ +#![crate_name="t_upper"] +#![crate_type="dylib"] + +pub extern crate m_middle as m; + +mod t_upper_core; +pub use t_upper_core::*; diff --git a/src/test/ui/dylibs/auxiliary/t_upper_rlib.rs b/src/test/ui/dylibs/auxiliary/t_upper_rlib.rs new file mode 100644 index 0000000000000..8fbf1fafbafa8 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/t_upper_rlib.rs @@ -0,0 +1,10 @@ +#![crate_name="t_upper"] +#![crate_type="rlib"] + +// no-prefer-dynamic : flag controls both `-C prefer-dynamic` *and* overrides the +// output crate type for this file. + +pub extern crate m_middle as m; + +mod t_upper_core; +pub use t_upper_core::*; diff --git a/src/test/ui/dylibs/auxiliary/z_roof_both.rs b/src/test/ui/dylibs/auxiliary/z_roof_both.rs new file mode 100644 index 0000000000000..cafff2618e8a7 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/z_roof_both.rs @@ -0,0 +1,11 @@ +#![crate_name="z_roof"] +#![crate_type="dylib"] +#![crate_type="rlib"] + +// no-prefer-dynamic + +pub extern crate s_upper as s; +pub extern crate t_upper as t; + +mod z_roof_core; +pub use z_roof_core::*; diff --git a/src/test/ui/dylibs/auxiliary/z_roof_core.rs b/src/test/ui/dylibs/auxiliary/z_roof_core.rs new file mode 100644 index 0000000000000..683336ea918d9 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/z_roof_core.rs @@ -0,0 +1,29 @@ +pub fn z() -> String { + format!("z_roof_core -> ({}), -> ({})", s::s(), t::t()) +} + +pub fn z_addr() -> usize { z as fn() -> String as *const u8 as usize } + +pub fn s_addr() -> usize { s::s_addr() } + +pub fn t_addr() -> usize { t::t_addr() } + +pub fn s_m_addr() -> usize { s::m_addr() } + +pub fn t_m_addr() -> usize { t::m_addr() } + +pub fn s_m_i_addr() -> usize { s::m_i_addr() } + +pub fn s_m_j_addr() -> usize { s::m_j_addr() } + +pub fn t_m_i_addr() -> usize { t::m_i_addr() } + +pub fn t_m_j_addr() -> usize { t::m_j_addr() } + +pub fn s_m_i_a_addr() -> usize { s::m_i_a_addr() } + +pub fn s_m_j_a_addr() -> usize { s::m_j_a_addr() } + +pub fn t_m_i_a_addr() -> usize { t::m_i_a_addr() } + +pub fn t_m_j_a_addr() -> usize { t::m_j_a_addr() } diff --git a/src/test/ui/dylibs/auxiliary/z_roof_dynamic.rs b/src/test/ui/dylibs/auxiliary/z_roof_dynamic.rs new file mode 100644 index 0000000000000..f56ecea700156 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/z_roof_dynamic.rs @@ -0,0 +1,8 @@ +#![crate_name="z_roof"] +#![crate_type="dylib"] + +pub extern crate s_upper as s; +pub extern crate t_upper as t; + +mod z_roof_core; +pub use z_roof_core::*; diff --git a/src/test/ui/dylibs/auxiliary/z_roof_rlib.rs b/src/test/ui/dylibs/auxiliary/z_roof_rlib.rs new file mode 100644 index 0000000000000..dbdea28c22ee7 --- /dev/null +++ b/src/test/ui/dylibs/auxiliary/z_roof_rlib.rs @@ -0,0 +1,11 @@ +#![crate_name="z_roof"] +#![crate_type="rlib"] + +// no-prefer-dynamic : flag controls both `-C prefer-dynamic` *and* overrides the +// output crate type for this file. + +pub extern crate s_upper as s; +pub extern crate t_upper as t; + +mod z_roof_core; +pub use z_roof_core::*; diff --git a/src/test/ui/dylibs/diamonds-b-prefdynstd.rs b/src/test/ui/dylibs/diamonds-b-prefdynstd.rs new file mode 100644 index 0000000000000..ebc68766ca326 --- /dev/null +++ b/src/test/ui/dylibs/diamonds-b-prefdynstd.rs @@ -0,0 +1,12 @@ +// run-pass + +// no-prefer-dynamic +// compile-flags: -C prefer-dynamic=std -Z prefer-dynamic-std + +// aux-build: a_basement_both.rs + +pub extern crate a_basement as a; + +fn main() { + a::a(); +} diff --git a/src/test/ui/dylibs/diamonds-b.rs b/src/test/ui/dylibs/diamonds-b.rs new file mode 100644 index 0000000000000..94cd678451164 --- /dev/null +++ b/src/test/ui/dylibs/diamonds-b.rs @@ -0,0 +1,14 @@ +// build-fail + +// The a_basement dependency has been compiled with `-C prefer-dynamic=no`, +// which ends up leading to a duplication of `std` (and all crates underneath +// it) in both the `a_basement` crate and in this crate. Rust does not support +// having duplicate libraries like that, so this compilation will fail. + +// aux-build: a_basement_both.rs + +pub extern crate a_basement as a; + +fn main() { + a::a(); +} diff --git a/src/test/ui/dylibs/diamonds-b.stderr b/src/test/ui/dylibs/diamonds-b.stderr new file mode 100644 index 0000000000000..e13c06d00ea80 --- /dev/null +++ b/src/test/ui/dylibs/diamonds-b.stderr @@ -0,0 +1,74 @@ +error: cannot satisfy dependencies so `std` only shows up once (previously required dynamic, via [`diamonds_b`], and now also requires static, via [`a_basement`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `core` only shows up once (two static copies from multiple different locations, via [`std`, `a_basement`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `compiler_builtins` only shows up once (two static copies from multiple different locations, via [`std`, `a_basement`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `rustc_std_workspace_core` only shows up once (two static copies from multiple different locations, via [`std`, `a_basement`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `alloc` only shows up once (two static copies from multiple different locations, via [`std`, `a_basement`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `libc` only shows up once (two static copies from multiple different locations, via [`std`, `a_basement`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `unwind` only shows up once (two static copies from multiple different locations, via [`std`, `a_basement`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `cfg_if` only shows up once (two static copies from multiple different locations, via [`std`, `a_basement`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `hashbrown` only shows up once (two static copies from multiple different locations, via [`std`, `a_basement`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `rustc_std_workspace_alloc` only shows up once (two static copies from multiple different locations, via [`std`, `a_basement`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `rustc_demangle` only shows up once (two static copies from multiple different locations, via [`std`, `a_basement`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `std_detect` only shows up once (two static copies from multiple different locations, via [`std`, `a_basement`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `addr2line` only shows up once (two static copies from multiple different locations, via [`std`, `a_basement`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `gimli` only shows up once (two static copies from multiple different locations, via [`std`, `a_basement`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `object` only shows up once (two static copies from multiple different locations, via [`std`, `a_basement`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `miniz_oxide` only shows up once (two static copies from multiple different locations, via [`std`, `a_basement`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `adler` only shows up once (two static copies from multiple different locations, via [`std`, `a_basement`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `panic_unwind` only shows up once (two static copies from multiple different locations, via [`std`, `a_basement`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: aborting due to 18 previous errors + diff --git a/src/test/ui/dylibs/diamonds-bbbbbbb-prefdyn-z.rs b/src/test/ui/dylibs/diamonds-bbbbbbb-prefdyn-z.rs new file mode 100644 index 0000000000000..622ccdec74ae0 --- /dev/null +++ b/src/test/ui/dylibs/diamonds-bbbbbbb-prefdyn-z.rs @@ -0,0 +1,23 @@ +// run-pass + +// Make use of new `-C prefer-dynamic=...` flag so only `z` is linked dynamically. + +// no-prefer-dynamic +// compile-flags: -C prefer-dynamic=z_roof -Z prefer-dynamic-subset + +// aux-build: a_basement_both.rs +// aux-build: i_ground_both.rs +// aux-build: j_ground_both.rs +// aux-build: m_middle_both.rs +// aux-build: s_upper_both.rs +// aux-build: t_upper_both.rs +// aux-build: z_roof_both.rs + +extern crate z_roof as z; + +mod diamonds_core; + +fn main() { + diamonds_core::sanity_check(); + diamonds_core::check_linked_function_equivalence(); +} diff --git a/src/test/ui/dylibs/diamonds-bbbbbbb-prefdynstd.rs b/src/test/ui/dylibs/diamonds-bbbbbbb-prefdynstd.rs new file mode 100644 index 0000000000000..7ea63e416ce7d --- /dev/null +++ b/src/test/ui/dylibs/diamonds-bbbbbbb-prefdynstd.rs @@ -0,0 +1,23 @@ +// run-pass + +// Make use of new `-C prefer-dynamic=...` flag to allow *only* `std` to be linked dynamically. + +// no-prefer-dynamic +// compile-flags: -C prefer-dynamic=std -Z prefer-dynamic-std + +// aux-build: a_basement_both.rs +// aux-build: i_ground_both.rs +// aux-build: j_ground_both.rs +// aux-build: m_middle_both.rs +// aux-build: s_upper_both.rs +// aux-build: t_upper_both.rs +// aux-build: z_roof_both.rs + +extern crate z_roof as z; + +mod diamonds_core; + +fn main() { + diamonds_core::sanity_check(); + diamonds_core::check_linked_function_equivalence(); +} diff --git a/src/test/ui/dylibs/diamonds-d-prefdynstd.rs b/src/test/ui/dylibs/diamonds-d-prefdynstd.rs new file mode 100644 index 0000000000000..ad1d13f6e9277 --- /dev/null +++ b/src/test/ui/dylibs/diamonds-d-prefdynstd.rs @@ -0,0 +1,14 @@ +// run-pass + +// Make use of new `-C prefer-dynamic=...` flag to allow *only* `std` to be linked dynamically. + +// no-prefer-dynamic +// compile-flags: -C prefer-dynamic=std -Z prefer-dynamic-std -la_basement + +// aux-build: a_basement_dynamic.rs + +extern crate a_basement as a; + +fn main() { + a::a(); +} diff --git a/src/test/ui/dylibs/diamonds-ddddddd-prefdynstd.rs b/src/test/ui/dylibs/diamonds-ddddddd-prefdynstd.rs new file mode 100644 index 0000000000000..edb47f3fed864 --- /dev/null +++ b/src/test/ui/dylibs/diamonds-ddddddd-prefdynstd.rs @@ -0,0 +1,27 @@ +// run-pass + +// Make use of new `-C prefer-dynamic=...` flag to allow *only* `std` to be +// linked dynamically via rustc's injected flags +// +// All the dependencies are dylibs, so we can successfully link them all and run them, *if* we +// provide the right additional flags. + +// no-prefer-dynamic +// compile-flags: -C prefer-dynamic=std -Z prefer-dynamic-std -la_basement -li_ground -lj_ground -lm_middle -ls_upper -lt_upper -lz_roof + +// aux-build: a_basement_dynamic.rs +// aux-build: i_ground_dynamic.rs +// aux-build: j_ground_dynamic.rs +// aux-build: m_middle_dynamic.rs +// aux-build: s_upper_dynamic.rs +// aux-build: t_upper_dynamic.rs +// aux-build: z_roof_dynamic.rs + +extern crate z_roof as z; + +mod diamonds_core; + +fn main() { + diamonds_core::sanity_check(); + diamonds_core::check_linked_function_equivalence(); +} diff --git a/src/test/ui/dylibs/diamonds-ddddddd.rs b/src/test/ui/dylibs/diamonds-ddddddd.rs new file mode 100644 index 0000000000000..f985da64c69ee --- /dev/null +++ b/src/test/ui/dylibs/diamonds-ddddddd.rs @@ -0,0 +1,20 @@ +// run-pass + +// All the dependencies are dylibs, so we can successfully link them all and run them. + +// aux-build: a_basement_dynamic.rs +// aux-build: i_ground_dynamic.rs +// aux-build: j_ground_dynamic.rs +// aux-build: m_middle_dynamic.rs +// aux-build: s_upper_dynamic.rs +// aux-build: t_upper_dynamic.rs +// aux-build: z_roof_dynamic.rs + +extern crate z_roof as z; + +mod diamonds_core; + +fn main() { + diamonds_core::sanity_check(); + diamonds_core::check_linked_function_equivalence(); +} diff --git a/src/test/ui/dylibs/diamonds-ddddrrr.rs b/src/test/ui/dylibs/diamonds-ddddrrr.rs new file mode 100644 index 0000000000000..c824803235434 --- /dev/null +++ b/src/test/ui/dylibs/diamonds-ddddrrr.rs @@ -0,0 +1,21 @@ +// run-pass + +// There is no sharing of an rlib via two dylibs, and thus we can link and run +// this program. + +// aux-build: a_basement_dynamic.rs +// aux-build: i_ground_dynamic.rs +// aux-build: j_ground_dynamic.rs +// aux-build: m_middle_dynamic.rs +// aux-build: s_upper_rlib.rs +// aux-build: t_upper_rlib.rs +// aux-build: z_roof_rlib.rs + +extern crate z_roof as z; + +mod diamonds_core; + +fn main() { + diamonds_core::sanity_check(); + diamonds_core::check_linked_function_equivalence(); +} diff --git a/src/test/ui/dylibs/diamonds-dddrdd.rs b/src/test/ui/dylibs/diamonds-dddrdd.rs new file mode 100644 index 0000000000000..b0d1cffca8cef --- /dev/null +++ b/src/test/ui/dylibs/diamonds-dddrdd.rs @@ -0,0 +1,18 @@ +// build-fail + +// This fails to compile because the middle static library (m) is included via +// two dylibs: `s_upper` and `t_upper`. + +// aux-build: a_basement_dynamic.rs +// aux-build: i_ground_dynamic.rs +// aux-build: j_ground_dynamic.rs +// aux-build: m_middle_rlib.rs +// aux-build: s_upper_dynamic.rs +// aux-build: t_upper_dynamic.rs + +extern crate s_upper as s; +extern crate t_upper as t; + +fn main() { + s::s(); t::t(); +} diff --git a/src/test/ui/dylibs/diamonds-dddrdd.stderr b/src/test/ui/dylibs/diamonds-dddrdd.stderr new file mode 100644 index 0000000000000..440be5e532709 --- /dev/null +++ b/src/test/ui/dylibs/diamonds-dddrdd.stderr @@ -0,0 +1,6 @@ +error: cannot satisfy dependencies so `m_middle` only shows up once (two static copies from multiple different locations, via [`s_upper`, `t_upper`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: aborting due to previous error + diff --git a/src/test/ui/dylibs/diamonds-dddrrrr.rs b/src/test/ui/dylibs/diamonds-dddrrrr.rs new file mode 100644 index 0000000000000..fa35d098affa9 --- /dev/null +++ b/src/test/ui/dylibs/diamonds-dddrrrr.rs @@ -0,0 +1,21 @@ +// run-pass + +// There is no sharing of an rlib via two dylibs, and thus we can link and run +// this program. + +// aux-build: a_basement_dynamic.rs +// aux-build: i_ground_dynamic.rs +// aux-build: j_ground_dynamic.rs +// aux-build: m_middle_rlib.rs +// aux-build: s_upper_rlib.rs +// aux-build: t_upper_rlib.rs +// aux-build: z_roof_rlib.rs + +extern crate z_roof as z; + +mod diamonds_core; + +fn main() { + diamonds_core::sanity_check(); + diamonds_core::check_linked_function_equivalence(); +} diff --git a/src/test/ui/dylibs/diamonds-rdd.rs b/src/test/ui/dylibs/diamonds-rdd.rs new file mode 100644 index 0000000000000..d32d8b07eca8d --- /dev/null +++ b/src/test/ui/dylibs/diamonds-rdd.rs @@ -0,0 +1,15 @@ +// build-fail + +// This fails to compile because the static library foundation (a) is +// included via two dylibs: `i_ground` and `j_ground`. + +// aux-build: a_basement_rlib.rs +// aux-build: i_ground_dynamic.rs +// aux-build: j_ground_dynamic.rs + +extern crate i_ground as i; +extern crate j_ground as j; + +fn main() { + i::i(); j::j(); +} diff --git a/src/test/ui/dylibs/diamonds-rdd.stderr b/src/test/ui/dylibs/diamonds-rdd.stderr new file mode 100644 index 0000000000000..ed4c78f8bb493 --- /dev/null +++ b/src/test/ui/dylibs/diamonds-rdd.stderr @@ -0,0 +1,6 @@ +error: cannot satisfy dependencies so `a_basement` only shows up once (two static copies from multiple different locations, via [`i_ground`, `j_ground`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: aborting due to previous error + diff --git a/src/test/ui/dylibs/diamonds-rdrddrd.rs b/src/test/ui/dylibs/diamonds-rdrddrd.rs new file mode 100644 index 0000000000000..7a146dc97f71b --- /dev/null +++ b/src/test/ui/dylibs/diamonds-rdrddrd.rs @@ -0,0 +1,24 @@ +// run-pass + +// You might expect this to fail to compile because the static library +// foundations (a) is linked via both a dylib `i_ground` and an rlib `j_upper` +// that are themselves linked via a dylib `m_middle`. But, it currently passes, +// presumably due to internal details of rustc's heuristic selection between +// dynamic and static linking. + +// aux-build: a_basement_rlib.rs +// aux-build: i_ground_dynamic.rs +// aux-build: j_ground_rlib.rs +// aux-build: m_middle_dynamic.rs +// aux-build: s_upper_dynamic.rs +// aux-build: t_upper_rlib.rs +// aux-build: z_roof_dynamic.rs + +extern crate z_roof as z; + +mod diamonds_core; + +fn main() { + diamonds_core::sanity_check(); + diamonds_core::check_linked_function_equivalence(); +} diff --git a/src/test/ui/dylibs/diamonds-rdrrdrd.rs b/src/test/ui/dylibs/diamonds-rdrrdrd.rs new file mode 100644 index 0000000000000..2c0a7a0565a09 --- /dev/null +++ b/src/test/ui/dylibs/diamonds-rdrrdrd.rs @@ -0,0 +1,24 @@ +// run-pass + +// You might expect this to fail to compile because the static library +// foundations (a) is linked via both a dylib `i_ground` and an rlib `j_upper` +// that are themselves linked via an rlib `m_middle`. But, it currently passes, +// presumably due to internal details of rustc's heuristic selection between +// dynamic and static linking. + +// aux-build: a_basement_rlib.rs +// aux-build: i_ground_dynamic.rs +// aux-build: j_ground_rlib.rs +// aux-build: m_middle_rlib.rs +// aux-build: s_upper_dynamic.rs +// aux-build: t_upper_rlib.rs +// aux-build: z_roof_dynamic.rs + +extern crate z_roof as z; + +mod diamonds_core; + +fn main() { + diamonds_core::sanity_check(); + diamonds_core::check_linked_function_equivalence(); +} diff --git a/src/test/ui/dylibs/diamonds-rdrrrrd.rs b/src/test/ui/dylibs/diamonds-rdrrrrd.rs new file mode 100644 index 0000000000000..09713503ccff3 --- /dev/null +++ b/src/test/ui/dylibs/diamonds-rdrrrrd.rs @@ -0,0 +1,24 @@ +// run-pass + +// You might expect this to fail to compile because the static library +// foundations (a) is linked via both a dylib `i_ground` and an rlib `j_upper` +// that are themselves linked via an rlib `m_middle`. But, it currently passes, +// presumably due to internal details of rustc's heuristic selection between +// dynamic and static linking. + +// aux-build: a_basement_rlib.rs +// aux-build: i_ground_dynamic.rs +// aux-build: j_ground_rlib.rs +// aux-build: m_middle_rlib.rs +// aux-build: s_upper_rlib.rs +// aux-build: t_upper_rlib.rs +// aux-build: z_roof_dynamic.rs + +extern crate z_roof as z; + +mod diamonds_core; + +fn main() { + diamonds_core::sanity_check(); + diamonds_core::check_linked_function_equivalence(); +} diff --git a/src/test/ui/dylibs/diamonds-rdrrrrr.rs b/src/test/ui/dylibs/diamonds-rdrrrrr.rs new file mode 100644 index 0000000000000..4e9a7ddefdaa7 --- /dev/null +++ b/src/test/ui/dylibs/diamonds-rdrrrrr.rs @@ -0,0 +1,24 @@ +// run-pass + +// You might expect this to fail to compile because the static library +// foundations (a) is linked via both a dylib `i_ground` and an rlib `j_upper` +// that are themselves linked via an rlib `m_middle`. But, it currently passes, +// presumably due to internal details of rustc's heuristic selection between +// dynamic and static linking. + +// aux-build: a_basement_rlib.rs +// aux-build: i_ground_dynamic.rs +// aux-build: j_ground_rlib.rs +// aux-build: m_middle_rlib.rs +// aux-build: s_upper_rlib.rs +// aux-build: t_upper_rlib.rs +// aux-build: z_roof_rlib.rs + +extern crate z_roof as z; + +mod diamonds_core; + +fn main() { + diamonds_core::sanity_check(); + diamonds_core::check_linked_function_equivalence(); +} diff --git a/src/test/ui/dylibs/diamonds-rrrrdd.rs b/src/test/ui/dylibs/diamonds-rrrrdd.rs new file mode 100644 index 0000000000000..58e9974f7978d --- /dev/null +++ b/src/test/ui/dylibs/diamonds-rrrrdd.rs @@ -0,0 +1,18 @@ +// build-fail + +// This fails to compile because the static library foundations (a, i, j, m) are +// included via two dylibs: `s_upper` and `t_upper`. + +// aux-build: a_basement_rlib.rs +// aux-build: i_ground_rlib.rs +// aux-build: j_ground_rlib.rs +// aux-build: m_middle_rlib.rs +// aux-build: s_upper_dynamic.rs +// aux-build: t_upper_dynamic.rs + +extern crate s_upper as s; +extern crate t_upper as t; + +fn main() { + s::s(); t::t(); +} diff --git a/src/test/ui/dylibs/diamonds-rrrrdd.stderr b/src/test/ui/dylibs/diamonds-rrrrdd.stderr new file mode 100644 index 0000000000000..556f39774e712 --- /dev/null +++ b/src/test/ui/dylibs/diamonds-rrrrdd.stderr @@ -0,0 +1,18 @@ +error: cannot satisfy dependencies so `m_middle` only shows up once (two static copies from multiple different locations, via [`s_upper`, `t_upper`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `i_ground` only shows up once (two static copies from multiple different locations, via [`s_upper`, `t_upper`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `a_basement` only shows up once (two static copies from multiple different locations, via [`s_upper`, `t_upper`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `j_ground` only shows up once (two static copies from multiple different locations, via [`s_upper`, `t_upper`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/dylibs/diamonds-rrrrdrd.rs b/src/test/ui/dylibs/diamonds-rrrrdrd.rs new file mode 100644 index 0000000000000..1aff2117a0106 --- /dev/null +++ b/src/test/ui/dylibs/diamonds-rrrrdrd.rs @@ -0,0 +1,24 @@ +// run-pass + +// You might expect this to fail to compile because the static library +// foundations (a, i, j, m) are linked via both a dylib `s_upper` and an rlib +// `t_upper` that are themselves linked via a dylib `z_roof`. But, it currently +// passes, presumably due to internal details of rustc's heuristic selection +// between dynamic and static linking. + +// aux-build: a_basement_rlib.rs +// aux-build: i_ground_rlib.rs +// aux-build: j_ground_rlib.rs +// aux-build: m_middle_rlib.rs +// aux-build: s_upper_dynamic.rs +// aux-build: t_upper_rlib.rs +// aux-build: z_roof_dynamic.rs + +extern crate z_roof as z; + +mod diamonds_core; + +fn main() { + diamonds_core::sanity_check(); + diamonds_core::check_linked_function_equivalence(); +} diff --git a/src/test/ui/dylibs/diamonds-rrrrdrr.rs b/src/test/ui/dylibs/diamonds-rrrrdrr.rs new file mode 100644 index 0000000000000..9579832c8352f --- /dev/null +++ b/src/test/ui/dylibs/diamonds-rrrrdrr.rs @@ -0,0 +1,23 @@ +// run-pass + +// You might expect this to fail to compile because the static library +// foundations (a, i, j, m) are included via both a dylib `s_upper` and an rlib +// `t_upper` that are themselves linked via an rlib `z_roof`. But, inexplicably, +// it currently passes. + +// aux-build: a_basement_rlib.rs +// aux-build: i_ground_rlib.rs +// aux-build: j_ground_rlib.rs +// aux-build: m_middle_rlib.rs +// aux-build: s_upper_dynamic.rs +// aux-build: t_upper_rlib.rs +// aux-build: z_roof_rlib.rs + +extern crate z_roof as z; + +mod diamonds_core; + +fn main() { + diamonds_core::sanity_check(); + diamonds_core::check_linked_function_equivalence(); +} diff --git a/src/test/ui/dylibs/diamonds-rrrrrrd.rs b/src/test/ui/dylibs/diamonds-rrrrrrd.rs new file mode 100644 index 0000000000000..324e1fd690d46 --- /dev/null +++ b/src/test/ui/dylibs/diamonds-rrrrrrd.rs @@ -0,0 +1,20 @@ +// run-pass + +// All the dependencies are rlibs, so we can successfully link them all and run them. + +// aux-build: a_basement_rlib.rs +// aux-build: i_ground_rlib.rs +// aux-build: j_ground_rlib.rs +// aux-build: m_middle_rlib.rs +// aux-build: s_upper_rlib.rs +// aux-build: t_upper_rlib.rs +// aux-build: z_roof_dynamic.rs + +extern crate z_roof as z; + +mod diamonds_core; + +fn main() { + diamonds_core::sanity_check(); + diamonds_core::check_linked_function_equivalence(); +} diff --git a/src/test/ui/dylibs/diamonds-rrrrrrr.rs b/src/test/ui/dylibs/diamonds-rrrrrrr.rs new file mode 100644 index 0000000000000..01a735083068b --- /dev/null +++ b/src/test/ui/dylibs/diamonds-rrrrrrr.rs @@ -0,0 +1,20 @@ +// run-pass + +// All the dependencies are rlibs, so we can successfully link them all and run them. + +// aux-build: a_basement_rlib.rs +// aux-build: i_ground_rlib.rs +// aux-build: j_ground_rlib.rs +// aux-build: m_middle_rlib.rs +// aux-build: s_upper_rlib.rs +// aux-build: t_upper_rlib.rs +// aux-build: z_roof_rlib.rs + +extern crate z_roof as z; + +mod diamonds_core; + +fn main() { + diamonds_core::sanity_check(); + diamonds_core::check_linked_function_equivalence(); +} diff --git a/src/test/ui/dylibs/diamonds_core.rs b/src/test/ui/dylibs/diamonds_core.rs new file mode 100644 index 0000000000000..c38f7873717dd --- /dev/null +++ b/src/test/ui/dylibs/diamonds_core.rs @@ -0,0 +1,21 @@ +// ignore-test Not a test. Used by the other tests. + +pub fn sanity_check() { + // Sanity-check: getting back non-trival values from addr functions + assert_ne!(z::s_addr(), z::t_addr()); + assert_ne!(z::s_m_addr(), z::s_m_i_addr()); + assert_ne!(z::s_m_i_addr(), z::s_m_j_addr()); + assert_ne!(z::s_m_i_addr(), z::s_m_i_a_addr()); +} + +pub fn check_linked_function_equivalence() { + // Check that the linked functions are the same code by comparing their + // underlying addresses. + assert_eq!(z::s_m_addr(), z::s::m_addr()); + assert_eq!(z::s_m_addr(), z::t_m_addr()); + assert_eq!(z::s_m_i_addr(), z::s::m::i_addr()); + assert_eq!(z::s_m_i_addr(), z::t_m_i_addr()); + assert_eq!(z::s_m_i_a_addr(), z::s::m::i::a_addr()); + assert_eq!(z::s_m_i_a_addr(), z::t_m_i_a_addr()); + assert_eq!(z::s_m_i_a_addr(), z::t_m_j_a_addr()); +} diff --git a/src/test/ui/dylibs/issue-82151-serverctl-noprefdyn.rs b/src/test/ui/dylibs/issue-82151-serverctl-noprefdyn.rs new file mode 100644 index 0000000000000..5f0cdc3e0b35e --- /dev/null +++ b/src/test/ui/dylibs/issue-82151-serverctl-noprefdyn.rs @@ -0,0 +1,13 @@ +// build-fail + +// no-prefer-dynamic + +// aux-build: aaa_issue_82151_bar_noprefdyn.rs +// aux-build: aaa_issue_82151_foo_noprefdyn.rs +// aux-build: aaa_issue_82151_shared_noprefdyn.rs + +extern crate shared; + +fn main() { + let _ = shared::Test::new(); +} diff --git a/src/test/ui/dylibs/issue-82151-serverctl-noprefdyn.stderr b/src/test/ui/dylibs/issue-82151-serverctl-noprefdyn.stderr new file mode 100644 index 0000000000000..0ee4c660b0e69 --- /dev/null +++ b/src/test/ui/dylibs/issue-82151-serverctl-noprefdyn.stderr @@ -0,0 +1,78 @@ +error: cannot satisfy dependencies so `std` only shows up once (previously required dynamic, via [`issue_82151_serverctl_noprefdyn`], and now also requires static, via [`shared`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `core` only shows up once (two static copies from multiple different locations, via [`std`, `shared`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `compiler_builtins` only shows up once (two static copies from multiple different locations, via [`std`, `shared`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `rustc_std_workspace_core` only shows up once (two static copies from multiple different locations, via [`std`, `shared`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `alloc` only shows up once (two static copies from multiple different locations, via [`std`, `shared`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `libc` only shows up once (two static copies from multiple different locations, via [`std`, `shared`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `unwind` only shows up once (two static copies from multiple different locations, via [`std`, `shared`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `cfg_if` only shows up once (two static copies from multiple different locations, via [`std`, `shared`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `hashbrown` only shows up once (two static copies from multiple different locations, via [`std`, `shared`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `rustc_std_workspace_alloc` only shows up once (two static copies from multiple different locations, via [`std`, `shared`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `rustc_demangle` only shows up once (two static copies from multiple different locations, via [`std`, `shared`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `std_detect` only shows up once (two static copies from multiple different locations, via [`std`, `shared`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `addr2line` only shows up once (two static copies from multiple different locations, via [`std`, `shared`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `gimli` only shows up once (two static copies from multiple different locations, via [`std`, `shared`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `object` only shows up once (two static copies from multiple different locations, via [`std`, `shared`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `miniz_oxide` only shows up once (two static copies from multiple different locations, via [`std`, `shared`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `adler` only shows up once (two static copies from multiple different locations, via [`std`, `shared`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `panic_unwind` only shows up once (two static copies from multiple different locations, via [`std`, `shared`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: cannot satisfy dependencies so `bar` only shows up once (previously required static, via [`shared`], and now also requires dynamic, via [`issue_82151_serverctl_noprefdyn`]) + | + = help: having upstream crates all available in one format will likely make this go away + +error: aborting due to 19 previous errors + diff --git a/src/test/ui/dylibs/issue-82151-serverctl-prefdyn.rs b/src/test/ui/dylibs/issue-82151-serverctl-prefdyn.rs new file mode 100644 index 0000000000000..f785fb3f15151 --- /dev/null +++ b/src/test/ui/dylibs/issue-82151-serverctl-prefdyn.rs @@ -0,0 +1,16 @@ +// build-fail +// normalize-stderr-test "note: .*undefined reference to `bar::bar'" -> "note: undefined reference to `bar::bar'" +// normalize-stderr-test "note: .cc..*" -> "note: $$CC_INVOCATION" + +// no-prefer-dynamic +// compile-flags: -C prefer-dynamic + +// aux-build: aaa_issue_82151_bar_prefdyn.rs +// aux-build: aaa_issue_82151_foo_prefdyn.rs +// aux-build: aaa_issue_82151_shared_prefdyn.rs + +extern crate shared; + +fn main() { + let _ = shared::Test::new(); +} diff --git a/src/test/ui/dylibs/issue-82151-serverctl-prefdyn.stderr b/src/test/ui/dylibs/issue-82151-serverctl-prefdyn.stderr new file mode 100644 index 0000000000000..50e7c088b8f9a --- /dev/null +++ b/src/test/ui/dylibs/issue-82151-serverctl-prefdyn.stderr @@ -0,0 +1,12 @@ +error: linking with `cc` failed: exit status: 1 + | + = note: $CC_INVOCATION + = note: undefined reference to `bar::bar' + collect2: error: ld returned 1 exit status + + = help: some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified + = note: use the `-l` flag to specify native libraries to link + = note: use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorustc-link-libkindname) + +error: aborting due to previous error + diff --git a/src/test/ui/dylibs/issue-82151-serverctl-prefdynstd.rs b/src/test/ui/dylibs/issue-82151-serverctl-prefdynstd.rs new file mode 100644 index 0000000000000..ee001038e7dc2 --- /dev/null +++ b/src/test/ui/dylibs/issue-82151-serverctl-prefdynstd.rs @@ -0,0 +1,18 @@ +// run-pass + +// Make use of new `-C prefer-dynamic=...` flag to allow *only* `std` to be +// linked dynamically via the rustc injected flags, and then also manually link +// to `shared`. + +// no-prefer-dynamic +// compile-flags: -C prefer-dynamic=std -Z prefer-dynamic-std -lshared + +// aux-build: aaa_issue_82151_bar_prefdynstd.rs +// aux-build: aaa_issue_82151_foo_prefdynstd.rs +// aux-build: aaa_issue_82151_shared_prefdynstd.rs + +extern crate shared; + +fn main() { + let _ = shared::Test::new(); +} diff --git a/src/test/ui/dylibs/issue-82151-serverctl-prefdynsubset.rs b/src/test/ui/dylibs/issue-82151-serverctl-prefdynsubset.rs new file mode 100644 index 0000000000000..43c4aef98207a --- /dev/null +++ b/src/test/ui/dylibs/issue-82151-serverctl-prefdynsubset.rs @@ -0,0 +1,16 @@ +// run-pass + +// Make use of new `-C prefer-dynamic=...` to choose `shared` and `std` to be linked dynamically. + +// no-prefer-dynamic +// compile-flags: -C prefer-dynamic=shared,std -Z prefer-dynamic-subset + +// aux-build: aaa_issue_82151_bar_prefdynsubset.rs +// aux-build: aaa_issue_82151_foo_prefdynsubset.rs +// aux-build: aaa_issue_82151_shared_prefdynsubset.rs + +extern crate shared; + +fn main() { + let _ = shared::Test::new(); +}