• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2018 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	"slices"
20	"strings"
21	"testing"
22
23	"android/soong/android"
24)
25
26func testGenruleContext(config android.Config) *android.TestContext {
27	ctx := android.NewTestArchContext(config)
28	ctx.RegisterModuleType("cc_genrule", GenRuleFactory)
29	ctx.Register()
30
31	return ctx
32}
33
34func TestArchGenruleCmd(t *testing.T) {
35	fs := map[string][]byte{
36		"tool": nil,
37		"foo":  nil,
38		"bar":  nil,
39	}
40	bp := `
41				cc_genrule {
42					name: "gen",
43					tool_files: ["tool"],
44					cmd: "$(location tool) $(in) $(out)",
45					out: ["out_arm"],
46					arch: {
47						arm: {
48							srcs: ["foo"],
49						},
50						arm64: {
51							srcs: ["bar"],
52						},
53					},
54				}
55			`
56	config := android.TestArchConfig(t.TempDir(), nil, bp, fs)
57
58	ctx := testGenruleContext(config)
59
60	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
61	if errs == nil {
62		_, errs = ctx.PrepareBuildActions(config)
63	}
64	if errs != nil {
65		t.Fatal(errs)
66	}
67
68	gen := ctx.ModuleForTests(t, "gen", "android_arm_armv7-a-neon").Output("out_arm")
69	expected := []string{"foo"}
70	if !reflect.DeepEqual(expected, gen.Implicits.Strings()[:len(expected)]) {
71		t.Errorf(`want arm inputs %v, got %v`, expected, gen.Implicits.Strings())
72	}
73
74	gen = ctx.ModuleForTests(t, "gen", "android_arm64_armv8-a").Output("out_arm")
75	expected = []string{"bar"}
76	if !reflect.DeepEqual(expected, gen.Implicits.Strings()[:len(expected)]) {
77		t.Errorf(`want arm64 inputs %v, got %v`, expected, gen.Implicits.Strings())
78	}
79}
80
81func TestLibraryGenruleCmd(t *testing.T) {
82	bp := `
83		cc_library {
84			name: "libboth",
85		}
86
87		cc_library_shared {
88			name: "libshared",
89		}
90
91		cc_library_static {
92			name: "libstatic",
93		}
94
95		cc_genrule {
96			name: "gen",
97			tool_files: ["tool"],
98			srcs: [
99				":libboth",
100				":libshared",
101				":libstatic",
102			],
103			cmd: "$(location tool) $(in) $(out)",
104			out: ["out"],
105		}
106		`
107	ctx := testCc(t, bp)
108
109	gen := ctx.ModuleForTests(t, "gen", "android_arm_armv7-a-neon").Output("out")
110	expected := []string{"libboth.so", "libshared.so", "libstatic.a"}
111	var got []string
112	for _, input := range gen.Implicits {
113		got = append(got, input.Base())
114	}
115	if !reflect.DeepEqual(expected, got[:len(expected)]) {
116		t.Errorf(`want inputs %v, got %v`, expected, got)
117	}
118}
119
120func TestCmdPrefix(t *testing.T) {
121	bp := `
122		cc_genrule {
123			name: "gen",
124			cmd: "echo foo",
125			out: ["out"],
126			native_bridge_supported: true,
127		}
128		`
129
130	testCases := []struct {
131		name     string
132		variant  string
133		preparer android.FixturePreparer
134
135		arch         string
136		nativeBridge string
137		multilib     string
138	}{
139		{
140			name:     "arm",
141			variant:  "android_arm_armv7-a-neon",
142			arch:     "arm",
143			multilib: "lib32",
144		},
145		{
146			name:     "arm64",
147			variant:  "android_arm64_armv8-a",
148			arch:     "arm64",
149			multilib: "lib64",
150		},
151		{
152			name:    "nativebridge",
153			variant: "android_native_bridge_arm_armv7-a-neon",
154			preparer: android.FixtureModifyConfig(func(config android.Config) {
155				config.Targets[android.Android] = []android.Target{
156					{
157						Os:           android.Android,
158						Arch:         android.Arch{ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}},
159						NativeBridge: android.NativeBridgeDisabled,
160					},
161					{
162						Os:                       android.Android,
163						Arch:                     android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}},
164						NativeBridge:             android.NativeBridgeEnabled,
165						NativeBridgeHostArchName: "x86",
166						NativeBridgeRelativePath: "arm",
167					},
168				}
169			}),
170			arch:         "arm",
171			multilib:     "lib32",
172			nativeBridge: "arm",
173		},
174	}
175
176	for _, tt := range testCases {
177		t.Run(tt.name, func(t *testing.T) {
178			result := android.GroupFixturePreparers(
179				PrepareForIntegrationTestWithCc,
180				android.OptionalFixturePreparer(tt.preparer),
181			).RunTestWithBp(t, bp)
182			gen := result.ModuleForTests(t, "gen", tt.variant)
183			sboxProto := android.RuleBuilderSboxProtoForTests(t, result.TestContext, gen.Output("genrule.sbox.textproto"))
184			cmd := *sboxProto.Commands[0].Command
185			android.AssertStringDoesContain(t, "incorrect CC_ARCH", cmd, "CC_ARCH="+tt.arch+" ")
186			android.AssertStringDoesContain(t, "incorrect CC_NATIVE_BRIDGE", cmd, "CC_NATIVE_BRIDGE="+tt.nativeBridge+" ")
187			android.AssertStringDoesContain(t, "incorrect CC_MULTILIB", cmd, "CC_MULTILIB="+tt.multilib+" ")
188		})
189	}
190}
191
192func TestVendorProductVariantGenrule(t *testing.T) {
193	bp := `
194	cc_genrule {
195		name: "gen",
196		tool_files: ["tool"],
197		cmd: "$(location tool) $(in) $(out)",
198		out: ["out"],
199		vendor_available: true,
200		product_available: true,
201	}
202	`
203	t.Helper()
204	ctx := PrepareForIntegrationTestWithCc.RunTestWithBp(t, bp)
205
206	variants := ctx.ModuleVariantsForTests("gen")
207	if !slices.Contains(variants, "android_vendor_arm64_armv8-a") {
208		t.Errorf(`expected vendor variant, but does not exist in %v`, variants)
209	}
210	if !slices.Contains(variants, "android_product_arm64_armv8-a") {
211		t.Errorf(`expected product variant, but does not exist in %v`, variants)
212	}
213}
214
215// cc_genrule is initialized to android.InitAndroidArchModule
216// that is an architecture-specific Android module.
217// So testing properties tagged with `android:"arch_variant"`
218// for cc_genrule.
219func TestMultilibGenruleOut(t *testing.T) {
220	bp := `
221	cc_genrule {
222		name: "gen",
223		cmd: "cp $(in) $(out)",
224		srcs: ["foo"],
225		multilib: {
226			lib32: {
227				out: [
228					"subdir32/external-module32",
229				],
230			},
231			lib64: {
232				out: [
233					"subdir64/external-module64",
234				],
235			},
236		},
237	}
238	`
239	result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, bp)
240	gen_32bit := result.ModuleForTests(t, "gen", "android_arm_armv7-a-neon").OutputFiles(result.TestContext, t, "")
241	android.AssertPathsEndWith(t,
242		"genrule_out",
243		[]string{
244			"subdir32/external-module32",
245		},
246		gen_32bit,
247	)
248
249	gen_64bit := result.ModuleForTests(t, "gen", "android_arm64_armv8-a").OutputFiles(result.TestContext, t, "")
250	android.AssertPathsEndWith(t,
251		"genrule_out",
252		[]string{
253			"subdir64/external-module64",
254		},
255		gen_64bit,
256	)
257}
258
259// Test that a genrule can depend on a tool with symlinks. The symlinks are ignored, but
260// at least it doesn't cause errors.
261func TestGenruleToolWithSymlinks(t *testing.T) {
262	bp := `
263	genrule {
264		name: "gen",
265		tools: ["tool_with_symlinks"],
266		cmd: "$(location tool_with_symlinks) $(in) $(out)",
267		out: ["out"],
268	}
269
270	cc_binary_host {
271		name: "tool_with_symlinks",
272		symlinks: ["symlink1", "symlink2"],
273	}
274	`
275	ctx := PrepareForIntegrationTestWithCc.
276		ExtendWithErrorHandler(android.FixtureExpectsNoErrors).
277		RunTestWithBp(t, bp)
278	gen := ctx.ModuleForTests(t, "gen", "").Output("out")
279	toolFound := false
280	symlinkFound := false
281	for _, dep := range gen.RuleParams.CommandDeps {
282		if strings.HasSuffix(dep, "/tool_with_symlinks") {
283			toolFound = true
284		}
285		if strings.HasSuffix(dep, "/symlink1") || strings.HasSuffix(dep, "/symlink2") {
286			symlinkFound = true
287		}
288	}
289	if !toolFound {
290		t.Errorf("Tool not found")
291	}
292	// We may want to change genrules to include symlinks later
293	if symlinkFound {
294		t.Errorf("Symlinks found")
295	}
296}
297