1// Copyright 2017 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	"reflect"
19	"testing"
20
21	"android/soong/android"
22)
23
24func TestLibraryReuse(t *testing.T) {
25	t.Parallel()
26	t.Run("simple", func(t *testing.T) {
27		ctx := testCc(t, `
28		cc_library {
29			name: "libfoo",
30			srcs: ["foo.c", "baz.o"],
31		}`)
32
33		libfooShared := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
34		libfooStatic := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a")
35
36		if len(libfooShared.Inputs) != 2 {
37			t.Fatalf("unexpected inputs to libfoo shared: %#v", libfooShared.Inputs.Strings())
38		}
39
40		if len(libfooStatic.Inputs) != 2 {
41			t.Fatalf("unexpected inputs to libfoo static: %#v", libfooStatic.Inputs.Strings())
42		}
43
44		if libfooShared.Inputs[0] != libfooStatic.Inputs[0] {
45			t.Errorf("static object not reused for shared library")
46		}
47		if libfooShared.Inputs[1] != libfooStatic.Inputs[1] {
48			t.Errorf("static object not reused for shared library")
49		}
50	})
51
52	t.Run("extra static source", func(t *testing.T) {
53		ctx := testCc(t, `
54		cc_library {
55			name: "libfoo",
56			srcs: ["foo.c"],
57			static: {
58				srcs: ["bar.c"]
59			},
60		}`)
61
62		libfooShared := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
63		libfooStatic := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a")
64
65		if len(libfooShared.Inputs) != 1 {
66			t.Fatalf("unexpected inputs to libfoo shared: %#v", libfooShared.Inputs.Strings())
67		}
68
69		if len(libfooStatic.Inputs) != 2 {
70			t.Fatalf("unexpected inputs to libfoo static: %#v", libfooStatic.Inputs.Strings())
71		}
72
73		if libfooShared.Inputs[0] != libfooStatic.Inputs[0] {
74			t.Errorf("static object not reused for shared library")
75		}
76	})
77
78	t.Run("extra shared source", func(t *testing.T) {
79		ctx := testCc(t, `
80		cc_library {
81			name: "libfoo",
82			srcs: ["foo.c"],
83			shared: {
84				srcs: ["bar.c"]
85			},
86		}`)
87
88		libfooShared := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
89		libfooStatic := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a")
90
91		if len(libfooShared.Inputs) != 2 {
92			t.Fatalf("unexpected inputs to libfoo shared: %#v", libfooShared.Inputs.Strings())
93		}
94
95		if len(libfooStatic.Inputs) != 1 {
96			t.Fatalf("unexpected inputs to libfoo static: %#v", libfooStatic.Inputs.Strings())
97		}
98
99		if libfooShared.Inputs[0] != libfooStatic.Inputs[0] {
100			t.Errorf("static object not reused for shared library")
101		}
102	})
103
104	t.Run("extra static cflags", func(t *testing.T) {
105		ctx := testCc(t, `
106		cc_library {
107			name: "libfoo",
108			srcs: ["foo.c"],
109			static: {
110				cflags: ["-DFOO"],
111			},
112		}`)
113
114		libfooShared := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
115		libfooStatic := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a")
116
117		if len(libfooShared.Inputs) != 1 {
118			t.Fatalf("unexpected inputs to libfoo shared: %#v", libfooShared.Inputs.Strings())
119		}
120
121		if len(libfooStatic.Inputs) != 1 {
122			t.Fatalf("unexpected inputs to libfoo static: %#v", libfooStatic.Inputs.Strings())
123		}
124
125		if libfooShared.Inputs[0] == libfooStatic.Inputs[0] {
126			t.Errorf("static object reused for shared library when it shouldn't be")
127		}
128	})
129
130	t.Run("extra shared cflags", func(t *testing.T) {
131		ctx := testCc(t, `
132		cc_library {
133			name: "libfoo",
134			srcs: ["foo.c"],
135			shared: {
136				cflags: ["-DFOO"],
137			},
138		}`)
139
140		libfooShared := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
141		libfooStatic := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a")
142
143		if len(libfooShared.Inputs) != 1 {
144			t.Fatalf("unexpected inputs to libfoo shared: %#v", libfooShared.Inputs.Strings())
145		}
146
147		if len(libfooStatic.Inputs) != 1 {
148			t.Fatalf("unexpected inputs to libfoo static: %#v", libfooStatic.Inputs.Strings())
149		}
150
151		if libfooShared.Inputs[0] == libfooStatic.Inputs[0] {
152			t.Errorf("static object reused for shared library when it shouldn't be")
153		}
154	})
155
156	t.Run("global cflags for reused generated sources", func(t *testing.T) {
157		ctx := testCc(t, `
158		cc_library {
159			name: "libfoo",
160			srcs: [
161				"foo.c",
162				"a.proto",
163			],
164			shared: {
165				srcs: [
166					"bar.c",
167				],
168			},
169		}`)
170
171		libfooShared := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
172		libfooStatic := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a")
173
174		if len(libfooShared.Inputs) != 3 {
175			t.Fatalf("unexpected inputs to libfoo shared: %#v", libfooShared.Inputs.Strings())
176		}
177
178		if len(libfooStatic.Inputs) != 2 {
179			t.Fatalf("unexpected inputs to libfoo static: %#v", libfooStatic.Inputs.Strings())
180		}
181
182		if !reflect.DeepEqual(libfooShared.Inputs[0:2].Strings(), libfooStatic.Inputs.Strings()) {
183			t.Errorf("static objects not reused for shared library")
184		}
185
186		libfoo := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Module().(*Module)
187		if !inList("-DGOOGLE_PROTOBUF_NO_RTTI", libfoo.flags.Local.CFlags) {
188			t.Errorf("missing protobuf cflags")
189		}
190	})
191}
192
193func TestStubsVersions(t *testing.T) {
194	t.Parallel()
195	bp := `
196		cc_library {
197			name: "libfoo",
198			srcs: ["foo.c"],
199			stubs: {
200				versions: ["29", "R", "current"],
201			},
202		}
203	`
204	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
205	config.TestProductVariables.Platform_version_active_codenames = []string{"R"}
206	ctx := testCcWithConfig(t, config)
207
208	variants := ctx.ModuleVariantsForTests("libfoo")
209	for _, expectedVer := range []string{"29", "R", "current"} {
210		expectedVariant := "android_arm_armv7-a-neon_shared_" + expectedVer
211		if !inList(expectedVariant, variants) {
212			t.Errorf("missing expected variant: %q", expectedVariant)
213		}
214	}
215}
216
217func TestStubsVersions_NotSorted(t *testing.T) {
218	t.Parallel()
219	bp := `
220		cc_library {
221			name: "libfoo",
222			srcs: ["foo.c"],
223			stubs: {
224				versions: ["29", "current", "R"],
225			},
226		}
227	`
228	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
229	config.TestProductVariables.Platform_version_active_codenames = []string{"R"}
230	testCcErrorWithConfig(t, `"libfoo" .*: versions: not sorted`, config)
231}
232
233func TestStubsVersions_ParseError(t *testing.T) {
234	t.Parallel()
235	bp := `
236		cc_library {
237			name: "libfoo",
238			srcs: ["foo.c"],
239			stubs: {
240				versions: ["29", "current", "X"],
241			},
242		}
243	`
244
245	testCcError(t, `"libfoo" .*: versions: "X" could not be parsed as an integer and is not a recognized codename`, bp)
246}
247
248func TestLibraryVersionScript(t *testing.T) {
249	t.Parallel()
250	result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, `
251		cc_library {
252			name: "libfoo",
253			srcs: ["foo.c"],
254			version_script: "foo.map.txt",
255		}`)
256
257	libfoo := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("ld")
258
259	android.AssertStringListContains(t, "missing dependency on version_script",
260		libfoo.Implicits.Strings(), "foo.map.txt")
261	android.AssertStringDoesContain(t, "missing flag for version_script",
262		libfoo.Args["ldFlags"], "-Wl,--version-script,foo.map.txt")
263
264}
265
266func TestLibraryDynamicList(t *testing.T) {
267	t.Parallel()
268	result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, `
269		cc_library {
270			name: "libfoo",
271			srcs: ["foo.c"],
272			dynamic_list: "foo.dynamic.txt",
273		}`)
274
275	libfoo := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("ld")
276
277	android.AssertStringListContains(t, "missing dependency on dynamic_list",
278		libfoo.Implicits.Strings(), "foo.dynamic.txt")
279	android.AssertStringDoesContain(t, "missing flag for dynamic_list",
280		libfoo.Args["ldFlags"], "-Wl,--dynamic-list,foo.dynamic.txt")
281
282}
283
284func TestWholeStaticLibPrebuilts(t *testing.T) {
285	t.Parallel()
286	result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, `
287		cc_prebuilt_library_static {
288			name: "libprebuilt",
289			srcs: ["foo.a"],
290		}
291
292		cc_library_static {
293			name: "libdirect",
294			whole_static_libs: ["libprebuilt"],
295		}
296
297		cc_library_static {
298			name: "libtransitive",
299			whole_static_libs: ["libdirect"],
300		}
301
302		cc_library_static {
303			name: "libdirect_with_srcs",
304			srcs: ["bar.c"],
305			whole_static_libs: ["libprebuilt"],
306		}
307
308		cc_library_static {
309			name: "libtransitive_with_srcs",
310			srcs: ["baz.c"],
311			whole_static_libs: ["libdirect_with_srcs"],
312		}
313	`)
314
315	libdirect := result.ModuleForTests("libdirect", "android_arm64_armv8-a_static").Rule("arWithLibs")
316	libtransitive := result.ModuleForTests("libtransitive", "android_arm64_armv8-a_static").Rule("arWithLibs")
317
318	libdirectWithSrcs := result.ModuleForTests("libdirect_with_srcs", "android_arm64_armv8-a_static").Rule("arWithLibs")
319	libtransitiveWithSrcs := result.ModuleForTests("libtransitive_with_srcs", "android_arm64_armv8-a_static").Rule("arWithLibs")
320
321	barObj := result.ModuleForTests("libdirect_with_srcs", "android_arm64_armv8-a_static").Rule("cc")
322	bazObj := result.ModuleForTests("libtransitive_with_srcs", "android_arm64_armv8-a_static").Rule("cc")
323
324	android.AssertStringListContains(t, "missing dependency on foo.a",
325		libdirect.Inputs.Strings(), "foo.a")
326	android.AssertStringDoesContain(t, "missing flag for foo.a",
327		libdirect.Args["arLibs"], "foo.a")
328
329	android.AssertStringListContains(t, "missing dependency on foo.a",
330		libtransitive.Inputs.Strings(), "foo.a")
331	android.AssertStringDoesContain(t, "missing flag for foo.a",
332		libtransitive.Args["arLibs"], "foo.a")
333
334	android.AssertStringListContains(t, "missing dependency on foo.a",
335		libdirectWithSrcs.Inputs.Strings(), "foo.a")
336	android.AssertStringDoesContain(t, "missing flag for foo.a",
337		libdirectWithSrcs.Args["arLibs"], "foo.a")
338	android.AssertStringListContains(t, "missing dependency on bar.o",
339		libdirectWithSrcs.Inputs.Strings(), barObj.Output.String())
340	android.AssertStringDoesContain(t, "missing flag for bar.o",
341		libdirectWithSrcs.Args["arObjs"], barObj.Output.String())
342
343	android.AssertStringListContains(t, "missing dependency on foo.a",
344		libtransitiveWithSrcs.Inputs.Strings(), "foo.a")
345	android.AssertStringDoesContain(t, "missing flag for foo.a",
346		libtransitiveWithSrcs.Args["arLibs"], "foo.a")
347
348	android.AssertStringListContains(t, "missing dependency on bar.o",
349		libtransitiveWithSrcs.Inputs.Strings(), barObj.Output.String())
350	android.AssertStringDoesContain(t, "missing flag for bar.o",
351		libtransitiveWithSrcs.Args["arObjs"], barObj.Output.String())
352
353	android.AssertStringListContains(t, "missing dependency on baz.o",
354		libtransitiveWithSrcs.Inputs.Strings(), bazObj.Output.String())
355	android.AssertStringDoesContain(t, "missing flag for baz.o",
356		libtransitiveWithSrcs.Args["arObjs"], bazObj.Output.String())
357}
358