• 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.Parallel()
27	t.Run("simple", func(t *testing.T) {
28		ctx := testCc(t, `
29		cc_library {
30			name: "libfoo",
31			srcs: ["foo.c", "baz.o"],
32		}`)
33
34		libfooShared := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
35		libfooStatic := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a")
36
37		if len(libfooShared.Inputs) != 2 {
38			t.Fatalf("unexpected inputs to libfoo shared: %#v", libfooShared.Inputs.Strings())
39		}
40
41		if len(libfooStatic.Inputs) != 2 {
42			t.Fatalf("unexpected inputs to libfoo static: %#v", libfooStatic.Inputs.Strings())
43		}
44
45		if libfooShared.Inputs[0] != libfooStatic.Inputs[0] {
46			t.Errorf("static object not reused for shared library")
47		}
48		if libfooShared.Inputs[1] != libfooStatic.Inputs[1] {
49			t.Errorf("static object not reused for shared library")
50		}
51	})
52
53	t.Run("extra static source", func(t *testing.T) {
54		ctx := testCc(t, `
55		cc_library {
56			name: "libfoo",
57			srcs: ["foo.c"],
58			static: {
59				srcs: ["bar.c"]
60			},
61		}`)
62
63		libfooShared := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
64		libfooStatic := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a")
65
66		if len(libfooShared.Inputs) != 1 {
67			t.Fatalf("unexpected inputs to libfoo shared: %#v", libfooShared.Inputs.Strings())
68		}
69
70		if len(libfooStatic.Inputs) != 2 {
71			t.Fatalf("unexpected inputs to libfoo static: %#v", libfooStatic.Inputs.Strings())
72		}
73
74		if libfooShared.Inputs[0] != libfooStatic.Inputs[0] {
75			t.Errorf("static object not reused for shared library")
76		}
77	})
78
79	t.Run("extra shared source", func(t *testing.T) {
80		ctx := testCc(t, `
81		cc_library {
82			name: "libfoo",
83			srcs: ["foo.c"],
84			shared: {
85				srcs: ["bar.c"]
86			},
87		}`)
88
89		libfooShared := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
90		libfooStatic := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a")
91
92		if len(libfooShared.Inputs) != 2 {
93			t.Fatalf("unexpected inputs to libfoo shared: %#v", libfooShared.Inputs.Strings())
94		}
95
96		if len(libfooStatic.Inputs) != 1 {
97			t.Fatalf("unexpected inputs to libfoo static: %#v", libfooStatic.Inputs.Strings())
98		}
99
100		if libfooShared.Inputs[0] != libfooStatic.Inputs[0] {
101			t.Errorf("static object not reused for shared library")
102		}
103	})
104
105	t.Run("extra static cflags", func(t *testing.T) {
106		ctx := testCc(t, `
107		cc_library {
108			name: "libfoo",
109			srcs: ["foo.c"],
110			static: {
111				cflags: ["-DFOO"],
112			},
113		}`)
114
115		libfooShared := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
116		libfooStatic := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a")
117
118		if len(libfooShared.Inputs) != 1 {
119			t.Fatalf("unexpected inputs to libfoo shared: %#v", libfooShared.Inputs.Strings())
120		}
121
122		if len(libfooStatic.Inputs) != 1 {
123			t.Fatalf("unexpected inputs to libfoo static: %#v", libfooStatic.Inputs.Strings())
124		}
125
126		if libfooShared.Inputs[0] == libfooStatic.Inputs[0] {
127			t.Errorf("static object reused for shared library when it shouldn't be")
128		}
129	})
130
131	t.Run("extra shared cflags", func(t *testing.T) {
132		ctx := testCc(t, `
133		cc_library {
134			name: "libfoo",
135			srcs: ["foo.c"],
136			shared: {
137				cflags: ["-DFOO"],
138			},
139		}`)
140
141		libfooShared := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
142		libfooStatic := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a")
143
144		if len(libfooShared.Inputs) != 1 {
145			t.Fatalf("unexpected inputs to libfoo shared: %#v", libfooShared.Inputs.Strings())
146		}
147
148		if len(libfooStatic.Inputs) != 1 {
149			t.Fatalf("unexpected inputs to libfoo static: %#v", libfooStatic.Inputs.Strings())
150		}
151
152		if libfooShared.Inputs[0] == libfooStatic.Inputs[0] {
153			t.Errorf("static object reused for shared library when it shouldn't be")
154		}
155	})
156
157	t.Run("global cflags for reused generated sources", func(t *testing.T) {
158		ctx := testCc(t, `
159		cc_library {
160			name: "libfoo",
161			srcs: [
162				"foo.c",
163				"a.proto",
164			],
165			shared: {
166				srcs: [
167					"bar.c",
168				],
169			},
170		}`)
171
172		libfooShared := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
173		libfooStatic := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a")
174
175		if len(libfooShared.Inputs) != 3 {
176			t.Fatalf("unexpected inputs to libfoo shared: %#v", libfooShared.Inputs.Strings())
177		}
178
179		if len(libfooStatic.Inputs) != 2 {
180			t.Fatalf("unexpected inputs to libfoo static: %#v", libfooStatic.Inputs.Strings())
181		}
182
183		if !reflect.DeepEqual(libfooShared.Inputs[0:2].Strings(), libfooStatic.Inputs.Strings()) {
184			t.Errorf("static objects not reused for shared library")
185		}
186
187		libfoo := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Module().(*Module)
188		if !inList("-DGOOGLE_PROTOBUF_NO_RTTI", libfoo.flags.Local.CFlags) {
189			t.Errorf("missing protobuf cflags")
190		}
191	})
192}
193
194func TestStubsVersions(t *testing.T) {
195	t.Parallel()
196	bp := `
197		cc_library {
198			name: "libfoo",
199			srcs: ["foo.c"],
200			stubs: {
201				versions: ["29", "R", "current"],
202			},
203		}
204	`
205	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
206	config.TestProductVariables.Platform_version_active_codenames = []string{"R"}
207	ctx := testCcWithConfig(t, config)
208
209	variants := ctx.ModuleVariantsForTests("libfoo")
210	for _, expectedVer := range []string{"29", "R", "current"} {
211		expectedVariant := "android_arm_armv7-a-neon_shared_" + expectedVer
212		if !inList(expectedVariant, variants) {
213			t.Errorf("missing expected variant: %q", expectedVariant)
214		}
215	}
216}
217
218func TestStubsVersions_NotSorted(t *testing.T) {
219	t.Parallel()
220	bp := `
221		cc_library {
222			name: "libfoo",
223			srcs: ["foo.c"],
224			stubs: {
225				versions: ["29", "current", "R"],
226			},
227		}
228	`
229	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
230	config.TestProductVariables.Platform_version_active_codenames = []string{"R"}
231	testCcErrorWithConfig(t, `"libfoo" .*: versions: not sorted`, config)
232}
233
234func TestStubsVersions_ParseError(t *testing.T) {
235	t.Parallel()
236	bp := `
237		cc_library {
238			name: "libfoo",
239			srcs: ["foo.c"],
240			stubs: {
241				versions: ["29", "current", "X"],
242			},
243		}
244	`
245
246	testCcError(t, `"libfoo" .*: versions: "X" could not be parsed as an integer and is not a recognized codename`, bp)
247}
248
249func TestCcLibraryWithBazel(t *testing.T) {
250	t.Parallel()
251	bp := `
252cc_library {
253	name: "foo",
254	srcs: ["foo.cc"],
255	bazel_module: { label: "//foo/bar:bar" },
256}`
257	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
258	config.BazelContext = android.MockBazelContext{
259		OutputBaseDir: "outputbase",
260		LabelToCcInfo: map[string]cquery.CcInfo{
261			"//foo/bar:bar": cquery.CcInfo{
262				CcObjectFiles:        []string{"foo.o"},
263				Includes:             []string{"include"},
264				SystemIncludes:       []string{"system_include"},
265				Headers:              []string{"foo.h"},
266				RootDynamicLibraries: []string{"foo.so"},
267				UnstrippedOutput:     "foo_unstripped.so",
268			},
269			"//foo/bar:bar_bp2build_cc_library_static": cquery.CcInfo{
270				CcObjectFiles:      []string{"foo.o"},
271				Includes:           []string{"include"},
272				SystemIncludes:     []string{"system_include"},
273				Headers:            []string{"foo.h"},
274				RootStaticArchives: []string{"foo.a"},
275			},
276		},
277	}
278	ctx := testCcWithConfig(t, config)
279
280	staticFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_static").Module()
281	outputFiles, err := staticFoo.(android.OutputFileProducer).OutputFiles("")
282	if err != nil {
283		t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
284	}
285
286	expectedOutputFiles := []string{"outputbase/execroot/__main__/foo.a"}
287	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
288
289	flagExporter := ctx.ModuleProvider(staticFoo, FlagExporterInfoProvider).(FlagExporterInfo)
290	android.AssertPathsRelativeToTopEquals(t, "exported include dirs", []string{"outputbase/execroot/__main__/include"}, flagExporter.IncludeDirs)
291	android.AssertPathsRelativeToTopEquals(t, "exported system include dirs", []string{"outputbase/execroot/__main__/system_include"}, flagExporter.SystemIncludeDirs)
292	android.AssertPathsRelativeToTopEquals(t, "exported headers", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.GeneratedHeaders)
293	android.AssertPathsRelativeToTopEquals(t, "deps", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.Deps)
294
295	sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
296	outputFiles, err = sharedFoo.(android.OutputFileProducer).OutputFiles("")
297	if err != nil {
298		t.Errorf("Unexpected error getting cc_library outputfiles %s", err)
299	}
300	expectedOutputFiles = []string{"outputbase/execroot/__main__/foo.so"}
301	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
302
303	android.AssertStringEquals(t, "unstripped shared library", "outputbase/execroot/__main__/foo_unstripped.so", sharedFoo.(*Module).linker.unstrippedOutputFilePath().String())
304	flagExporter = ctx.ModuleProvider(sharedFoo, FlagExporterInfoProvider).(FlagExporterInfo)
305	android.AssertPathsRelativeToTopEquals(t, "exported include dirs", []string{"outputbase/execroot/__main__/include"}, flagExporter.IncludeDirs)
306	android.AssertPathsRelativeToTopEquals(t, "exported system include dirs", []string{"outputbase/execroot/__main__/system_include"}, flagExporter.SystemIncludeDirs)
307	android.AssertPathsRelativeToTopEquals(t, "exported headers", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.GeneratedHeaders)
308	android.AssertPathsRelativeToTopEquals(t, "deps", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.Deps)
309}
310
311func TestCcLibraryWithBazelValidations(t *testing.T) {
312	t.Parallel()
313	bp := `
314cc_library {
315	name: "foo",
316	srcs: ["foo.cc"],
317	bazel_module: { label: "//foo/bar:bar" },
318	tidy: true,
319}`
320	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
321	config.BazelContext = android.MockBazelContext{
322		OutputBaseDir: "outputbase",
323		LabelToCcInfo: map[string]cquery.CcInfo{
324			"//foo/bar:bar": cquery.CcInfo{
325				CcObjectFiles:        []string{"foo.o"},
326				Includes:             []string{"include"},
327				SystemIncludes:       []string{"system_include"},
328				Headers:              []string{"foo.h"},
329				RootDynamicLibraries: []string{"foo.so"},
330				UnstrippedOutput:     "foo_unstripped.so",
331			},
332			"//foo/bar:bar_bp2build_cc_library_static": cquery.CcInfo{
333				CcObjectFiles:      []string{"foo.o"},
334				Includes:           []string{"include"},
335				SystemIncludes:     []string{"system_include"},
336				Headers:            []string{"foo.h"},
337				RootStaticArchives: []string{"foo.a"},
338				TidyFiles:          []string{"foo.c.tidy"},
339			},
340		},
341	}
342	ctx := android.GroupFixturePreparers(
343		prepareForCcTest,
344		android.FixtureMergeEnv(map[string]string{
345			"ALLOW_LOCAL_TIDY_TRUE": "1",
346		}),
347	).RunTestWithConfig(t, config).TestContext
348
349	staticFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_static").Module()
350	outputFiles, err := staticFoo.(android.OutputFileProducer).OutputFiles("")
351	if err != nil {
352		t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
353	}
354
355	expectedOutputFiles := []string{"out/soong/.intermediates/foo/android_arm_armv7-a-neon_static/validated/foo.a"}
356	android.AssertPathsRelativeToTopEquals(t, "output files", expectedOutputFiles, outputFiles)
357
358	flagExporter := ctx.ModuleProvider(staticFoo, FlagExporterInfoProvider).(FlagExporterInfo)
359	android.AssertPathsRelativeToTopEquals(t, "exported include dirs", []string{"outputbase/execroot/__main__/include"}, flagExporter.IncludeDirs)
360	android.AssertPathsRelativeToTopEquals(t, "exported system include dirs", []string{"outputbase/execroot/__main__/system_include"}, flagExporter.SystemIncludeDirs)
361	android.AssertPathsRelativeToTopEquals(t, "exported headers", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.GeneratedHeaders)
362	android.AssertPathsRelativeToTopEquals(t, "deps", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.Deps)
363
364	sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
365	outputFiles, err = sharedFoo.(android.OutputFileProducer).OutputFiles("")
366	if err != nil {
367		t.Errorf("Unexpected error getting cc_library outputfiles %s", err)
368	}
369	expectedOutputFiles = []string{"outputbase/execroot/__main__/foo.so"}
370	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
371
372	android.AssertStringEquals(t, "unstripped shared library", "outputbase/execroot/__main__/foo_unstripped.so", sharedFoo.(*Module).linker.unstrippedOutputFilePath().String())
373	flagExporter = ctx.ModuleProvider(sharedFoo, FlagExporterInfoProvider).(FlagExporterInfo)
374	android.AssertPathsRelativeToTopEquals(t, "exported include dirs", []string{"outputbase/execroot/__main__/include"}, flagExporter.IncludeDirs)
375	android.AssertPathsRelativeToTopEquals(t, "exported system include dirs", []string{"outputbase/execroot/__main__/system_include"}, flagExporter.SystemIncludeDirs)
376	android.AssertPathsRelativeToTopEquals(t, "exported headers", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.GeneratedHeaders)
377	android.AssertPathsRelativeToTopEquals(t, "deps", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.Deps)
378}
379
380func TestLibraryVersionScript(t *testing.T) {
381	t.Parallel()
382	result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, `
383		cc_library {
384			name: "libfoo",
385			srcs: ["foo.c"],
386			version_script: "foo.map.txt",
387		}`)
388
389	libfoo := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("ld")
390
391	android.AssertStringListContains(t, "missing dependency on version_script",
392		libfoo.Implicits.Strings(), "foo.map.txt")
393	android.AssertStringDoesContain(t, "missing flag for version_script",
394		libfoo.Args["ldFlags"], "-Wl,--version-script,foo.map.txt")
395
396}
397
398func TestLibraryDynamicList(t *testing.T) {
399	t.Parallel()
400	result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, `
401		cc_library {
402			name: "libfoo",
403			srcs: ["foo.c"],
404			dynamic_list: "foo.dynamic.txt",
405		}`)
406
407	libfoo := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("ld")
408
409	android.AssertStringListContains(t, "missing dependency on dynamic_list",
410		libfoo.Implicits.Strings(), "foo.dynamic.txt")
411	android.AssertStringDoesContain(t, "missing flag for dynamic_list",
412		libfoo.Args["ldFlags"], "-Wl,--dynamic-list,foo.dynamic.txt")
413
414}
415
416func TestCcLibrarySharedWithBazelValidations(t *testing.T) {
417	t.Parallel()
418	bp := `
419cc_library_shared {
420	name: "foo",
421	srcs: ["foo.cc"],
422	bazel_module: { label: "//foo/bar:bar" },
423	tidy: true,
424}`
425	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
426	config.BazelContext = android.MockBazelContext{
427		OutputBaseDir: "outputbase",
428		LabelToCcInfo: map[string]cquery.CcInfo{
429			"//foo/bar:bar": cquery.CcInfo{
430				CcObjectFiles:        []string{"foo.o"},
431				Includes:             []string{"include"},
432				SystemIncludes:       []string{"system_include"},
433				RootDynamicLibraries: []string{"foo.so"},
434				TocFile:              "foo.so.toc",
435				TidyFiles:            []string{"foo.c.tidy"},
436			},
437		},
438	}
439	ctx := android.GroupFixturePreparers(
440		prepareForCcTest,
441		android.FixtureMergeEnv(map[string]string{
442			"ALLOW_LOCAL_TIDY_TRUE": "1",
443		}),
444	).RunTestWithConfig(t, config).TestContext
445
446	sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
447	producer := sharedFoo.(android.OutputFileProducer)
448	outputFiles, err := producer.OutputFiles("")
449	if err != nil {
450		t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
451	}
452	expectedOutputFiles := []string{"out/soong/.intermediates/foo/android_arm_armv7-a-neon_shared/validated/foo.so"}
453	android.AssertPathsRelativeToTopEquals(t, "output files", expectedOutputFiles, outputFiles)
454
455	tocFilePath := sharedFoo.(*Module).Toc()
456	if !tocFilePath.Valid() {
457		t.Errorf("Invalid tocFilePath: %s", tocFilePath)
458	}
459	tocFile := tocFilePath.Path()
460	expectedToc := "outputbase/execroot/__main__/foo.so.toc"
461	android.AssertStringEquals(t, "toc file", expectedToc, tocFile.String())
462
463	entries := android.AndroidMkEntriesForTest(t, ctx, sharedFoo)[0]
464	expectedFlags := []string{"-Ioutputbase/execroot/__main__/include", "-isystem outputbase/execroot/__main__/system_include"}
465	gotFlags := entries.EntryMap["LOCAL_EXPORT_CFLAGS"]
466	android.AssertDeepEquals(t, "androidmk exported cflags", expectedFlags, gotFlags)
467	android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "cc_library_shared", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
468}
469
470func TestCcLibrarySharedWithBazel(t *testing.T) {
471	t.Parallel()
472	bp := `
473cc_library_shared {
474	name: "foo",
475	srcs: ["foo.cc"],
476	bazel_module: { label: "//foo/bar:bar" },
477}`
478	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
479	config.BazelContext = android.MockBazelContext{
480		OutputBaseDir: "outputbase",
481		LabelToCcInfo: map[string]cquery.CcInfo{
482			"//foo/bar:bar": cquery.CcInfo{
483				CcObjectFiles:        []string{"foo.o"},
484				Includes:             []string{"include"},
485				SystemIncludes:       []string{"system_include"},
486				RootDynamicLibraries: []string{"foo.so"},
487				TocFile:              "foo.so.toc",
488			},
489		},
490	}
491	ctx := testCcWithConfig(t, config)
492
493	sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
494	producer := sharedFoo.(android.OutputFileProducer)
495	outputFiles, err := producer.OutputFiles("")
496	if err != nil {
497		t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
498	}
499	expectedOutputFiles := []string{"outputbase/execroot/__main__/foo.so"}
500	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
501
502	tocFilePath := sharedFoo.(*Module).Toc()
503	if !tocFilePath.Valid() {
504		t.Errorf("Invalid tocFilePath: %s", tocFilePath)
505	}
506	tocFile := tocFilePath.Path()
507	expectedToc := "outputbase/execroot/__main__/foo.so.toc"
508	android.AssertStringEquals(t, "toc file", expectedToc, tocFile.String())
509
510	entries := android.AndroidMkEntriesForTest(t, ctx, sharedFoo)[0]
511	expectedFlags := []string{"-Ioutputbase/execroot/__main__/include", "-isystem outputbase/execroot/__main__/system_include"}
512	gotFlags := entries.EntryMap["LOCAL_EXPORT_CFLAGS"]
513	android.AssertDeepEquals(t, "androidmk exported cflags", expectedFlags, gotFlags)
514	android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "cc_library_shared", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
515}
516
517func TestWholeStaticLibPrebuilts(t *testing.T) {
518	t.Parallel()
519	result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, `
520		cc_prebuilt_library_static {
521			name: "libprebuilt",
522			srcs: ["foo.a"],
523		}
524
525		cc_library_static {
526			name: "libdirect",
527			whole_static_libs: ["libprebuilt"],
528		}
529
530		cc_library_static {
531			name: "libtransitive",
532			whole_static_libs: ["libdirect"],
533		}
534
535		cc_library_static {
536			name: "libdirect_with_srcs",
537			srcs: ["bar.c"],
538			whole_static_libs: ["libprebuilt"],
539		}
540
541		cc_library_static {
542			name: "libtransitive_with_srcs",
543			srcs: ["baz.c"],
544			whole_static_libs: ["libdirect_with_srcs"],
545		}
546	`)
547
548	libdirect := result.ModuleForTests("libdirect", "android_arm64_armv8-a_static").Rule("arWithLibs")
549	libtransitive := result.ModuleForTests("libtransitive", "android_arm64_armv8-a_static").Rule("arWithLibs")
550
551	libdirectWithSrcs := result.ModuleForTests("libdirect_with_srcs", "android_arm64_armv8-a_static").Rule("arWithLibs")
552	libtransitiveWithSrcs := result.ModuleForTests("libtransitive_with_srcs", "android_arm64_armv8-a_static").Rule("arWithLibs")
553
554	barObj := result.ModuleForTests("libdirect_with_srcs", "android_arm64_armv8-a_static").Rule("cc")
555	bazObj := result.ModuleForTests("libtransitive_with_srcs", "android_arm64_armv8-a_static").Rule("cc")
556
557	android.AssertStringListContains(t, "missing dependency on foo.a",
558		libdirect.Inputs.Strings(), "foo.a")
559	android.AssertStringDoesContain(t, "missing flag for foo.a",
560		libdirect.Args["arLibs"], "foo.a")
561
562	android.AssertStringListContains(t, "missing dependency on foo.a",
563		libtransitive.Inputs.Strings(), "foo.a")
564	android.AssertStringDoesContain(t, "missing flag for foo.a",
565		libtransitive.Args["arLibs"], "foo.a")
566
567	android.AssertStringListContains(t, "missing dependency on foo.a",
568		libdirectWithSrcs.Inputs.Strings(), "foo.a")
569	android.AssertStringDoesContain(t, "missing flag for foo.a",
570		libdirectWithSrcs.Args["arLibs"], "foo.a")
571	android.AssertStringListContains(t, "missing dependency on bar.o",
572		libdirectWithSrcs.Inputs.Strings(), barObj.Output.String())
573	android.AssertStringDoesContain(t, "missing flag for bar.o",
574		libdirectWithSrcs.Args["arObjs"], barObj.Output.String())
575
576	android.AssertStringListContains(t, "missing dependency on foo.a",
577		libtransitiveWithSrcs.Inputs.Strings(), "foo.a")
578	android.AssertStringDoesContain(t, "missing flag for foo.a",
579		libtransitiveWithSrcs.Args["arLibs"], "foo.a")
580
581	android.AssertStringListContains(t, "missing dependency on bar.o",
582		libtransitiveWithSrcs.Inputs.Strings(), barObj.Output.String())
583	android.AssertStringDoesContain(t, "missing flag for bar.o",
584		libtransitiveWithSrcs.Args["arObjs"], barObj.Output.String())
585
586	android.AssertStringListContains(t, "missing dependency on baz.o",
587		libtransitiveWithSrcs.Inputs.Strings(), bazObj.Output.String())
588	android.AssertStringDoesContain(t, "missing flag for baz.o",
589		libtransitiveWithSrcs.Args["arObjs"], bazObj.Output.String())
590}
591