From a8ed3a401737b57310174f8b23d3645416b490b0 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 14 Aug 2021 09:43:27 -0400 Subject: [PATCH 01/10] extra details about library mismatches. Added reverse map that tells us for a given dependency and its preferred format, what were the parent crates that requested that dependency+format combination. --- .../rustc_metadata/src/dependency_format.rs | 61 ++++++++++++++++--- compiler/rustc_middle/src/middle/cstore.rs | 2 +- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index 2d4deb1d8d5da..3d4ef81d2393b 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -54,7 +54,7 @@ use crate::creader::CStore; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::def_id::CrateNum; +use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_middle::middle::cstore::CrateDepKind; use rustc_middle::middle::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic}; use rustc_middle::middle::dependency_format::{Dependencies, DependencyList, Linkage}; @@ -62,6 +62,8 @@ use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; use rustc_target::spec::PanicStrategy; +type RevDeps = FxHashMap<(CrateNum, LinkagePreference), Vec>; + crate fn calculate(tcx: TyCtxt<'_>) -> Dependencies { tcx.sess .crate_types() @@ -148,6 +150,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { } 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 @@ -159,12 +162,18 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { 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); + 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); } } } @@ -192,7 +201,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { { assert!(src.rlib.is_some() || src.rmeta.is_some()); tracing::info!("adding staticlib: {}", tcx.crate_name(cnum)); - add_library(tcx, cnum, RequireStatic, &mut formats); + add_library(tcx, cnum, RequireStatic, &mut formats, &mut rev_deps, LOCAL_CRATE); ret[cnum.as_usize() - 1] = Linkage::Static; } } @@ -243,7 +252,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 +266,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, From dbe4d27826eeddd58fca175b2ddb805c105b9a5f Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 14 Aug 2021 09:55:51 -0400 Subject: [PATCH 02/10] improve debugging experience slightly. (type annotations are to help rust-analyzer as much as humans.) --- compiler/rustc_metadata/src/dependency_format.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index 3d4ef81d2393b..47a5d740f5172 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -55,8 +55,8 @@ use crate::creader::CStore; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; -use rustc_middle::middle::cstore::CrateDepKind; 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; @@ -64,6 +64,8 @@ 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() @@ -135,7 +137,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; } @@ -160,7 +162,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { continue; } let name = tcx.crate_name(cnum); - let src = tcx.used_crate_source(cnum); + let src: Lrc = tcx.used_crate_source(cnum); if src.dylib.is_some() { tracing::info!("calculate_type {} adding dylib: {}", tcx.crate_name(LOCAL_CRATE), name); add_library(tcx, cnum, RequireDynamic, &mut formats, &mut rev_deps, LOCAL_CRATE); @@ -194,7 +196,7 @@ 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); + let src: Lrc = tcx.used_crate_source(cnum); if src.dylib.is_none() && !formats.contains_key(&cnum) && tcx.dep_kind(cnum) == CrateDepKind::Explicit @@ -224,7 +226,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, From bf817f6779612db9354fda69ee7b8f6ec24d4070 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 14 Aug 2021 15:28:29 -0400 Subject: [PATCH 03/10] Generalize `-C prefer-dyanmic` to carry an optional subset of the crates to prefer dynamic linkage on. Note: carrying an empty set here is *not* the same as `-C prefer-dyanmic=no` (and the latter is the default behavior for `rustc`). As discussed in detail in the comments for `enum PreferDynamicSet` (and also in the comments of `rustc_metadata::dependency_format`), `-C prefer-dynamic=no` asks the compiler to guess what linkage to use, and it currently guesses all static first, and if that fails, then it prefers dynamic linkage for all crates that provide both dynamic and static libraries. Using an empty set for `-C prefer-dynamic`, on the other hand, means the compiler should never prefer dynamic linkage over static linkage, even if that means it won't be able to successfully link the build product. --- compiler/rustc_codegen_llvm/src/back/lto.rs | 2 +- compiler/rustc_codegen_llvm/src/consts.rs | 2 +- compiler/rustc_codegen_ssa/src/back/write.rs | 2 +- .../rustc_metadata/src/dependency_format.rs | 71 ++++++++++++++----- compiler/rustc_session/src/config.rs | 67 ++++++++++++++++- compiler/rustc_session/src/options.rs | 36 +++++++++- compiler/rustc_session/src/session.rs | 2 +- src/doc/rustc/src/codegen-options/index.md | 7 ++ 8 files changed, 164 insertions(+), 25 deletions(-) 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_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index 47a5d740f5172..2fea8a099df83 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -85,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, @@ -148,6 +168,11 @@ 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) + ); } } @@ -163,7 +188,14 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { } let name = tcx.crate_name(cnum); let src: Lrc = tcx.used_crate_source(cnum); - if src.dylib.is_some() { + // 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); @@ -196,13 +228,16 @@ 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 name = tcx.crate_name(cnum); let src: Lrc = tcx.used_crate_source(cnum); - if src.dylib.is_none() - && !formats.contains_key(&cnum) - && tcx.dep_kind(cnum) == CrateDepKind::Explicit - { + 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)); + tracing::info!("adding staticlib: {}", name); add_library(tcx, cnum, RequireStatic, &mut formats, &mut rev_deps, LOCAL_CRATE); ret[cnum.as_usize() - 1] = Linkage::Static; } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 123f47b430a17..e6f11c42052d0 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 @@ -2420,8 +2482,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 +2572,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..173f6f8ac1db2 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], 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 From 5d7747967ae6a1936f241caf374f11bf089846d7 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 14 Aug 2021 15:32:16 -0400 Subject: [PATCH 04/10] Guard new variants of `-C prefer-dynamic=...` via `-Z` flags. --- compiler/rustc_session/src/config.rs | 30 +++++++++++++++++++++++++++ compiler/rustc_session/src/options.rs | 4 ++++ 2 files changed, 34 insertions(+) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index e6f11c42052d0..35a9fa11f9ae8 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2168,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; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 173f6f8ac1db2..dc81dc6ba1a5d 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1238,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], From 0099f6ba14bc4021dffc5e9bd14079b757cb1aad Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 14 Aug 2021 15:36:57 -0400 Subject: [PATCH 05/10] Add some simple tests of how `-C prefer-dynamic` interacts with dependency tracking. --- compiler/rustc_interface/src/tests.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) 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] From 8d63ba2a6f21a65a0eeac6950b2b1ba61595bb48 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 16 Aug 2021 13:59:23 -0400 Subject: [PATCH 06/10] Some tests of the current behavior, including the elaborated output when we fail due to repeated static library. --- src/test/ui/dylibs/README.md | 30 +++++++++++++++++++ .../ui/dylibs/auxiliary/a_basement_core.rs | 5 ++++ .../ui/dylibs/auxiliary/a_basement_dynamic.rs | 5 ++++ .../ui/dylibs/auxiliary/a_basement_rlib.rs | 8 +++++ src/test/ui/dylibs/auxiliary/i_ground_core.rs | 7 +++++ .../ui/dylibs/auxiliary/i_ground_dynamic.rs | 7 +++++ src/test/ui/dylibs/auxiliary/i_ground_rlib.rs | 10 +++++++ src/test/ui/dylibs/auxiliary/j_ground_core.rs | 7 +++++ .../ui/dylibs/auxiliary/j_ground_dynamic.rs | 7 +++++ src/test/ui/dylibs/auxiliary/j_ground_rlib.rs | 10 +++++++ src/test/ui/dylibs/auxiliary/m_middle_core.rs | 13 ++++++++ .../ui/dylibs/auxiliary/m_middle_dynamic.rs | 8 +++++ src/test/ui/dylibs/auxiliary/m_middle_rlib.rs | 11 +++++++ src/test/ui/dylibs/auxiliary/s_upper_core.rs | 15 ++++++++++ .../ui/dylibs/auxiliary/s_upper_dynamic.rs | 7 +++++ src/test/ui/dylibs/auxiliary/s_upper_rlib.rs | 10 +++++++ src/test/ui/dylibs/auxiliary/t_upper_core.rs | 15 ++++++++++ .../ui/dylibs/auxiliary/t_upper_dynamic.rs | 7 +++++ src/test/ui/dylibs/auxiliary/t_upper_rlib.rs | 10 +++++++ src/test/ui/dylibs/auxiliary/z_roof_core.rs | 29 ++++++++++++++++++ .../ui/dylibs/auxiliary/z_roof_dynamic.rs | 8 +++++ src/test/ui/dylibs/auxiliary/z_roof_rlib.rs | 11 +++++++ src/test/ui/dylibs/diamonds-ddddddd.rs | 20 +++++++++++++ src/test/ui/dylibs/diamonds-ddddrrr.rs | 21 +++++++++++++ src/test/ui/dylibs/diamonds-dddrdd.rs | 18 +++++++++++ src/test/ui/dylibs/diamonds-dddrdd.stderr | 6 ++++ src/test/ui/dylibs/diamonds-dddrrrr.rs | 21 +++++++++++++ src/test/ui/dylibs/diamonds-rdd.rs | 15 ++++++++++ src/test/ui/dylibs/diamonds-rdd.stderr | 6 ++++ src/test/ui/dylibs/diamonds-rdrddrd.rs | 24 +++++++++++++++ src/test/ui/dylibs/diamonds-rdrrdrd.rs | 24 +++++++++++++++ src/test/ui/dylibs/diamonds-rdrrrrd.rs | 24 +++++++++++++++ src/test/ui/dylibs/diamonds-rdrrrrr.rs | 24 +++++++++++++++ src/test/ui/dylibs/diamonds-rrrrdd.rs | 18 +++++++++++ src/test/ui/dylibs/diamonds-rrrrdd.stderr | 18 +++++++++++ src/test/ui/dylibs/diamonds-rrrrdrd.rs | 24 +++++++++++++++ src/test/ui/dylibs/diamonds-rrrrdrr.rs | 23 ++++++++++++++ src/test/ui/dylibs/diamonds-rrrrrrd.rs | 20 +++++++++++++ src/test/ui/dylibs/diamonds-rrrrrrr.rs | 20 +++++++++++++ src/test/ui/dylibs/diamonds_core.rs | 21 +++++++++++++ 40 files changed, 587 insertions(+) create mode 100644 src/test/ui/dylibs/README.md create mode 100644 src/test/ui/dylibs/auxiliary/a_basement_core.rs create mode 100644 src/test/ui/dylibs/auxiliary/a_basement_dynamic.rs create mode 100644 src/test/ui/dylibs/auxiliary/a_basement_rlib.rs create mode 100644 src/test/ui/dylibs/auxiliary/i_ground_core.rs create mode 100644 src/test/ui/dylibs/auxiliary/i_ground_dynamic.rs create mode 100644 src/test/ui/dylibs/auxiliary/i_ground_rlib.rs create mode 100644 src/test/ui/dylibs/auxiliary/j_ground_core.rs create mode 100644 src/test/ui/dylibs/auxiliary/j_ground_dynamic.rs create mode 100644 src/test/ui/dylibs/auxiliary/j_ground_rlib.rs create mode 100644 src/test/ui/dylibs/auxiliary/m_middle_core.rs create mode 100644 src/test/ui/dylibs/auxiliary/m_middle_dynamic.rs create mode 100644 src/test/ui/dylibs/auxiliary/m_middle_rlib.rs create mode 100644 src/test/ui/dylibs/auxiliary/s_upper_core.rs create mode 100644 src/test/ui/dylibs/auxiliary/s_upper_dynamic.rs create mode 100644 src/test/ui/dylibs/auxiliary/s_upper_rlib.rs create mode 100644 src/test/ui/dylibs/auxiliary/t_upper_core.rs create mode 100644 src/test/ui/dylibs/auxiliary/t_upper_dynamic.rs create mode 100644 src/test/ui/dylibs/auxiliary/t_upper_rlib.rs create mode 100644 src/test/ui/dylibs/auxiliary/z_roof_core.rs create mode 100644 src/test/ui/dylibs/auxiliary/z_roof_dynamic.rs create mode 100644 src/test/ui/dylibs/auxiliary/z_roof_rlib.rs create mode 100644 src/test/ui/dylibs/diamonds-ddddddd.rs create mode 100644 src/test/ui/dylibs/diamonds-ddddrrr.rs create mode 100644 src/test/ui/dylibs/diamonds-dddrdd.rs create mode 100644 src/test/ui/dylibs/diamonds-dddrdd.stderr create mode 100644 src/test/ui/dylibs/diamonds-dddrrrr.rs create mode 100644 src/test/ui/dylibs/diamonds-rdd.rs create mode 100644 src/test/ui/dylibs/diamonds-rdd.stderr create mode 100644 src/test/ui/dylibs/diamonds-rdrddrd.rs create mode 100644 src/test/ui/dylibs/diamonds-rdrrdrd.rs create mode 100644 src/test/ui/dylibs/diamonds-rdrrrrd.rs create mode 100644 src/test/ui/dylibs/diamonds-rdrrrrr.rs create mode 100644 src/test/ui/dylibs/diamonds-rrrrdd.rs create mode 100644 src/test/ui/dylibs/diamonds-rrrrdd.stderr create mode 100644 src/test/ui/dylibs/diamonds-rrrrdrd.rs create mode 100644 src/test/ui/dylibs/diamonds-rrrrdrr.rs create mode 100644 src/test/ui/dylibs/diamonds-rrrrrrd.rs create mode 100644 src/test/ui/dylibs/diamonds-rrrrrrr.rs create mode 100644 src/test/ui/dylibs/diamonds_core.rs 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_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/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_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_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_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_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_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-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()); +} From 172ba702b733ea7eb2a188cfd444c1fc9470c24e Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 16 Aug 2021 19:59:27 -0400 Subject: [PATCH 07/10] A collection of test cases showing how the new `-C prefer-dynamic=crate,...` flag can be used to resolve issue 82151. These differ from the diamonds-*.rs in a couple of ways: * The most foundational library is being compiled to multiple crate output types, and * The most foundational library is being compiled to a `cdylib`, not a `dylib`. These two details seemed to be critical for reproducing the exact set of unfortunate link-time behaviors that we observed on issue 82151, as illustrated by the family of tests named `issue-82151-serverctl-*.rs`. ---- issue-82151-serverctl-prefdyn.rs works around ld-binary specific details by adding extra normalization to test, including normalizing stage number in output. --- .../dylibs/auxiliary/aaa_issue_82151_bar.rs | 9 +++ .../aaa_issue_82151_bar_noprefdyn.rs | 11 +++ .../auxiliary/aaa_issue_82151_bar_prefdyn.rs | 12 +++ .../aaa_issue_82151_bar_prefdynstd.rs | 12 +++ .../aaa_issue_82151_bar_prefdynsubset.rs | 12 +++ .../aaa_issue_82151_foo_noprefdyn.rs | 13 ++++ .../auxiliary/aaa_issue_82151_foo_prefdyn.rs | 14 ++++ .../aaa_issue_82151_foo_prefdynstd.rs | 14 ++++ .../aaa_issue_82151_foo_prefdynsubset.rs | 14 ++++ .../aaa_issue_82151_shared_noprefdyn.rs | 17 ++++ .../aaa_issue_82151_shared_prefdyn.rs | 18 +++++ .../aaa_issue_82151_shared_prefdynstd.rs | 18 +++++ .../aaa_issue_82151_shared_prefdynsubset.rs | 18 +++++ .../dylibs/issue-82151-serverctl-noprefdyn.rs | 13 ++++ .../issue-82151-serverctl-noprefdyn.stderr | 78 +++++++++++++++++++ .../dylibs/issue-82151-serverctl-prefdyn.rs | 16 ++++ .../issue-82151-serverctl-prefdyn.stderr | 12 +++ .../issue-82151-serverctl-prefdynstd.rs | 18 +++++ .../issue-82151-serverctl-prefdynsubset.rs | 16 ++++ 19 files changed, 335 insertions(+) create mode 100644 src/test/ui/dylibs/auxiliary/aaa_issue_82151_bar.rs create mode 100644 src/test/ui/dylibs/auxiliary/aaa_issue_82151_bar_noprefdyn.rs create mode 100644 src/test/ui/dylibs/auxiliary/aaa_issue_82151_bar_prefdyn.rs create mode 100644 src/test/ui/dylibs/auxiliary/aaa_issue_82151_bar_prefdynstd.rs create mode 100644 src/test/ui/dylibs/auxiliary/aaa_issue_82151_bar_prefdynsubset.rs create mode 100644 src/test/ui/dylibs/auxiliary/aaa_issue_82151_foo_noprefdyn.rs create mode 100644 src/test/ui/dylibs/auxiliary/aaa_issue_82151_foo_prefdyn.rs create mode 100644 src/test/ui/dylibs/auxiliary/aaa_issue_82151_foo_prefdynstd.rs create mode 100644 src/test/ui/dylibs/auxiliary/aaa_issue_82151_foo_prefdynsubset.rs create mode 100644 src/test/ui/dylibs/auxiliary/aaa_issue_82151_shared_noprefdyn.rs create mode 100644 src/test/ui/dylibs/auxiliary/aaa_issue_82151_shared_prefdyn.rs create mode 100644 src/test/ui/dylibs/auxiliary/aaa_issue_82151_shared_prefdynstd.rs create mode 100644 src/test/ui/dylibs/auxiliary/aaa_issue_82151_shared_prefdynsubset.rs create mode 100644 src/test/ui/dylibs/issue-82151-serverctl-noprefdyn.rs create mode 100644 src/test/ui/dylibs/issue-82151-serverctl-noprefdyn.stderr create mode 100644 src/test/ui/dylibs/issue-82151-serverctl-prefdyn.rs create mode 100644 src/test/ui/dylibs/issue-82151-serverctl-prefdyn.stderr create mode 100644 src/test/ui/dylibs/issue-82151-serverctl-prefdynstd.rs create mode 100644 src/test/ui/dylibs/issue-82151-serverctl-prefdynsubset.rs 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/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(); +} From a2231a476d893cb6962e5c7727a9e672e694bac2 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 16 Aug 2021 20:02:40 -0400 Subject: [PATCH 08/10] Variations on the dylibs/diamonds tests inspired by issue 82151. These tests specifically show the effects of having both rlib and dylib library variants present, as well as what happens when you mix in various settings for `-C prefer-dynamic=...`. --- .../ui/dylibs/auxiliary/a_basement_both.rs | 8 ++ src/test/ui/dylibs/auxiliary/i_ground_both.rs | 10 +++ src/test/ui/dylibs/auxiliary/j_ground_both.rs | 10 +++ src/test/ui/dylibs/auxiliary/m_middle_both.rs | 11 +++ src/test/ui/dylibs/auxiliary/s_upper_both.rs | 10 +++ src/test/ui/dylibs/auxiliary/t_upper_both.rs | 10 +++ src/test/ui/dylibs/auxiliary/z_roof_both.rs | 11 +++ src/test/ui/dylibs/diamonds-b-prefdynstd.rs | 12 +++ src/test/ui/dylibs/diamonds-b.rs | 14 ++++ src/test/ui/dylibs/diamonds-b.stderr | 74 +++++++++++++++++++ .../ui/dylibs/diamonds-bbbbbbb-prefdyn-z.rs | 23 ++++++ .../ui/dylibs/diamonds-bbbbbbb-prefdynstd.rs | 23 ++++++ src/test/ui/dylibs/diamonds-d-prefdynstd.rs | 14 ++++ .../ui/dylibs/diamonds-ddddddd-prefdynstd.rs | 27 +++++++ 14 files changed, 257 insertions(+) create mode 100644 src/test/ui/dylibs/auxiliary/a_basement_both.rs create mode 100644 src/test/ui/dylibs/auxiliary/i_ground_both.rs create mode 100644 src/test/ui/dylibs/auxiliary/j_ground_both.rs create mode 100644 src/test/ui/dylibs/auxiliary/m_middle_both.rs create mode 100644 src/test/ui/dylibs/auxiliary/s_upper_both.rs create mode 100644 src/test/ui/dylibs/auxiliary/t_upper_both.rs create mode 100644 src/test/ui/dylibs/auxiliary/z_roof_both.rs create mode 100644 src/test/ui/dylibs/diamonds-b-prefdynstd.rs create mode 100644 src/test/ui/dylibs/diamonds-b.rs create mode 100644 src/test/ui/dylibs/diamonds-b.stderr create mode 100644 src/test/ui/dylibs/diamonds-bbbbbbb-prefdyn-z.rs create mode 100644 src/test/ui/dylibs/diamonds-bbbbbbb-prefdynstd.rs create mode 100644 src/test/ui/dylibs/diamonds-d-prefdynstd.rs create mode 100644 src/test/ui/dylibs/diamonds-ddddddd-prefdynstd.rs 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/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/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/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/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/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/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/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(); +} From 5509ab20e6c521b17f0da8527a8456a90e6baea8 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 18 Aug 2021 09:58:58 -0400 Subject: [PATCH 09/10] Update a comment to reflect the new status quo established in this PR. --- compiler/rustc_metadata/src/dependency_format.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index 2fea8a099df83..a911aab994c5e 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -46,10 +46,10 @@ //! 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; From 21778cba8e73fa28849ad31d0839df3b413947fe Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 19 Aug 2021 12:59:43 -0400 Subject: [PATCH 10/10] run-make test exploring behavior of -C prefer-dynamic. --- .../run-make-fulldeps/dylib-subset/Makefile | 176 ++++++++++++++++++ .../dylib-subset/common_body.rs | 20 ++ src/test/run-make-fulldeps/dylib-subset/m1.rs | 5 + src/test/run-make-fulldeps/dylib-subset/m2.rs | 7 + src/test/run-make-fulldeps/dylib-subset/m3.rs | 7 + src/test/run-make-fulldeps/dylib-subset/m4.rs | 7 + src/test/run-make-fulldeps/dylib-subset/m5.rs | 7 + src/test/run-make-fulldeps/dylib-subset/m6.rs | 11 ++ 8 files changed, 240 insertions(+) create mode 100644 src/test/run-make-fulldeps/dylib-subset/Makefile create mode 100644 src/test/run-make-fulldeps/dylib-subset/common_body.rs create mode 100644 src/test/run-make-fulldeps/dylib-subset/m1.rs create mode 100644 src/test/run-make-fulldeps/dylib-subset/m2.rs create mode 100644 src/test/run-make-fulldeps/dylib-subset/m3.rs create mode 100644 src/test/run-make-fulldeps/dylib-subset/m4.rs create mode 100644 src/test/run-make-fulldeps/dylib-subset/m5.rs create mode 100644 src/test/run-make-fulldeps/dylib-subset/m6.rs 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()); +}