1// Copyright 2021 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 bp2build 16 17import ( 18 "fmt" 19 "testing" 20 21 "android/soong/android" 22 "android/soong/cc" 23 "android/soong/genrule" 24 "android/soong/java" 25) 26 27func registerGenruleModuleTypes(ctx android.RegistrationContext) { 28 ctx.RegisterModuleType("genrule_defaults", func() android.Module { return genrule.DefaultsFactory() }) 29} 30 31func runGenruleTestCase(t *testing.T, tc Bp2buildTestCase) { 32 t.Helper() 33 (&tc).ModuleTypeUnderTest = "genrule" 34 (&tc).ModuleTypeUnderTestFactory = genrule.GenRuleFactory 35 RunBp2BuildTestCase(t, registerGenruleModuleTypes, tc) 36} 37 38func otherGenruleBp(genruleTarget string) map[string]string { 39 return map[string]string{ 40 "other/Android.bp": fmt.Sprintf(`%s { 41 name: "foo.tool", 42 out: ["foo_tool.out"], 43 srcs: ["foo_tool.in"], 44 cmd: "cp $(in) $(out)", 45} 46%s { 47 name: "other.tool", 48 out: ["other_tool.out"], 49 srcs: ["other_tool.in"], 50 cmd: "cp $(in) $(out)", 51}`, genruleTarget, genruleTarget), 52 } 53} 54 55func TestGenruleCliVariableReplacement(t *testing.T) { 56 testCases := []struct { 57 moduleType string 58 factory android.ModuleFactory 59 genDir string 60 hod android.HostOrDeviceSupported 61 }{ 62 { 63 moduleType: "genrule", 64 factory: genrule.GenRuleFactory, 65 genDir: "$(RULEDIR)", 66 }, 67 { 68 moduleType: "cc_genrule", 69 factory: cc.GenRuleFactory, 70 genDir: "$(RULEDIR)", 71 hod: android.DeviceSupported, 72 }, 73 { 74 moduleType: "java_genrule", 75 factory: java.GenRuleFactory, 76 genDir: "$(RULEDIR)", 77 hod: android.DeviceSupported, 78 }, 79 { 80 moduleType: "java_genrule_host", 81 factory: java.GenRuleFactoryHost, 82 genDir: "$(RULEDIR)", 83 hod: android.HostSupported, 84 }, 85 } 86 87 bp := `%s { 88 name: "foo.tool", 89 out: ["foo_tool.out"], 90 srcs: ["foo_tool.in"], 91 cmd: "cp $(in) $(out)", 92 bazel_module: { bp2build_available: false }, 93} 94 95%s { 96 name: "foo", 97 out: ["foo.out"], 98 srcs: ["foo.in"], 99 tools: [":foo.tool"], 100 cmd: "$(location :foo.tool) --genDir=$(genDir) arg $(in) $(out)", 101 bazel_module: { bp2build_available: true }, 102}` 103 104 for _, tc := range testCases { 105 moduleAttrs := AttrNameToString{ 106 "cmd": fmt.Sprintf(`"$(location :foo.tool) --genDir=%s arg $(SRCS) $(OUTS)"`, tc.genDir), 107 "outs": `["foo.out"]`, 108 "srcs": `["foo.in"]`, 109 "tools": `[":foo.tool"]`, 110 } 111 112 expectedBazelTargets := []string{ 113 makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod), 114 } 115 116 t.Run(tc.moduleType, func(t *testing.T) { 117 RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, 118 Bp2buildTestCase{ 119 ModuleTypeUnderTest: tc.moduleType, 120 ModuleTypeUnderTestFactory: tc.factory, 121 Blueprint: fmt.Sprintf(bp, tc.moduleType, tc.moduleType), 122 ExpectedBazelTargets: expectedBazelTargets, 123 }) 124 }) 125 } 126} 127 128func TestGenruleLocationsLabel(t *testing.T) { 129 testCases := []struct { 130 moduleType string 131 factory android.ModuleFactory 132 hod android.HostOrDeviceSupported 133 }{ 134 { 135 moduleType: "genrule", 136 factory: genrule.GenRuleFactory, 137 }, 138 { 139 moduleType: "cc_genrule", 140 factory: cc.GenRuleFactory, 141 hod: android.DeviceSupported, 142 }, 143 { 144 moduleType: "java_genrule", 145 factory: java.GenRuleFactory, 146 hod: android.DeviceSupported, 147 }, 148 { 149 moduleType: "java_genrule_host", 150 factory: java.GenRuleFactoryHost, 151 hod: android.HostSupported, 152 }, 153 } 154 155 bp := `%s { 156 name: "foo.tools", 157 out: ["foo_tool.out", "foo_tool2.out"], 158 srcs: ["foo_tool.in"], 159 cmd: "cp $(in) $(out)", 160 bazel_module: { bp2build_available: true }, 161} 162 163%s { 164 name: "foo", 165 out: ["foo.out"], 166 srcs: ["foo.in"], 167 tools: [":foo.tools"], 168 cmd: "$(locations :foo.tools) -s $(out) $(in)", 169 bazel_module: { bp2build_available: true }, 170}` 171 172 for _, tc := range testCases { 173 fooAttrs := AttrNameToString{ 174 "cmd": `"$(locations :foo.tools) -s $(OUTS) $(SRCS)"`, 175 "outs": `["foo.out"]`, 176 "srcs": `["foo.in"]`, 177 "tools": `[":foo.tools"]`, 178 } 179 fooToolsAttrs := AttrNameToString{ 180 "cmd": `"cp $(SRCS) $(OUTS)"`, 181 "outs": `[ 182 "foo_tool.out", 183 "foo_tool2.out", 184 ]`, 185 "srcs": `["foo_tool.in"]`, 186 } 187 188 expectedBazelTargets := []string{ 189 makeBazelTargetHostOrDevice("genrule", "foo", fooAttrs, tc.hod), 190 makeBazelTargetHostOrDevice("genrule", "foo.tools", fooToolsAttrs, tc.hod), 191 } 192 193 t.Run(tc.moduleType, func(t *testing.T) { 194 RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, 195 Bp2buildTestCase{ 196 ModuleTypeUnderTest: tc.moduleType, 197 ModuleTypeUnderTestFactory: tc.factory, 198 Blueprint: fmt.Sprintf(bp, tc.moduleType, tc.moduleType), 199 ExpectedBazelTargets: expectedBazelTargets, 200 }) 201 }) 202 } 203} 204 205func TestGenruleLocationsAbsoluteLabel(t *testing.T) { 206 testCases := []struct { 207 moduleType string 208 factory android.ModuleFactory 209 hod android.HostOrDeviceSupported 210 }{ 211 { 212 moduleType: "genrule", 213 factory: genrule.GenRuleFactory, 214 }, 215 { 216 moduleType: "cc_genrule", 217 factory: cc.GenRuleFactory, 218 hod: android.DeviceSupported, 219 }, 220 { 221 moduleType: "java_genrule", 222 factory: java.GenRuleFactory, 223 hod: android.DeviceSupported, 224 }, 225 { 226 moduleType: "java_genrule_host", 227 factory: java.GenRuleFactoryHost, 228 hod: android.HostSupported, 229 }, 230 } 231 232 bp := `%s { 233 name: "foo", 234 out: ["foo.out"], 235 srcs: ["foo.in"], 236 tool_files: [":foo.tool"], 237 cmd: "$(locations :foo.tool) -s $(out) $(in)", 238 bazel_module: { bp2build_available: true }, 239}` 240 241 for _, tc := range testCases { 242 moduleAttrs := AttrNameToString{ 243 "cmd": `"$(locations //other:foo.tool) -s $(OUTS) $(SRCS)"`, 244 "outs": `["foo.out"]`, 245 "srcs": `["foo.in"]`, 246 "tools": `["//other:foo.tool"]`, 247 } 248 249 expectedBazelTargets := []string{ 250 makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod), 251 } 252 253 t.Run(tc.moduleType, func(t *testing.T) { 254 RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, 255 Bp2buildTestCase{ 256 ModuleTypeUnderTest: tc.moduleType, 257 ModuleTypeUnderTestFactory: tc.factory, 258 Blueprint: fmt.Sprintf(bp, tc.moduleType), 259 ExpectedBazelTargets: expectedBazelTargets, 260 Filesystem: otherGenruleBp(tc.moduleType), 261 }) 262 }) 263 } 264} 265 266func TestGenruleSrcsLocationsAbsoluteLabel(t *testing.T) { 267 testCases := []struct { 268 moduleType string 269 factory android.ModuleFactory 270 hod android.HostOrDeviceSupported 271 }{ 272 { 273 moduleType: "genrule", 274 factory: genrule.GenRuleFactory, 275 }, 276 { 277 moduleType: "cc_genrule", 278 factory: cc.GenRuleFactory, 279 hod: android.DeviceSupported, 280 }, 281 { 282 moduleType: "java_genrule", 283 factory: java.GenRuleFactory, 284 hod: android.DeviceSupported, 285 }, 286 { 287 moduleType: "java_genrule_host", 288 factory: java.GenRuleFactoryHost, 289 hod: android.HostSupported, 290 }, 291 } 292 293 bp := `%s { 294 name: "foo", 295 out: ["foo.out"], 296 srcs: [":other.tool"], 297 tool_files: [":foo.tool"], 298 cmd: "$(locations :foo.tool) -s $(out) $(location :other.tool)", 299 bazel_module: { bp2build_available: true }, 300}` 301 302 for _, tc := range testCases { 303 moduleAttrs := AttrNameToString{ 304 "cmd": `"$(locations //other:foo.tool) -s $(OUTS) $(location //other:other.tool)"`, 305 "outs": `["foo.out"]`, 306 "srcs": `["//other:other.tool"]`, 307 "tools": `["//other:foo.tool"]`, 308 } 309 310 expectedBazelTargets := []string{ 311 makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod), 312 } 313 314 t.Run(tc.moduleType, func(t *testing.T) { 315 RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, 316 Bp2buildTestCase{ 317 ModuleTypeUnderTest: tc.moduleType, 318 ModuleTypeUnderTestFactory: tc.factory, 319 Blueprint: fmt.Sprintf(bp, tc.moduleType), 320 ExpectedBazelTargets: expectedBazelTargets, 321 Filesystem: otherGenruleBp(tc.moduleType), 322 }) 323 }) 324 } 325} 326 327func TestGenruleLocationLabelShouldSubstituteFirstToolLabel(t *testing.T) { 328 testCases := []struct { 329 moduleType string 330 factory android.ModuleFactory 331 hod android.HostOrDeviceSupported 332 }{ 333 { 334 moduleType: "genrule", 335 factory: genrule.GenRuleFactory, 336 }, 337 { 338 moduleType: "cc_genrule", 339 factory: cc.GenRuleFactory, 340 hod: android.DeviceSupported, 341 }, 342 { 343 moduleType: "java_genrule", 344 factory: java.GenRuleFactory, 345 hod: android.DeviceSupported, 346 }, 347 { 348 moduleType: "java_genrule_host", 349 factory: java.GenRuleFactoryHost, 350 hod: android.HostSupported, 351 }, 352 } 353 354 bp := `%s { 355 name: "foo", 356 out: ["foo.out"], 357 srcs: ["foo.in"], 358 tool_files: [":foo.tool", ":other.tool"], 359 cmd: "$(location) -s $(out) $(in)", 360 bazel_module: { bp2build_available: true }, 361}` 362 363 for _, tc := range testCases { 364 moduleAttrs := AttrNameToString{ 365 "cmd": `"$(location //other:foo.tool) -s $(OUTS) $(SRCS)"`, 366 "outs": `["foo.out"]`, 367 "srcs": `["foo.in"]`, 368 "tools": `[ 369 "//other:foo.tool", 370 "//other:other.tool", 371 ]`, 372 } 373 374 expectedBazelTargets := []string{ 375 makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod), 376 } 377 378 t.Run(tc.moduleType, func(t *testing.T) { 379 RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, 380 Bp2buildTestCase{ 381 ModuleTypeUnderTest: tc.moduleType, 382 ModuleTypeUnderTestFactory: tc.factory, 383 Blueprint: fmt.Sprintf(bp, tc.moduleType), 384 ExpectedBazelTargets: expectedBazelTargets, 385 Filesystem: otherGenruleBp(tc.moduleType), 386 }) 387 }) 388 } 389} 390 391func TestGenruleLocationsLabelShouldSubstituteFirstToolLabel(t *testing.T) { 392 testCases := []struct { 393 moduleType string 394 factory android.ModuleFactory 395 hod android.HostOrDeviceSupported 396 }{ 397 { 398 moduleType: "genrule", 399 factory: genrule.GenRuleFactory, 400 }, 401 { 402 moduleType: "cc_genrule", 403 factory: cc.GenRuleFactory, 404 hod: android.DeviceSupported, 405 }, 406 { 407 moduleType: "java_genrule", 408 factory: java.GenRuleFactory, 409 hod: android.DeviceSupported, 410 }, 411 { 412 moduleType: "java_genrule_host", 413 factory: java.GenRuleFactoryHost, 414 hod: android.HostSupported, 415 }, 416 } 417 418 bp := `%s { 419 name: "foo", 420 out: ["foo.out"], 421 srcs: ["foo.in"], 422 tool_files: [":foo.tool", ":other.tool"], 423 cmd: "$(locations) -s $(out) $(in)", 424 bazel_module: { bp2build_available: true }, 425}` 426 427 for _, tc := range testCases { 428 moduleAttrs := AttrNameToString{ 429 "cmd": `"$(locations //other:foo.tool) -s $(OUTS) $(SRCS)"`, 430 "outs": `["foo.out"]`, 431 "srcs": `["foo.in"]`, 432 "tools": `[ 433 "//other:foo.tool", 434 "//other:other.tool", 435 ]`, 436 } 437 438 expectedBazelTargets := []string{ 439 makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod), 440 } 441 442 t.Run(tc.moduleType, func(t *testing.T) { 443 RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, 444 Bp2buildTestCase{ 445 ModuleTypeUnderTest: tc.moduleType, 446 ModuleTypeUnderTestFactory: tc.factory, 447 Blueprint: fmt.Sprintf(bp, tc.moduleType), 448 ExpectedBazelTargets: expectedBazelTargets, 449 Filesystem: otherGenruleBp(tc.moduleType), 450 }) 451 }) 452 } 453} 454 455func TestGenruleWithoutToolsOrToolFiles(t *testing.T) { 456 testCases := []struct { 457 moduleType string 458 factory android.ModuleFactory 459 hod android.HostOrDeviceSupported 460 }{ 461 { 462 moduleType: "genrule", 463 factory: genrule.GenRuleFactory, 464 }, 465 { 466 moduleType: "cc_genrule", 467 factory: cc.GenRuleFactory, 468 hod: android.DeviceSupported, 469 }, 470 { 471 moduleType: "java_genrule", 472 factory: java.GenRuleFactory, 473 hod: android.DeviceSupported, 474 }, 475 { 476 moduleType: "java_genrule_host", 477 factory: java.GenRuleFactoryHost, 478 hod: android.HostSupported, 479 }, 480 } 481 482 bp := `%s { 483 name: "foo", 484 out: ["foo.out"], 485 srcs: ["foo.in"], 486 cmd: "cp $(in) $(out)", 487 bazel_module: { bp2build_available: true }, 488}` 489 490 for _, tc := range testCases { 491 moduleAttrs := AttrNameToString{ 492 "cmd": `"cp $(SRCS) $(OUTS)"`, 493 "outs": `["foo.out"]`, 494 "srcs": `["foo.in"]`, 495 } 496 497 expectedBazelTargets := []string{ 498 makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod), 499 } 500 501 t.Run(tc.moduleType, func(t *testing.T) { 502 RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, 503 Bp2buildTestCase{ 504 ModuleTypeUnderTest: tc.moduleType, 505 ModuleTypeUnderTestFactory: tc.factory, 506 Blueprint: fmt.Sprintf(bp, tc.moduleType), 507 ExpectedBazelTargets: expectedBazelTargets, 508 }) 509 }) 510 } 511} 512 513func TestGenruleBp2BuildInlinesDefaults(t *testing.T) { 514 testCases := []Bp2buildTestCase{ 515 { 516 Description: "genrule applies properties from a genrule_defaults dependency if not specified", 517 Blueprint: `genrule_defaults { 518 name: "gen_defaults", 519 cmd: "do-something $(in) $(out)", 520} 521genrule { 522 name: "gen", 523 out: ["out"], 524 srcs: ["in1"], 525 defaults: ["gen_defaults"], 526 bazel_module: { bp2build_available: true }, 527} 528`, 529 ExpectedBazelTargets: []string{ 530 MakeBazelTargetNoRestrictions("genrule", "gen", AttrNameToString{ 531 "cmd": `"do-something $(SRCS) $(OUTS)"`, 532 "outs": `["out"]`, 533 "srcs": `["in1"]`, 534 }), 535 }, 536 }, 537 { 538 Description: "genrule does merges properties from a genrule_defaults dependency, latest-first", 539 Blueprint: `genrule_defaults { 540 name: "gen_defaults", 541 out: ["out-from-defaults"], 542 srcs: ["in-from-defaults"], 543 cmd: "cmd-from-defaults", 544} 545genrule { 546 name: "gen", 547 out: ["out"], 548 srcs: ["in1"], 549 defaults: ["gen_defaults"], 550 cmd: "do-something $(in) $(out)", 551 bazel_module: { bp2build_available: true }, 552} 553`, 554 ExpectedBazelTargets: []string{ 555 MakeBazelTargetNoRestrictions("genrule", "gen", AttrNameToString{ 556 "cmd": `"do-something $(SRCS) $(OUTS)"`, 557 "outs": `[ 558 "out-from-defaults", 559 "out", 560 ]`, 561 "srcs": `[ 562 "in-from-defaults", 563 "in1", 564 ]`, 565 }), 566 }, 567 }, 568 { 569 Description: "genrule applies properties from list of genrule_defaults", 570 Blueprint: `genrule_defaults { 571 name: "gen_defaults1", 572 cmd: "cp $(in) $(out)", 573} 574 575genrule_defaults { 576 name: "gen_defaults2", 577 srcs: ["in1"], 578} 579 580genrule { 581 name: "gen", 582 out: ["out"], 583 defaults: ["gen_defaults1", "gen_defaults2"], 584 bazel_module: { bp2build_available: true }, 585} 586`, 587 ExpectedBazelTargets: []string{ 588 MakeBazelTargetNoRestrictions("genrule", "gen", AttrNameToString{ 589 "cmd": `"cp $(SRCS) $(OUTS)"`, 590 "outs": `["out"]`, 591 "srcs": `["in1"]`, 592 }), 593 }, 594 }, 595 { 596 Description: "genrule applies properties from genrule_defaults transitively", 597 Blueprint: `genrule_defaults { 598 name: "gen_defaults1", 599 defaults: ["gen_defaults2"], 600 cmd: "cmd1 $(in) $(out)", // overrides gen_defaults2's cmd property value. 601} 602 603genrule_defaults { 604 name: "gen_defaults2", 605 defaults: ["gen_defaults3"], 606 cmd: "cmd2 $(in) $(out)", 607 out: ["out-from-2"], 608 srcs: ["in1"], 609} 610 611genrule_defaults { 612 name: "gen_defaults3", 613 out: ["out-from-3"], 614 srcs: ["srcs-from-3"], 615} 616 617genrule { 618 name: "gen", 619 out: ["out"], 620 defaults: ["gen_defaults1"], 621 bazel_module: { bp2build_available: true }, 622} 623`, 624 ExpectedBazelTargets: []string{ 625 MakeBazelTargetNoRestrictions("genrule", "gen", AttrNameToString{ 626 "cmd": `"cmd1 $(SRCS) $(OUTS)"`, 627 "outs": `[ 628 "out-from-3", 629 "out-from-2", 630 "out", 631 ]`, 632 "srcs": `[ 633 "srcs-from-3", 634 "in1", 635 ]`, 636 }), 637 }, 638 }, 639 } 640 641 for _, testCase := range testCases { 642 t.Run(testCase.Description, func(t *testing.T) { 643 runGenruleTestCase(t, testCase) 644 }) 645 } 646} 647 648func TestCcGenruleArchAndExcludeSrcs(t *testing.T) { 649 name := "cc_genrule with arch" 650 bp := ` 651 cc_genrule { 652 name: "foo", 653 srcs: [ 654 "foo1.in", 655 "foo2.in", 656 ], 657 exclude_srcs: ["foo2.in"], 658 arch: { 659 arm: { 660 srcs: [ 661 "foo1_arch.in", 662 "foo2_arch.in", 663 ], 664 exclude_srcs: ["foo2_arch.in"], 665 }, 666 }, 667 cmd: "cat $(in) > $(out)", 668 bazel_module: { bp2build_available: true }, 669 }` 670 671 expectedBazelAttrs := AttrNameToString{ 672 "srcs": `["foo1.in"] + select({ 673 "//build/bazel/platforms/arch:arm": ["foo1_arch.in"], 674 "//conditions:default": [], 675 })`, 676 "cmd": `"cat $(SRCS) > $(OUTS)"`, 677 "target_compatible_with": `["//build/bazel/platforms/os:android"]`, 678 } 679 680 expectedBazelTargets := []string{ 681 MakeBazelTargetNoRestrictions("genrule", "foo", expectedBazelAttrs), 682 } 683 684 t.Run(name, func(t *testing.T) { 685 RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, 686 Bp2buildTestCase{ 687 ModuleTypeUnderTest: "cc_genrule", 688 ModuleTypeUnderTestFactory: cc.GenRuleFactory, 689 Blueprint: bp, 690 ExpectedBazelTargets: expectedBazelTargets, 691 }) 692 }) 693} 694