• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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	"android/soong/bazel/cquery"
23)
24
25func TestLibraryReuse(t *testing.T) {
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	bp := `
195		cc_library {
196			name: "libfoo",
197			srcs: ["foo.c"],
198			stubs: {
199				versions: ["29", "R", "current"],
200			},
201		}
202	`
203	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
204	config.TestProductVariables.Platform_version_active_codenames = []string{"R"}
205	ctx := testCcWithConfig(t, config)
206
207	variants := ctx.ModuleVariantsForTests("libfoo")
208	for _, expectedVer := range []string{"29", "R", "current"} {
209		expectedVariant := "android_arm_armv7-a-neon_shared_" + expectedVer
210		if !inList(expectedVariant, variants) {
211			t.Errorf("missing expected variant: %q", expectedVariant)
212		}
213	}
214}
215
216func TestStubsVersions_NotSorted(t *testing.T) {
217	bp := `
218		cc_library {
219			name: "libfoo",
220			srcs: ["foo.c"],
221			stubs: {
222				versions: ["29", "current", "R"],
223			},
224		}
225	`
226	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
227	config.TestProductVariables.Platform_version_active_codenames = []string{"R"}
228	testCcErrorWithConfig(t, `"libfoo" .*: versions: not sorted`, config)
229}
230
231func TestStubsVersions_ParseError(t *testing.T) {
232	bp := `
233		cc_library {
234			name: "libfoo",
235			srcs: ["foo.c"],
236			stubs: {
237				versions: ["29", "current", "X"],
238			},
239		}
240	`
241
242	testCcError(t, `"libfoo" .*: versions: "X" could not be parsed as an integer and is not a recognized codename`, bp)
243}
244
245func TestCcLibraryWithBazel(t *testing.T) {
246	bp := `
247cc_library {
248	name: "foo",
249	srcs: ["foo.cc"],
250	bazel_module: { label: "//foo/bar:bar" },
251}`
252	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
253	config.BazelContext = android.MockBazelContext{
254		OutputBaseDir: "outputbase",
255		LabelToCcInfo: map[string]cquery.CcInfo{
256			"//foo/bar:bar": cquery.CcInfo{
257				CcObjectFiles:        []string{"foo.o"},
258				Includes:             []string{"include"},
259				SystemIncludes:       []string{"system_include"},
260				Headers:              []string{"foo.h"},
261				RootDynamicLibraries: []string{"foo.so"},
262			},
263			"//foo/bar:bar_bp2build_cc_library_static": cquery.CcInfo{
264				CcObjectFiles:      []string{"foo.o"},
265				Includes:           []string{"include"},
266				SystemIncludes:     []string{"system_include"},
267				Headers:            []string{"foo.h"},
268				RootStaticArchives: []string{"foo.a"},
269			},
270		},
271	}
272	ctx := testCcWithConfig(t, config)
273
274	staticFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_static").Module()
275	outputFiles, err := staticFoo.(android.OutputFileProducer).OutputFiles("")
276	if err != nil {
277		t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
278	}
279
280	expectedOutputFiles := []string{"outputbase/execroot/__main__/foo.a"}
281	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
282
283	flagExporter := ctx.ModuleProvider(staticFoo, FlagExporterInfoProvider).(FlagExporterInfo)
284	android.AssertPathsRelativeToTopEquals(t, "exported include dirs", []string{"outputbase/execroot/__main__/include"}, flagExporter.IncludeDirs)
285	android.AssertPathsRelativeToTopEquals(t, "exported system include dirs", []string{"outputbase/execroot/__main__/system_include"}, flagExporter.SystemIncludeDirs)
286	android.AssertPathsRelativeToTopEquals(t, "exported headers", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.GeneratedHeaders)
287	android.AssertPathsRelativeToTopEquals(t, "deps", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.Deps)
288
289	sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
290	outputFiles, err = sharedFoo.(android.OutputFileProducer).OutputFiles("")
291	if err != nil {
292		t.Errorf("Unexpected error getting cc_library outputfiles %s", err)
293	}
294	expectedOutputFiles = []string{"outputbase/execroot/__main__/foo.so"}
295	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
296
297	flagExporter = ctx.ModuleProvider(sharedFoo, FlagExporterInfoProvider).(FlagExporterInfo)
298	android.AssertPathsRelativeToTopEquals(t, "exported include dirs", []string{"outputbase/execroot/__main__/include"}, flagExporter.IncludeDirs)
299	android.AssertPathsRelativeToTopEquals(t, "exported system include dirs", []string{"outputbase/execroot/__main__/system_include"}, flagExporter.SystemIncludeDirs)
300	android.AssertPathsRelativeToTopEquals(t, "exported headers", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.GeneratedHeaders)
301	android.AssertPathsRelativeToTopEquals(t, "deps", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.Deps)
302}
303
304func TestLibraryVersionScript(t *testing.T) {
305	result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, `
306		cc_library {
307			name: "libfoo",
308			srcs: ["foo.c"],
309			version_script: "foo.map.txt",
310		}`)
311
312	libfoo := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("ld")
313
314	android.AssertStringListContains(t, "missing dependency on version_script",
315		libfoo.Implicits.Strings(), "foo.map.txt")
316	android.AssertStringDoesContain(t, "missing flag for version_script",
317		libfoo.Args["ldFlags"], "-Wl,--version-script,foo.map.txt")
318
319}
320
321func TestLibraryDynamicList(t *testing.T) {
322	result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, `
323		cc_library {
324			name: "libfoo",
325			srcs: ["foo.c"],
326			dynamic_list: "foo.dynamic.txt",
327		}`)
328
329	libfoo := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("ld")
330
331	android.AssertStringListContains(t, "missing dependency on dynamic_list",
332		libfoo.Implicits.Strings(), "foo.dynamic.txt")
333	android.AssertStringDoesContain(t, "missing flag for dynamic_list",
334		libfoo.Args["ldFlags"], "-Wl,--dynamic-list,foo.dynamic.txt")
335
336}
337
338func TestCcLibrarySharedWithBazel(t *testing.T) {
339	bp := `
340cc_library_shared {
341	name: "foo",
342	srcs: ["foo.cc"],
343	bazel_module: { label: "//foo/bar:bar" },
344}`
345	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
346	config.BazelContext = android.MockBazelContext{
347		OutputBaseDir: "outputbase",
348		LabelToCcInfo: map[string]cquery.CcInfo{
349			"//foo/bar:bar": cquery.CcInfo{
350				CcObjectFiles:        []string{"foo.o"},
351				Includes:             []string{"include"},
352				SystemIncludes:       []string{"system_include"},
353				RootDynamicLibraries: []string{"foo.so"},
354				TocFile:              "foo.so.toc",
355			},
356		},
357	}
358	ctx := testCcWithConfig(t, config)
359
360	sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
361	producer := sharedFoo.(android.OutputFileProducer)
362	outputFiles, err := producer.OutputFiles("")
363	if err != nil {
364		t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
365	}
366	expectedOutputFiles := []string{"outputbase/execroot/__main__/foo.so"}
367	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
368
369	tocFilePath := sharedFoo.(*Module).Toc()
370	if !tocFilePath.Valid() {
371		t.Errorf("Invalid tocFilePath: %s", tocFilePath)
372	}
373	tocFile := tocFilePath.Path()
374	expectedToc := "outputbase/execroot/__main__/foo.so.toc"
375	android.AssertStringEquals(t, "toc file", expectedToc, tocFile.String())
376
377	entries := android.AndroidMkEntriesForTest(t, ctx, sharedFoo)[0]
378	expectedFlags := []string{"-Ioutputbase/execroot/__main__/include", "-isystem outputbase/execroot/__main__/system_include"}
379	gotFlags := entries.EntryMap["LOCAL_EXPORT_CFLAGS"]
380	android.AssertDeepEquals(t, "androidmk exported cflags", expectedFlags, gotFlags)
381}
382
383func TestWholeStaticLibPrebuilts(t *testing.T) {
384	result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, `
385		cc_prebuilt_library_static {
386			name: "libprebuilt",
387			srcs: ["foo.a"],
388		}
389
390		cc_library_static {
391			name: "libdirect",
392			whole_static_libs: ["libprebuilt"],
393		}
394
395		cc_library_static {
396			name: "libtransitive",
397			whole_static_libs: ["libdirect"],
398		}
399
400		cc_library_static {
401			name: "libdirect_with_srcs",
402			srcs: ["bar.c"],
403			whole_static_libs: ["libprebuilt"],
404		}
405
406		cc_library_static {
407			name: "libtransitive_with_srcs",
408			srcs: ["baz.c"],
409			whole_static_libs: ["libdirect_with_srcs"],
410		}
411	`)
412
413	libdirect := result.ModuleForTests("libdirect", "android_arm64_armv8-a_static").Rule("arWithLibs")
414	libtransitive := result.ModuleForTests("libtransitive", "android_arm64_armv8-a_static").Rule("arWithLibs")
415
416	libdirectWithSrcs := result.ModuleForTests("libdirect_with_srcs", "android_arm64_armv8-a_static").Rule("arWithLibs")
417	libtransitiveWithSrcs := result.ModuleForTests("libtransitive_with_srcs", "android_arm64_armv8-a_static").Rule("arWithLibs")
418
419	barObj := result.ModuleForTests("libdirect_with_srcs", "android_arm64_armv8-a_static").Rule("cc")
420	bazObj := result.ModuleForTests("libtransitive_with_srcs", "android_arm64_armv8-a_static").Rule("cc")
421
422	android.AssertStringListContains(t, "missing dependency on foo.a",
423		libdirect.Inputs.Strings(), "foo.a")
424	android.AssertStringDoesContain(t, "missing flag for foo.a",
425		libdirect.Args["arLibs"], "foo.a")
426
427	android.AssertStringListContains(t, "missing dependency on foo.a",
428		libtransitive.Inputs.Strings(), "foo.a")
429	android.AssertStringDoesContain(t, "missing flag for foo.a",
430		libtransitive.Args["arLibs"], "foo.a")
431
432	android.AssertStringListContains(t, "missing dependency on foo.a",
433		libdirectWithSrcs.Inputs.Strings(), "foo.a")
434	android.AssertStringDoesContain(t, "missing flag for foo.a",
435		libdirectWithSrcs.Args["arLibs"], "foo.a")
436	android.AssertStringListContains(t, "missing dependency on bar.o",
437		libdirectWithSrcs.Inputs.Strings(), barObj.Output.String())
438	android.AssertStringDoesContain(t, "missing flag for bar.o",
439		libdirectWithSrcs.Args["arObjs"], barObj.Output.String())
440
441	android.AssertStringListContains(t, "missing dependency on foo.a",
442		libtransitiveWithSrcs.Inputs.Strings(), "foo.a")
443	android.AssertStringDoesContain(t, "missing flag for foo.a",
444		libtransitiveWithSrcs.Args["arLibs"], "foo.a")
445
446	android.AssertStringListContains(t, "missing dependency on bar.o",
447		libtransitiveWithSrcs.Inputs.Strings(), barObj.Output.String())
448	android.AssertStringDoesContain(t, "missing flag for bar.o",
449		libtransitiveWithSrcs.Args["arObjs"], barObj.Output.String())
450
451	android.AssertStringListContains(t, "missing dependency on baz.o",
452		libtransitiveWithSrcs.Inputs.Strings(), bazObj.Output.String())
453	android.AssertStringDoesContain(t, "missing flag for baz.o",
454		libtransitiveWithSrcs.Args["arObjs"], bazObj.Output.String())
455}
456