diff --git a/bp2build/cc_prebuilt_library_conversion_test.go b/bp2build/cc_prebuilt_library_conversion_test.go new file mode 100644 index 000000000..818331634 --- /dev/null +++ b/bp2build/cc_prebuilt_library_conversion_test.go @@ -0,0 +1,250 @@ +// Copyright 2022 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 ( + "fmt" + "testing" + + "android/soong/cc" +) + +func TestPrebuiltLibraryStaticAndSharedSimple(t *testing.T) { + runBp2BuildTestCaseSimple(t, + bp2buildTestCase{ + description: "prebuilt library static and shared simple", + moduleTypeUnderTest: "cc_prebuilt_library", + moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory, + filesystem: map[string]string{ + "libf.so": "", + }, + blueprint: ` +cc_prebuilt_library { + name: "libtest", + srcs: ["libf.so"], + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", attrNameToString{ + "static_library": `"libf.so"`, + }), + makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{ + "shared_library": `"libf.so"`, + }), + }, + }) +} + +func TestPrebuiltLibraryWithArchVariance(t *testing.T) { + runBp2BuildTestCaseSimple(t, + bp2buildTestCase{ + description: "prebuilt library with arch variance", + moduleTypeUnderTest: "cc_prebuilt_library", + moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory, + filesystem: map[string]string{ + "libf.so": "", + "libg.so": "", + }, + blueprint: ` +cc_prebuilt_library { + name: "libtest", + arch: { + arm64: { srcs: ["libf.so"], }, + arm: { srcs: ["libg.so"], }, + }, + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", attrNameToString{ + "static_library": `select({ + "//build/bazel/platforms/arch:arm": "libg.so", + "//build/bazel/platforms/arch:arm64": "libf.so", + "//conditions:default": None, + })`, + }), + makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{ + "shared_library": `select({ + "//build/bazel/platforms/arch:arm": "libg.so", + "//build/bazel/platforms/arch:arm64": "libf.so", + "//conditions:default": None, + })`, + }), + }, + }) +} + +func TestPrebuiltLibraryAdditionalAttrs(t *testing.T) { + runBp2BuildTestCaseSimple(t, + bp2buildTestCase{ + description: "prebuilt library additional attributes", + moduleTypeUnderTest: "cc_prebuilt_library", + moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory, + filesystem: map[string]string{ + "libf.so": "", + "testdir/1/": "", + "testdir/2/": "", + }, + blueprint: ` +cc_prebuilt_library { + name: "libtest", + srcs: ["libf.so"], + export_include_dirs: ["testdir/1/"], + export_system_include_dirs: ["testdir/2/"], + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", attrNameToString{ + "static_library": `"libf.so"`, + "export_includes": `["testdir/1/"]`, + "export_system_includes": `["testdir/2/"]`, + }), + // TODO(b/229374533): When fixed, update this test + makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{ + "shared_library": `"libf.so"`, + }), + }, + }) +} + +func TestPrebuiltLibrarySharedStanzaFails(t *testing.T) { + runBp2BuildTestCaseSimple(t, + bp2buildTestCase{ + description: "prebuilt library with shared stanza fails because multiple sources", + moduleTypeUnderTest: "cc_prebuilt_library", + moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory, + filesystem: map[string]string{ + "libf.so": "", + "libg.so": "", + }, + blueprint: ` +cc_prebuilt_library { + name: "libtest", + srcs: ["libf.so"], + shared: { + srcs: ["libg.so"], + }, + bazel_module: { bp2build_available: true }, +}`, + expectedErr: fmt.Errorf("Expected at most once source file"), + }) +} + +func TestPrebuiltLibraryStaticStanzaFails(t *testing.T) { + runBp2BuildTestCaseSimple(t, + bp2buildTestCase{ + description: "prebuilt library with static stanza fails because multiple sources", + moduleTypeUnderTest: "cc_prebuilt_library", + moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory, + filesystem: map[string]string{ + "libf.so": "", + "libg.so": "", + }, + blueprint: ` +cc_prebuilt_library { + name: "libtest", + srcs: ["libf.so"], + static: { + srcs: ["libg.so"], + }, + bazel_module: { bp2build_available: true }, +}`, + expectedErr: fmt.Errorf("Expected at most once source file"), + }) +} + +func TestPrebuiltLibrarySharedAndStaticStanzas(t *testing.T) { + runBp2BuildTestCaseSimple(t, + bp2buildTestCase{ + description: "prebuilt library with both shared and static stanzas", + moduleTypeUnderTest: "cc_prebuilt_library", + moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory, + filesystem: map[string]string{ + "libf.so": "", + "libg.so": "", + }, + blueprint: ` +cc_prebuilt_library { + name: "libtest", + static: { + srcs: ["libf.so"], + }, + shared: { + srcs: ["libg.so"], + }, + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", attrNameToString{ + "static_library": `"libf.so"`, + }), + makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{ + "shared_library": `"libg.so"`, + }), + }, + }) +} + +// TODO(b/228623543): When this bug is fixed, enable this test +//func TestPrebuiltLibraryOnlyShared(t *testing.T) { +// runBp2BuildTestCaseSimple(t, +// bp2buildTestCase{ +// description: "prebuilt library shared only", +// moduleTypeUnderTest: "cc_prebuilt_library", +// moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory, +// filesystem: map[string]string{ +// "libf.so": "", +// }, +// blueprint: ` +//cc_prebuilt_library { +// name: "libtest", +// srcs: ["libf.so"], +// static: { +// enabled: false, +// }, +// bazel_module: { bp2build_available: true }, +//}`, +// expectedBazelTargets: []string{ +// makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{ +// "shared_library": `"libf.so"`, +// }), +// }, +// }) +//} + +// TODO(b/228623543): When this bug is fixed, enable this test +//func TestPrebuiltLibraryOnlyStatic(t *testing.T) { +// runBp2BuildTestCaseSimple(t, +// bp2buildTestCase{ +// description: "prebuilt library static only", +// moduleTypeUnderTest: "cc_prebuilt_library", +// moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory, +// filesystem: map[string]string{ +// "libf.so": "", +// }, +// blueprint: ` +//cc_prebuilt_library { +// name: "libtest", +// srcs: ["libf.so"], +// shared: { +// enabled: false, +// }, +// bazel_module: { bp2build_available: true }, +//}`, +// expectedBazelTargets: []string{ +// makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", attrNameToString{ +// "static_library": `"libf.so"`, +// }), +// }, +// }) +//} diff --git a/bp2build/cc_prebuilt_library_shared_test.go b/bp2build/cc_prebuilt_library_shared_test.go index ef2fddc5b..57905e559 100644 --- a/bp2build/cc_prebuilt_library_shared_test.go +++ b/bp2build/cc_prebuilt_library_shared_test.go @@ -1,6 +1,7 @@ package bp2build import ( + "fmt" "testing" "android/soong/cc" @@ -59,3 +60,26 @@ cc_prebuilt_library_shared { }, }) } + +func TestSharedPrebuiltLibrarySharedStanzaFails(t *testing.T) { + runBp2BuildTestCaseSimple(t, + bp2buildTestCase{ + description: "prebuilt library shared with shared stanza fails because multiple sources", + moduleTypeUnderTest: "cc_prebuilt_library_shared", + moduleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory, + filesystem: map[string]string{ + "libf.so": "", + "libg.so": "", + }, + blueprint: ` +cc_prebuilt_library_shared { + name: "libtest", + srcs: ["libf.so"], + shared: { + srcs: ["libg.so"], + }, + bazel_module: { bp2build_available: true}, +}`, + expectedErr: fmt.Errorf("Expected at most one source file"), + }) +} diff --git a/bp2build/cc_prebuilt_library_static_test.go b/bp2build/cc_prebuilt_library_static_test.go new file mode 100644 index 000000000..3feb1f155 --- /dev/null +++ b/bp2build/cc_prebuilt_library_static_test.go @@ -0,0 +1,98 @@ +// Copyright 2022 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 ( + "fmt" + "testing" + + "android/soong/cc" +) + +func TestStaticPrebuiltLibrary(t *testing.T) { + runBp2BuildTestCaseSimple(t, + bp2buildTestCase{ + description: "prebuilt library static simple", + moduleTypeUnderTest: "cc_prebuilt_library_static", + moduleTypeUnderTestFactory: cc.PrebuiltStaticLibraryFactory, + filesystem: map[string]string{ + "libf.so": "", + }, + blueprint: ` +cc_prebuilt_library_static { + name: "libtest", + srcs: ["libf.so"], + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("prebuilt_library_static", "libtest", attrNameToString{ + "static_library": `"libf.so"`, + }), + }, + }) +} + +func TestStaticPrebuiltLibraryWithArchVariance(t *testing.T) { + runBp2BuildTestCaseSimple(t, + bp2buildTestCase{ + description: "prebuilt library static with arch variance", + moduleTypeUnderTest: "cc_prebuilt_library_static", + moduleTypeUnderTestFactory: cc.PrebuiltStaticLibraryFactory, + filesystem: map[string]string{ + "libf.so": "", + "libg.so": "", + }, + blueprint: ` +cc_prebuilt_library_static { + name: "libtest", + arch: { + arm64: { srcs: ["libf.so"], }, + arm: { srcs: ["libg.so"], }, + }, + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("prebuilt_library_static", "libtest", attrNameToString{ + "static_library": `select({ + "//build/bazel/platforms/arch:arm": "libg.so", + "//build/bazel/platforms/arch:arm64": "libf.so", + "//conditions:default": None, + })`, + }), + }, + }) +} + +func TestStaticPrebuiltLibraryStaticStanzaFails(t *testing.T) { + runBp2BuildTestCaseSimple(t, + bp2buildTestCase{ + description: "prebuilt library with static stanza fails because multiple sources", + moduleTypeUnderTest: "cc_prebuilt_library_static", + moduleTypeUnderTestFactory: cc.PrebuiltStaticLibraryFactory, + filesystem: map[string]string{ + "libf.so": "", + "libg.so": "", + }, + blueprint: ` +cc_prebuilt_library_static { + name: "libtest", + srcs: ["libf.so"], + static: { + srcs: ["libg.so"], + }, + bazel_module: { bp2build_available: true }, +}`, + expectedErr: fmt.Errorf("Expected at most one source file"), + }) +} diff --git a/bp2build/testing.go b/bp2build/testing.go index 156e08249..029ba4938 100644 --- a/bp2build/testing.go +++ b/bp2build/testing.go @@ -84,8 +84,9 @@ type bp2buildTestCase struct { expectedBazelTargets []string filesystem map[string]string dir string - expectedErr error - unconvertedDepsMode unconvertedDepsMode + // An error with a string contained within the string of the expected error + expectedErr error + unconvertedDepsMode unconvertedDepsMode } func runBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc bp2buildTestCase) { diff --git a/cc/bp2build.go b/cc/bp2build.go index 811e22886..cc378b3b4 100644 --- a/cc/bp2build.go +++ b/cc/bp2build.go @@ -141,6 +141,7 @@ func maybePartitionExportedAndImplementationsDepsExcludes(ctx android.BazelConve } } +// Parses properties common to static and shared libraries. Also used for prebuilt libraries. func bp2buildParseStaticOrSharedProps(ctx android.BazelConversionPathContext, module *Module, lib *libraryDecorator, isStatic bool) staticOrSharedAttributes { attrs := staticOrSharedAttributes{} @@ -198,30 +199,72 @@ func bp2buildParseStaticOrSharedProps(ctx android.BazelConversionPathContext, mo // Convenience struct to hold all attributes parsed from prebuilt properties. type prebuiltAttributes struct { - Src bazel.LabelAttribute + Src bazel.LabelAttribute + Enabled bazel.BoolAttribute } // NOTE: Used outside of Soong repo project, in the clangprebuilts.go bootstrap_go_package -func Bp2BuildParsePrebuiltLibraryProps(ctx android.BazelConversionPathContext, module *Module) prebuiltAttributes { +func Bp2BuildParsePrebuiltLibraryProps(ctx android.BazelConversionPathContext, module *Module, isStatic bool) prebuiltAttributes { + manySourceFileError := func(axis bazel.ConfigurationAxis, config string) { + ctx.ModuleErrorf("Bp2BuildParsePrebuiltLibraryProps: Expected at most one source file for %s %s\n", axis, config) + } var srcLabelAttribute bazel.LabelAttribute - for axis, configToProps := range module.GetArchVariantProperties(ctx, &prebuiltLinkerProperties{}) { - for config, props := range configToProps { - if prebuiltLinkerProperties, ok := props.(*prebuiltLinkerProperties); ok { - if len(prebuiltLinkerProperties.Srcs) > 1 { - ctx.ModuleErrorf("Bp2BuildParsePrebuiltLibraryProps: Expected at most once source file for %s %s\n", axis, config) - continue - } else if len(prebuiltLinkerProperties.Srcs) == 0 { - continue - } - src := android.BazelLabelForModuleSrcSingle(ctx, prebuiltLinkerProperties.Srcs[0]) - srcLabelAttribute.SetSelectValue(axis, config, src) - } + parseSrcs := func(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis, config string, srcs []string) { + if len(srcs) > 1 { + manySourceFileError(axis, config) + return + } else if len(srcs) == 0 { + return } + if srcLabelAttribute.SelectValue(axis, config) != nil { + manySourceFileError(axis, config) + return + } + + src := android.BazelLabelForModuleSrcSingle(ctx, srcs[0]) + srcLabelAttribute.SetSelectValue(axis, config, src) + } + + bp2BuildPropParseHelper(ctx, module, &prebuiltLinkerProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { + if prebuiltLinkerProperties, ok := props.(*prebuiltLinkerProperties); ok { + parseSrcs(ctx, axis, config, prebuiltLinkerProperties.Srcs) + } + }) + + var enabledLabelAttribute bazel.BoolAttribute + parseAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) { + if props.Enabled != nil { + enabledLabelAttribute.SetSelectValue(axis, config, props.Enabled) + } + parseSrcs(ctx, axis, config, props.Srcs) + } + + if isStatic { + bp2BuildPropParseHelper(ctx, module, &StaticProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { + if staticProperties, ok := props.(*StaticProperties); ok { + parseAttrs(axis, config, staticProperties.Static) + } + }) + } else { + bp2BuildPropParseHelper(ctx, module, &SharedProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { + if sharedProperties, ok := props.(*SharedProperties); ok { + parseAttrs(axis, config, sharedProperties.Shared) + } + }) } return prebuiltAttributes{ - Src: srcLabelAttribute, + Src: srcLabelAttribute, + Enabled: enabledLabelAttribute, + } +} + +func bp2BuildPropParseHelper(ctx android.ArchVariantContext, module *Module, propsType interface{}, parseFunc func(axis bazel.ConfigurationAxis, config string, props interface{})) { + for axis, configToProps := range module.GetArchVariantProperties(ctx, propsType) { + for config, props := range configToProps { + parseFunc(axis, config, props) + } } } @@ -542,8 +585,8 @@ func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) } func bp2BuildParseSdkAttributes(module *Module) sdkAttributes { - return sdkAttributes { - Sdk_version: module.Properties.Sdk_version, + return sdkAttributes{ + Sdk_version: module.Properties.Sdk_version, Min_sdk_version: module.Properties.Min_sdk_version, } } diff --git a/cc/cc.go b/cc/cc.go index 00b82d552..456b73628 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -3556,13 +3556,14 @@ func (c *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { case fullLibrary: if !prebuilt { libraryBp2Build(ctx, c) + } else { + prebuiltLibraryBp2Build(ctx, c) } case headerLibrary: libraryHeadersBp2Build(ctx, c) case staticLibrary: - if prebuilt { - prebuiltLibraryStaticBp2Build(ctx, c) + prebuiltLibraryStaticBp2Build(ctx, c, false) } else { sharedOrStaticLibraryBp2Build(ctx, c, true) } diff --git a/cc/prebuilt.go b/cc/prebuilt.go index 598031914..4ad8a9030 100644 --- a/cc/prebuilt.go +++ b/cc/prebuilt.go @@ -253,6 +253,7 @@ func (p *prebuiltLibraryLinker) implementationModuleName(name string) string { func NewPrebuiltLibrary(hod android.HostOrDeviceSupported, srcsProperty string) (*Module, *libraryDecorator) { module, library := NewLibrary(hod) module.compiler = nil + module.bazelable = true prebuilt := &prebuiltLibraryLinker{ libraryDecorator: library, @@ -338,8 +339,21 @@ type bazelPrebuiltLibraryStaticAttributes struct { Export_system_includes bazel.StringListAttribute } -func prebuiltLibraryStaticBp2Build(ctx android.TopDownMutatorContext, module *Module) { - prebuiltAttrs := Bp2BuildParsePrebuiltLibraryProps(ctx, module) +// TODO(b/228623543): The below is not entirely true until the bug is fixed. For now, both targets are always generated +// Implements bp2build for cc_prebuilt_library modules. This will generate: +// * Only a prebuilt_library_static if the shared.enabled property is set to false across all variants. +// * Only a prebuilt_library_shared if the static.enabled property is set to false across all variants +// * Both a prebuilt_library_static and prebuilt_library_shared if the aforementioned properties are not false across +// all variants +// +// In all cases, prebuilt_library_static target names will be appended with "_bp2build_cc_library_static". +func prebuiltLibraryBp2Build(ctx android.TopDownMutatorContext, module *Module) { + prebuiltLibraryStaticBp2Build(ctx, module, true) + prebuiltLibrarySharedBp2Build(ctx, module) +} + +func prebuiltLibraryStaticBp2Build(ctx android.TopDownMutatorContext, module *Module, fullBuild bool) { + prebuiltAttrs := Bp2BuildParsePrebuiltLibraryProps(ctx, module, true) exportedIncludes := Bp2BuildParseExportedIncludesForPrebuiltLibrary(ctx, module) attrs := &bazelPrebuiltLibraryStaticAttributes{ @@ -354,7 +368,10 @@ func prebuiltLibraryStaticBp2Build(ctx android.TopDownMutatorContext, module *Mo } name := android.RemoveOptionalPrebuiltPrefix(module.Name()) - ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name}, attrs) + if fullBuild { + name += "_bp2build_cc_library_static" + } + ctx.CreateBazelTargetModuleWithRestrictions(props, android.CommonAttributes{Name: name}, attrs, prebuiltAttrs.Enabled) } type bazelPrebuiltLibrarySharedAttributes struct { @@ -362,7 +379,7 @@ type bazelPrebuiltLibrarySharedAttributes struct { } func prebuiltLibrarySharedBp2Build(ctx android.TopDownMutatorContext, module *Module) { - prebuiltAttrs := Bp2BuildParsePrebuiltLibraryProps(ctx, module) + prebuiltAttrs := Bp2BuildParsePrebuiltLibraryProps(ctx, module, false) attrs := &bazelPrebuiltLibrarySharedAttributes{ Shared_library: prebuiltAttrs.Src, @@ -374,7 +391,7 @@ func prebuiltLibrarySharedBp2Build(ctx android.TopDownMutatorContext, module *Mo } name := android.RemoveOptionalPrebuiltPrefix(module.Name()) - ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name}, attrs) + ctx.CreateBazelTargetModuleWithRestrictions(props, android.CommonAttributes{Name: name}, attrs, prebuiltAttrs.Enabled) } type prebuiltObjectProperties struct {