diff --git a/bp2build/Android.bp b/bp2build/Android.bp index ddde1b7fc..521bb0601 100644 --- a/bp2build/Android.bp +++ b/bp2build/Android.bp @@ -22,7 +22,8 @@ bootstrap_go_package { testSrcs: [ "build_conversion_test.go", "bzl_conversion_test.go", - "cc_conversion_test.go", + "cc_library_headers_conversion_test.go", + "cc_object_conversion_test.go", "conversion_test.go", "sh_conversion_test.go", "testing.go", diff --git a/bp2build/cc_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go similarity index 100% rename from bp2build/cc_conversion_test.go rename to bp2build/cc_library_headers_conversion_test.go diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go new file mode 100644 index 000000000..e4ffe1680 --- /dev/null +++ b/bp2build/cc_object_conversion_test.go @@ -0,0 +1,186 @@ +// 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" + "fmt" + "strings" + "testing" +) + +func TestCcObjectBp2Build(t *testing.T) { + testCases := []struct { + description string + moduleTypeUnderTest string + moduleTypeUnderTestFactory android.ModuleFactory + moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext) + blueprint string + expectedBazelTargets []string + filesystem map[string]string + }{ + { + description: "simple cc_object generates cc_object with include header dep", + moduleTypeUnderTest: "cc_object", + moduleTypeUnderTestFactory: cc.ObjectFactory, + moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build, + filesystem: map[string]string{ + "a/b/foo.h": "", + "a/b/bar.h": "", + "a/b/c.c": "", + }, + blueprint: `cc_object { + name: "foo", + local_include_dirs: ["include"], + cflags: [ + "-Wno-gcc-compat", + "-Wall", + "-Werror", + ], + srcs: [ + "a/b/*.h", + "a/b/c.c" + ], + + bazel_module: { bp2build_available: true }, +} +`, + expectedBazelTargets: []string{`cc_object( + name = "foo", + copts = [ + "-fno-addrsig", + "-Wno-gcc-compat", + "-Wall", + "-Werror", + ], + local_include_dirs = [ + "include", + ], + srcs = [ + "a/b/bar.h", + "a/b/foo.h", + "a/b/c.c", + ], +)`, + }, + }, + { + description: "simple cc_object with defaults", + moduleTypeUnderTest: "cc_object", + moduleTypeUnderTestFactory: cc.ObjectFactory, + moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build, + blueprint: `cc_object { + name: "foo", + local_include_dirs: ["include"], + srcs: [ + "a/b/*.h", + "a/b/c.c" + ], + + defaults: ["foo_defaults"], + bazel_module: { bp2build_available: true }, +} + +cc_defaults { + name: "foo_defaults", + defaults: ["foo_bar_defaults"], + // TODO(b/178130668): handle configurable attributes that depend on the platform + arch: { + x86: { + cflags: ["-fPIC"], + }, + x86_64: { + cflags: ["-fPIC"], + }, + }, +} + +cc_defaults { + name: "foo_bar_defaults", + cflags: [ + "-Wno-gcc-compat", + "-Wall", + "-Werror", + ], +} +`, + expectedBazelTargets: []string{`cc_object( + name = "foo", + copts = [ + "-Wno-gcc-compat", + "-Wall", + "-Werror", + "-fno-addrsig", + ], + local_include_dirs = [ + "include", + ], + srcs = [ + "a/b/c.c", + ], +)`, + }, + }, + } + + 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.blueprint, filesystem) + ctx := android.NewTestContext(config) + // Always register cc_defaults module factory + ctx.RegisterModuleType("cc_defaults", func() android.Module { return cc.DefaultsFactory() }) + + ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory) + 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 + } + + bazelTargets := GenerateBazelTargets(ctx.Context.Context, Bp2Build)[dir] + if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount { + fmt.Println(bazelTargets) + 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/cc.go b/cc/cc.go index 7f59158f6..6c1469f9a 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -28,6 +28,7 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/bazel" "android/soong/cc/config" "android/soong/genrule" ) @@ -364,6 +365,8 @@ type BaseProperties struct { // can depend on libraries that are not exported by the APEXes and use private symbols // from the exported libraries. Test_for []string + + bazel.Properties } type VendorProperties struct { diff --git a/cc/library.go b/cc/library.go index bdcb8ae04..65533bc2b 100644 --- a/cc/library.go +++ b/cc/library.go @@ -27,7 +27,6 @@ import ( "github.com/google/blueprint/pathtools" "android/soong/android" - "android/soong/bazel" "android/soong/cc/config" ) @@ -121,9 +120,6 @@ type LibraryProperties struct { // If this is an LLNDK library, properties to describe the LLNDK stubs. Will be copied from // the module pointed to by llndk_stubs if it is set. Llndk llndkLibraryProperties - - // Properties for Bazel migration purposes. - bazel.Properties } // StaticProperties is a properties stanza to affect only attributes of the "static" variants of a diff --git a/cc/library_headers.go b/cc/library_headers.go index 448e1444d..e5a555729 100644 --- a/cc/library_headers.go +++ b/cc/library_headers.go @@ -86,6 +86,10 @@ func CcLibraryHeadersBp2Build(ctx android.TopDownMutatorContext) { return } + if !module.Properties.Bazel_module.Bp2build_available { + return + } + lib, ok := module.linker.(*libraryDecorator) if !ok { // Not a cc_library module @@ -96,10 +100,6 @@ func CcLibraryHeadersBp2Build(ctx android.TopDownMutatorContext) { return } - if !lib.Properties.Bazel_module.Bp2build_available { - return - } - // 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 diff --git a/cc/object.go b/cc/object.go index 3ce76765f..d92e1109f 100644 --- a/cc/object.go +++ b/cc/object.go @@ -18,6 +18,7 @@ import ( "fmt" "android/soong/android" + "android/soong/bazel" ) // @@ -27,6 +28,8 @@ import ( func init() { android.RegisterModuleType("cc_object", ObjectFactory) android.RegisterSdkMemberType(ccObjectSdkMemberType) + + android.RegisterBp2BuildMutator("cc_object", ObjectBp2Build) } var ccObjectSdkMemberType = &librarySdkMemberType{ @@ -82,9 +85,80 @@ func ObjectFactory() android.Module { module.compiler.appendCflags([]string{"-fno-addrsig"}) module.sdkMemberTypes = []android.SdkMemberType{ccObjectSdkMemberType} + return module.Init() } +// For bp2build conversion. +type bazelObjectAttributes struct { + Srcs bazel.LabelList + Copts []string + Local_include_dirs []string +} + +type bazelObject struct { + android.BazelTargetModuleBase + bazelObjectAttributes +} + +func (m *bazelObject) Name() string { + return m.BaseModuleName() +} + +func (m *bazelObject) GenerateAndroidBuildActions(ctx android.ModuleContext) {} + +func BazelObjectFactory() android.Module { + module := &bazelObject{} + module.AddProperties(&module.bazelObjectAttributes) + android.InitBazelTargetModule(module) + return module +} + +// ObjectBp2Build is the bp2build converter from cc_object modules to the +// Bazel equivalent target, plus any necessary include deps for the cc_object. +func ObjectBp2Build(ctx android.TopDownMutatorContext) { + m, ok := ctx.Module().(*Module) + if !ok || !m.Properties.Bazel_module.Bp2build_available { + return + } + + // a Module can be something other than a cc_object. + if ctx.ModuleType() != "cc_object" { + return + } + + if m.compiler == nil { + // a cc_object must have access to the compiler decorator for its props. + ctx.ModuleErrorf("compiler must not be nil for a cc_object module") + } + + var copts []string + var srcs []string + var localIncludeDirs []string + for _, props := range m.compiler.compilerProps() { + if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok { + copts = baseCompilerProps.Cflags + srcs = baseCompilerProps.Srcs + localIncludeDirs = baseCompilerProps.Local_include_dirs + break + } + } + + attrs := &bazelObjectAttributes{ + Srcs: android.BazelLabelForModuleSrc(ctx, srcs), + Copts: copts, + Local_include_dirs: localIncludeDirs, + } + + props := bazel.NewBazelTargetModuleProperties( + m.Name(), + "cc_object", + "//build/bazel/rules:cc_object.bzl", + ) + + ctx.CreateBazelTargetModule(BazelObjectFactory, props, attrs) +} + func (object *objectLinker) appendLdflags(flags []string) { panic(fmt.Errorf("appendLdflags on objectLinker not supported")) }