From f52f4896029b6fc828f6ca3795192f01cc8192e3 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 26 Jan 2018 14:26:13 -0800 Subject: [PATCH] Allow configuration of LTO in [profile] This should help give access to ThinLTO when desired! --- src/cargo/core/manifest.rs | 10 ++++++++-- src/cargo/ops/cargo_rustc/mod.rs | 19 +++++++++++++++---- src/cargo/util/toml/mod.rs | 12 ++++++++---- tests/path.rs | 26 ++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 10 deletions(-) diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index ad85eb0b7..5ba9419e4 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -156,7 +156,7 @@ impl ser::Serialize for TargetKind { pub struct Profile { pub opt_level: String, #[serde(skip_serializing)] - pub lto: bool, + pub lto: Lto, #[serde(skip_serializing)] pub codegen_units: Option, // None = use rustc default #[serde(skip_serializing)] @@ -181,6 +181,12 @@ pub struct Profile { pub incremental: bool, } +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub enum Lto { + Bool(bool), + Named(String), +} + #[derive(Default, Clone, Debug, PartialEq, Eq)] pub struct Profiles { pub release: Profile, @@ -702,7 +708,7 @@ impl Default for Profile { fn default() -> Profile { Profile { opt_level: "0".to_string(), - lto: false, + lto: Lto::Bool(false), codegen_units: None, rustc_args: None, rustdoc_args: None, diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index ea9294fd0..7a413194e 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -11,6 +11,7 @@ use serde_json; use core::{Package, PackageId, PackageSet, Target, Resolve}; use core::{Profile, Profiles, Workspace}; +use core::manifest::Lto; use core::shell::ColorChoice; use util::{self, ProcessBuilder, machine_message}; use util::{Config, internal, profile, join_paths}; @@ -744,7 +745,7 @@ fn build_base_args<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>, crate_types: &[&str]) -> CargoResult<()> { let Profile { - ref opt_level, lto, codegen_units, ref rustc_args, debuginfo, + ref opt_level, ref lto, codegen_units, ref rustc_args, debuginfo, debug_assertions, overflow_checks, rpath, test, doc: _doc, run_custom_build, ref panic, rustdoc_args: _, check, incremental: _, } = *unit.profile; @@ -806,9 +807,19 @@ fn build_base_args<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, // Disable LTO for host builds as prefer_dynamic and it are mutually // exclusive. - if unit.target.can_lto() && lto && !unit.target.for_host() { - cmd.args(&["-C", "lto"]); - } else if let Some(n) = codegen_units { + if unit.target.can_lto() && !unit.target.for_host() { + match *lto { + Lto::Bool(false) => {} + Lto::Bool(true) => { + cmd.args(&["-C", "lto"]); + } + Lto::Named(ref s) => { + cmd.arg("-C").arg(format!("lto={}", s)); + } + } + } + + if let Some(n) = codegen_units { // There are some restrictions with LTO and codegen-units, so we // only add codegen units when LTO is not used. cmd.arg("-C").arg(&format!("codegen-units={}", n)); diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index f73790941..a088598e9 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -16,7 +16,7 @@ use core::{SourceId, Profiles, PackageIdSpec, GitReference, WorkspaceConfig, Wor use core::{Summary, Manifest, Target, Dependency, PackageId}; use core::{EitherManifest, VirtualManifest, Features, Feature}; use core::dependency::{Kind, Platform}; -use core::manifest::{LibKind, Profile, ManifestMetadata}; +use core::manifest::{LibKind, Profile, ManifestMetadata, Lto}; use sources::CRATES_IO; use util::paths; use util::{self, ToUrl, Config}; @@ -327,7 +327,7 @@ impl<'de> de::Deserialize<'de> for U32OrBool { pub struct TomlProfile { #[serde(rename = "opt-level")] opt_level: Option, - lto: Option, + lto: Option, #[serde(rename = "codegen-units")] codegen_units: Option, debug: Option, @@ -1150,7 +1150,7 @@ fn build_profiles(profiles: &Option) -> Profiles { fn merge(profile: Profile, toml: Option<&TomlProfile>) -> Profile { let &TomlProfile { - ref opt_level, lto, codegen_units, ref debug, debug_assertions, rpath, + ref opt_level, ref lto, codegen_units, ref debug, debug_assertions, rpath, ref panic, ref overflow_checks, ref incremental, } = match toml { Some(toml) => toml, @@ -1164,7 +1164,11 @@ fn build_profiles(profiles: &Option) -> Profiles { }; Profile { opt_level: opt_level.clone().unwrap_or(TomlOptLevel(profile.opt_level)).0, - lto: lto.unwrap_or(profile.lto), + lto: match *lto { + Some(StringOrBool::Bool(b)) => Lto::Bool(b), + Some(StringOrBool::String(ref n)) => Lto::Named(n.clone()), + None => profile.lto, + }, codegen_units: codegen_units, rustc_args: None, rustdoc_args: None, diff --git a/tests/path.rs b/tests/path.rs index 0e6fd3373..4936aee17 100644 --- a/tests/path.rs +++ b/tests/path.rs @@ -986,3 +986,29 @@ fn workspace_produces_rlib() { assert_that(&p.root().join("target/debug/libfoo.rlib"), existing_file()); } + +#[test] +fn thin_lto_works() { + if !cargotest::is_nightly() { + return + } + let p = project("foo") + .file("Cargo.toml", r#" + [project] + name = "top" + version = "0.5.0" + authors = [] + + [profile.release] + lto = 'thin' + "#) + .file("src/main.rs", "fn main() {}") + .build(); + + assert_that(p.cargo("build").arg("--release").arg("-v"), + execs().with_stderr("\ +[COMPILING] top [..] +[RUNNING] `rustc [..] -C lto=thin [..]` +[FINISHED] [..] +")); +} -- 2.39.5