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