diff --git a/bp2build/Android.bp b/bp2build/Android.bp index c74f90232..cc616f23e 100644 --- a/bp2build/Android.bp +++ b/bp2build/Android.bp @@ -27,6 +27,7 @@ bootstrap_go_package { "build_conversion_test.go", "bzl_conversion_test.go", "cc_library_headers_conversion_test.go", + "cc_library_static_conversion_test.go", "cc_object_conversion_test.go", "conversion_test.go", "python_binary_conversion_test.go", diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go index 5bf5c802f..049f84a02 100644 --- a/bp2build/cc_library_headers_conversion_test.go +++ b/bp2build/cc_library_headers_conversion_test.go @@ -123,7 +123,8 @@ cc_library_headers { name: "foo_headers", export_include_dirs: ["dir-1", "dir-2"], header_libs: ["lib-1", "lib-2"], - export_header_lib_headers: ["lib-1", "lib-2"], + + // TODO: Also support export_header_lib_headers bazel_module: { bp2build_available: true }, }`, expectedBazelTargets: []string{`cc_library_headers( diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go new file mode 100644 index 000000000..7bf5fd3e4 --- /dev/null +++ b/bp2build/cc_library_static_conversion_test.go @@ -0,0 +1,307 @@ +// Copyright 2021 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bp2build + +import ( + "android/soong/android" + "android/soong/cc" + "strings" + "testing" +) + +const ( + // See cc/testing.go for more context + soongCcLibraryStaticPreamble = ` +cc_defaults { + name: "linux_bionic_supported", +} + +toolchain_library { + name: "libclang_rt.builtins-x86_64-android", + defaults: ["linux_bionic_supported"], + vendor_available: true, + vendor_ramdisk_available: true, + product_available: true, + recovery_available: true, + native_bridge_supported: true, + src: "", +} + +toolchain_library { + name: "libatomic", + defaults: ["linux_bionic_supported"], + vendor_available: true, + vendor_ramdisk_available: true, + product_available: true, + recovery_available: true, + native_bridge_supported: true, + src: "", +}` +) + +func TestCcLibraryStaticLoadStatement(t *testing.T) { + testCases := []struct { + bazelTargets BazelTargets + expectedLoadStatements string + }{ + { + bazelTargets: BazelTargets{ + BazelTarget{ + name: "cc_library_static_target", + ruleClass: "cc_library_static", + // NOTE: No bzlLoadLocation for native rules + }, + }, + expectedLoadStatements: ``, + }, + } + + for _, testCase := range testCases { + actual := testCase.bazelTargets.LoadStatements() + expected := testCase.expectedLoadStatements + if actual != expected { + t.Fatalf("Expected load statements to be %s, got %s", expected, actual) + } + } + +} + +func TestCcLibraryStaticBp2Build(t *testing.T) { + testCases := []struct { + description string + moduleTypeUnderTest string + moduleTypeUnderTestFactory android.ModuleFactory + moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext) + preArchMutators []android.RegisterMutatorFunc + depsMutators []android.RegisterMutatorFunc + bp string + expectedBazelTargets []string + filesystem map[string]string + dir string + }{ + { + description: "cc_library_static test", + moduleTypeUnderTest: "cc_library_static", + moduleTypeUnderTestFactory: cc.LibraryStaticFactory, + moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build, + filesystem: map[string]string{ + // NOTE: include_dir headers *should not* appear in Bazel hdrs later (?) + "include_dir_1/include_dir_1_a.h": "", + "include_dir_1/include_dir_1_b.h": "", + "include_dir_2/include_dir_2_a.h": "", + "include_dir_2/include_dir_2_b.h": "", + // NOTE: local_include_dir headers *should not* appear in Bazel hdrs later (?) + "local_include_dir_1/local_include_dir_1_a.h": "", + "local_include_dir_1/local_include_dir_1_b.h": "", + "local_include_dir_2/local_include_dir_2_a.h": "", + "local_include_dir_2/local_include_dir_2_b.h": "", + // NOTE: export_include_dir headers *should* appear in Bazel hdrs later + "export_include_dir_1/export_include_dir_1_a.h": "", + "export_include_dir_1/export_include_dir_1_b.h": "", + "export_include_dir_2/export_include_dir_2_a.h": "", + "export_include_dir_2/export_include_dir_2_b.h": "", + }, + bp: soongCcLibraryStaticPreamble + ` +cc_library_headers { + name: "header_lib_1", + export_include_dirs: ["header_lib_1"], +} + +cc_library_headers { + name: "header_lib_2", + export_include_dirs: ["header_lib_2"], +} + +cc_library_static { + name: "static_lib_1", + srcs: ["static_lib_1.cc"], + bazel_module: { bp2build_available: true }, +} + +cc_library_static { + name: "static_lib_2", + srcs: ["static_lib_2.cc"], + bazel_module: { bp2build_available: true }, +} + +cc_library_static { + name: "whole_static_lib_1", + srcs: ["whole_static_lib_1.cc"], + bazel_module: { bp2build_available: true }, +} + +cc_library_static { + name: "whole_static_lib_2", + srcs: ["whole_static_lib_2.cc"], + bazel_module: { bp2build_available: true }, +} + +cc_library_static { + name: "foo_static", + srcs: [ + "foo_static1.cc", + "foo_static2.cc", + ], + cflags: [ + "-Dflag1", + "-Dflag2" + ], + static_libs: [ + "static_lib_1", + "static_lib_2" + ], + whole_static_libs: [ + "whole_static_lib_1", + "whole_static_lib_2" + ], + include_dirs: [ + "include_dir_1", + "include_dir_2", + ], + local_include_dirs: [ + "local_include_dir_1", + "local_include_dir_2", + ], + export_include_dirs: [ + "export_include_dir_1", + "export_include_dir_2" + ], + header_libs: [ + "header_lib_1", + "header_lib_2" + ], + + // TODO: Also support export_header_lib_headers + + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTargets: []string{`cc_library_static( + name = "foo_static", + copts = [ + "-Dflag1", + "-Dflag2", + ], + deps = [ + ":header_lib_1", + ":header_lib_2", + ":static_lib_1", + ":static_lib_2", + ":whole_static_lib_1", + ":whole_static_lib_2", + ], + hdrs = [ + "export_include_dir_1/export_include_dir_1_a.h", + "export_include_dir_1/export_include_dir_1_b.h", + "export_include_dir_2/export_include_dir_2_a.h", + "export_include_dir_2/export_include_dir_2_b.h", + ], + includes = [ + "export_include_dir_1", + "export_include_dir_2", + "include_dir_1", + "include_dir_2", + "local_include_dir_1", + "local_include_dir_2", + ], + linkstatic = True, + srcs = [ + "foo_static1.cc", + "foo_static2.cc", + ], +)`, `cc_library_static( + name = "static_lib_1", + linkstatic = True, + srcs = [ + "static_lib_1.cc", + ], +)`, `cc_library_static( + name = "static_lib_2", + linkstatic = True, + srcs = [ + "static_lib_2.cc", + ], +)`, `cc_library_static( + name = "whole_static_lib_1", + linkstatic = True, + srcs = [ + "whole_static_lib_1.cc", + ], +)`, `cc_library_static( + name = "whole_static_lib_2", + linkstatic = True, + srcs = [ + "whole_static_lib_2.cc", + ], +)`}, + }, + } + + dir := "." + for _, testCase := range testCases { + filesystem := make(map[string][]byte) + toParse := []string{ + "Android.bp", + } + for f, content := range testCase.filesystem { + if strings.HasSuffix(f, "Android.bp") { + toParse = append(toParse, f) + } + filesystem[f] = []byte(content) + } + config := android.TestConfig(buildDir, nil, testCase.bp, filesystem) + ctx := android.NewTestContext(config) + + cc.RegisterCCBuildComponents(ctx) + ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory) + ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory) + + ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory) + for _, m := range testCase.depsMutators { + ctx.DepsBp2BuildMutators(m) + } + ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator) + ctx.RegisterForBazelConversion() + + _, errs := ctx.ParseFileList(dir, toParse) + if Errored(t, testCase.description, errs) { + continue + } + _, errs = ctx.ResolveDependencies(config) + if Errored(t, testCase.description, errs) { + continue + } + + checkDir := dir + if testCase.dir != "" { + checkDir = testCase.dir + } + codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build) + bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir) + if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount { + t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount) + } else { + for i, target := range bazelTargets { + if w, g := testCase.expectedBazelTargets[i], target.content; w != g { + t.Errorf( + "%s: Expected generated Bazel target to be '%s', got '%s'", + testCase.description, + w, + g, + ) + } + } + } + } +} diff --git a/cc/Android.bp b/cc/Android.bp index bdbb3c0b4..79e92cb23 100644 --- a/cc/Android.bp +++ b/cc/Android.bp @@ -10,6 +10,7 @@ bootstrap_go_package { "blueprint-pathtools", "soong", "soong-android", + "soong-bazel", "soong-cc-config", "soong-etc", "soong-genrule", diff --git a/cc/library.go b/cc/library.go index 22a36c6b9..4aac6234e 100644 --- a/cc/library.go +++ b/cc/library.go @@ -27,6 +27,7 @@ import ( "github.com/google/blueprint/pathtools" "android/soong/android" + "android/soong/bazel" "android/soong/cc/config" ) @@ -200,6 +201,8 @@ type FlagExporterProperties struct { func init() { RegisterLibraryBuildComponents(android.InitRegistrationContext) + + android.RegisterBp2BuildMutator("cc_library_static", CcLibraryStaticBp2Build) } func RegisterLibraryBuildComponents(ctx android.RegistrationContext) { @@ -2024,3 +2027,137 @@ func maybeInjectBoringSSLHash(ctx android.ModuleContext, outputFile android.Modu return outputFile } + +func Bp2BuildParseHeaderLibs(ctx android.TopDownMutatorContext, module *Module) bazel.LabelList { + var headerLibs []string + for _, linkerProps := range module.linker.linkerProps() { + if baseLinkerProps, ok := linkerProps.(*BaseLinkerProperties); ok { + headerLibs = baseLinkerProps.Header_libs + // FIXME: re-export include dirs from baseLinkerProps.Export_header_lib_headers? + break + } + } + + headerLibsLabels := android.BazelLabelForModuleDeps(ctx, headerLibs) + return headerLibsLabels +} + +func Bp2BuildParseExportedIncludes(ctx android.TopDownMutatorContext, module *Module) (bazel.LabelList, bazel.LabelList) { + libraryDecorator := module.linker.(*libraryDecorator) + + includeDirs := libraryDecorator.flagExporter.Properties.Export_system_include_dirs + includeDirs = append(includeDirs, libraryDecorator.flagExporter.Properties.Export_include_dirs...) + + includeDirsLabels := android.BazelLabelForModuleSrc(ctx, includeDirs) + + var includeDirGlobs []string + for _, includeDir := range includeDirs { + includeDirGlobs = append(includeDirGlobs, includeDir+"/**/*.h") + includeDirGlobs = append(includeDirGlobs, includeDir+"/**/*.inc") + includeDirGlobs = append(includeDirGlobs, includeDir+"/**/*.hpp") + } + + headersLabels := android.BazelLabelForModuleSrc(ctx, includeDirGlobs) + + return includeDirsLabels, headersLabels +} + +type bazelCcLibraryStaticAttributes struct { + Copts []string + Srcs bazel.LabelList + Deps bazel.LabelList + Linkstatic bool + Includes bazel.LabelList + Hdrs bazel.LabelList +} + +type bazelCcLibraryStatic struct { + android.BazelTargetModuleBase + bazelCcLibraryStaticAttributes +} + +func BazelCcLibraryStaticFactory() android.Module { + module := &bazelCcLibraryStatic{} + module.AddProperties(&module.bazelCcLibraryStaticAttributes) + android.InitBazelTargetModule(module) + return module +} + +func CcLibraryStaticBp2Build(ctx android.TopDownMutatorContext) { + module, ok := ctx.Module().(*Module) + if !ok { + // Not a cc module + return + } + if !module.ConvertWithBp2build(ctx) { + return + } + if ctx.ModuleType() != "cc_library_static" { + return + } + + var copts []string + var srcs []string + var includeDirs []string + var localIncludeDirs []string + for _, props := range module.compiler.compilerProps() { + if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok { + copts = baseCompilerProps.Cflags + srcs = baseCompilerProps.Srcs + includeDirs = baseCompilerProps.Include_dirs + localIncludeDirs = baseCompilerProps.Local_include_dirs + break + } + } + srcsLabels := android.BazelLabelForModuleSrc(ctx, srcs) + + var staticLibs []string + var wholeStaticLibs []string + for _, props := range module.linker.linkerProps() { + if baseLinkerProperties, ok := props.(*BaseLinkerProperties); ok { + staticLibs = baseLinkerProperties.Static_libs + wholeStaticLibs = baseLinkerProperties.Whole_static_libs + break + } + } + + // FIXME: Treat Static_libs and Whole_static_libs differently? + allDeps := staticLibs + allDeps = append(allDeps, wholeStaticLibs...) + + depsLabels := android.BazelLabelForModuleDeps(ctx, allDeps) + + // FIXME: Unify absolute vs relative paths + // FIXME: Use -I copts instead of setting includes= ? + allIncludes := includeDirs + allIncludes = append(allIncludes, localIncludeDirs...) + includesLabels := android.BazelLabelForModuleSrc(ctx, allIncludes) + + exportedIncludesLabels, exportedIncludesHeadersLabels := Bp2BuildParseExportedIncludes(ctx, module) + includesLabels.Append(exportedIncludesLabels) + + headerLibsLabels := Bp2BuildParseHeaderLibs(ctx, module) + depsLabels.Append(headerLibsLabels) + + attrs := &bazelCcLibraryStaticAttributes{ + Copts: copts, + Srcs: bazel.UniqueBazelLabelList(srcsLabels), + Deps: bazel.UniqueBazelLabelList(depsLabels), + Linkstatic: true, + Includes: bazel.UniqueBazelLabelList(includesLabels), + Hdrs: bazel.UniqueBazelLabelList(exportedIncludesHeadersLabels), + } + + props := bazel.BazelTargetModuleProperties{ + Rule_class: "cc_library_static", + Bzl_load_location: "//build/bazel/rules:cc_library_static.bzl", + } + + ctx.CreateBazelTargetModule(BazelCcLibraryStaticFactory, module.Name(), props, attrs) +} + +func (m *bazelCcLibraryStatic) Name() string { + return m.BaseModuleName() +} + +func (m *bazelCcLibraryStatic) GenerateAndroidBuildActions(ctx android.ModuleContext) {} diff --git a/cc/library_headers.go b/cc/library_headers.go index 0f4d8a69e..719d5383c 100644 --- a/cc/library_headers.go +++ b/cc/library_headers.go @@ -94,35 +94,14 @@ func CcLibraryHeadersBp2Build(ctx android.TopDownMutatorContext) { return } - lib, _ := module.linker.(*libraryDecorator) + exportedIncludesLabels, exportedIncludesHeadersLabels := Bp2BuildParseExportedIncludes(ctx, module) - // list of directories that will be added to the include path (using -I) for this - // module and any module that links against this module. - includeDirs := lib.flagExporter.Properties.Export_system_include_dirs - includeDirs = append(includeDirs, lib.flagExporter.Properties.Export_include_dirs...) - includeDirLabels := android.BazelLabelForModuleSrc(ctx, includeDirs) - - var includeDirGlobs []string - for _, includeDir := range includeDirs { - includeDirGlobs = append(includeDirGlobs, includeDir+"/**/*.h") - } - - headerLabels := android.BazelLabelForModuleSrc(ctx, includeDirGlobs) - - // list of modules that should only provide headers for this module. - var headerLibs []string - for _, linkerProps := range lib.linkerProps() { - if baseLinkerProps, ok := linkerProps.(*BaseLinkerProperties); ok { - headerLibs = baseLinkerProps.Export_header_lib_headers - break - } - } - headerLibLabels := android.BazelLabelForModuleDeps(ctx, headerLibs) + headerLibsLabels := Bp2BuildParseHeaderLibs(ctx, module) attrs := &bazelCcLibraryHeadersAttributes{ - Includes: includeDirLabels, - Hdrs: headerLabels, - Deps: headerLibLabels, + Includes: exportedIncludesLabels, + Hdrs: exportedIncludesHeadersLabels, + Deps: headerLibsLabels, } props := bazel.BazelTargetModuleProperties{