From 779041cd5a27c7b775c9ed45948a1343a3f25f04 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 2 Sep 2017 18:15:57 -0500 Subject: [PATCH 1/2] Require rlibs for dependent crates when linking static executables This handles the case for `CrateTypeExecutable` and `+crt_static`. I reworked the match block to avoid duplicating the `attempt_static` and error checking code again (this case would have been a copy of the `CrateTypeCdylib`/`CrateTypeStaticlib` case). On `linux-musl` targets where `std` was built with `crt_static = false` in `config.toml`, this change brings the test suite from entirely failing to mostly passing. This change should not affect behavior for other crate types, or for targets which do not respect `+crt_static`. --- src/librustc/middle/dependency_format.rs | 74 +++++++++++++----------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index 1c7d0b76a64..41fcce27bc5 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -112,26 +112,51 @@ fn calculate_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return Vec::new(); } - match ty { - // If the global prefer_dynamic switch is turned off, first attempt - // static linkage (this can fail). - config::CrateTypeExecutable if !sess.opts.cg.prefer_dynamic => { - if let Some(v) = attempt_static(tcx) { - return v; - } - } + let preferred_linkage = match ty { + // cdylibs must have all static dependencies. + config::CrateTypeCdylib => Linkage::Static, + + // 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. + config::CrateTypeDylib if !sess.opts.cg.prefer_dynamic => Linkage::Static, + config::CrateTypeDylib => Linkage::Dynamic, + + // If the global prefer_dynamic switch is turned off, or the final + // executable will be statically linked, prefer static crate linkage. + config::CrateTypeExecutable if !sess.opts.cg.prefer_dynamic || + sess.crt_static() => Linkage::Static, + config::CrateTypeExecutable => Linkage::Dynamic, + + // proc-macro crates are required to be dylibs, and they're currently + // required to link to libsyntax as well. + config::CrateTypeProcMacro => Linkage::Dynamic, // No linkage happens with rlibs, we just needed the metadata (which we // got long ago), so don't bother with anything. - config::CrateTypeRlib => return Vec::new(), + config::CrateTypeRlib => Linkage::NotLinked, - // Staticlibs and cdylibs must have all static dependencies. If any fail - // to be found, we generate some nice pretty errors. - config::CrateTypeStaticlib | - config::CrateTypeCdylib => { - if let Some(v) = attempt_static(tcx) { - return v; - } + // staticlibs must have all static dependencies. + config::CrateTypeStaticlib => Linkage::Static, + }; + + if preferred_linkage == Linkage::NotLinked { + // If the crate is not linked, there are no link-time dependencies. + return Vec::new(); + } + + if preferred_linkage == Linkage::Static { + // Attempt static linkage first. For dylibs and executables, we may be + // able to retry below with dynamic linkage. + if let Some(v) = attempt_static(tcx) { + return v; + } + + // Staticlibs, cdylibs, and static executables must have all static + // dependencies. If any are not found, generate some nice pretty errors. + if ty == config::CrateTypeCdylib || ty == config::CrateTypeStaticlib || + (ty == config::CrateTypeExecutable && sess.crt_static() && + !sess.target.target.options.crt_static_allows_dylibs) { for &cnum in tcx.crates().iter() { if tcx.dep_kind(cnum).macros_only() { continue } let src = tcx.used_crate_source(cnum); @@ -141,23 +166,6 @@ fn calculate_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } return Vec::new(); } - - // 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. - config::CrateTypeDylib if !sess.opts.cg.prefer_dynamic => { - if let Some(v) = attempt_static(tcx) { - return v; - } - } - - // Everything else falls through below. This will happen either with the - // `-C prefer-dynamic` or because we're a proc-macro crate. Note that - // proc-macro crates are required to be dylibs, and they're currently - // required to link to libsyntax as well. - config::CrateTypeExecutable | - config::CrateTypeDylib | - config::CrateTypeProcMacro => {}, } let mut formats = FxHashMap(); From 314c2b14479a98acf9155dce43348e77073a09a1 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Thu, 14 Sep 2017 23:42:21 -0500 Subject: [PATCH 2/2] Adjust dependency-resolution errors to be more consistent --- src/librustc/middle/dependency_format.rs | 10 +++++----- src/test/compile-fail/cdylib-deps-must-be-static.rs | 2 +- src/test/compile-fail/rmeta_lib.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index 41fcce27bc5..db0ecb6aa5e 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -161,7 +161,8 @@ fn calculate_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if tcx.dep_kind(cnum).macros_only() { continue } let src = tcx.used_crate_source(cnum); if src.rlib.is_some() { continue } - sess.err(&format!("dependency `{}` not found in rlib format", + sess.err(&format!("crate `{}` required to be available in rlib format, \ + but was not found in this form", tcx.crate_name(cnum))); } return Vec::new(); @@ -244,10 +245,9 @@ fn calculate_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Linkage::Static => "rlib", _ => "dylib", }; - let name = tcx.crate_name(cnum); - sess.err(&format!("crate `{}` required to be available in {}, \ - but it was not available in this form", - name, kind)); + sess.err(&format!("crate `{}` required to be available in {} format, \ + but was not found in this form", + tcx.crate_name(cnum), kind)); } } } diff --git a/src/test/compile-fail/cdylib-deps-must-be-static.rs b/src/test/compile-fail/cdylib-deps-must-be-static.rs index 853507cbc6d..bf7189c21fb 100644 --- a/src/test/compile-fail/cdylib-deps-must-be-static.rs +++ b/src/test/compile-fail/cdylib-deps-must-be-static.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: dependency `cdylib_dep` not found in rlib format +// error-pattern: crate `cdylib_dep` required to be available in rlib format, but was not found // aux-build:cdylib-dep.rs // ignore-musl // ignore-emscripten diff --git a/src/test/compile-fail/rmeta_lib.rs b/src/test/compile-fail/rmeta_lib.rs index 3b7d1f3cc90..a61ff05e8c8 100644 --- a/src/test/compile-fail/rmeta_lib.rs +++ b/src/test/compile-fail/rmeta_lib.rs @@ -10,7 +10,7 @@ // aux-build:rmeta_meta.rs // no-prefer-dynamic -// error-pattern: crate `rmeta_meta` required to be available in rlib, but it was not available +// error-pattern: crate `rmeta_meta` required to be available in rlib format, but was not found // Check that building a non-metadata crate fails if a dependent crate is // metadata-only.