Allow configuration of LTO in [profile]
authorAlex Crichton <alex@alexcrichton.com>
Fri, 26 Jan 2018 22:26:13 +0000 (14:26 -0800)
committerAlex Crichton <alex@alexcrichton.com>
Fri, 26 Jan 2018 22:27:36 +0000 (14:27 -0800)
This should help give access to ThinLTO when desired!

src/cargo/core/manifest.rs
src/cargo/ops/cargo_rustc/mod.rs
src/cargo/util/toml/mod.rs
tests/path.rs

index ad85eb0b7f4b7f06d35847e8240d61650e770ad1..5ba9419e4678d2ef61410dc4f1ac86357d827eab 100644 (file)
@@ -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<u32>,    // 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,
index ea9294fd06ba14e3a18a2365b3314a091b85cfd4..7a413194e206edf7fd77bfcce24dcaaeade77756 100644 (file)
@@ -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));
index f73790941d2441d06299423436f1d74c038bd515..a088598e9ba43b8cf8e3c5e1e6bf9f94bd20b635 100644 (file)
@@ -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<TomlOptLevel>,
-    lto: Option<bool>,
+    lto: Option<StringOrBool>,
     #[serde(rename = "codegen-units")]
     codegen_units: Option<u32>,
     debug: Option<U32OrBool>,
@@ -1150,7 +1150,7 @@ fn build_profiles(profiles: &Option<TomlProfiles>) -> 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<TomlProfiles>) -> 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,
index 0e6fd337333c88394c08fd126eff41f0bc28f2fb..4936aee17ae85b544aa6d2a4847d7e2f6abbc94e 100644 (file)
@@ -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] [..]
+"));
+}