xref: /aosp_15_r20/build/soong/cc/lto_test.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2021 Google Inc. All rights reserved.
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Workerpackage cc
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Workerimport (
18*333d2b36SAndroid Build Coastguard Worker	"strings"
19*333d2b36SAndroid Build Coastguard Worker	"testing"
20*333d2b36SAndroid Build Coastguard Worker
21*333d2b36SAndroid Build Coastguard Worker	"android/soong/android"
22*333d2b36SAndroid Build Coastguard Worker
23*333d2b36SAndroid Build Coastguard Worker	"github.com/google/blueprint"
24*333d2b36SAndroid Build Coastguard Worker)
25*333d2b36SAndroid Build Coastguard Worker
26*333d2b36SAndroid Build Coastguard Workervar LTOPreparer = android.GroupFixturePreparers(
27*333d2b36SAndroid Build Coastguard Worker	prepareForCcTest,
28*333d2b36SAndroid Build Coastguard Worker)
29*333d2b36SAndroid Build Coastguard Worker
30*333d2b36SAndroid Build Coastguard Workerfunc hasDep(result *android.TestResult, m android.Module, wantDep android.Module) bool {
31*333d2b36SAndroid Build Coastguard Worker	var found bool
32*333d2b36SAndroid Build Coastguard Worker	result.VisitDirectDeps(m, func(dep blueprint.Module) {
33*333d2b36SAndroid Build Coastguard Worker		if dep == wantDep {
34*333d2b36SAndroid Build Coastguard Worker			found = true
35*333d2b36SAndroid Build Coastguard Worker		}
36*333d2b36SAndroid Build Coastguard Worker	})
37*333d2b36SAndroid Build Coastguard Worker	return found
38*333d2b36SAndroid Build Coastguard Worker}
39*333d2b36SAndroid Build Coastguard Worker
40*333d2b36SAndroid Build Coastguard Workerfunc TestThinLtoDeps(t *testing.T) {
41*333d2b36SAndroid Build Coastguard Worker	t.Parallel()
42*333d2b36SAndroid Build Coastguard Worker	bp := `
43*333d2b36SAndroid Build Coastguard Worker	cc_library_shared {
44*333d2b36SAndroid Build Coastguard Worker		name: "lto_enabled",
45*333d2b36SAndroid Build Coastguard Worker		srcs: ["src.c"],
46*333d2b36SAndroid Build Coastguard Worker		static_libs: ["foo", "lib_never_lto"],
47*333d2b36SAndroid Build Coastguard Worker		shared_libs: ["bar"],
48*333d2b36SAndroid Build Coastguard Worker	}
49*333d2b36SAndroid Build Coastguard Worker	cc_library_static {
50*333d2b36SAndroid Build Coastguard Worker		name: "foo",
51*333d2b36SAndroid Build Coastguard Worker		static_libs: ["baz"],
52*333d2b36SAndroid Build Coastguard Worker	}
53*333d2b36SAndroid Build Coastguard Worker	cc_library_shared {
54*333d2b36SAndroid Build Coastguard Worker		name: "bar",
55*333d2b36SAndroid Build Coastguard Worker		static_libs: ["qux"],
56*333d2b36SAndroid Build Coastguard Worker	}
57*333d2b36SAndroid Build Coastguard Worker	cc_library_static {
58*333d2b36SAndroid Build Coastguard Worker		name: "baz",
59*333d2b36SAndroid Build Coastguard Worker	}
60*333d2b36SAndroid Build Coastguard Worker	cc_library_static {
61*333d2b36SAndroid Build Coastguard Worker		name: "qux",
62*333d2b36SAndroid Build Coastguard Worker	}
63*333d2b36SAndroid Build Coastguard Worker	cc_library_static {
64*333d2b36SAndroid Build Coastguard Worker		name: "lib_never_lto",
65*333d2b36SAndroid Build Coastguard Worker		lto: {
66*333d2b36SAndroid Build Coastguard Worker			never: true,
67*333d2b36SAndroid Build Coastguard Worker		},
68*333d2b36SAndroid Build Coastguard Worker	}
69*333d2b36SAndroid Build Coastguard Worker`
70*333d2b36SAndroid Build Coastguard Worker
71*333d2b36SAndroid Build Coastguard Worker	result := LTOPreparer.RunTestWithBp(t, bp)
72*333d2b36SAndroid Build Coastguard Worker
73*333d2b36SAndroid Build Coastguard Worker	libLto := result.ModuleForTests("lto_enabled", "android_arm64_armv8-a_shared").Module()
74*333d2b36SAndroid Build Coastguard Worker
75*333d2b36SAndroid Build Coastguard Worker	libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static").Module()
76*333d2b36SAndroid Build Coastguard Worker	if !hasDep(result, libLto, libFoo) {
77*333d2b36SAndroid Build Coastguard Worker		t.Errorf("'lto_enabled' missing dependency on the default variant of 'foo'")
78*333d2b36SAndroid Build Coastguard Worker	}
79*333d2b36SAndroid Build Coastguard Worker
80*333d2b36SAndroid Build Coastguard Worker	libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static").Module()
81*333d2b36SAndroid Build Coastguard Worker	if !hasDep(result, libFoo, libBaz) {
82*333d2b36SAndroid Build Coastguard Worker		t.Errorf("'foo' missing dependency on the default variant of transitive dep 'baz'")
83*333d2b36SAndroid Build Coastguard Worker	}
84*333d2b36SAndroid Build Coastguard Worker
85*333d2b36SAndroid Build Coastguard Worker	libNeverLto := result.ModuleForTests("lib_never_lto", "android_arm64_armv8-a_static").Module()
86*333d2b36SAndroid Build Coastguard Worker	if !hasDep(result, libLto, libNeverLto) {
87*333d2b36SAndroid Build Coastguard Worker		t.Errorf("'lto_enabled' missing dependency on the default variant of 'lib_never_lto'")
88*333d2b36SAndroid Build Coastguard Worker	}
89*333d2b36SAndroid Build Coastguard Worker
90*333d2b36SAndroid Build Coastguard Worker	libBar := result.ModuleForTests("bar", "android_arm64_armv8-a_shared").Module()
91*333d2b36SAndroid Build Coastguard Worker	if !hasDep(result, libLto, libBar) {
92*333d2b36SAndroid Build Coastguard Worker		t.Errorf("'lto_enabled' missing dependency on the default variant of 'bar'")
93*333d2b36SAndroid Build Coastguard Worker	}
94*333d2b36SAndroid Build Coastguard Worker
95*333d2b36SAndroid Build Coastguard Worker	barVariants := result.ModuleVariantsForTests("bar")
96*333d2b36SAndroid Build Coastguard Worker	for _, v := range barVariants {
97*333d2b36SAndroid Build Coastguard Worker		if strings.Contains(v, "lto-none") {
98*333d2b36SAndroid Build Coastguard Worker			t.Errorf("Expected variants for 'bar' to not contain 'lto-none', but found %q", v)
99*333d2b36SAndroid Build Coastguard Worker		}
100*333d2b36SAndroid Build Coastguard Worker	}
101*333d2b36SAndroid Build Coastguard Worker	quxVariants := result.ModuleVariantsForTests("qux")
102*333d2b36SAndroid Build Coastguard Worker	for _, v := range quxVariants {
103*333d2b36SAndroid Build Coastguard Worker		if strings.Contains(v, "lto-none") {
104*333d2b36SAndroid Build Coastguard Worker			t.Errorf("Expected variants for 'qux' to not contain 'lto-none', but found %q", v)
105*333d2b36SAndroid Build Coastguard Worker		}
106*333d2b36SAndroid Build Coastguard Worker	}
107*333d2b36SAndroid Build Coastguard Worker}
108*333d2b36SAndroid Build Coastguard Worker
109*333d2b36SAndroid Build Coastguard Workerfunc TestThinLtoOnlyOnStaticDep(t *testing.T) {
110*333d2b36SAndroid Build Coastguard Worker	t.Parallel()
111*333d2b36SAndroid Build Coastguard Worker	bp := `
112*333d2b36SAndroid Build Coastguard Worker	cc_library_shared {
113*333d2b36SAndroid Build Coastguard Worker		name: "root",
114*333d2b36SAndroid Build Coastguard Worker		srcs: ["src.c"],
115*333d2b36SAndroid Build Coastguard Worker		static_libs: ["foo"],
116*333d2b36SAndroid Build Coastguard Worker	}
117*333d2b36SAndroid Build Coastguard Worker	cc_library_shared {
118*333d2b36SAndroid Build Coastguard Worker		name: "root_no_lto",
119*333d2b36SAndroid Build Coastguard Worker		srcs: ["src.c"],
120*333d2b36SAndroid Build Coastguard Worker		static_libs: ["foo"],
121*333d2b36SAndroid Build Coastguard Worker		lto: {
122*333d2b36SAndroid Build Coastguard Worker			never: true,
123*333d2b36SAndroid Build Coastguard Worker		}
124*333d2b36SAndroid Build Coastguard Worker	}
125*333d2b36SAndroid Build Coastguard Worker	cc_library_static {
126*333d2b36SAndroid Build Coastguard Worker		name: "foo",
127*333d2b36SAndroid Build Coastguard Worker		srcs: ["foo.c"],
128*333d2b36SAndroid Build Coastguard Worker		static_libs: ["baz"],
129*333d2b36SAndroid Build Coastguard Worker		lto: {
130*333d2b36SAndroid Build Coastguard Worker			thin: true,
131*333d2b36SAndroid Build Coastguard Worker		}
132*333d2b36SAndroid Build Coastguard Worker	}
133*333d2b36SAndroid Build Coastguard Worker	cc_library_static {
134*333d2b36SAndroid Build Coastguard Worker		name: "baz",
135*333d2b36SAndroid Build Coastguard Worker		srcs: ["baz.c"],
136*333d2b36SAndroid Build Coastguard Worker	}
137*333d2b36SAndroid Build Coastguard Worker`
138*333d2b36SAndroid Build Coastguard Worker
139*333d2b36SAndroid Build Coastguard Worker	result := LTOPreparer.RunTestWithBp(t, bp)
140*333d2b36SAndroid Build Coastguard Worker
141*333d2b36SAndroid Build Coastguard Worker	libRoot := result.ModuleForTests("root", "android_arm64_armv8-a_shared").Module()
142*333d2b36SAndroid Build Coastguard Worker	libRootLtoNever := result.ModuleForTests("root_no_lto", "android_arm64_armv8-a_shared").Module()
143*333d2b36SAndroid Build Coastguard Worker
144*333d2b36SAndroid Build Coastguard Worker	libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static")
145*333d2b36SAndroid Build Coastguard Worker	if !hasDep(result, libRoot, libFoo.Module()) {
146*333d2b36SAndroid Build Coastguard Worker		t.Errorf("'root' missing dependency on the default variant of 'foo'")
147*333d2b36SAndroid Build Coastguard Worker	}
148*333d2b36SAndroid Build Coastguard Worker
149*333d2b36SAndroid Build Coastguard Worker	libFooNoLto := result.ModuleForTests("foo", "android_arm64_armv8-a_static_lto-none")
150*333d2b36SAndroid Build Coastguard Worker	if !hasDep(result, libRootLtoNever, libFooNoLto.Module()) {
151*333d2b36SAndroid Build Coastguard Worker		t.Errorf("'root_no_lto' missing dependency on the lto_none variant of 'foo'")
152*333d2b36SAndroid Build Coastguard Worker	}
153*333d2b36SAndroid Build Coastguard Worker
154*333d2b36SAndroid Build Coastguard Worker	libFooCFlags := libFoo.Rule("cc").Args["cFlags"]
155*333d2b36SAndroid Build Coastguard Worker	if w := "-flto=thin -fsplit-lto-unit"; !strings.Contains(libFooCFlags, w) {
156*333d2b36SAndroid Build Coastguard Worker		t.Errorf("'foo' expected to have flags %q, but got %q", w, libFooCFlags)
157*333d2b36SAndroid Build Coastguard Worker	}
158*333d2b36SAndroid Build Coastguard Worker
159*333d2b36SAndroid Build Coastguard Worker	libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static")
160*333d2b36SAndroid Build Coastguard Worker	if !hasDep(result, libFoo.Module(), libBaz.Module()) {
161*333d2b36SAndroid Build Coastguard Worker		t.Errorf("'foo' missing dependency on the default variant of transitive dep 'baz'")
162*333d2b36SAndroid Build Coastguard Worker	}
163*333d2b36SAndroid Build Coastguard Worker
164*333d2b36SAndroid Build Coastguard Worker	libBazCFlags := libFoo.Rule("cc").Args["cFlags"]
165*333d2b36SAndroid Build Coastguard Worker	if w := "-flto=thin -fsplit-lto-unit"; !strings.Contains(libBazCFlags, w) {
166*333d2b36SAndroid Build Coastguard Worker		t.Errorf("'baz' expected to have flags %q, but got %q", w, libFooCFlags)
167*333d2b36SAndroid Build Coastguard Worker	}
168*333d2b36SAndroid Build Coastguard Worker}
169*333d2b36SAndroid Build Coastguard Worker
170*333d2b36SAndroid Build Coastguard Workerfunc TestLtoDisabledButEnabledForArch(t *testing.T) {
171*333d2b36SAndroid Build Coastguard Worker	t.Parallel()
172*333d2b36SAndroid Build Coastguard Worker	bp := `
173*333d2b36SAndroid Build Coastguard Worker	cc_library {
174*333d2b36SAndroid Build Coastguard Worker		name: "libfoo",
175*333d2b36SAndroid Build Coastguard Worker		srcs: ["foo.c"],
176*333d2b36SAndroid Build Coastguard Worker		lto: {
177*333d2b36SAndroid Build Coastguard Worker			never: true,
178*333d2b36SAndroid Build Coastguard Worker		},
179*333d2b36SAndroid Build Coastguard Worker		target: {
180*333d2b36SAndroid Build Coastguard Worker			android_arm: {
181*333d2b36SAndroid Build Coastguard Worker				lto: {
182*333d2b36SAndroid Build Coastguard Worker					never: false,
183*333d2b36SAndroid Build Coastguard Worker					thin: true,
184*333d2b36SAndroid Build Coastguard Worker				},
185*333d2b36SAndroid Build Coastguard Worker			},
186*333d2b36SAndroid Build Coastguard Worker		},
187*333d2b36SAndroid Build Coastguard Worker	}`
188*333d2b36SAndroid Build Coastguard Worker	result := LTOPreparer.RunTestWithBp(t, bp)
189*333d2b36SAndroid Build Coastguard Worker
190*333d2b36SAndroid Build Coastguard Worker	libFooWithLto := result.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
191*333d2b36SAndroid Build Coastguard Worker	libFooWithoutLto := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("ld")
192*333d2b36SAndroid Build Coastguard Worker
193*333d2b36SAndroid Build Coastguard Worker	android.AssertStringDoesContain(t, "missing flag for LTO in variant that expects it",
194*333d2b36SAndroid Build Coastguard Worker		libFooWithLto.Args["ldFlags"], "-flto=thin")
195*333d2b36SAndroid Build Coastguard Worker	android.AssertStringDoesNotContain(t, "got flag for LTO in variant that doesn't expect it",
196*333d2b36SAndroid Build Coastguard Worker		libFooWithoutLto.Args["ldFlags"], "-flto=thin")
197*333d2b36SAndroid Build Coastguard Worker}
198*333d2b36SAndroid Build Coastguard Worker
199*333d2b36SAndroid Build Coastguard Workerfunc TestLtoDoesNotPropagateToRuntimeLibs(t *testing.T) {
200*333d2b36SAndroid Build Coastguard Worker	t.Parallel()
201*333d2b36SAndroid Build Coastguard Worker	bp := `
202*333d2b36SAndroid Build Coastguard Worker	cc_library {
203*333d2b36SAndroid Build Coastguard Worker		name: "runtime_libbar",
204*333d2b36SAndroid Build Coastguard Worker		srcs: ["bar.c"],
205*333d2b36SAndroid Build Coastguard Worker	}
206*333d2b36SAndroid Build Coastguard Worker
207*333d2b36SAndroid Build Coastguard Worker	cc_library {
208*333d2b36SAndroid Build Coastguard Worker		name: "libfoo",
209*333d2b36SAndroid Build Coastguard Worker		srcs: ["foo.c"],
210*333d2b36SAndroid Build Coastguard Worker		runtime_libs: ["runtime_libbar"],
211*333d2b36SAndroid Build Coastguard Worker		lto: {
212*333d2b36SAndroid Build Coastguard Worker			thin: true,
213*333d2b36SAndroid Build Coastguard Worker		},
214*333d2b36SAndroid Build Coastguard Worker	}`
215*333d2b36SAndroid Build Coastguard Worker
216*333d2b36SAndroid Build Coastguard Worker	result := LTOPreparer.RunTestWithBp(t, bp)
217*333d2b36SAndroid Build Coastguard Worker
218*333d2b36SAndroid Build Coastguard Worker	libFoo := result.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
219*333d2b36SAndroid Build Coastguard Worker	libBar := result.ModuleForTests("runtime_libbar", "android_arm_armv7-a-neon_shared").Rule("ld")
220*333d2b36SAndroid Build Coastguard Worker
221*333d2b36SAndroid Build Coastguard Worker	android.AssertStringDoesContain(t, "missing flag for LTO in LTO enabled library",
222*333d2b36SAndroid Build Coastguard Worker		libFoo.Args["ldFlags"], "-flto=thin")
223*333d2b36SAndroid Build Coastguard Worker	android.AssertStringDoesNotContain(t, "got flag for LTO in runtime_lib",
224*333d2b36SAndroid Build Coastguard Worker		libBar.Args["ldFlags"], "-flto=thin")
225*333d2b36SAndroid Build Coastguard Worker}
226