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