1 use cargo::core::compiler::Lto;
2 use cargo_test_support::registry::Package;
3 use cargo_test_support::{basic_manifest, project, Project};
4 use std::process::Output;
5 
6 #[cargo_test]
with_deps()7 fn with_deps() {
8     Package::new("bar", "0.0.1").publish();
9 
10     let p = project()
11         .file(
12             "Cargo.toml",
13             r#"
14                 [package]
15                 name = "test"
16                 version = "0.0.0"
17 
18                 [dependencies]
19                 bar = "*"
20 
21                 [profile.release]
22                 lto = true
23             "#,
24         )
25         .file("src/main.rs", "extern crate bar; fn main() {}")
26         .build();
27     p.cargo("build -v --release")
28         .with_stderr_contains("[..]`rustc[..]--crate-name bar[..]-C linker-plugin-lto[..]`")
29         .with_stderr_contains("[..]`rustc[..]--crate-name test[..]-C lto[..]`")
30         .run();
31 }
32 
33 #[cargo_test]
shared_deps()34 fn shared_deps() {
35     Package::new("bar", "0.0.1").publish();
36 
37     let p = project()
38         .file(
39             "Cargo.toml",
40             r#"
41                 [package]
42                 name = "test"
43                 version = "0.0.0"
44 
45                 [dependencies]
46                 bar = "*"
47 
48                 [build-dependencies]
49                 bar = "*"
50 
51                 [profile.release]
52                 lto = true
53             "#,
54         )
55         .file("build.rs", "extern crate bar; fn main() {}")
56         .file("src/main.rs", "extern crate bar; fn main() {}")
57         .build();
58     p.cargo("build -v --release")
59         .with_stderr_contains("[..]`rustc[..]--crate-name test[..]-C lto[..]`")
60         .run();
61 }
62 
63 #[cargo_test]
build_dep_not_ltod()64 fn build_dep_not_ltod() {
65     Package::new("bar", "0.0.1").publish();
66 
67     let p = project()
68         .file(
69             "Cargo.toml",
70             r#"
71                 [package]
72                 name = "test"
73                 version = "0.0.0"
74 
75                 [build-dependencies]
76                 bar = "*"
77 
78                 [profile.release]
79                 lto = true
80             "#,
81         )
82         .file("build.rs", "extern crate bar; fn main() {}")
83         .file("src/main.rs", "fn main() {}")
84         .build();
85     p.cargo("build -v --release")
86         .with_stderr_contains("[..]`rustc[..]--crate-name bar[..]-C embed-bitcode=no[..]`")
87         .with_stderr_contains("[..]`rustc[..]--crate-name test[..]-C lto[..]`")
88         .run();
89 }
90 
91 #[cargo_test]
complicated()92 fn complicated() {
93     Package::new("dep-shared", "0.0.1")
94         .file("src/lib.rs", "pub fn foo() {}")
95         .publish();
96     Package::new("dep-normal2", "0.0.1")
97         .file("src/lib.rs", "pub fn foo() {}")
98         .publish();
99     Package::new("dep-normal", "0.0.1")
100         .dep("dep-shared", "*")
101         .dep("dep-normal2", "*")
102         .file(
103             "src/lib.rs",
104             "
105                 pub fn foo() {
106                     dep_shared::foo();
107                     dep_normal2::foo();
108                 }
109             ",
110         )
111         .publish();
112     Package::new("dep-build2", "0.0.1")
113         .file("src/lib.rs", "pub fn foo() {}")
114         .publish();
115     Package::new("dep-build", "0.0.1")
116         .dep("dep-shared", "*")
117         .dep("dep-build2", "*")
118         .file(
119             "src/lib.rs",
120             "
121                 pub fn foo() {
122                     dep_shared::foo();
123                     dep_build2::foo();
124                 }
125             ",
126         )
127         .publish();
128     Package::new("dep-proc-macro2", "0.0.1")
129         .file("src/lib.rs", "pub fn foo() {}")
130         .publish();
131     Package::new("dep-proc-macro", "0.0.1")
132         .proc_macro(true)
133         .dep("dep-shared", "*")
134         .dep("dep-proc-macro2", "*")
135         .file(
136             "src/lib.rs",
137             "
138                 extern crate proc_macro;
139                 use proc_macro::TokenStream;
140 
141                 #[proc_macro_attribute]
142                 pub fn foo(_: TokenStream, a: TokenStream) -> TokenStream {
143                     dep_shared::foo();
144                     dep_proc_macro2::foo();
145                     a
146                 }
147             ",
148         )
149         .publish();
150 
151     let p = project()
152         .file(
153             "Cargo.toml",
154             r#"
155                 [package]
156                 name = "test"
157                 version = "0.0.0"
158 
159                 [lib]
160                 crate-type = ['cdylib', 'staticlib']
161 
162                 [dependencies]
163                 dep-normal = "*"
164                 dep-proc-macro = "*"
165 
166                 [build-dependencies]
167                 dep-build = "*"
168 
169                 [profile.release]
170                 lto = true
171 
172                 # force build deps to share an opt-level with the rest of the
173                 # graph so they only get built once.
174                 [profile.release.build-override]
175                 opt-level = 3
176             "#,
177         )
178         .file("build.rs", "fn main() { dep_build::foo() }")
179         .file(
180             "src/main.rs",
181             "#[dep_proc_macro::foo] fn main() { dep_normal::foo() }",
182         )
183         .file(
184             "src/lib.rs",
185             "#[dep_proc_macro::foo] pub fn foo() { dep_normal::foo() }",
186         )
187         .build();
188     p.cargo("build -v --release")
189         // normal deps and their transitive dependencies do not need object
190         // code, so they should have linker-plugin-lto specified
191         .with_stderr_contains(
192             "[..]`rustc[..]--crate-name dep_normal2 [..]-C linker-plugin-lto[..]`",
193         )
194         .with_stderr_contains("[..]`rustc[..]--crate-name dep_normal [..]-C linker-plugin-lto[..]`")
195         // build dependencies and their transitive deps don't need any bitcode,
196         // so embedding should be turned off
197         .with_stderr_contains("[..]`rustc[..]--crate-name dep_build2 [..]-C embed-bitcode=no[..]`")
198         .with_stderr_contains("[..]`rustc[..]--crate-name dep_build [..]-C embed-bitcode=no[..]`")
199         .with_stderr_contains(
200             "[..]`rustc[..]--crate-name build_script_build [..]-C embed-bitcode=no[..]`",
201         )
202         // proc macro deps are the same as build deps here
203         .with_stderr_contains(
204             "[..]`rustc[..]--crate-name dep_proc_macro2 [..]-C embed-bitcode=no[..]`",
205         )
206         .with_stderr_contains(
207             "[..]`rustc[..]--crate-name dep_proc_macro [..]-C embed-bitcode=no[..]`",
208         )
209         .with_stderr_contains("[..]`rustc[..]--crate-name test [..]--crate-type bin[..]-C lto[..]`")
210         .with_stderr_contains(
211             "[..]`rustc[..]--crate-name test [..]--crate-type cdylib[..]-C lto[..]`",
212         )
213         .with_stderr_contains("[..]`rustc[..]--crate-name dep_shared [..]`")
214         .with_stderr_does_not_contain("[..]--crate-name dep_shared[..]-C lto[..]")
215         .with_stderr_does_not_contain("[..]--crate-name dep_shared[..]-C linker-plugin-lto[..]")
216         .with_stderr_does_not_contain("[..]--crate-name dep_shared[..]-C embed-bitcode[..]")
217         .run();
218 }
219 
220 #[cargo_test]
off_in_manifest_works()221 fn off_in_manifest_works() {
222     Package::new("bar", "0.0.1")
223         .file("src/lib.rs", "pub fn foo() {}")
224         .publish();
225 
226     let p = project()
227         .file(
228             "Cargo.toml",
229             r#"
230                 [package]
231                 name = "test"
232                 version = "0.0.0"
233 
234                 [dependencies]
235                 bar = "*"
236 
237                 [profile.release]
238                 lto = "off"
239             "#,
240         )
241         .file("src/lib.rs", "pub fn foo() {}")
242         .file(
243             "src/main.rs",
244             "fn main() {
245             test::foo();
246             bar::foo();
247         }",
248         )
249         .build();
250     p.cargo("build -v --release")
251         .with_stderr(
252             "\
253 [UPDATING] [..]
254 [DOWNLOADING] [..]
255 [DOWNLOADED] [..]
256 [COMPILING] bar v0.0.1
257 [RUNNING] `rustc --crate-name bar [..]--crate-type lib [..]-C lto=off -C embed-bitcode=no[..]
258 [COMPILING] test [..]
259 [RUNNING] `rustc --crate-name test [..]--crate-type lib [..]-C lto=off -C embed-bitcode=no[..]
260 [RUNNING] `rustc --crate-name test src/main.rs [..]--crate-type bin [..]-C lto=off[..]
261 [FINISHED] [..]
262 ",
263         )
264         .run();
265 }
266 
267 #[cargo_test]
between_builds()268 fn between_builds() {
269     let p = project()
270         .file(
271             "Cargo.toml",
272             r#"
273                 [package]
274                 name = "test"
275                 version = "0.0.0"
276 
277                 [profile.release]
278                 lto = true
279             "#,
280         )
281         .file("src/lib.rs", "pub fn foo() {}")
282         .file("src/main.rs", "fn main() { test::foo() }")
283         .build();
284     p.cargo("build -v --release --lib")
285         .with_stderr(
286             "\
287 [COMPILING] test [..]
288 [RUNNING] `rustc [..]--crate-type lib[..]-C linker-plugin-lto[..]
289 [FINISHED] [..]
290 ",
291         )
292         .run();
293     p.cargo("build -v --release")
294         .with_stderr_contains(
295             "\
296 [COMPILING] test [..]
297 [RUNNING] `rustc [..]--crate-type bin[..]-C lto[..]
298 [FINISHED] [..]
299 ",
300         )
301         .run();
302 }
303 
304 #[cargo_test]
test_all()305 fn test_all() {
306     let p = project()
307         .file(
308             "Cargo.toml",
309             r#"
310                 [package]
311                 name = "foo"
312                 version = "0.0.0"
313 
314                 [profile.release]
315                 lto = true
316             "#,
317         )
318         .file("src/main.rs", "fn main() {}")
319         .file("tests/a.rs", "")
320         .file("tests/b.rs", "")
321         .build();
322     p.cargo("test --release -v")
323         .with_stderr_contains("[RUNNING] `rustc[..]--crate-name foo[..]-C lto[..]")
324         .run();
325 }
326 
327 #[cargo_test]
test_all_and_bench()328 fn test_all_and_bench() {
329     let p = project()
330         .file(
331             "Cargo.toml",
332             r#"
333                 [package]
334                 name = "foo"
335                 version = "0.0.0"
336 
337                 [profile.release]
338                 lto = true
339                 [profile.bench]
340                 lto = true
341             "#,
342         )
343         .file("src/main.rs", "fn main() {}")
344         .file("tests/a.rs", "")
345         .file("tests/b.rs", "")
346         .build();
347     p.cargo("test --release -v")
348         .with_stderr_contains("[RUNNING] `rustc[..]--crate-name a[..]-C lto[..]")
349         .with_stderr_contains("[RUNNING] `rustc[..]--crate-name b[..]-C lto[..]")
350         .with_stderr_contains("[RUNNING] `rustc[..]--crate-name foo[..]-C lto[..]")
351         .run();
352 }
353 
354 /// Basic setup:
355 ///
356 /// foo v0.0.0
357 /// ├── bar v0.0.0
358 /// │   ├── registry v0.0.1
359 /// │   └── registry-shared v0.0.1
360 /// └── registry-shared v0.0.1
361 ///
362 /// Where `bar` will have the given crate types.
project_with_dep(crate_types: &str) -> Project363 fn project_with_dep(crate_types: &str) -> Project {
364     Package::new("registry", "0.0.1")
365         .file("src/lib.rs", r#"pub fn foo() { println!("registry"); }"#)
366         .publish();
367     Package::new("registry-shared", "0.0.1")
368         .file("src/lib.rs", r#"pub fn foo() { println!("shared"); }"#)
369         .publish();
370 
371     project()
372         .file(
373             "Cargo.toml",
374             r#"
375                 [package]
376                 name = "foo"
377                 version = "0.0.0"
378 
379                 [workspace]
380 
381                 [dependencies]
382                 bar = { path = 'bar' }
383                 registry-shared = "*"
384 
385                 [profile.release]
386                 lto = true
387             "#,
388         )
389         .file(
390             "src/main.rs",
391             "
392                 fn main() {
393                     bar::foo();
394                     registry_shared::foo();
395                 }
396             ",
397         )
398         .file(
399             "bar/Cargo.toml",
400             &format!(
401                 r#"
402                     [package]
403                     name = "bar"
404                     version = "0.0.0"
405 
406                     [dependencies]
407                     registry = "*"
408                     registry-shared = "*"
409 
410                     [lib]
411                     crate-type = [{}]
412                 "#,
413                 crate_types
414             ),
415         )
416         .file(
417             "bar/src/lib.rs",
418             r#"
419                 pub fn foo() {
420                     println!("bar");
421                     registry::foo();
422                     registry_shared::foo();
423                 }
424             "#,
425         )
426         .file("tests/a.rs", "")
427         .file("bar/tests/b.rs", "")
428         .build()
429 }
430 
431 /// Helper for checking which LTO behavior is used for a specific crate.
432 ///
433 /// `krate_info` is extra compiler flags used to distinguish this if the same
434 /// crate name is being built multiple times.
verify_lto(output: &Output, krate: &str, krate_info: &str, expected_lto: Lto)435 fn verify_lto(output: &Output, krate: &str, krate_info: &str, expected_lto: Lto) {
436     let stderr = std::str::from_utf8(&output.stderr).unwrap();
437     let mut matches = stderr.lines().filter(|line| {
438         line.contains("Running")
439             && line.contains(&format!("--crate-name {} ", krate))
440             && line.contains(krate_info)
441     });
442     let line = matches.next().unwrap_or_else(|| {
443         panic!(
444             "expected to find crate `{}` info: `{}`, not found in output:\n{}",
445             krate, krate_info, stderr
446         );
447     });
448     if let Some(line2) = matches.next() {
449         panic!(
450             "found multiple lines matching crate `{}` info: `{}`:\nline1:{}\nline2:{}\noutput:\n{}",
451             krate, krate_info, line, line2, stderr
452         );
453     }
454     let actual_lto = if let Some(index) = line.find("-C lto=") {
455         let s = &line[index..];
456         let end = s.find(' ').unwrap();
457         let mode = &line[index..index + end];
458         if mode == "off" {
459             Lto::Off
460         } else {
461             Lto::Run(Some(mode.into()))
462         }
463     } else if line.contains("-C lto") {
464         Lto::Run(None)
465     } else if line.contains("-C linker-plugin-lto") {
466         Lto::OnlyBitcode
467     } else if line.contains("-C embed-bitcode=no") {
468         Lto::OnlyObject
469     } else {
470         Lto::ObjectAndBitcode
471     };
472     assert_eq!(
473         actual_lto, expected_lto,
474         "did not find expected LTO in line: {}",
475         line
476     );
477 }
478 
479 #[cargo_test]
cdylib_and_rlib()480 fn cdylib_and_rlib() {
481     let p = project_with_dep("'cdylib', 'rlib'");
482     let output = p.cargo("build --release -v").exec_with_output().unwrap();
483     // `registry` is ObjectAndBitcode because because it needs Object for the
484     // rlib, and Bitcode for the cdylib (which doesn't support LTO).
485     verify_lto(
486         &output,
487         "registry",
488         "--crate-type lib",
489         Lto::ObjectAndBitcode,
490     );
491     // Same as `registry`
492     verify_lto(
493         &output,
494         "registry_shared",
495         "--crate-type lib",
496         Lto::ObjectAndBitcode,
497     );
498     // Same as `registry`
499     verify_lto(
500         &output,
501         "bar",
502         "--crate-type cdylib --crate-type rlib",
503         Lto::ObjectAndBitcode,
504     );
505     verify_lto(&output, "foo", "--crate-type bin", Lto::Run(None));
506     p.cargo("test --release -v")
507         .with_stderr_unordered(
508             "\
509 [FRESH] registry v0.0.1
510 [FRESH] registry-shared v0.0.1
511 [FRESH] bar v0.0.0 [..]
512 [COMPILING] foo [..]
513 [RUNNING] `rustc --crate-name foo [..]-C lto [..]--test[..]
514 [RUNNING] `rustc --crate-name a [..]-C lto [..]--test[..]
515 [FINISHED] [..]
516 [RUNNING] [..]
517 [RUNNING] [..]
518 ",
519         )
520         .run();
521     p.cargo("build --release -v --manifest-path bar/Cargo.toml")
522         .with_stderr_unordered(
523             "\
524 [FRESH] registry-shared v0.0.1
525 [FRESH] registry v0.0.1
526 [FRESH] bar v0.0.0 [..]
527 [FINISHED] [..]
528 ",
529         )
530         .run();
531     p.cargo("test --release -v --manifest-path bar/Cargo.toml")
532         .with_stderr_unordered(
533             "\
534 [FRESH] registry-shared v0.0.1
535 [FRESH] registry v0.0.1
536 [COMPILING] bar [..]
537 [RUNNING] `rustc --crate-name bar [..]-C lto[..]--test[..]
538 [RUNNING] `rustc --crate-name b [..]-C lto[..]--test[..]
539 [FINISHED] [..]
540 [RUNNING] [..]target/release/deps/bar-[..]
541 [RUNNING] [..]target/release/deps/b-[..]
542 [DOCTEST] bar
543 [RUNNING] `rustdoc --crate-type cdylib --crate-type rlib --crate-name bar --test [..]-C lto[..]
544 ",
545         )
546         .run();
547 }
548 
549 #[cargo_test]
dylib()550 fn dylib() {
551     let p = project_with_dep("'dylib'");
552     let output = p.cargo("build --release -v").exec_with_output().unwrap();
553     // `registry` is OnlyObject because rustc doesn't support LTO with dylibs.
554     verify_lto(&output, "registry", "--crate-type lib", Lto::OnlyObject);
555     // `registry_shared` is both because it is needed by both bar (Object) and
556     // foo (Bitcode for LTO).
557     verify_lto(
558         &output,
559         "registry_shared",
560         "--crate-type lib",
561         Lto::ObjectAndBitcode,
562     );
563     // `bar` is OnlyObject because rustc doesn't support LTO with dylibs.
564     verify_lto(&output, "bar", "--crate-type dylib", Lto::OnlyObject);
565     // `foo` is LTO because it is a binary, and the profile specifies `lto=true`.
566     verify_lto(&output, "foo", "--crate-type bin", Lto::Run(None));
567     // `cargo test` should not rebuild dependencies. It builds the test
568     // executables with `lto=true` because the tests are built with the
569     // `--release` flag.
570     p.cargo("test --release -v")
571         .with_stderr_unordered(
572             "\
573 [FRESH] registry v0.0.1
574 [FRESH] registry-shared v0.0.1
575 [FRESH] bar v0.0.0 [..]
576 [COMPILING] foo [..]
577 [RUNNING] `rustc --crate-name foo [..]-C lto [..]--test[..]
578 [RUNNING] `rustc --crate-name a [..]-C lto [..]--test[..]
579 [FINISHED] [..]
580 [RUNNING] [..]
581 [RUNNING] [..]
582 ",
583         )
584         .run();
585     // Building just `bar` causes `registry-shared` to get rebuilt because it
586     // switches to OnlyObject because it is now only being used with a dylib
587     // which does not support LTO.
588     //
589     // `bar` gets rebuilt because `registry_shared` got rebuilt.
590     p.cargo("build --release -v --manifest-path bar/Cargo.toml")
591         .with_stderr_unordered(
592             "\
593 [COMPILING] registry-shared v0.0.1
594 [FRESH] registry v0.0.1
595 [RUNNING] `rustc --crate-name registry_shared [..]-C embed-bitcode=no[..]
596 [COMPILING] bar [..]
597 [RUNNING] `rustc --crate-name bar [..]--crate-type dylib [..]-C embed-bitcode=no[..]
598 [FINISHED] [..]
599 ",
600         )
601         .run();
602     // Testing just `bar` causes `registry` to get rebuilt because it switches
603     // to needing both Object (for the `bar` dylib) and Bitcode (for the test
604     // built with LTO).
605     //
606     // `bar` the dylib gets rebuilt because `registry` got rebuilt.
607     p.cargo("test --release -v --manifest-path bar/Cargo.toml")
608         .with_stderr_unordered(
609             "\
610 [FRESH] registry-shared v0.0.1
611 [COMPILING] registry v0.0.1
612 [RUNNING] `rustc --crate-name registry [..]
613 [COMPILING] bar [..]
614 [RUNNING] `rustc --crate-name bar [..]--crate-type dylib [..]-C embed-bitcode=no[..]
615 [RUNNING] `rustc --crate-name bar [..]-C lto [..]--test[..]
616 [RUNNING] `rustc --crate-name b [..]-C lto [..]--test[..]
617 [FINISHED] [..]
618 [RUNNING] [..]
619 [RUNNING] [..]
620 ",
621         )
622         .run();
623 }
624 
625 #[cargo_test]
test_profile()626 fn test_profile() {
627     Package::new("bar", "0.0.1")
628         .file("src/lib.rs", "pub fn foo() -> i32 { 123 } ")
629         .publish();
630 
631     let p = project()
632         .file(
633             "Cargo.toml",
634             r#"
635                 [package]
636                 name = "foo"
637                 version = "0.1.0"
638                 edition = "2018"
639 
640                 [profile.test]
641                 lto = 'thin'
642 
643                 [dependencies]
644                 bar = "*"
645             "#,
646         )
647         .file(
648             "src/lib.rs",
649             r#"
650                 #[test]
651                 fn t1() {
652                     assert_eq!(123, bar::foo());
653                 }
654             "#,
655         )
656         .build();
657 
658     p.cargo("test -v")
659         // unordered because the two `foo` builds start in parallel
660         .with_stderr_unordered("\
661 [UPDATING] [..]
662 [DOWNLOADING] [..]
663 [DOWNLOADED] [..]
664 [COMPILING] bar v0.0.1
665 [RUNNING] `rustc --crate-name bar [..]crate-type lib[..]
666 [COMPILING] foo [..]
667 [RUNNING] `rustc --crate-name foo [..]--crate-type lib --emit=dep-info,metadata,link -C linker-plugin-lto[..]
668 [RUNNING] `rustc --crate-name foo [..]--emit=dep-info,link -C lto=thin [..]--test[..]
669 [FINISHED] [..]
670 [RUNNING] [..]
671 [DOCTEST] foo
672 [RUNNING] `rustdoc [..]
673 ")
674         .run();
675 }
676 
677 #[cargo_test]
doctest()678 fn doctest() {
679     let p = project()
680         .file(
681             "Cargo.toml",
682             r#"
683                 [package]
684                 name = "foo"
685                 version = "0.1.0"
686                 edition = "2018"
687 
688                 [profile.release]
689                 lto = true
690 
691                 [dependencies]
692                 bar = { path = "bar" }
693             "#,
694         )
695         .file(
696             "src/lib.rs",
697             r#"
698                 /// Foo!
699                 ///
700                 /// ```
701                 /// foo::foo();
702                 /// ```
703                 pub fn foo() { bar::bar(); }
704             "#,
705         )
706         .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
707         .file(
708             "bar/src/lib.rs",
709             r#"
710                 pub fn bar() { println!("hi!"); }
711             "#,
712         )
713         .build();
714 
715     p.cargo("test --doc --release -v")
716         .with_stderr_contains("[..]`rustc --crate-name bar[..]-C linker-plugin-lto[..]")
717         .with_stderr_contains("[..]`rustc --crate-name foo[..]-C linker-plugin-lto[..]")
718         // embed-bitcode should be harmless here
719         .with_stderr_contains("[..]`rustdoc [..]-C lto[..]")
720         .run();
721 
722     // Try with bench profile.
723     p.cargo("test --doc --release -v")
724         .env("CARGO_PROFILE_BENCH_LTO", "true")
725         .with_stderr_unordered(
726             "\
727 [FRESH] bar v0.1.0 [..]
728 [FRESH] foo v0.1.0 [..]
729 [FINISHED] release [..]
730 [DOCTEST] foo
731 [RUNNING] `rustdoc [..]-C lto[..]
732 ",
733         )
734         .run();
735 }
736 
737 #[cargo_test]
dylib_rlib_bin()738 fn dylib_rlib_bin() {
739     // dylib+rlib linked with a binary
740     let p = project()
741         .file(
742             "Cargo.toml",
743             r#"
744                 [package]
745                 name = "foo"
746                 version = "0.1.0"
747 
748                 [lib]
749                 crate-type = ["dylib", "rlib"]
750 
751                 [profile.release]
752                 lto = true
753             "#,
754         )
755         .file("src/lib.rs", "pub fn foo() { println!(\"hi!\"); }")
756         .file("src/main.rs", "fn main() { foo::foo(); }")
757         .build();
758 
759     let output = p.cargo("build --release -v").exec_with_output().unwrap();
760     verify_lto(
761         &output,
762         "foo",
763         "--crate-type dylib --crate-type rlib",
764         Lto::ObjectAndBitcode,
765     );
766     verify_lto(&output, "foo", "--crate-type bin", Lto::Run(None));
767 }
768 
769 #[cargo_test]
fresh_swapping_commands()770 fn fresh_swapping_commands() {
771     // In some rare cases, different commands end up building dependencies
772     // with different LTO settings. This checks that it doesn't cause the
773     // cache to thrash in that scenario.
774     Package::new("bar", "1.0.0").publish();
775 
776     let p = project()
777         .file(
778             "Cargo.toml",
779             r#"
780                 [package]
781                 name = "foo"
782                 version = "0.1.0"
783 
784                 [dependencies]
785                 bar = "1.0"
786 
787                 [profile.release]
788                 lto = true
789             "#,
790         )
791         .file("src/lib.rs", "pub fn foo() { println!(\"hi!\"); }")
792         .build();
793 
794     p.cargo("build --release -v")
795         .with_stderr(
796             "\
797 [UPDATING] [..]
798 [DOWNLOADING] crates ...
799 [DOWNLOADED] bar v1.0.0 [..]
800 [COMPILING] bar v1.0.0
801 [RUNNING] `rustc --crate-name bar [..]-C linker-plugin-lto[..]
802 [COMPILING] foo v0.1.0 [..]
803 [RUNNING] `rustc --crate-name foo src/lib.rs [..]-C linker-plugin-lto[..]
804 [FINISHED] [..]
805 ",
806         )
807         .run();
808     p.cargo("test --release -v")
809         .with_stderr_unordered(
810             "\
811 [FRESH] bar v1.0.0
812 [COMPILING] foo v0.1.0 [..]
813 [RUNNING] `rustc --crate-name foo src/lib.rs [..]-C lto[..]--test[..]
814 [FINISHED] [..]
815 [RUNNING] `[..]/foo[..]`
816 [DOCTEST] foo
817 [RUNNING] `rustdoc [..]-C lto[..]
818 ",
819         )
820         .run();
821 
822     p.cargo("build --release -v")
823         .with_stderr(
824             "\
825 [FRESH] bar v1.0.0
826 [FRESH] foo [..]
827 [FINISHED] [..]
828 ",
829         )
830         .run();
831     p.cargo("test --release -v --no-run -v")
832         .with_stderr(
833             "\
834 [FRESH] bar v1.0.0
835 [FRESH] foo [..]
836 [FINISHED] [..]
837 ",
838         )
839         .run();
840 }
841