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 "android/soong/android" 19 "android/soong/cc" 20 "strings" 21 "testing" 22) 23 24const ( 25 // See cc/testing.go for more context 26 soongCcLibraryPreamble = ` 27cc_defaults { 28 name: "linux_bionic_supported", 29} 30 31toolchain_library { 32 name: "libclang_rt.builtins-x86_64-android", 33 defaults: ["linux_bionic_supported"], 34 vendor_available: true, 35 vendor_ramdisk_available: true, 36 product_available: true, 37 recovery_available: true, 38 native_bridge_supported: true, 39 src: "", 40}` 41) 42 43func TestCcLibraryBp2Build(t *testing.T) { 44 // b/191166471 disabled in sc-dev 45 t.Skip() 46 testCases := []struct { 47 description string 48 moduleTypeUnderTest string 49 moduleTypeUnderTestFactory android.ModuleFactory 50 moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext) 51 bp string 52 expectedBazelTargets []string 53 filesystem map[string]string 54 dir string 55 depsMutators []android.RegisterMutatorFunc 56 }{ 57 { 58 description: "cc_library - simple example", 59 moduleTypeUnderTest: "cc_library", 60 moduleTypeUnderTestFactory: cc.LibraryFactory, 61 moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, 62 filesystem: map[string]string{ 63 "android.cpp": "", 64 "darwin.cpp": "", 65 // Refer to cc.headerExts for the supported header extensions in Soong. 66 "header.h": "", 67 "header.hh": "", 68 "header.hpp": "", 69 "header.hxx": "", 70 "header.h++": "", 71 "header.inl": "", 72 "header.inc": "", 73 "header.ipp": "", 74 "header.h.generic": "", 75 "impl.cpp": "", 76 "linux.cpp": "", 77 "x86.cpp": "", 78 "x86_64.cpp": "", 79 "foo-dir/a.h": "", 80 }, 81 bp: soongCcLibraryPreamble + ` 82cc_library_headers { name: "some-headers" } 83cc_library { 84 name: "foo-lib", 85 srcs: ["impl.cpp"], 86 cflags: ["-Wall"], 87 header_libs: ["some-headers"], 88 export_include_dirs: ["foo-dir"], 89 ldflags: ["-Wl,--exclude-libs=bar.a"], 90 arch: { 91 x86: { 92 ldflags: ["-Wl,--exclude-libs=baz.a"], 93 srcs: ["x86.cpp"], 94 }, 95 x86_64: { 96 ldflags: ["-Wl,--exclude-libs=qux.a"], 97 srcs: ["x86_64.cpp"], 98 }, 99 }, 100 target: { 101 android: { 102 srcs: ["android.cpp"], 103 }, 104 linux_glibc: { 105 srcs: ["linux.cpp"], 106 }, 107 darwin: { 108 srcs: ["darwin.cpp"], 109 }, 110 }, 111} 112`, 113 expectedBazelTargets: []string{`cc_library( 114 name = "foo-lib", 115 copts = [ 116 "-Wall", 117 "-I.", 118 ], 119 deps = [":some-headers"], 120 includes = ["foo-dir"], 121 linkopts = ["-Wl,--exclude-libs=bar.a"] + select({ 122 "//build/bazel/platforms/arch:x86": ["-Wl,--exclude-libs=baz.a"], 123 "//build/bazel/platforms/arch:x86_64": ["-Wl,--exclude-libs=qux.a"], 124 "//conditions:default": [], 125 }), 126 srcs = ["impl.cpp"] + select({ 127 "//build/bazel/platforms/arch:x86": ["x86.cpp"], 128 "//build/bazel/platforms/arch:x86_64": ["x86_64.cpp"], 129 "//conditions:default": [], 130 }) + select({ 131 "//build/bazel/platforms/os:android": ["android.cpp"], 132 "//build/bazel/platforms/os:darwin": ["darwin.cpp"], 133 "//build/bazel/platforms/os:linux": ["linux.cpp"], 134 "//conditions:default": [], 135 }), 136)`}, 137 }, 138 { 139 description: "cc_library - trimmed example of //bionic/linker:ld-android", 140 moduleTypeUnderTest: "cc_library", 141 moduleTypeUnderTestFactory: cc.LibraryFactory, 142 moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, 143 filesystem: map[string]string{ 144 "ld-android.cpp": "", 145 "linked_list.h": "", 146 "linker.h": "", 147 "linker_block_allocator.h": "", 148 "linker_cfi.h": "", 149 }, 150 bp: soongCcLibraryPreamble + ` 151cc_library_headers { name: "libc_headers" } 152cc_library { 153 name: "fake-ld-android", 154 srcs: ["ld_android.cpp"], 155 cflags: [ 156 "-Wall", 157 "-Wextra", 158 "-Wunused", 159 "-Werror", 160 ], 161 header_libs: ["libc_headers"], 162 ldflags: [ 163 "-Wl,--exclude-libs=libgcc.a", 164 "-Wl,--exclude-libs=libgcc_stripped.a", 165 "-Wl,--exclude-libs=libclang_rt.builtins-arm-android.a", 166 "-Wl,--exclude-libs=libclang_rt.builtins-aarch64-android.a", 167 "-Wl,--exclude-libs=libclang_rt.builtins-i686-android.a", 168 "-Wl,--exclude-libs=libclang_rt.builtins-x86_64-android.a", 169 ], 170 arch: { 171 x86: { 172 ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"], 173 }, 174 x86_64: { 175 ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"], 176 }, 177 }, 178} 179`, 180 expectedBazelTargets: []string{`cc_library( 181 name = "fake-ld-android", 182 copts = [ 183 "-Wall", 184 "-Wextra", 185 "-Wunused", 186 "-Werror", 187 "-I.", 188 ], 189 deps = [":libc_headers"], 190 linkopts = [ 191 "-Wl,--exclude-libs=libgcc.a", 192 "-Wl,--exclude-libs=libgcc_stripped.a", 193 "-Wl,--exclude-libs=libclang_rt.builtins-arm-android.a", 194 "-Wl,--exclude-libs=libclang_rt.builtins-aarch64-android.a", 195 "-Wl,--exclude-libs=libclang_rt.builtins-i686-android.a", 196 "-Wl,--exclude-libs=libclang_rt.builtins-x86_64-android.a", 197 ] + select({ 198 "//build/bazel/platforms/arch:x86": ["-Wl,--exclude-libs=libgcc_eh.a"], 199 "//build/bazel/platforms/arch:x86_64": ["-Wl,--exclude-libs=libgcc_eh.a"], 200 "//conditions:default": [], 201 }), 202 srcs = ["ld_android.cpp"], 203)`}, 204 }, 205 { 206 description: "cc_library exclude_srcs - trimmed example of //external/arm-optimized-routines:libarm-optimized-routines-math", 207 moduleTypeUnderTest: "cc_library", 208 moduleTypeUnderTestFactory: cc.LibraryFactory, 209 moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, 210 dir: "external", 211 filesystem: map[string]string{ 212 "external/math/cosf.c": "", 213 "external/math/erf.c": "", 214 "external/math/erf_data.c": "", 215 "external/math/erff.c": "", 216 "external/math/erff_data.c": "", 217 "external/Android.bp": ` 218cc_library { 219 name: "fake-libarm-optimized-routines-math", 220 exclude_srcs: [ 221 // Provided by: 222 // bionic/libm/upstream-freebsd/lib/msun/src/s_erf.c 223 // bionic/libm/upstream-freebsd/lib/msun/src/s_erff.c 224 "math/erf.c", 225 "math/erf_data.c", 226 "math/erff.c", 227 "math/erff_data.c", 228 ], 229 srcs: [ 230 "math/*.c", 231 ], 232 // arch-specific settings 233 arch: { 234 arm64: { 235 cflags: [ 236 "-DHAVE_FAST_FMA=1", 237 ], 238 }, 239 }, 240 bazel_module: { bp2build_available: true }, 241} 242`, 243 }, 244 bp: soongCcLibraryPreamble, 245 expectedBazelTargets: []string{`cc_library( 246 name = "fake-libarm-optimized-routines-math", 247 copts = ["-Iexternal"] + select({ 248 "//build/bazel/platforms/arch:arm64": ["-DHAVE_FAST_FMA=1"], 249 "//conditions:default": [], 250 }), 251 srcs = ["math/cosf.c"], 252)`}, 253 }, 254 { 255 description: "cc_library shared/static props", 256 moduleTypeUnderTest: "cc_library", 257 moduleTypeUnderTestFactory: cc.LibraryFactory, 258 moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, 259 depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build}, 260 dir: "foo/bar", 261 filesystem: map[string]string{ 262 "foo/bar/both.cpp": "", 263 "foo/bar/sharedonly.cpp": "", 264 "foo/bar/staticonly.cpp": "", 265 "foo/bar/Android.bp": ` 266cc_library { 267 name: "a", 268 srcs: ["both.cpp"], 269 cflags: ["bothflag"], 270 shared_libs: ["shared_dep_for_both"], 271 static_libs: ["static_dep_for_both"], 272 whole_static_libs: ["whole_static_lib_for_both"], 273 static: { 274 srcs: ["staticonly.cpp"], 275 cflags: ["staticflag"], 276 shared_libs: ["shared_dep_for_static"], 277 static_libs: ["static_dep_for_static"], 278 whole_static_libs: ["whole_static_lib_for_static"], 279 }, 280 shared: { 281 srcs: ["sharedonly.cpp"], 282 cflags: ["sharedflag"], 283 shared_libs: ["shared_dep_for_shared"], 284 static_libs: ["static_dep_for_shared"], 285 whole_static_libs: ["whole_static_lib_for_shared"], 286 }, 287 bazel_module: { bp2build_available: true }, 288} 289 290cc_library_static { name: "static_dep_for_shared" } 291 292cc_library_static { name: "static_dep_for_static" } 293 294cc_library_static { name: "static_dep_for_both" } 295 296cc_library_static { name: "whole_static_lib_for_shared" } 297 298cc_library_static { name: "whole_static_lib_for_static" } 299 300cc_library_static { name: "whole_static_lib_for_both" } 301 302cc_library { name: "shared_dep_for_shared" } 303 304cc_library { name: "shared_dep_for_static" } 305 306cc_library { name: "shared_dep_for_both" } 307`, 308 }, 309 bp: soongCcLibraryPreamble, 310 expectedBazelTargets: []string{`cc_library( 311 name = "a", 312 copts = [ 313 "bothflag", 314 "-Ifoo/bar", 315 ], 316 deps = [":static_dep_for_both"], 317 dynamic_deps = [":shared_dep_for_both"], 318 dynamic_deps_for_shared = [":shared_dep_for_shared"], 319 dynamic_deps_for_static = [":shared_dep_for_static"], 320 shared_copts = ["sharedflag"], 321 shared_srcs = ["sharedonly.cpp"], 322 srcs = ["both.cpp"], 323 static_copts = ["staticflag"], 324 static_deps_for_shared = [":static_dep_for_shared"], 325 static_deps_for_static = [":static_dep_for_static"], 326 static_srcs = ["staticonly.cpp"], 327 whole_archive_deps = [":whole_static_lib_for_both"], 328 whole_archive_deps_for_shared = [":whole_static_lib_for_shared"], 329 whole_archive_deps_for_static = [":whole_static_lib_for_static"], 330)`}, 331 }, 332 { 333 description: "cc_library non-configured version script", 334 moduleTypeUnderTest: "cc_library", 335 moduleTypeUnderTestFactory: cc.LibraryFactory, 336 moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, 337 depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build}, 338 dir: "foo/bar", 339 filesystem: map[string]string{ 340 "foo/bar/Android.bp": ` 341cc_library { 342 name: "a", 343 srcs: ["a.cpp"], 344 version_script: "v.map", 345 bazel_module: { bp2build_available: true }, 346} 347`, 348 }, 349 bp: soongCcLibraryPreamble, 350 expectedBazelTargets: []string{`cc_library( 351 name = "a", 352 copts = ["-Ifoo/bar"], 353 srcs = ["a.cpp"], 354 version_script = "v.map", 355)`}, 356 }, 357 { 358 description: "cc_library configured version script", 359 moduleTypeUnderTest: "cc_library", 360 moduleTypeUnderTestFactory: cc.LibraryFactory, 361 moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, 362 depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build}, 363 dir: "foo/bar", 364 filesystem: map[string]string{ 365 "foo/bar/Android.bp": ` 366 cc_library { 367 name: "a", 368 srcs: ["a.cpp"], 369 arch: { 370 arm: { 371 version_script: "arm.map", 372 }, 373 arm64: { 374 version_script: "arm64.map", 375 }, 376 }, 377 378 bazel_module: { bp2build_available: true }, 379 } 380 `, 381 }, 382 bp: soongCcLibraryPreamble, 383 expectedBazelTargets: []string{`cc_library( 384 name = "a", 385 copts = ["-Ifoo/bar"], 386 srcs = ["a.cpp"], 387 version_script = select({ 388 "//build/bazel/platforms/arch:arm": "arm.map", 389 "//build/bazel/platforms/arch:arm64": "arm64.map", 390 "//conditions:default": None, 391 }), 392)`}, 393 }, 394 { 395 description: "cc_library shared_libs", 396 moduleTypeUnderTest: "cc_library", 397 moduleTypeUnderTestFactory: cc.LibraryFactory, 398 moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, 399 depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build}, 400 dir: "foo/bar", 401 filesystem: map[string]string{ 402 "foo/bar/Android.bp": ` 403cc_library { 404 name: "mylib", 405 bazel_module: { bp2build_available: true }, 406} 407 408cc_library { 409 name: "a", 410 shared_libs: ["mylib",], 411 bazel_module: { bp2build_available: true }, 412} 413`, 414 }, 415 bp: soongCcLibraryPreamble, 416 expectedBazelTargets: []string{`cc_library( 417 name = "a", 418 copts = ["-Ifoo/bar"], 419 dynamic_deps = [":mylib"], 420)`, `cc_library( 421 name = "mylib", 422 copts = ["-Ifoo/bar"], 423)`}, 424 }, 425 { 426 description: "cc_library pack_relocations test", 427 moduleTypeUnderTest: "cc_library", 428 moduleTypeUnderTestFactory: cc.LibraryFactory, 429 moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, 430 depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build}, 431 dir: "foo/bar", 432 filesystem: map[string]string{ 433 "foo/bar/Android.bp": ` 434cc_library { 435 name: "a", 436 srcs: ["a.cpp"], 437 pack_relocations: false, 438 bazel_module: { bp2build_available: true }, 439} 440 441cc_library { 442 name: "b", 443 srcs: ["b.cpp"], 444 arch: { 445 x86_64: { 446 pack_relocations: false, 447 }, 448 }, 449 bazel_module: { bp2build_available: true }, 450} 451 452cc_library { 453 name: "c", 454 srcs: ["c.cpp"], 455 target: { 456 darwin: { 457 pack_relocations: false, 458 }, 459 }, 460 bazel_module: { bp2build_available: true }, 461}`, 462 }, 463 bp: soongCcLibraryPreamble, 464 expectedBazelTargets: []string{`cc_library( 465 name = "a", 466 copts = ["-Ifoo/bar"], 467 linkopts = ["-Wl,--pack-dyn-relocs=none"], 468 srcs = ["a.cpp"], 469)`, `cc_library( 470 name = "b", 471 copts = ["-Ifoo/bar"], 472 linkopts = select({ 473 "//build/bazel/platforms/arch:x86_64": ["-Wl,--pack-dyn-relocs=none"], 474 "//conditions:default": [], 475 }), 476 srcs = ["b.cpp"], 477)`, `cc_library( 478 name = "c", 479 copts = ["-Ifoo/bar"], 480 linkopts = select({ 481 "//build/bazel/platforms/os:darwin": ["-Wl,--pack-dyn-relocs=none"], 482 "//conditions:default": [], 483 }), 484 srcs = ["c.cpp"], 485)`}, 486 }, 487 { 488 description: "cc_library spaces in copts", 489 moduleTypeUnderTest: "cc_library", 490 moduleTypeUnderTestFactory: cc.LibraryFactory, 491 moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, 492 depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build}, 493 dir: "foo/bar", 494 filesystem: map[string]string{ 495 "foo/bar/Android.bp": ` 496cc_library { 497 name: "a", 498 cflags: ["-include header.h",], 499 bazel_module: { bp2build_available: true }, 500} 501`, 502 }, 503 bp: soongCcLibraryPreamble, 504 expectedBazelTargets: []string{`cc_library( 505 name = "a", 506 copts = [ 507 "-include", 508 "header.h", 509 "-Ifoo/bar", 510 ], 511)`}, 512 }, 513 { 514 description: "cc_library cppflags goes into copts", 515 moduleTypeUnderTest: "cc_library", 516 moduleTypeUnderTestFactory: cc.LibraryFactory, 517 moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, 518 depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build}, 519 dir: "foo/bar", 520 filesystem: map[string]string{ 521 "foo/bar/Android.bp": `cc_library { 522 name: "a", 523 srcs: ["a.cpp"], 524 cflags: [ 525 "-Wall", 526 ], 527 cppflags: [ 528 "-fsigned-char", 529 "-pedantic", 530 ], 531 arch: { 532 arm64: { 533 cppflags: ["-DARM64=1"], 534 }, 535 }, 536 target: { 537 android: { 538 cppflags: ["-DANDROID=1"], 539 }, 540 }, 541 bazel_module: { bp2build_available: true }, 542} 543`, 544 }, 545 bp: soongCcLibraryPreamble, 546 expectedBazelTargets: []string{`cc_library( 547 name = "a", 548 copts = [ 549 "-Wall", 550 "-fsigned-char", 551 "-pedantic", 552 "-Ifoo/bar", 553 ] + select({ 554 "//build/bazel/platforms/arch:arm64": ["-DARM64=1"], 555 "//conditions:default": [], 556 }) + select({ 557 "//build/bazel/platforms/os:android": ["-DANDROID=1"], 558 "//conditions:default": [], 559 }), 560 srcs = ["a.cpp"], 561)`}, 562 }, 563 } 564 565 dir := "." 566 for _, testCase := range testCases { 567 filesystem := make(map[string][]byte) 568 toParse := []string{ 569 "Android.bp", 570 } 571 for f, content := range testCase.filesystem { 572 if strings.HasSuffix(f, "Android.bp") { 573 toParse = append(toParse, f) 574 } 575 filesystem[f] = []byte(content) 576 } 577 config := android.TestConfig(buildDir, nil, testCase.bp, filesystem) 578 ctx := android.NewTestContext(config) 579 580 cc.RegisterCCBuildComponents(ctx) 581 ctx.RegisterModuleType("cc_library_static", cc.LibraryStaticFactory) 582 ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory) 583 ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory) 584 ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory) 585 ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator) 586 ctx.RegisterBp2BuildConfig(bp2buildConfig) // TODO(jingwen): make this the default for all tests 587 for _, m := range testCase.depsMutators { 588 ctx.DepsBp2BuildMutators(m) 589 } 590 ctx.RegisterForBazelConversion() 591 592 _, errs := ctx.ParseFileList(dir, toParse) 593 if Errored(t, testCase.description, errs) { 594 continue 595 } 596 _, errs = ctx.ResolveDependencies(config) 597 if Errored(t, testCase.description, errs) { 598 continue 599 } 600 601 checkDir := dir 602 if testCase.dir != "" { 603 checkDir = testCase.dir 604 } 605 codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build) 606 bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir) 607 if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount { 608 t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount) 609 } else { 610 for i, target := range bazelTargets { 611 if w, g := testCase.expectedBazelTargets[i], target.content; w != g { 612 t.Errorf( 613 "%s: Expected generated Bazel target to be '%s', got '%s'", 614 testCase.description, 615 w, 616 g, 617 ) 618 } 619 } 620 } 621 } 622} 623