diff options
221 files changed, 8887 insertions, 3570 deletions
@@ -26,8 +26,6 @@ review request is enough. For more substantial changes, file a bug in our [bug tracker](https://issuetracker.google.com/issues/new?component=381517) or or write us at android-building@googlegroups.com . -For Googlers, see our [internal documentation](http://go/soong). - ## Android.bp file format By design, Android.bp files are very simple. There are no conditionals or diff --git a/aconfig/Android.bp b/aconfig/Android.bp index d2ddfdfc6..faa4ddbb6 100644 --- a/aconfig/Android.bp +++ b/aconfig/Android.bp @@ -32,6 +32,8 @@ bootstrap_go_package { "aconfig_values_test.go", "aconfig_value_set_test.go", "java_aconfig_library_test.go", + "cc_aconfig_library_test.go", + "rust_aconfig_library_test.go", ], pluginFor: ["soong_build"], } diff --git a/aconfig/aconfig_declarations.go b/aconfig/aconfig_declarations.go index 5cdf5b605..f19ddb8be 100644 --- a/aconfig/aconfig_declarations.go +++ b/aconfig/aconfig_declarations.go @@ -15,16 +15,18 @@ package aconfig import ( - "android/soong/android" "fmt" "strings" + "android/soong/android" + "android/soong/bazel" "github.com/google/blueprint" ) type DeclarationsModule struct { android.ModuleBase android.DefaultableModuleBase + android.BazelModuleBase // Properties for "aconfig_declarations" properties struct { @@ -47,8 +49,7 @@ func DeclarationsFactory() android.Module { android.InitAndroidModule(module) android.InitDefaultableModule(module) module.AddProperties(&module.properties) - // TODO: bp2build - //android.InitBazelModule(module) + android.InitBazelModule(module) return module } @@ -73,7 +74,9 @@ func (module *DeclarationsModule) DepsMutator(ctx android.BottomUpMutatorContext // RELEASE_ACONFIG_VALUE_SETS, and add any aconfig_values that // match our package. valuesFromConfig := ctx.Config().ReleaseAconfigValueSets() - ctx.AddDependency(ctx.Module(), implicitValuesTag, valuesFromConfig...) + if valuesFromConfig != "" { + ctx.AddDependency(ctx.Module(), implicitValuesTag, valuesFromConfig) + } } func (module *DeclarationsModule) OutputFiles(tag string) (android.Paths, error) { @@ -159,3 +162,26 @@ func (module *DeclarationsModule) GenerateAndroidBuildActions(ctx android.Module }) } + +type bazelAconfigDeclarationsAttributes struct { + Srcs bazel.LabelListAttribute + Package string +} + +func (module *DeclarationsModule) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { + if ctx.ModuleType() != "aconfig_declarations" { + return + } + srcs := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, module.properties.Srcs)) + + attrs := bazelAconfigDeclarationsAttributes{ + Srcs: srcs, + Package: module.properties.Package, + } + props := bazel.BazelTargetModuleProperties{ + Rule_class: "aconfig_declarations", + Bzl_load_location: "//build/bazel/rules/aconfig:aconfig_declarations.bzl", + } + + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, &attrs) +} diff --git a/aconfig/aconfig_value_set.go b/aconfig/aconfig_value_set.go index 252908fa3..cd178d480 100644 --- a/aconfig/aconfig_value_set.go +++ b/aconfig/aconfig_value_set.go @@ -16,6 +16,7 @@ package aconfig import ( "android/soong/android" + "android/soong/bazel" "github.com/google/blueprint" ) @@ -23,6 +24,7 @@ import ( type ValueSetModule struct { android.ModuleBase android.DefaultableModuleBase + android.BazelModuleBase properties struct { // aconfig_values modules @@ -36,8 +38,7 @@ func ValueSetFactory() android.Module { android.InitAndroidModule(module) android.InitDefaultableModule(module) module.AddProperties(&module.properties) - // TODO: bp2build - //android.InitBazelModule(module) + android.InitBazelModule(module) return module } @@ -90,3 +91,23 @@ func (module *ValueSetModule) GenerateAndroidBuildActions(ctx android.ModuleCont AvailablePackages: packages, }) } + +type bazelAconfigValueSetAttributes struct { + Values bazel.LabelListAttribute +} + +func (module *ValueSetModule) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { + if ctx.ModuleType() != "aconfig_value_set" { + return + } + + attrs := bazelAconfigValueSetAttributes{ + Values: bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, module.properties.Values)), + } + props := bazel.BazelTargetModuleProperties{ + Rule_class: "aconfig_value_set", + Bzl_load_location: "//build/bazel/rules/aconfig:aconfig_value_set.bzl", + } + + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, &attrs) +} diff --git a/aconfig/aconfig_values.go b/aconfig/aconfig_values.go index 91f1c9098..03a930dbd 100644 --- a/aconfig/aconfig_values.go +++ b/aconfig/aconfig_values.go @@ -16,6 +16,7 @@ package aconfig import ( "android/soong/android" + "android/soong/bazel" "github.com/google/blueprint" ) @@ -23,6 +24,7 @@ import ( type ValuesModule struct { android.ModuleBase android.DefaultableModuleBase + android.BazelModuleBase properties struct { // aconfig files, relative to this Android.bp file @@ -39,8 +41,7 @@ func ValuesFactory() android.Module { android.InitAndroidModule(module) android.InitDefaultableModule(module) module.AddProperties(&module.properties) - // TODO: bp2build - //android.InitBazelModule(module) + android.InitBazelModule(module) return module } @@ -68,3 +69,27 @@ func (module *ValuesModule) GenerateAndroidBuildActions(ctx android.ModuleContex } ctx.SetProvider(valuesProviderKey, providerData) } + +type bazelAconfigValuesAttributes struct { + Srcs bazel.LabelListAttribute + Package string +} + +func (module *ValuesModule) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { + if ctx.ModuleType() != "aconfig_values" { + return + } + + srcs := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, module.properties.Srcs)) + + attrs := bazelAconfigValuesAttributes{ + Srcs: srcs, + Package: module.properties.Package, + } + props := bazel.BazelTargetModuleProperties{ + Rule_class: "aconfig_values", + Bzl_load_location: "//build/bazel/rules/aconfig:aconfig_values.bzl", + } + + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, &attrs) +} diff --git a/aconfig/cc_aconfig_library.go b/aconfig/cc_aconfig_library.go index 14090bc90..0583befc0 100644 --- a/aconfig/cc_aconfig_library.go +++ b/aconfig/cc_aconfig_library.go @@ -16,8 +16,11 @@ package aconfig import ( "android/soong/android" + "android/soong/bazel" "android/soong/cc" + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" "fmt" "strings" @@ -29,9 +32,14 @@ type ccDeclarationsTagType struct { var ccDeclarationsTag = ccDeclarationsTagType{} +const baseLibDep = "server_configurable_flags" + type CcAconfigLibraryProperties struct { // name of the aconfig_declarations module to generate a library for Aconfig_declarations string + + // whether to generate test mode version of the library + Test *bool } type CcAconfigLibraryCallbacks struct { @@ -67,7 +75,7 @@ func (this *CcAconfigLibraryCallbacks) GeneratorDeps(ctx cc.DepsContext, deps cc } // Add a dependency for the aconfig flags base library - deps.SharedLibs = append(deps.SharedLibs, "server_configurable_flags") + deps.SharedLibs = append(deps.SharedLibs, baseLibDep) // TODO: It'd be really nice if we could reexport this library and not make everyone do it. return deps @@ -113,6 +121,12 @@ func (this *CcAconfigLibraryCallbacks) GeneratorBuildActions(ctx cc.ModuleContex } declarations := ctx.OtherModuleProvider(declarationsModules[0], declarationsProviderKey).(declarationsProviderData) + var mode string + if proptools.Bool(this.properties.Test) { + mode = "test" + } else { + mode = "production" + } ctx.Build(pctx, android.BuildParams{ Rule: cppRule, Input: declarations.IntermediatePath, @@ -123,6 +137,37 @@ func (this *CcAconfigLibraryCallbacks) GeneratorBuildActions(ctx cc.ModuleContex Description: "cc_aconfig_library", Args: map[string]string{ "gendir": this.generatedDir.String(), + "mode": mode, }, }) } + +type bazelCcAconfigLibraryAttributes struct { + Aconfig_declarations bazel.LabelAttribute + Dynamic_deps bazel.LabelListAttribute +} + +// Convert the cc_aconfig_library module to bazel. +// +// This method is called from cc.ConvertWithBp2build to actually convert the +// cc_aconfig_library module. This is necessary since the factory method of this +// module type returns a cc library and the bp2build conversion is called on the +// cc library type. + +func (this *CcAconfigLibraryCallbacks) GeneratorBp2build(ctx android.Bp2buildMutatorContext) bool { + if ctx.ModuleType() != "cc_aconfig_library" { + return false + } + + attrs := bazelCcAconfigLibraryAttributes{ + Aconfig_declarations: *bazel.MakeLabelAttribute(android.BazelLabelForModuleDepSingle(ctx, this.properties.Aconfig_declarations).Label), + Dynamic_deps: bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, []string{baseLibDep})), + } + props := bazel.BazelTargetModuleProperties{ + Rule_class: "cc_aconfig_library", + Bzl_load_location: "//build/bazel/rules/cc:cc_aconfig_library.bzl", + } + + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: ctx.ModuleName()}, &attrs) + return true +} diff --git a/aconfig/cc_aconfig_library_test.go b/aconfig/cc_aconfig_library_test.go new file mode 100644 index 000000000..6f17c7594 --- /dev/null +++ b/aconfig/cc_aconfig_library_test.go @@ -0,0 +1,67 @@ +// Copyright 2023 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 aconfig + +import ( + "fmt" + "testing" + + "android/soong/android" + "android/soong/cc" +) + +var codegenModeTestData = []struct { + setting, expected string +}{ + {"", "production"}, + {"test: false,", "production"}, + {"test: true,", "test"}, +} + +func TestCCCodegenMode(t *testing.T) { + for _, testData := range codegenModeTestData { + testCCCodegenModeHelper(t, testData.setting, testData.expected) + } +} + +func testCCCodegenModeHelper(t *testing.T, bpMode string, ruleMode string) { + t.Helper() + result := android.GroupFixturePreparers( + PrepareForTestWithAconfigBuildComponents, + cc.PrepareForTestWithCcDefaultModules). + ExtendWithErrorHandler(android.FixtureExpectsNoErrors). + RunTestWithBp(t, fmt.Sprintf(` + aconfig_declarations { + name: "my_aconfig_declarations", + package: "com.example.package", + srcs: ["foo.aconfig"], + } + + cc_library { + name: "server_configurable_flags", + srcs: ["server_configurable_flags.cc"], + } + + cc_aconfig_library { + name: "my_cc_aconfig_library", + aconfig_declarations: "my_aconfig_declarations", + %s + } + `, bpMode)) + + module := result.ModuleForTests("my_cc_aconfig_library", "android_arm64_armv8-a_shared") + rule := module.Rule("cc_aconfig_library") + android.AssertStringEquals(t, "rule must contain test mode", rule.Args["mode"], ruleMode) +} diff --git a/aconfig/init.go b/aconfig/init.go index 797388d6c..3d62714bc 100644 --- a/aconfig/init.go +++ b/aconfig/init.go @@ -64,13 +64,14 @@ var ( Command: `rm -rf ${gendir}` + ` && mkdir -p ${gendir}` + ` && ${aconfig} create-cpp-lib` + + ` --mode ${mode}` + ` --cache ${in}` + ` --out ${gendir}`, CommandDeps: []string{ "$aconfig", "$soong_zip", }, - }, "gendir") + }, "gendir", "mode") rustRule = pctx.AndroidStaticRule("rust_aconfig_library", blueprint.RuleParams{ @@ -97,12 +98,12 @@ var ( ) func init() { - registerBuildComponents(android.InitRegistrationContext) + RegisterBuildComponents(android.InitRegistrationContext) pctx.HostBinToolVariable("aconfig", "aconfig") pctx.HostBinToolVariable("soong_zip", "soong_zip") } -func registerBuildComponents(ctx android.RegistrationContext) { +func RegisterBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("aconfig_declarations", DeclarationsFactory) ctx.RegisterModuleType("aconfig_values", ValuesFactory) ctx.RegisterModuleType("aconfig_value_set", ValueSetFactory) diff --git a/aconfig/java_aconfig_library.go b/aconfig/java_aconfig_library.go index 53f8bd1ba..4db0ef794 100644 --- a/aconfig/java_aconfig_library.go +++ b/aconfig/java_aconfig_library.go @@ -52,6 +52,9 @@ func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) DepsMutator(module *ja } else { ctx.AddDependency(ctx.Module(), declarationsTag, declarations) } + + // Add aconfig-annotations-lib as a dependency for the optimization / code stripping annotations + module.AddSharedLibrary("aconfig-annotations-lib") } func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuildActions(module *java.GeneratedJavaLibraryModule, ctx android.ModuleContext) android.Path { diff --git a/aconfig/rust_aconfig_library_test.go b/aconfig/rust_aconfig_library_test.go index 17385c3d1..90b09c814 100644 --- a/aconfig/rust_aconfig_library_test.go +++ b/aconfig/rust_aconfig_library_test.go @@ -50,11 +50,11 @@ func TestRustAconfigLibrary(t *testing.T) { } for _, variant := range variants { - android.AssertStringEquals( + android.AssertStringListContains( t, "dylib variant builds from generated rust code", + variant.Rule("rustc").Implicits.RelativeToTop().Strings(), "out/soong/.intermediates/libmy_rust_aconfig_library/android_arm64_armv8-a_source/gen/src/lib.rs", - variant.Rule("rustc").Inputs[0].RelativeToTop().String(), ) } } diff --git a/aconfig/testing.go b/aconfig/testing.go index 60cefeb2b..f6489ec3f 100644 --- a/aconfig/testing.go +++ b/aconfig/testing.go @@ -20,7 +20,7 @@ import ( "android/soong/android" ) -var PrepareForTestWithAconfigBuildComponents = android.FixtureRegisterWithContext(registerBuildComponents) +var PrepareForTestWithAconfigBuildComponents = android.FixtureRegisterWithContext(RegisterBuildComponents) func runTest(t *testing.T, errorHandler android.FixtureErrorHandler, bp string) *android.TestResult { return android.GroupFixturePreparers(PrepareForTestWithAconfigBuildComponents). diff --git a/aidl_library/aidl_library.go b/aidl_library/aidl_library.go index 7449d678c..2c0aef77f 100644 --- a/aidl_library/aidl_library.go +++ b/aidl_library/aidl_library.go @@ -64,7 +64,7 @@ type bazelAidlLibraryAttributes struct { Deps bazel.LabelListAttribute } -func (lib *AidlLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (lib *AidlLibrary) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { srcs := bazel.MakeLabelListAttribute( android.BazelLabelForModuleSrc( ctx, diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go index f411026aa..a00ac98af 100644 --- a/android/allowlists/allowlists.go +++ b/android/allowlists/allowlists.go @@ -65,6 +65,7 @@ var ( "build/bazel": Bp2BuildDefaultTrueRecursively, "build/make/target/product/security": Bp2BuildDefaultTrue, + "build/make/tools": Bp2BuildDefaultTrue, "build/make/tools/protos": Bp2BuildDefaultTrue, "build/make/tools/releasetools": Bp2BuildDefaultTrue, "build/make/tools/sbom": Bp2BuildDefaultTrue, @@ -79,6 +80,9 @@ var ( "build/soong/scripts": Bp2BuildDefaultTrueRecursively, "cts/common/device-side/nativetesthelper/jni": Bp2BuildDefaultTrueRecursively, + "cts/libs/json": Bp2BuildDefaultTrueRecursively, + "cts/tests/tests/gesture": Bp2BuildDefaultTrueRecursively, + "platform_testing/libraries/annotations": Bp2BuildDefaultTrueRecursively, "dalvik/tools/dexdeps": Bp2BuildDefaultTrueRecursively, @@ -127,6 +131,7 @@ var ( "external/auto/android-annotation-stubs": Bp2BuildDefaultTrueRecursively, "external/auto/common": Bp2BuildDefaultTrueRecursively, "external/auto/service": Bp2BuildDefaultTrueRecursively, + "external/auto/value": Bp2BuildDefaultTrueRecursively, "external/boringssl": Bp2BuildDefaultTrueRecursively, "external/bouncycastle": Bp2BuildDefaultTrue, "external/brotli": Bp2BuildDefaultTrue, @@ -178,6 +183,7 @@ var ( "external/libjpeg-turbo": Bp2BuildDefaultTrueRecursively, "external/libmpeg2": Bp2BuildDefaultTrueRecursively, "external/libpng": Bp2BuildDefaultTrueRecursively, + "external/libphonenumber": Bp2BuildDefaultTrueRecursively, "external/libvpx": Bp2BuildDefaultTrueRecursively, "external/libyuv": Bp2BuildDefaultTrueRecursively, "external/lz4/lib": Bp2BuildDefaultTrue, @@ -221,6 +227,8 @@ var ( "frameworks/av/media/module/foundation": Bp2BuildDefaultTrueRecursively, "frameworks/av/media/module/minijail": Bp2BuildDefaultTrueRecursively, "frameworks/av/services/minijail": Bp2BuildDefaultTrueRecursively, + "frameworks/base/apex/jobscheduler/service/jni": Bp2BuildDefaultTrueRecursively, + "frameworks/base/core/java": Bp2BuildDefaultTrue, "frameworks/base/libs/androidfw": Bp2BuildDefaultTrue, "frameworks/base/libs/services": Bp2BuildDefaultTrue, "frameworks/base/media/tests/MediaDump": Bp2BuildDefaultTrue, @@ -228,19 +236,24 @@ var ( "frameworks/base/services/tests/servicestests/aidl": Bp2BuildDefaultTrue, "frameworks/base/startop/apps/test": Bp2BuildDefaultTrue, "frameworks/base/tests/appwidgets/AppWidgetHostTest": Bp2BuildDefaultTrueRecursively, + "frameworks/base/tools/aapt": Bp2BuildDefaultTrue, "frameworks/base/tools/aapt2": Bp2BuildDefaultTrue, "frameworks/base/tools/codegen": Bp2BuildDefaultTrueRecursively, + "frameworks/base/tools/locked_region_code_injection": Bp2BuildDefaultTrueRecursively, "frameworks/base/tools/streaming_proto": Bp2BuildDefaultTrueRecursively, "frameworks/hardware/interfaces/stats/aidl": Bp2BuildDefaultTrue, "frameworks/libs/modules-utils/build": Bp2BuildDefaultTrueRecursively, - "frameworks/libs/net/common/native": Bp2BuildDefaultTrueRecursively, + "frameworks/libs/modules-utils/java": Bp2BuildDefaultTrue, + "frameworks/libs/net/common/native": Bp2BuildDefaultTrueRecursively, // TODO(b/296014682): Remove this path "frameworks/native": Bp2BuildDefaultTrue, "frameworks/native/libs/adbd_auth": Bp2BuildDefaultTrueRecursively, "frameworks/native/libs/arect": Bp2BuildDefaultTrueRecursively, + "frameworks/native/libs/binder": Bp2BuildDefaultTrue, "frameworks/native/libs/gui": Bp2BuildDefaultTrue, "frameworks/native/libs/math": Bp2BuildDefaultTrueRecursively, "frameworks/native/libs/nativebase": Bp2BuildDefaultTrueRecursively, "frameworks/native/libs/permission": Bp2BuildDefaultTrueRecursively, + "frameworks/native/libs/ui": Bp2BuildDefaultTrue, "frameworks/native/libs/vr": Bp2BuildDefaultTrueRecursively, "frameworks/native/opengl/tests/gl2_cameraeye": Bp2BuildDefaultTrue, "frameworks/native/opengl/tests/gl2_java": Bp2BuildDefaultTrue, @@ -284,13 +297,9 @@ var ( "hardware/interfaces/health/2.1": Bp2BuildDefaultTrue, "hardware/interfaces/health/aidl": Bp2BuildDefaultTrue, "hardware/interfaces/health/utils": Bp2BuildDefaultTrueRecursively, - "hardware/interfaces/media/1.0": Bp2BuildDefaultTrue, - "hardware/interfaces/media/bufferpool": Bp2BuildDefaultTrueRecursively, + "hardware/interfaces/media": Bp2BuildDefaultTrueRecursively, "hardware/interfaces/media/bufferpool/aidl/default/tests": Bp2BuildDefaultFalseRecursively, - "hardware/interfaces/media/c2/1.0": Bp2BuildDefaultTrue, - "hardware/interfaces/media/c2/1.1": Bp2BuildDefaultTrue, - "hardware/interfaces/media/c2/1.2": Bp2BuildDefaultTrue, - "hardware/interfaces/media/omx/1.0": Bp2BuildDefaultTrue, + "hardware/interfaces/media/omx/1.0/vts": Bp2BuildDefaultFalseRecursively, "hardware/interfaces/neuralnetworks": Bp2BuildDefaultTrueRecursively, "hardware/interfaces/neuralnetworks/aidl/vts": Bp2BuildDefaultFalseRecursively, "hardware/interfaces/neuralnetworks/1.0/vts": Bp2BuildDefaultFalseRecursively, @@ -310,12 +319,14 @@ var ( "packages/modules/StatsD/lib/libstatssocket": Bp2BuildDefaultTrueRecursively, "packages/modules/adb": Bp2BuildDefaultTrue, "packages/modules/adb/apex": Bp2BuildDefaultTrue, + "packages/modules/adb/fastdeploy": Bp2BuildDefaultTrue, "packages/modules/adb/crypto": Bp2BuildDefaultTrueRecursively, "packages/modules/adb/libs": Bp2BuildDefaultTrueRecursively, "packages/modules/adb/pairing_auth": Bp2BuildDefaultTrueRecursively, "packages/modules/adb/pairing_connection": Bp2BuildDefaultTrueRecursively, "packages/modules/adb/proto": Bp2BuildDefaultTrueRecursively, "packages/modules/adb/tls": Bp2BuildDefaultTrueRecursively, + "packages/modules/Connectivity/staticlibs/native": Bp2BuildDefaultTrueRecursively, "packages/modules/Gki/libkver": Bp2BuildDefaultTrue, "packages/modules/NetworkStack/common/captiveportal": Bp2BuildDefaultTrue, "packages/modules/NeuralNetworks/apex": Bp2BuildDefaultTrue, @@ -329,6 +340,7 @@ var ( "prebuilts/clang/host/linux-x86": Bp2BuildDefaultTrueRecursively, "prebuilts/gradle-plugin": Bp2BuildDefaultTrueRecursively, "prebuilts/runtime/mainline/platform/sdk": Bp2BuildDefaultTrueRecursively, + "prebuilts/module_sdk": Bp2BuildDefaultTrueRecursively, "prebuilts/sdk": Bp2BuildDefaultTrue, "prebuilts/sdk/current/androidx": Bp2BuildDefaultTrue, "prebuilts/sdk/current/androidx-legacy": Bp2BuildDefaultTrue, @@ -338,6 +350,7 @@ var ( "prebuilts/sdk/current/support": Bp2BuildDefaultTrue, "prebuilts/tools": Bp2BuildDefaultTrue, "prebuilts/tools/common/m2": Bp2BuildDefaultTrue, + "prebuilts/r8": Bp2BuildDefaultTrueRecursively, "sdk/dumpeventlog": Bp2BuildDefaultTrue, "sdk/eventanalyzer": Bp2BuildDefaultTrue, @@ -368,6 +381,7 @@ var ( "system/core/mkbootfs": Bp2BuildDefaultTrueRecursively, "system/core/property_service/libpropertyinfoparser": Bp2BuildDefaultTrueRecursively, "system/core/property_service/libpropertyinfoserializer": Bp2BuildDefaultTrueRecursively, + "system/core/trusty/libtrusty": Bp2BuildDefaultTrue, "system/extras/f2fs_utils": Bp2BuildDefaultTrueRecursively, "system/extras/toolchain-extras": Bp2BuildDefaultTrue, "system/extras/verity": Bp2BuildDefaultTrueRecursively, @@ -376,6 +390,7 @@ var ( "system/libartpalette": Bp2BuildDefaultTrueRecursively, "system/libbase": Bp2BuildDefaultTrueRecursively, "system/libfmq": Bp2BuildDefaultTrue, + "system/libhidl": Bp2BuildDefaultTrue, "system/libhidl/libhidlmemory": Bp2BuildDefaultTrue, "system/libhidl/transport": Bp2BuildDefaultTrue, "system/libhidl/transport/allocator/1.0": Bp2BuildDefaultTrue, @@ -410,17 +425,20 @@ var ( "system/tools/aidl/build/tests_bp2build": Bp2BuildDefaultTrue, "system/tools/aidl/metadata": Bp2BuildDefaultTrue, "system/tools/hidl/metadata": Bp2BuildDefaultTrue, + "system/tools/hidl/utils": Bp2BuildDefaultTrue, "system/tools/mkbootimg": Bp2BuildDefaultTrueRecursively, "system/tools/sysprop": Bp2BuildDefaultTrue, "system/tools/xsdc/utils": Bp2BuildDefaultTrueRecursively, "system/unwinding/libunwindstack": Bp2BuildDefaultTrueRecursively, - "tools/apifinder": Bp2BuildDefaultTrue, - "tools/apksig": Bp2BuildDefaultTrue, - "tools/external_updater": Bp2BuildDefaultTrueRecursively, - "tools/metalava": Bp2BuildDefaultTrue, - "tools/platform-compat/java/android/compat": Bp2BuildDefaultTrueRecursively, - "tools/tradefederation/prebuilts/filegroups": Bp2BuildDefaultTrueRecursively, + "tools/apifinder": Bp2BuildDefaultTrue, + "tools/apksig": Bp2BuildDefaultTrue, + "tools/dexter/slicer": Bp2BuildDefaultTrueRecursively, + "tools/external_updater": Bp2BuildDefaultTrueRecursively, + "tools/metalava": Bp2BuildDefaultTrueRecursively, + "tools/platform-compat/java/android/compat": Bp2BuildDefaultTrueRecursively, + "tools/platform-compat/java/androidprocessor": Bp2BuildDefaultTrueRecursively, + "tools/tradefederation/prebuilts/filegroups": Bp2BuildDefaultTrueRecursively, } Bp2buildKeepExistingBuildFile = map[string]bool{ @@ -486,6 +504,55 @@ var ( } Bp2buildModuleAlwaysConvertList = []string{ + // aconfig + "libonce_cell", + "libanyhow", + "libunicode_segmentation", + "libmemchr", + "libbitflags-1.3.2", + "libryu", + "libitoa", + "libos_str_bytes", + "libheck", + "libclap_lex", + "libsyn", + "libquote", + "libunicode_ident", + "libproc_macro2", + "libthiserror_impl", + "libserde_derive", + "libclap_derive", + "libthiserror", + "libserde", + "libclap", + "libbytes", + "libprotobuf_support", + "libtinytemplate", + "libserde_json", + "libprotobuf", + + "protoc-gen-rust", + "libprotobuf_codegen", + "libprotobuf_parse", + "libregex", + "libtempfile", + "libwhich", + "libregex_syntax", + "libfastrand", + "libeither", + "libaho_corasick", + "liblibc", + "libcfg_if", + "liblog_rust", + "libgetrandom", + "libremove_dir_all", + "libahash", + "libhashbrown", + "libindexmap", + "libaconfig_protos", + "libpaste", + "aconfig", + // ext "tagsoup", @@ -494,6 +561,7 @@ var ( "remote-color-resources-compile-colors", // framework-minus-apex + "ImmutabilityAnnotationProcessor", "android.mime.types.minimized", "debian.mime.types.minimized", "framework-javastream-protos", @@ -503,10 +571,8 @@ var ( "apache-commons-math", "cbor-java", "icu4j_calendar_astronomer", - "json", "remote-color-resources-compile-public", "statslog-art-java-gen", - "statslog-framework-java-gen", "AndroidCommonLint", "ImmutabilityAnnotation", @@ -539,10 +605,6 @@ var ( "libandroid_runtime_lazy", "libandroid_runtime_vm_headers", "libaudioclient_aidl_conversion_util", - "libbinder", - "libbinder_device_interface_sources", - "libbinder_aidl", - "libbinder_headers", "libbinder_headers_platform_shared", "libbinderthreadstateutils", "libbluetooth-types-header", @@ -575,9 +637,6 @@ var ( "libtextclassifier_hash_static", "libtflite_kernel_utils", "libtinyxml2", - "libui", - "libui-types", - "libui_headers", "libvorbisidec", "media_ndk_headers", "media_plugin_headers", @@ -585,8 +644,6 @@ var ( "mediaswcodec.xml", "neuralnetworks_types", "libneuralnetworks_common", - // packagemanager_aidl_interface is created implicitly in packagemanager_aidl module - "packagemanager_aidl_interface", "philox_random", "philox_random_headers", "server_configurable_flags", @@ -628,9 +685,6 @@ var ( //external/fec "libfec_rs", - //frameworks/base/core/java - "IDropBoxManagerService_aidl", - //system/extras/ext4_utils "libext4_utils", "mke2fs_conf", @@ -651,10 +705,6 @@ var ( "car-ui-androidx-lifecycle-common-nodeps", "car-ui-androidx-constraintlayout-solver-nodeps", - //system/libhidl - "libhidlbase", // needed by cc_hidl_library - "libhidl_gtest_helper", - //frameworks/native/libs/input "inputconstants_aidl", @@ -663,11 +713,6 @@ var ( "libusb", - // needed by liblogd - "ILogcatManagerService_aidl", - "libincremental_aidl-cpp", - "incremental_aidl", - //frameworks/native/cmds/cmd "libcmd", @@ -809,15 +854,14 @@ var ( "libstagefright_headers", + // Apps with JNI libs + "SimpleJNI", + "libsimplejni", + // aidl "aidl", "libaidl-common", - // java_resources containing only a single filegroup - "libauto_value_plugin", - "auto_value_plugin_resources", - "auto_value_extension", - // Used by xsd_config "xsdc", @@ -856,19 +900,57 @@ var ( "hal_unit_tests", "merge_annotation_zips_test", + + // java_resources with multiple resource_dirs + "emma", + + // NDK STL + "ndk_libc++abi", + "ndk_libunwind", + "ndk_libc++_static", + "ndk_libc++_shared", + "ndk_system", + + // allowlist //prebuilts/common/misc/androidx-test/... + "androidx.test.runner", + "androidx.test.runner-nodeps", + "androidx.test.services.storage", + "androidx.test.services.storage-nodeps", + "androidx.test.monitor", + "androidx.test.monitor-nodeps", + "androidx.test.annotation", + "androidx.test.annotation-nodeps", + + // jni deps of an internal android_test (b/297405812) + "libdexmakerjvmtiagent", + "libopenjdkjvmti_headers", + "libstaticjvmtiagent", } Bp2buildModuleTypeAlwaysConvertList = []string{ + // go/keep-sorted start + "aconfig_declarations", + "aconfig_value_set", + "aconfig_values", "aidl_interface_headers", "bpf", + "cc_aconfig_library", + "cc_prebuilt_library", + "cc_prebuilt_library_headers", + "cc_prebuilt_library_shared", + "cc_prebuilt_library_static", "combined_apis", - "license", - "linker_config", + "droiddoc_exported_dir", "java_import", "java_import_host", "java_sdk_library", + "java_sdk_library_import", + "license", + "linker_config", + "ndk_library", "sysprop_library", "xsd_config", + // go/keep-sorted end } // Add the names of modules that bp2build should never convert, if it is @@ -879,6 +961,20 @@ var ( // the "prebuilt_" prefix to the name, so that it's differentiable from // the source versions within Soong's module graph. Bp2buildModuleDoNotConvertList = []string{ + // rust modules that have cc deps + "liblogger", + "libbssl_ffi", + "libbssl_ffi_nostd", + "pull_rust", + "libstatslog_rust", + "libstatslog_rust_header", + "libflatbuffers", + "liblog_event_list", + "libminijail_rust", + "libminijail_sys", + "libfsverity_rs", + "libtombstoned_client_rust", + // TODO(b/263326760): Failed already. "minijail_compiler_unittest", "minijail_parser_unittest", @@ -911,8 +1007,9 @@ var ( "apexer_test", "apexer_test_host_tools", "host_apex_verifier", // java bugs - "libbase_ndk", // TODO(b/186826477): fails to link libctscamera2_jni for device (required for CtsCameraTestCases) - "bouncycastle", // TODO(b/274474005): Need support for custom system_modules. + "libbase_ndk", // TODO(b/186826477): fails to link libctscamera2_jni for device (required for CtsCameraTestCases) + "bouncycastle", // TODO(b/274474005): Need support for custom system_modules. + "bouncycastle-test-lib", // TODO(b/274474005): Reverse dependency of bouncycastle // genrule incompatibilities "brotli-fuzzer-corpus", // TODO(b/202015218): outputs are in location incompatible with bazel genrule handling. @@ -929,7 +1026,6 @@ var ( "conscrypt-for-host", // TODO(b/210751803), we don't handle path property for filegroups "host-libprotobuf-java-full", // TODO(b/210751803), we don't handle path property for filegroups "libprotobuf-internal-python-srcs", // TODO(b/210751803), we don't handle path property for filegroups - "libprotobuf-java-full", // TODO(b/210751803), we don't handle path property for filegroups "libprotobuf-java-util-full", // TODO(b/210751803), we don't handle path property for filegroups // go deps: @@ -942,15 +1038,15 @@ var ( "libtombstoned_client_rust_bridge_code", "libtombstoned_client_wrapper", // rust conversions are not supported // unconverted deps - "apexer_with_DCLA_preprocessing_test", // depends on unconverted modules: apexer_test_host_tools, com.android.example.apex + "CarHTMLViewer", // depends on unconverted modules android.car-stubs, car-ui-lib "adb", // depends on unconverted modules: AdbWinApi, libandroidfw, libopenscreen-discovery, libopenscreen-platform-impl, libusb, bin2c_fastdeployagent, AdbWinUsbApi "android_icu4j_srcgen", // depends on unconverted modules: currysrc "android_icu4j_srcgen_binary", // depends on unconverted modules: android_icu4j_srcgen, currysrc "apex_compression_test", // depends on unconverted modules: soong_zip, com.android.example.apex "apex_manifest_proto_java", // b/210751803, depends on libprotobuf-java-full + "apexer_with_DCLA_preprocessing_test", // depends on unconverted modules: apexer_test_host_tools, com.android.example.apex "art-script", // depends on unconverted modules: dalvikvm, dex2oat "bin2c_fastdeployagent", // depends on unconverted modules: deployagent - "CarHTMLViewer", // depends on unconverted modules android.car-stubs, car-ui-lib "com.android.runtime", // depends on unconverted modules: bionic-linker-config, linkerconfig "currysrc", // depends on unconverted modules: currysrc_org.eclipse, guavalib, jopt-simple-4.9 "dex2oat-script", // depends on unconverted modules: dex2oat @@ -960,12 +1056,12 @@ var ( "jacoco-stubs", // b/245767077, depends on droidstubs "libapexutil", // depends on unconverted modules: apex-info-list-tinyxml "libart", // depends on unconverted modules: apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api, art_operator_srcs, libcpu_features, libodrstatslog, libelffile, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfile, libnativebridge, libnativeloader, libsigchain, libartbase, libprofile, cpp-define-generator-asm-support + "libart-runtime", // depends on unconverted modules: apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api, art_operator_srcs, libcpu_features, libodrstatslog, libelffile, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfile, libnativebridge, libnativeloader, libsigchain, libartbase, libprofile, cpp-define-generator-asm-support + "libart-runtime-for-test", // depends on unconverted modules: apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api, art_operator_srcs, libcpu_features, libodrstatslog, libelffile, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfile, libnativebridge, libnativeloader, libsigchain, libartbase, libprofile, cpp-define-generator-asm-support "libart-runtime-gtest", // depends on unconverted modules: libgtest_isolated, libart-compiler, libdexfile, libprofile, libartbase, libartbase-art-gtest "libart_headers", // depends on unconverted modules: art_libartbase_headers "libartbase-art-gtest", // depends on unconverted modules: libgtest_isolated, libart, libart-compiler, libdexfile, libprofile "libartbased-art-gtest", // depends on unconverted modules: libgtest_isolated, libartd, libartd-compiler, libdexfiled, libprofiled - "libart-runtime", // depends on unconverted modules: apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api, art_operator_srcs, libcpu_features, libodrstatslog, libelffile, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfile, libnativebridge, libnativeloader, libsigchain, libartbase, libprofile, cpp-define-generator-asm-support - "libart-runtime-for-test", // depends on unconverted modules: apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api, art_operator_srcs, libcpu_features, libodrstatslog, libelffile, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfile, libnativebridge, libnativeloader, libsigchain, libartbase, libprofile, cpp-define-generator-asm-support "libartd", // depends on unconverted modules: art_operator_srcs, libcpu_features, libodrstatslog, libelffiled, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfiled, libnativebridge, libnativeloader, libsigchain, libartbased, libprofiled, cpp-define-generator-asm-support, apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api "libartd-runtime", // depends on unconverted modules: art_operator_srcs, libcpu_features, libodrstatslog, libelffiled, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfiled, libnativebridge, libnativeloader, libsigchain, libartbased, libprofiled, cpp-define-generator-asm-support, apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api "libartd-runtime-gtest", // depends on unconverted modules: libgtest_isolated, libartd-compiler, libdexfiled, libprofiled, libartbased, libartbased-art-gtest @@ -977,6 +1073,7 @@ var ( "libgmock_ndk", // depends on unconverted modules: libgtest_ndk_c++ "libnativehelper_lazy_mts_jni", "libnativehelper_mts_jni", // depends on unconverted modules: libnativetesthelper_jni, libgmock_ndk "libnativetesthelper_jni", // depends on unconverted modules: libgtest_ndk_c++ + "libphonenumber_test", // depends on android.test.mock "libstatslog", // depends on unconverted modules: libstatspull, statsd-aidl-ndk "libstatslog_art", // depends on unconverted modules: statslog_art.cpp, statslog_art.h "linker_reloc_bench_main", // depends on unconverted modules: liblinker_reloc_bench_* @@ -1543,6 +1640,7 @@ var ( "permissive_mte_test", "ICU4CTestRunner", "DeviceLongPollingStubTest", + "FastDeployHostTests", "libprotobuf-full-test", // TODO(b/246997908): cannot convert proto_libraries which implicitly include other srcs in the same directory "libprotobuf-lite-test", // TODO(b/246997908): cannot convert proto_libraries which implicitly include other srcs in the same directory @@ -1560,6 +1658,41 @@ var ( // depends on libart-unstripped and new module type llvm_prebuilt_build_tool "check_cfi", + + // depends on unconverted module tradefed + "HelloWorldPerformanceTest", + + // r8 is a java_binary, which creates an implicit "r8.jar" target, but the + // same package contains a "r8.jar" file which gets overshadowed by the implicit target. + // We don't need this target as we're not using the Soong wrapper for now + "r8", + + // Depends on the module defined in the directory not bp2build default allowed + "ota_from_raw_img", + + // TODO(b/299924782): Fix linking error + "libbinder_on_trusty_mock", + + // TODO(b/299943581): Depends on aidl filegroups with implicit headers + "libdataloader_aidl-cpp", + "libincremental_manager_aidl-cpp", + + // TODO(b/299974637) Fix linking error + "libbinder_rpc_unstable", + + // TODO(b/297356704) sdk_version is unset. + "VendorAtomCodeGenJavaTest", + + // android_test from allowlisted packages, but with unconverted deps + "MtsLibnativehelperLazyTestCases", + "ObjenesisTck", + "DevCodelabTest", + "MtsTimeZoneDataTestCases", + "NanoAndroidTest", + "MtsLibnativehelperTestCases", + + // android_test_helper_app from allowlisted packages, but with unconverted deps + "SharedLibraryInfoTestApp", } // Bazel prod-mode allowlist. Modules in this list are built by Bazel @@ -1631,5 +1764,9 @@ var ( Label: "//build/bazel/examples/partitions:system_image", Host: false, }, + { + Label: "//build/bazel/examples/partitions:run_test", + Host: false, + }, } ) diff --git a/android/apex.go b/android/apex.go index 6119b0836..d84499b9d 100644 --- a/android/apex.go +++ b/android/apex.go @@ -934,6 +934,19 @@ func CheckMinSdkVersion(ctx ModuleContext, minSdkVersion ApiLevel, walk WalkPayl }) } +// Construct ApiLevel object from min_sdk_version string value +func MinSdkVersionFromValue(ctx EarlyModuleContext, value string) ApiLevel { + if value == "" { + return NoneApiLevel + } + apiLevel, err := ApiLevelFromUser(ctx, value) + if err != nil { + ctx.PropertyErrorf("min_sdk_version", "%s", err.Error()) + return NoneApiLevel + } + return apiLevel +} + // Implemented by apexBundle. type ApexTestInterface interface { // Return true if the apex bundle is an apex_test diff --git a/android/api_levels.go b/android/api_levels.go index 44c86403d..3f538c038 100644 --- a/android/api_levels.go +++ b/android/api_levels.go @@ -19,6 +19,7 @@ import ( "encoding/json" "fmt" "strconv" + "strings" ) func init() { @@ -237,6 +238,14 @@ func uncheckedFinalApiLevel(num int) ApiLevel { } } +func uncheckedFinalIncrementalApiLevel(num int, increment int) ApiLevel { + return ApiLevel{ + value: strconv.Itoa(num) + "." + strconv.Itoa(increment), + number: num, + isPreview: false, + } +} + var NoneApiLevel = ApiLevel{ value: "(no version)", // Not 0 because we don't want this to compare equal with the first preview. @@ -371,6 +380,22 @@ func ApiLevelForTest(raw string) ApiLevel { return FutureApiLevel } + if strings.Contains(raw, ".") { + // Check prebuilt incremental API format MM.m for major (API level) and minor (incremental) revisions + parts := strings.Split(raw, ".") + if len(parts) != 2 { + panic(fmt.Errorf("Found unexpected version '%s' for incremental API - expect MM.m format for incremental API with both major (MM) an minor (m) revision.", raw)) + } + sdk, sdk_err := strconv.Atoi(parts[0]) + qpr, qpr_err := strconv.Atoi(parts[1]) + if sdk_err != nil || qpr_err != nil { + panic(fmt.Errorf("Unable to read version number for incremental api '%s'", raw)) + } + + apiLevel := uncheckedFinalIncrementalApiLevel(sdk, qpr) + return apiLevel + } + asInt, err := strconv.Atoi(raw) if err != nil { panic(fmt.Errorf("%q could not be parsed as an integer and is not a recognized codename", raw)) diff --git a/android/bazel.go b/android/bazel.go index 94b36e3ff..8634daba1 100644 --- a/android/bazel.go +++ b/android/bazel.go @@ -162,7 +162,7 @@ type Bazelable interface { // Modules must implement this function to be bp2build convertible. The function // must either create at least one Bazel target module (using ctx.CreateBazelTargetModule or // its related functions), or declare itself unconvertible using ctx.MarkBp2buildUnconvertible. - ConvertWithBp2build(ctx TopDownMutatorContext) + ConvertWithBp2build(ctx Bp2buildMutatorContext) // namespacedVariableProps is a map from a soong config variable namespace // (e.g. acme, android) to a map of interfaces{}, which are really @@ -510,12 +510,6 @@ func (b *BazelModuleBase) shouldConvertWithBp2build(ctx shouldConvertModuleConte } module := p.module - // In api_bp2build mode, all soong modules that can provide API contributions should be converted - // This is irrespective of its presence/absence in bp2build allowlists - if ctx.Config().BuildMode == ApiBp2build { - _, providesApis := module.(ApiProvider) - return providesApis - } propValue := b.bazelProperties.Bazel_module.Bp2build_available packagePath := moduleDirWithPossibleOverride(ctx, module, p.moduleDir) @@ -533,13 +527,13 @@ func (b *BazelModuleBase) shouldConvertWithBp2build(ctx shouldConvertModuleConte moduleTypeAllowed := allowlist.moduleTypeAlwaysConvert[p.moduleType] allowlistConvert := moduleNameAllowed || moduleTypeAllowed if moduleNameAllowed && moduleTypeAllowed { - ctx.ModuleErrorf("A module cannot be in moduleAlwaysConvert and also be in moduleTypeAlwaysConvert") + ctx.ModuleErrorf("A module %q of type %q cannot be in moduleAlwaysConvert and also be in moduleTypeAlwaysConvert", moduleName, p.moduleType) return false } if allowlist.moduleDoNotConvert[moduleName] { if moduleNameAllowed { - ctx.ModuleErrorf("a module cannot be in moduleDoNotConvert and also be in moduleAlwaysConvert") + ctx.ModuleErrorf("a module %q cannot be in moduleDoNotConvert and also be in moduleAlwaysConvert", moduleName) } return false } diff --git a/android/bazel_handler.go b/android/bazel_handler.go index fda8a2251..4b9834564 100644 --- a/android/bazel_handler.go +++ b/android/bazel_handler.go @@ -1382,7 +1382,11 @@ func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) { WriteFileRuleVerbatim(ctx, out, "") case "FileWrite", "SourceSymlinkManifest": out := PathForBazelOut(ctx, buildStatement.OutputPaths[0]) - WriteFileRuleVerbatim(ctx, out, buildStatement.FileContents) + if buildStatement.IsExecutable { + WriteExecutableFileRuleVerbatim(ctx, out, buildStatement.FileContents) + } else { + WriteFileRuleVerbatim(ctx, out, buildStatement.FileContents) + } case "SymlinkTree": // build-runfiles arguments are the manifest file and the target directory // where it creates the symlink tree according to this manifest (and then diff --git a/android/bazel_paths.go b/android/bazel_paths.go index 86829ce29..4ac58403c 100644 --- a/android/bazel_paths.go +++ b/android/bazel_paths.go @@ -487,6 +487,9 @@ func bp2buildModuleLabel(ctx BazelConversionContext, module blueprint.Module) st if moduleDir == Bp2BuildTopLevel { moduleDir = "" } + if a, ok := module.(Module); ok && IsModulePrebuilt(a) { + moduleName = RemoveOptionalPrebuiltPrefix(moduleName) + } return fmt.Sprintf("//%s:%s", moduleDir, moduleName) } @@ -585,7 +588,7 @@ func PathsForBazelOut(ctx PathContext, paths []string) Paths { // For the first two cases, they are defined using the label attribute. For the third case, // it's defined with the string attribute. func BazelStringOrLabelFromProp( - ctx TopDownMutatorContext, + ctx Bp2buildMutatorContext, propToDistinguish *string) (bazel.LabelAttribute, bazel.StringAttribute) { var labelAttr bazel.LabelAttribute diff --git a/android/bazel_test.go b/android/bazel_test.go index 194a6b359..e0145b527 100644 --- a/android/bazel_test.go +++ b/android/bazel_test.go @@ -252,7 +252,7 @@ func TestBp2BuildAllowlist(t *testing.T) { { description: "module in name allowlist and type allowlist fails", shouldConvert: false, - expectedErrors: []string{"A module cannot be in moduleAlwaysConvert and also be in moduleTypeAlwaysConvert"}, + expectedErrors: []string{"A module \"foo\" of type \"rule1\" cannot be in moduleAlwaysConvert and also be in moduleTypeAlwaysConvert"}, module: TestBazelModule{ TestModuleInfo: bazel.TestModuleInfo{ ModuleName: "foo", @@ -273,7 +273,7 @@ func TestBp2BuildAllowlist(t *testing.T) { { description: "module in allowlist and denylist fails", shouldConvert: false, - expectedErrors: []string{"a module cannot be in moduleDoNotConvert and also be in moduleAlwaysConvert"}, + expectedErrors: []string{"a module \"foo\" cannot be in moduleDoNotConvert and also be in moduleAlwaysConvert"}, module: TestBazelModule{ TestModuleInfo: bazel.TestModuleInfo{ ModuleName: "foo", @@ -469,7 +469,7 @@ func mixedBuildModuleFactory() Module { return m } -func (m *mixedBuildModule) ConvertWithBp2build(ctx TopDownMutatorContext) { +func (m *mixedBuildModule) ConvertWithBp2build(ctx Bp2buildMutatorContext) { } func (m *mixedBuildModule) DepsMutator(ctx BottomUpMutatorContext) { diff --git a/android/config.go b/android/config.go index 7e3bc7a29..df282ec20 100644 --- a/android/config.go +++ b/android/config.go @@ -87,7 +87,6 @@ type CmdArgs struct { SymlinkForestMarker string Bp2buildMarker string BazelQueryViewDir string - BazelApiBp2buildDir string ModuleGraphFile string ModuleActionsFile string DocFile string @@ -121,9 +120,6 @@ const ( // express build semantics. GenerateQueryView - // Generate BUILD files for API contributions to API surfaces - ApiBp2build - // Create a JSON representation of the module graph and exit. GenerateModuleGraph @@ -201,9 +197,22 @@ func (c Config) ReleaseVersion() string { return c.config.productVariables.ReleaseVersion } -// The flag values files passed to aconfig, derived from RELEASE_VERSION -func (c Config) ReleaseAconfigValueSets() []string { - return c.config.productVariables.ReleaseAconfigValueSets +// The aconfig value set passed to aconfig, derived from RELEASE_VERSION +func (c Config) ReleaseAconfigValueSets() string { + // This logic to handle both Soong module name and bazel target is temporary in order to + // provide backward compatibility where aosp and internal both have the release + // aconfig value set but can't be updated at the same time to use bazel target + value := strings.Split(c.config.productVariables.ReleaseAconfigValueSets, ":") + value_len := len(value) + if value_len > 2 { + // This shouldn't happen as this should be either a module name or a bazel target path. + panic(fmt.Errorf("config file: invalid value for release aconfig value sets: %s", + c.config.productVariables.ReleaseAconfigValueSets)) + } + if value_len > 0 { + return value[value_len-1] + } + return "" } // The flag default permission value passed to aconfig @@ -641,7 +650,6 @@ func NewConfig(cmdArgs CmdArgs, availableEnv map[string]string) (Config, error) setBuildMode(cmdArgs.SymlinkForestMarker, SymlinkForest) setBuildMode(cmdArgs.Bp2buildMarker, Bp2build) setBuildMode(cmdArgs.BazelQueryViewDir, GenerateQueryView) - setBuildMode(cmdArgs.BazelApiBp2buildDir, ApiBp2build) setBuildMode(cmdArgs.ModuleGraphFile, GenerateModuleGraph) setBuildMode(cmdArgs.DocFile, GenerateDocFile) setBazelMode(cmdArgs.BazelMode, "--bazel-mode", BazelProdMode) @@ -1662,11 +1670,18 @@ func (c *config) MemtagHeapSyncEnabledForPath(path string) bool { return HasAnyPrefix(path, c.productVariables.MemtagHeapSyncIncludePaths) && !c.MemtagHeapDisabledForPath(path) } +func (c *config) HWASanDisabledForPath(path string) bool { + if len(c.productVariables.HWASanExcludePaths) == 0 { + return false + } + return HasAnyPrefix(path, c.productVariables.HWASanExcludePaths) +} + func (c *config) HWASanEnabledForPath(path string) bool { if len(c.productVariables.HWASanIncludePaths) == 0 { return false } - return HasAnyPrefix(path, c.productVariables.HWASanIncludePaths) + return HasAnyPrefix(path, c.productVariables.HWASanIncludePaths) && !c.HWASanDisabledForPath(path) } func (c *config) VendorConfig(name string) VendorConfig { @@ -1792,30 +1807,6 @@ func (c *deviceConfig) BoardSepolicyVers() string { return c.PlatformSepolicyVersion() } -func (c *deviceConfig) BoardPlatVendorPolicy() []string { - return c.config.productVariables.BoardPlatVendorPolicy -} - -func (c *deviceConfig) BoardReqdMaskPolicy() []string { - return c.config.productVariables.BoardReqdMaskPolicy -} - -func (c *deviceConfig) BoardSystemExtPublicPrebuiltDirs() []string { - return c.config.productVariables.BoardSystemExtPublicPrebuiltDirs -} - -func (c *deviceConfig) BoardSystemExtPrivatePrebuiltDirs() []string { - return c.config.productVariables.BoardSystemExtPrivatePrebuiltDirs -} - -func (c *deviceConfig) BoardProductPublicPrebuiltDirs() []string { - return c.config.productVariables.BoardProductPublicPrebuiltDirs -} - -func (c *deviceConfig) BoardProductPrivatePrebuiltDirs() []string { - return c.config.productVariables.BoardProductPrivatePrebuiltDirs -} - func (c *deviceConfig) SystemExtSepolicyPrebuiltApiDir() string { return String(c.config.productVariables.SystemExtSepolicyPrebuiltApiDir) } @@ -1948,10 +1939,6 @@ func (c *deviceConfig) BuildBrokenVendorPropertyNamespace() bool { return c.config.productVariables.BuildBrokenVendorPropertyNamespace } -func (c *deviceConfig) BuildBrokenVendorSeappUsesCoredomain() bool { - return c.config.productVariables.BuildBrokenVendorSeappUsesCoredomain -} - func (c *deviceConfig) BuildBrokenInputDir(name string) bool { return InList(name, c.config.productVariables.BuildBrokenInputDirModules) } @@ -2085,3 +2072,12 @@ func (c *config) SetApiLibraries(libs []string) { func (c *config) GetApiLibraries() map[string]struct{} { return c.apiLibraries } + +// Bp2buildMode indicates whether the config is for bp2build mode of Soong +func (c *config) Bp2buildMode() bool { + return c.BuildMode == Bp2build +} + +func (c *deviceConfig) CheckVendorSeappViolations() bool { + return Bool(c.config.productVariables.CheckVendorSeappViolations) +} diff --git a/android/defaults.go b/android/defaults.go index e0e6e5cf1..cc723f728 100644 --- a/android/defaults.go +++ b/android/defaults.go @@ -180,7 +180,7 @@ func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) {} // ConvertWithBp2build to fulfill Bazelable interface; however, at this time defaults module are // *NOT* converted with bp2build -func (defaultable *DefaultsModuleBase) ConvertWithBp2build(ctx TopDownMutatorContext) { +func (defaultable *DefaultsModuleBase) ConvertWithBp2build(ctx Bp2buildMutatorContext) { // Defaults types are never convertible. ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "") } diff --git a/android/defs.go b/android/defs.go index 18eed2dae..b28d2fa3d 100644 --- a/android/defs.go +++ b/android/defs.go @@ -107,8 +107,8 @@ var ( Cat = pctx.AndroidStaticRule("Cat", blueprint.RuleParams{ - Command: "cat $in > $out", - Description: "concatenate licenses $out", + Command: "rm -f $out && cat $in > $out", + Description: "concatenate files to $out", }) // ubuntu 14.04 offcially use dash for /bin/sh, and its builtin echo command @@ -116,7 +116,7 @@ var ( // content to file. writeFile = pctx.AndroidStaticRule("writeFile", blueprint.RuleParams{ - Command: `/bin/bash -c 'echo -e -n "$$0" > $out' $content`, + Command: `rm -f $out && /bin/bash -c 'echo -e -n "$$0" > $out' $content`, Description: "writing file $out", }, "content") @@ -209,12 +209,14 @@ func WriteFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content buildWriteFileRule(ctx, outputFile, content) } -func CatFileRule(ctx BuilderContext, paths Paths, outputFile WritablePath) { +// WriteExecutableFileRuleVerbatim is the same as WriteFileRuleVerbatim, but runs chmod +x on the result +func WriteExecutableFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string) { + intermediate := PathForIntermediates(ctx, "write_executable_file_intermediates").Join(ctx, outputFile.String()) + WriteFileRuleVerbatim(ctx, intermediate, content) ctx.Build(pctx, BuildParams{ - Rule: Cat, - Inputs: paths, - Output: outputFile, - Description: "combine files to " + outputFile.Base(), + Rule: CpExecutable, + Output: outputFile, + Input: intermediate, }) } diff --git a/android/depset_generic.go b/android/depset_generic.go index 45c193715..9f07596b5 100644 --- a/android/depset_generic.go +++ b/android/depset_generic.go @@ -95,6 +95,12 @@ func NewDepSet[T depSettableType](order DepSetOrder, direct []T, transitive []*D } } +// AddDirectToDepSet returns a new DepSet with additional elements added to its direct set. +// The transitive sets remain untouched. +func AddDirectToDepSet[T depSettableType](d *DepSet[T], direct ...T) *DepSet[T] { + return NewDepSet[T](d.order, Concat(d.direct, direct), d.transitive) +} + // DepSetBuilder is used to create an immutable DepSet. type DepSetBuilder[T depSettableType] struct { order DepSetOrder @@ -188,3 +194,14 @@ func (d *DepSet[T]) ToList() []T { } return list } + +// ToListDirect returns the direct elements of a DepSet flattened to a list. +func (d *DepSet[T]) ToListDirect() []T { + if d == nil { + return nil + } + list := make([]T, len(d.direct)) + copy(list, d.direct) + list = firstUniqueInPlace(list) + return list +} diff --git a/android/filegroup.go b/android/filegroup.go index 6cc9232b6..a4bbcae99 100644 --- a/android/filegroup.go +++ b/android/filegroup.go @@ -93,7 +93,7 @@ func (fg *fileGroup) ConvertWithApiBp2build(ctx TopDownMutatorContext) { } // ConvertWithBp2build performs bp2build conversion of filegroup -func (fg *fileGroup) ConvertWithBp2build(ctx TopDownMutatorContext) { +func (fg *fileGroup) ConvertWithBp2build(ctx Bp2buildMutatorContext) { srcs := bazel.MakeLabelListAttribute( BazelLabelForModuleSrcExcludes(ctx, fg.properties.Srcs, fg.properties.Exclude_srcs)) @@ -209,10 +209,10 @@ func (fg *fileGroup) ConvertWithBp2build(ctx TopDownMutatorContext) { } type FileGroupPath interface { - GetPath(ctx TopDownMutatorContext) string + GetPath(ctx Bp2buildMutatorContext) string } -func (fg *fileGroup) GetPath(ctx TopDownMutatorContext) string { +func (fg *fileGroup) GetPath(ctx Bp2buildMutatorContext) string { if fg.properties.Path != nil { return *fg.properties.Path } diff --git a/android/fixture.go b/android/fixture.go index 6660afd65..5ad47e8c9 100644 --- a/android/fixture.go +++ b/android/fixture.go @@ -275,6 +275,15 @@ func FixtureModifyContext(mutator func(ctx *TestContext)) FixturePreparer { }) } +// Sync the mock filesystem with the current config, then modify the context, +// This allows context modification that requires filesystem access. +func FixtureModifyContextWithMockFs(mutator func(ctx *TestContext)) FixturePreparer { + return newSimpleFixturePreparer(func(f *fixture) { + f.config.mockFileSystem("", f.mockFS) + mutator(f.ctx) + }) +} + func FixtureRegisterWithContext(registeringFunc func(ctx RegistrationContext)) FixturePreparer { return FixtureModifyContext(func(ctx *TestContext) { registeringFunc(ctx) }) } diff --git a/android/license.go b/android/license.go index a09422b98..76f5115f5 100644 --- a/android/license.go +++ b/android/license.go @@ -71,7 +71,7 @@ type bazelLicenseAttributes struct { Visibility []string } -func (m *licenseModule) ConvertWithBp2build(ctx TopDownMutatorContext) { +func (m *licenseModule) ConvertWithBp2build(ctx Bp2buildMutatorContext) { attrs := &bazelLicenseAttributes{ License_kinds: m.properties.License_kinds, Copyright_notice: m.properties.Copyright_notice, diff --git a/android/license_kind.go b/android/license_kind.go index 24b91e4c2..78df93835 100644 --- a/android/license_kind.go +++ b/android/license_kind.go @@ -50,7 +50,7 @@ type bazelLicenseKindAttributes struct { Visibility []string } -func (m *licenseKindModule) ConvertWithBp2build(ctx TopDownMutatorContext) { +func (m *licenseKindModule) ConvertWithBp2build(ctx Bp2buildMutatorContext) { attrs := &bazelLicenseKindAttributes{ Conditions: m.properties.Conditions, Url: m.properties.Url, diff --git a/android/module.go b/android/module.go index 19502bae8..f48af4a03 100644 --- a/android/module.go +++ b/android/module.go @@ -1371,7 +1371,7 @@ func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *topDownMutator for _, axis := range enabledPropertyOverrides.SortedConfigurationAxes() { configToBools := enabledPropertyOverrides.ConfigurableValues[axis] for cfg, val := range configToBools { - if axis != bazel.OsConfigurationAxis || osSupport[cfg] { + if axis != bazel.OsConfigurationAxis || osSupport[cfg] || val /*If enabled is explicitly requested via overrides */ { enabledProperty.SetSelectValue(axis, cfg, &val) } } @@ -1418,15 +1418,50 @@ func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *topDownMutator moduleEnableConstraints := bazel.LabelListAttribute{} moduleEnableConstraints.Append(platformEnabledAttribute) moduleEnableConstraints.Append(productConfigEnabledAttribute) + addCompatibilityConstraintForCompileMultilib(ctx, &moduleEnableConstraints) return constraintAttributes{Target_compatible_with: moduleEnableConstraints} } +var ( + incompatible = bazel.LabelList{[]bazel.Label{{Label: "@platforms//:incompatible"}}, nil} +) + +// If compile_mulitilib is set to +// 1. 32: Add an incompatibility constraint for non-32 arches +// 1. 64: Add an incompatibility constraint for non-64 arches +func addCompatibilityConstraintForCompileMultilib(ctx *topDownMutatorContext, enabled *bazel.LabelListAttribute) { + mod := ctx.Module().base() + multilib, _ := decodeMultilib(mod, mod.commonProperties.CompileOS, ctx.Config().IgnorePrefer32OnDevice()) + + switch multilib { + case "32": + // Add an incompatibility constraint for all known 64-bit arches + enabled.SetSelectValue(bazel.ArchConfigurationAxis, "arm64", incompatible) + enabled.SetSelectValue(bazel.ArchConfigurationAxis, "x86_64", incompatible) + enabled.SetSelectValue(bazel.ArchConfigurationAxis, "riscv64", incompatible) + case "64": + // Add an incompatibility constraint for all known 32-bit arches + enabled.SetSelectValue(bazel.ArchConfigurationAxis, "arm", incompatible) + enabled.SetSelectValue(bazel.ArchConfigurationAxis, "x86", incompatible) + case "both": + // Do nothing: "both" is trivially compatible with 32-bit and 64-bit + // The top level rule (e.g. apex/partition) will be responsible for building this module in both variants via an + // outgoing_transition. + default: // e.g. first, common + // TODO - b/299135307: Add bp2build support for these properties. + } + +} + // Check product variables for `enabled: true` flag override. // Returns a list of the constraint_value targets who enable this override. func productVariableConfigEnableAttribute(ctx *topDownMutatorContext) bazel.LabelListAttribute { result := bazel.LabelListAttribute{} - productVariableProps := ProductVariableProperties(ctx, ctx.Module()) + productVariableProps, errs := ProductVariableProperties(ctx, ctx.Module()) + for _, err := range errs { + ctx.ModuleErrorf("ProductVariableProperties error: %s", err) + } if productConfigProps, exists := productVariableProps["Enabled"]; exists { for productConfigProp, prop := range productConfigProps { flag, ok := prop.(*bool) @@ -1604,15 +1639,23 @@ func (b bp2buildInfo) BazelAttributes() []interface{} { } func (m *ModuleBase) addBp2buildInfo(info bp2buildInfo) { - if m.commonProperties.BazelConversionStatus.UnconvertedReason != nil { - panic(fmt.Errorf("bp2build: module '%s' marked unconvertible and also is converted", m.Name())) + reason := m.commonProperties.BazelConversionStatus.UnconvertedReason + if reason != nil { + panic(fmt.Errorf("bp2build: internal error trying to convert module '%s' marked unconvertible. Reason type %d: %s", + m.Name(), + reason.ReasonType, + reason.Detail)) } m.commonProperties.BazelConversionStatus.Bp2buildInfo = append(m.commonProperties.BazelConversionStatus.Bp2buildInfo, info) } func (m *ModuleBase) setBp2buildUnconvertible(reasonType bp2build_metrics_proto.UnconvertedReasonType, detail string) { if len(m.commonProperties.BazelConversionStatus.Bp2buildInfo) > 0 { - panic(fmt.Errorf("bp2build: module '%s' marked unconvertible and also is converted", m.Name())) + fmt.Println(m.commonProperties.BazelConversionStatus.Bp2buildInfo) + panic(fmt.Errorf("bp2build: internal error trying to mark converted module '%s' as unconvertible. Reason type %d: %s", + m.Name(), + reasonType, + detail)) } m.commonProperties.BazelConversionStatus.UnconvertedReason = &UnconvertedReason{ ReasonType: int(reasonType), @@ -3057,11 +3100,21 @@ func (b *baseModuleContext) ModuleFromName(name string) (blueprint.Module, bool) if !b.isBazelConversionMode() { panic("cannot call ModuleFromName if not in bazel conversion mode") } + var m blueprint.Module + var ok bool if moduleName, _ := SrcIsModuleWithTag(name); moduleName != "" { - return b.bp.ModuleFromName(moduleName) + m, ok = b.bp.ModuleFromName(moduleName) } else { - return b.bp.ModuleFromName(name) + m, ok = b.bp.ModuleFromName(name) + } + if !ok { + return m, ok + } + // If this module is not preferred, tried to get the prebuilt version instead + if a, aOk := m.(Module); aOk && !IsModulePrebuilt(a) && !IsModulePreferred(a) { + return b.ModuleFromName("prebuilt_" + name) } + return m, ok } func (b *baseModuleContext) VisitDirectDepsBlueprint(visit func(blueprint.Module)) { diff --git a/android/mutator.go b/android/mutator.go index 6bcac93c1..336f8f73c 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -15,9 +15,10 @@ package android import ( + "path/filepath" + "android/soong/bazel" "android/soong/ui/metrics/bp2build_metrics_proto" - "path/filepath" "github.com/google/blueprint" ) @@ -55,6 +56,7 @@ func registerMutatorsForBazelConversion(ctx *Context, bp2buildMutators []Registe // TODO(b/165114590): this is required to resolve deps that are only prebuilts, but we should // evaluate the impact on conversion. RegisterPrebuiltsPreArchMutators, + RegisterPrebuiltsPostDepsMutators, }, bp2buildMutators...) @@ -229,36 +231,8 @@ var bp2buildPreArchMutators = []RegisterMutatorFunc{} // A minimal context for Bp2build conversion type Bp2buildMutatorContext interface { BazelConversionPathContext - - CreateBazelTargetModule(bazel.BazelTargetModuleProperties, CommonAttributes, interface{}) -} - -// PreArchBp2BuildMutators adds mutators to be register for converting Android Blueprint modules -// into Bazel BUILD targets that should run prior to deps and conversion. -func PreArchBp2BuildMutators(f RegisterMutatorFunc) { - bp2buildPreArchMutators = append(bp2buildPreArchMutators, f) -} - -type BaseMutatorContext interface { - BaseModuleContext - - // MutatorName returns the name that this mutator was registered with. - MutatorName() string - - // Rename all variants of a module. The new name is not visible to calls to ModuleName, - // AddDependency or OtherModuleName until after this mutator pass is complete. - Rename(name string) -} - -type TopDownMutator func(TopDownMutatorContext) - -type TopDownMutatorContext interface { BaseMutatorContext - // CreateModule creates a new module by calling the factory method for the specified moduleType, and applies - // the specified property structs to it as if the properties were set in a blueprint file. - CreateModule(ModuleFactory, ...interface{}) Module - // CreateBazelTargetModule creates a BazelTargetModule by calling the // factory method, just like in CreateModule, but also requires // BazelTargetModuleProperties containing additional metadata for the @@ -289,6 +263,34 @@ type TopDownMutatorContext interface { CreateBazelConfigSetting(csa bazel.ConfigSettingAttributes, ca CommonAttributes, dir string) } +// PreArchBp2BuildMutators adds mutators to be register for converting Android Blueprint modules +// into Bazel BUILD targets that should run prior to deps and conversion. +func PreArchBp2BuildMutators(f RegisterMutatorFunc) { + bp2buildPreArchMutators = append(bp2buildPreArchMutators, f) +} + +type BaseMutatorContext interface { + BaseModuleContext + + // MutatorName returns the name that this mutator was registered with. + MutatorName() string + + // Rename all variants of a module. The new name is not visible to calls to ModuleName, + // AddDependency or OtherModuleName until after this mutator pass is complete. + Rename(name string) +} + +type TopDownMutator func(TopDownMutatorContext) + +type TopDownMutatorContext interface { + BaseMutatorContext + Bp2buildMutatorContext + + // CreateModule creates a new module by calling the factory method for the specified moduleType, and applies + // the specified property structs to it as if the properties were set in a blueprint file. + CreateModule(ModuleFactory, ...interface{}) Module +} + type topDownMutatorContext struct { bp blueprint.TopDownMutatorContext baseModuleContext diff --git a/android/neverallow.go b/android/neverallow.go index 24031ba39..2be6a74f5 100644 --- a/android/neverallow.go +++ b/android/neverallow.go @@ -60,6 +60,7 @@ func init() { AddNeverAllowRules(createBp2BuildRule()) AddNeverAllowRules(createCcStubsRule()) AddNeverAllowRules(createJavaExcludeStaticLibsRule()) + AddNeverAllowRules(createProhibitHeaderOnlyRule()) } // Add a NeverAllow rule to the set of rules to apply. @@ -264,6 +265,13 @@ func createJavaExcludeStaticLibsRule() Rule { Because("exclude_static_libs property is only allowed for java modules defined in build/soong, libcore, and frameworks/base/api") } +func createProhibitHeaderOnlyRule() Rule { + return NeverAllow(). + Without("name", "framework-minus-apex-headers"). + With("headers_only", "true"). + Because("headers_only can only be used for generating framework-minus-apex headers for non-updatable modules") +} + func neverallowMutator(ctx BottomUpMutatorContext) { m, ok := ctx.Module().(Module) if !ok { diff --git a/android/neverallow_test.go b/android/neverallow_test.go index 2a938b811..b2620ef92 100644 --- a/android/neverallow_test.go +++ b/android/neverallow_test.go @@ -361,6 +361,21 @@ var neverallowTests = []struct { `exclude_static_libs property is only allowed for java modules defined in build/soong, libcore, and frameworks/base/api`, }, }, + // Test for only allowing headers_only for framework-minus-apex-headers + { + name: `"headers_only" outside framework-minus-apex-headers modules`, + fs: map[string][]byte{ + "a/b/Android.bp": []byte(` + java_library { + name: "baz", + headers_only: true, + } + `), + }, + expectedErrors: []string{ + `headers_only can only be used for generating framework-minus-apex headers for non-updatable modules`, + }, + }, } var prepareForNeverAllowTest = GroupFixturePreparers( @@ -451,6 +466,7 @@ type mockJavaLibraryProperties struct { Sdk_version *string Uncompress_dex *bool Exclude_static_libs []string + Headers_only *bool } type mockJavaLibraryModule struct { diff --git a/android/package.go b/android/package.go index 7fbc70041..ce0b15013 100644 --- a/android/package.go +++ b/android/package.go @@ -54,7 +54,7 @@ type packageModule struct { var _ Bazelable = &packageModule{} -func (p *packageModule) ConvertWithBp2build(ctx TopDownMutatorContext) { +func (p *packageModule) ConvertWithBp2build(ctx Bp2buildMutatorContext) { defaultPackageMetadata := bazel.MakeLabelListAttribute(BazelLabelForModuleDeps(ctx, p.properties.Default_applicable_licenses)) // If METADATA file exists in the package, add it to package(default_package_metadata=) using a // filegroup(name="default_metadata_file") which can be accessed later on each module in Bazel diff --git a/android/paths.go b/android/paths.go index 325a953c4..d4b1d6e29 100644 --- a/android/paths.go +++ b/android/paths.go @@ -171,6 +171,9 @@ type Path interface { // Base returns the last element of the path Base() string + // Dir returns a path pointing the directory containing the path + Dir() Path + // Rel returns the portion of the path relative to the directory it was created from. For // example, Rel on a PathsForModuleSrc would return the path relative to the module source // directory, and OutputPath.Join("foo").Rel() would return "foo". @@ -1012,6 +1015,12 @@ func (p basePath) Base() string { return filepath.Base(p.path) } +func (p basePath) Dir() Path { + p.path = filepath.Dir(p.path) + p.rel = filepath.Dir(p.rel) + return p +} + func (p basePath) Rel() string { if p.rel != "" { return p.rel @@ -1046,6 +1055,11 @@ func (p SourcePath) withRel(rel string) SourcePath { return p } +func (p SourcePath) Dir() Path { + p.basePath = p.basePath.Dir().(basePath) + return p +} + // safePathForSource is for paths that we expect are safe -- only for use by go // code that is embedding ninja variables in paths func safePathForSource(ctx PathContext, pathComponents ...string) (SourcePath, error) { @@ -1248,6 +1262,12 @@ func (p OutputPath) withRel(rel string) OutputPath { return p } +func (p OutputPath) Dir() Path { + p.basePath = p.basePath.Dir().(basePath) + p.fullPath = filepath.Dir(p.fullPath) + return p +} + func (p OutputPath) WithoutRel() OutputPath { p.basePath.rel = filepath.Base(p.basePath.path) return p @@ -1280,6 +1300,11 @@ type toolDepPath struct { basePath } +func (p toolDepPath) Dir() Path { + p.basePath = p.basePath.Dir().(basePath) + return p +} + func (t toolDepPath) RelativeToTop() Path { ensureTestOnly() return t @@ -1463,6 +1488,11 @@ type ModuleOutPath struct { OutputPath } +func (p ModuleOutPath) Dir() Path { + p.OutputPath = p.OutputPath.Dir().(OutputPath) + return p +} + func (p ModuleOutPath) RelativeToTop() Path { p.OutputPath = p.outputPathRelativeToTop() return p @@ -1507,6 +1537,11 @@ type ModuleGenPath struct { ModuleOutPath } +func (p ModuleGenPath) Dir() Path { + p.ModuleOutPath = p.ModuleOutPath.Dir().(ModuleOutPath) + return p +} + func (p ModuleGenPath) RelativeToTop() Path { p.OutputPath = p.outputPathRelativeToTop() return p @@ -1546,6 +1581,11 @@ type ModuleObjPath struct { ModuleOutPath } +func (p ModuleObjPath) Dir() Path { + p.ModuleOutPath = p.ModuleOutPath.Dir().(ModuleOutPath) + return p +} + func (p ModuleObjPath) RelativeToTop() Path { p.OutputPath = p.outputPathRelativeToTop() return p @@ -1570,6 +1610,11 @@ type ModuleResPath struct { ModuleOutPath } +func (p ModuleResPath) Dir() Path { + p.ModuleOutPath = p.ModuleOutPath.Dir().(ModuleOutPath) + return p +} + func (p ModuleResPath) RelativeToTop() Path { p.OutputPath = p.outputPathRelativeToTop() return p @@ -1606,6 +1651,11 @@ type InstallPath struct { makePath bool } +func (p InstallPath) Dir() Path { + p.basePath = p.basePath.Dir().(basePath) + return p +} + // Will panic if called from outside a test environment. func ensureTestOnly() { if PrefixInList(os.Args, "-test.") { @@ -1922,6 +1972,11 @@ type PhonyPath struct { basePath } +func (p PhonyPath) Dir() Path { + p.basePath = p.basePath.Dir().(basePath) + return p +} + func (p PhonyPath) writablePath() {} func (p PhonyPath) getSoongOutDir() string { @@ -1947,6 +2002,11 @@ type testPath struct { basePath } +func (p testPath) Dir() Path { + p.basePath = p.basePath.Dir().(basePath) + return p +} + func (p testPath) RelativeToTop() Path { ensureTestOnly() return p diff --git a/android/prebuilt.go b/android/prebuilt.go index 95b772d41..e7b79796e 100644 --- a/android/prebuilt.go +++ b/android/prebuilt.go @@ -483,20 +483,55 @@ func PrebuiltPostDepsMutator(ctx BottomUpMutatorContext) { // usePrebuilt returns true if a prebuilt should be used instead of the source module. The prebuilt // will be used if it is marked "prefer" or if the source module is disabled. func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module, prebuilt Module) bool { - if p.srcsSupplier != nil && len(p.srcsSupplier(ctx, prebuilt)) == 0 { - return false - } + if !ctx.Config().Bp2buildMode() { + if p.srcsSupplier != nil && len(p.srcsSupplier(ctx, prebuilt)) == 0 { + return false + } - // Skip prebuilt modules under unexported namespaces so that we won't - // end up shadowing non-prebuilt module when prebuilt module under same - // name happens to have a `Prefer` property set to true. - if ctx.Config().KatiEnabled() && !prebuilt.ExportedToMake() { - return false + // Skip prebuilt modules under unexported namespaces so that we won't + // end up shadowing non-prebuilt module when prebuilt module under same + // name happens to have a `Prefer` property set to true. + if ctx.Config().KatiEnabled() && !prebuilt.ExportedToMake() { + return false + } } // If source is not available or is disabled then always use the prebuilt. if source == nil || !source.Enabled() { - return true + // If in bp2build mode, we need to check product variables & Soong config variables, which may + // have overridden the "enabled" property but have not been merged into the property value as + // they would in a non-bp2build mode invocation + if ctx.Config().Bp2buildMode() && source != nil { + productVariableProps, errs := ProductVariableProperties(ctx, source) + if productConfigProps, exists := productVariableProps["Enabled"]; len(errs) == 0 && exists && len(productConfigProps) == 1 { + var prop ProductConfigOrSoongConfigProperty + var value bool + for p, v := range productConfigProps { + prop = p + actual, ok := v.(*bool) + if ok { + value = proptools.Bool(actual) + } + } + if scv, ok := prop.(SoongConfigProperty); ok { + // If the product config var is enabled but the value of enabled is false still, the + // prebuilt is preferred. Otherwise, check if the prebulit is explicitly preferred + if ctx.Config().VendorConfig(scv.namespace).Bool(strings.ToLower(scv.name)) && !value { + return true + } + } else { + // TODO: b/300998219 - handle product vars + // We don't handle product variables yet, so return based on the non-product specific + // value of enabled + return true + } + } else { + // No "enabled" property override, return true since this module isn't enabled + return true + } + } else { + return true + } } // If the use_source_config_var property is set then it overrides the prefer property setting. diff --git a/android/prebuilt_build_tool.go b/android/prebuilt_build_tool.go index aeae20f48..c00b22ba4 100644 --- a/android/prebuilt_build_tool.go +++ b/android/prebuilt_build_tool.go @@ -14,10 +14,14 @@ package android -import "path/filepath" +import ( + "path/filepath" + + "github.com/google/blueprint" +) func init() { - RegisterModuleType("prebuilt_build_tool", prebuiltBuildToolFactory) + RegisterModuleType("prebuilt_build_tool", NewPrebuiltBuildTool) } type prebuiltBuildToolProperties struct { @@ -55,6 +59,13 @@ func (t *prebuiltBuildTool) DepsMutator(ctx BottomUpMutatorContext) { } } +type PrebuiltBuildToolInfo struct { + Src Path + Deps Paths +} + +var PrebuiltBuildToolInfoProvider = blueprint.NewProvider(PrebuiltBuildToolInfo{}) + func (t *prebuiltBuildTool) GenerateAndroidBuildActions(ctx ModuleContext) { sourcePath := t.prebuilt.SingleSourcePath(ctx) installedPath := PathForModuleOut(ctx, t.BaseModuleName()) @@ -82,6 +93,11 @@ func (t *prebuiltBuildTool) GenerateAndroidBuildActions(ctx ModuleContext) { } t.toolPath = OptionalPathForPath(installedPath) + + ctx.SetProvider(PrebuiltBuildToolInfoProvider, PrebuiltBuildToolInfo{ + Src: sourcePath, + Deps: deps, + }) } func (t *prebuiltBuildTool) MakeVars(ctx MakeVarsModuleContext) { @@ -101,10 +117,6 @@ var _ HostToolProvider = &prebuiltBuildTool{} // prebuilt_build_tool is to declare prebuilts to be used during the build, particularly for use // in genrules with the "tools" property. -func prebuiltBuildToolFactory() Module { - return NewPrebuiltBuildTool() -} - func NewPrebuiltBuildTool() Module { module := &prebuiltBuildTool{} module.AddProperties(&module.properties) diff --git a/android/proto.go b/android/proto.go index 0ffb9b62a..fc21d0177 100644 --- a/android/proto.go +++ b/android/proto.go @@ -17,6 +17,7 @@ package android import ( "path/filepath" "strings" + "sync" "android/soong/bazel" @@ -268,12 +269,26 @@ func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, m *ModuleBase, srcs baz protoIncludeDirs = append(protoIncludeDirs, dir) } } + + // proto.local_include_dirs are similar to proto.include_dirs, except that it is relative to the module directory + for _, dir := range props.Proto.Local_include_dirs { + relativeToTop := pathForModuleSrc(ctx, dir).String() + protoIncludeDirs = append(protoIncludeDirs, relativeToTop) + } + } else if props.Proto.Type != info.Type && props.Proto.Type != nil { ctx.ModuleErrorf("Cannot handle arch-variant types for protos at this time.") } } } + if p, ok := m.module.(PkgPathInterface); ok && p.PkgPath(ctx) != nil { + // python_library with pkg_path + // proto_library for this module should have the pkg_path as the import_prefix + attrs.Import_prefix = p.PkgPath(ctx) + attrs.Strip_import_prefix = proptools.StringPtr("") + } + tags := ApexAvailableTagsWithoutTestApexes(ctx.(TopDownMutatorContext), ctx.Module()) moduleDir := ctx.ModuleDir() @@ -292,9 +307,14 @@ func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, m *ModuleBase, srcs baz // (or a different subpackage), it will not find it. // The CcProtoGen action itself runs fine because we construct the correct ProtoInfo, // but the FileDescriptorSet of each proto_library might not be compile-able - if pkg != ctx.ModuleDir() { + // + // Add manual tag if either + // 1. .proto files are in more than one package + // 2. proto.include_dirs is not empty + if len(SortedStringKeys(pkgToSrcs)) > 1 || len(protoIncludeDirs) > 0 { tags.Append(bazel.MakeStringListAttribute([]string{"manual"})) } + ctx.CreateBazelTargetModule( bazel.BazelTargetModuleProperties{Rule_class: "proto_library"}, CommonAttributes{Name: name, Dir: proptools.StringPtr(pkg), Tags: tags}, @@ -311,7 +331,8 @@ func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, m *ModuleBase, srcs baz Label: l, }) } - protoLibrariesInIncludeDir := createProtoLibraryTargetsForIncludeDirs(ctx, protoIncludeDirs) + // Partitioning by packages can create dupes of protoIncludeDirs, so dedupe it first. + protoLibrariesInIncludeDir := createProtoLibraryTargetsForIncludeDirs(ctx, SortedUniqueStrings(protoIncludeDirs)) transitiveProtoLibraries.Append(protoLibrariesInIncludeDir) } @@ -321,15 +342,20 @@ func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, m *ModuleBase, srcs baz return info, true } +// PkgPathInterface is used as a type assertion in bp2build to get pkg_path property of python_library_host +type PkgPathInterface interface { + PkgPath(ctx BazelConversionContext) *string +} + var ( protoIncludeDirGeneratedSuffix = ".include_dir_bp2build_generated_proto" protoIncludeDirsBp2buildKey = NewOnceKey("protoIncludeDirsBp2build") ) -func getProtoIncludeDirsBp2build(config Config) *map[protoIncludeDirKey]bool { +func getProtoIncludeDirsBp2build(config Config) *sync.Map { return config.Once(protoIncludeDirsBp2buildKey, func() interface{} { - return &map[protoIncludeDirKey]bool{} - }).(*map[protoIncludeDirKey]bool) + return &sync.Map{} + }).(*sync.Map) } // key for dynamically creating proto_library per proto.include_dirs @@ -359,11 +385,10 @@ func createProtoLibraryTargetsForIncludeDirs(ctx Bp2buildMutatorContext, include Label: "//" + pkg + ":" + label, }) key := protoIncludeDirKey{dir: dir, subpackgeInDir: pkg} - if _, exists := (*dirMap)[key]; exists { + if _, exists := dirMap.LoadOrStore(key, true); exists { // A proto_library has already been created for this package relative to this include dir continue } - (*dirMap)[key] = true srcs := protoLabelelsPartitionedByPkg[pkg] rel, err := filepath.Rel(dir, pkg) if err != nil { @@ -377,7 +402,18 @@ func createProtoLibraryTargetsForIncludeDirs(ctx Bp2buildMutatorContext, include if rel != "." { attrs.Import_prefix = proptools.StringPtr(rel) } - ctx.CreateBazelTargetModule( + + // If a specific directory is listed in proto.include_dirs of two separate modules (one host-specific and another device-specific), + // we do not want to create the proto_library with target_compatible_with of the first visited of these two modules + // As a workarounds, delete `target_compatible_with` + alwaysEnabled := bazel.BoolAttribute{} + alwaysEnabled.Value = proptools.BoolPtr(true) + // Add android and linux explicitly so that fillcommonbp2buildmoduleattrs can override these configs + // When we extend b support for other os'es (darwin/windows), we should add those configs here as well + alwaysEnabled.SetSelectValue(bazel.OsConfigurationAxis, bazel.OsAndroid, proptools.BoolPtr(true)) + alwaysEnabled.SetSelectValue(bazel.OsConfigurationAxis, bazel.OsLinux, proptools.BoolPtr(true)) + + ctx.CreateBazelTargetModuleWithRestrictions( bazel.BazelTargetModuleProperties{Rule_class: "proto_library"}, CommonAttributes{ Name: label, @@ -387,6 +423,7 @@ func createProtoLibraryTargetsForIncludeDirs(ctx Bp2buildMutatorContext, include Tags: bazel.MakeStringListAttribute([]string{"manual"}), }, &attrs, + alwaysEnabled, ) } } diff --git a/android/register.go b/android/register.go index 64b0207e7..f1c298691 100644 --- a/android/register.go +++ b/android/register.go @@ -15,9 +15,13 @@ package android import ( + "bufio" "fmt" + "path/filepath" "reflect" + "regexp" + "android/soong/shared" "github.com/google/blueprint" ) @@ -197,11 +201,54 @@ func (ctx *Context) RegisterForBazelConversion() { RegisterMutatorsForBazelConversion(ctx, bp2buildPreArchMutators) } -// RegisterForApiBazelConversion is similar to RegisterForBazelConversion except that -// it only generates API targets in the generated workspace -func (ctx *Context) RegisterForApiBazelConversion() { - registerModuleTypes(ctx) - RegisterMutatorsForApiBazelConversion(ctx, bp2buildPreArchMutators) +// RegisterExistingBazelTargets reads Bazel BUILD.bazel and BUILD files under +// the workspace, and returns a map containing names of Bazel targets defined in +// these BUILD files. +// For example, maps "//foo/bar" to ["baz", "qux"] if `//foo/bar:{baz,qux}` exist. +func (c *Context) RegisterExistingBazelTargets(topDir string, existingBazelFiles []string) error { + result := map[string][]string{} + + // Search for instances of `name = "$NAME"` (with arbitrary spacing). + targetNameRegex := regexp.MustCompile(`(?m)^\s*name\s*=\s*\"([^\"]+)\"`) + + parseBuildFile := func(path string) error { + fullPath := shared.JoinPath(topDir, path) + sourceDir := filepath.Dir(path) + + fileInfo, err := c.Config().fs.Stat(fullPath) + if err != nil { + return fmt.Errorf("Error accessing Bazel file '%s': %s", path, err) + } + if !fileInfo.IsDir() && + (fileInfo.Name() == "BUILD" || fileInfo.Name() == "BUILD.bazel") { + f, err := c.Config().fs.Open(fullPath) + if err != nil { + return fmt.Errorf("Error reading Bazel file '%s': %s", path, err) + } + defer f.Close() + scanner := bufio.NewScanner(f) + for scanner.Scan() { + line := scanner.Text() + matches := targetNameRegex.FindAllStringSubmatch(line, -1) + for _, match := range matches { + result[sourceDir] = append(result[sourceDir], match[1]) + } + } + } + return nil + } + + for _, path := range existingBazelFiles { + if !c.Config().Bp2buildPackageConfig.ShouldKeepExistingBuildFileForDir(filepath.Dir(path)) { + continue + } + err := parseBuildFile(path) + if err != nil { + return err + } + } + c.Config().SetBazelBuildFileTargets(result) + return nil } // Register the pipeline of singletons, module types, and mutators for diff --git a/android/rule_builder.go b/android/rule_builder.go index 777c1cfc3..245b759ca 100644 --- a/android/rule_builder.go +++ b/android/rule_builder.go @@ -474,13 +474,23 @@ func (r *RuleBuilder) depFileMergerCmd(depFiles WritablePaths) *RuleBuilderComma Inputs(depFiles.Paths()) } +// BuildWithNinjaVars adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for +// Outputs. This function will not escape Ninja variables, so it may be used to write sandbox manifests using Ninja variables. +func (r *RuleBuilder) BuildWithUnescapedNinjaVars(name string, desc string) { + r.build(name, desc, false) +} + // Build adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for // Outputs. func (r *RuleBuilder) Build(name string, desc string) { + r.build(name, desc, true) +} + +func (r *RuleBuilder) build(name string, desc string, ninjaEscapeCommandString bool) { name = ninjaNameEscape(name) if len(r.missingDeps) > 0 { - r.ctx.Build(pctx, BuildParams{ + r.ctx.Build(r.pctx, BuildParams{ Rule: ErrorRule, Outputs: r.Outputs(), Description: desc, @@ -619,12 +629,35 @@ func (r *RuleBuilder) Build(name string, desc string) { name, r.sboxManifestPath.String(), r.outDir.String()) } - // Create a rule to write the manifest as a the textproto. + // Create a rule to write the manifest as textproto. pbText, err := prototext.Marshal(&manifest) if err != nil { ReportPathErrorf(r.ctx, "sbox manifest failed to marshal: %q", err) } - WriteFileRule(r.ctx, r.sboxManifestPath, string(pbText)) + if ninjaEscapeCommandString { + WriteFileRule(r.ctx, r.sboxManifestPath, string(pbText)) + } else { + // We need to have a rule to write files that is + // defined on the RuleBuilder's pctx in order to + // write Ninja variables in the string. + // The WriteFileRule function above rule can only write + // raw strings because it is defined on the android + // package's pctx, and it can't access variables defined + // in another context. + r.ctx.Build(r.pctx, BuildParams{ + Rule: r.ctx.Rule(r.pctx, "unescapedWriteFile", blueprint.RuleParams{ + Command: `rm -rf ${out} && cat ${out}.rsp > ${out}`, + Rspfile: "${out}.rsp", + RspfileContent: "${content}", + Description: "write file", + }, "content"), + Output: r.sboxManifestPath, + Description: "write sbox manifest " + r.sboxManifestPath.Base(), + Args: map[string]string{ + "content": string(pbText), + }, + }) + } // Generate a new string to use as the command line of the sbox rule. This uses // a RuleBuilderCommand as a convenience method of building the command line, then @@ -723,9 +756,13 @@ func (r *RuleBuilder) Build(name string, desc string) { pool = localPool } + if ninjaEscapeCommandString { + commandString = proptools.NinjaEscape(commandString) + } + r.ctx.Build(r.pctx, BuildParams{ - Rule: r.ctx.Rule(pctx, name, blueprint.RuleParams{ - Command: proptools.NinjaEscape(commandString), + Rule: r.ctx.Rule(r.pctx, name, blueprint.RuleParams{ + Command: commandString, CommandDeps: proptools.NinjaEscapeList(tools.Strings()), Restat: r.restat, Rspfile: proptools.NinjaEscape(rspFile), diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go index 86647eb22..a6b3a27a1 100644 --- a/android/rule_builder_test.go +++ b/android/rule_builder_test.go @@ -28,6 +28,17 @@ import ( "android/soong/shared" ) +var ( + pctx_ruleBuilderTest = NewPackageContext("android/soong/rule_builder") + pctx_ruleBuilderTestSubContext = NewPackageContext("android/soong/rule_builder/config") +) + +func init() { + pctx_ruleBuilderTest.Import("android/soong/rule_builder/config") + pctx_ruleBuilderTest.StaticVariable("cmdFlags", "${config.ConfigFlags}") + pctx_ruleBuilderTestSubContext.StaticVariable("ConfigFlags", "--some-clang-flag") +} + func builderContext() BuilderContext { return BuilderContextForTesting(TestConfig("out", nil, "", map[string][]byte{ "ld": nil, @@ -496,11 +507,13 @@ func testRuleBuilderFactory() Module { type testRuleBuilderModule struct { ModuleBase properties struct { - Srcs []string + Srcs []string + Flags []string - Restat bool - Sbox bool - Sbox_inputs bool + Restat bool + Sbox bool + Sbox_inputs bool + Unescape_ninja_vars bool } } @@ -518,8 +531,9 @@ func (t *testRuleBuilderModule) GenerateAndroidBuildActions(ctx ModuleContext) { rspFileContents2 := PathsForSource(ctx, []string{"rsp_in2"}) manifestPath := PathForModuleOut(ctx, "sbox.textproto") - testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, out, outDep, outDir, - manifestPath, t.properties.Restat, t.properties.Sbox, t.properties.Sbox_inputs, + testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, t.properties.Flags, + out, outDep, outDir, + manifestPath, t.properties.Restat, t.properties.Sbox, t.properties.Sbox_inputs, t.properties.Unescape_ninja_vars, rspFile, rspFileContents, rspFile2, rspFileContents2) } @@ -543,17 +557,18 @@ func (t *testRuleBuilderSingleton) GenerateBuildActions(ctx SingletonContext) { rspFileContents2 := PathsForSource(ctx, []string{"rsp_in2"}) manifestPath := PathForOutput(ctx, "singleton/sbox.textproto") - testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, out, outDep, outDir, - manifestPath, true, false, false, + testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, nil, out, outDep, outDir, + manifestPath, true, false, false, false, rspFile, rspFileContents, rspFile2, rspFileContents2) } func testRuleBuilder_Build(ctx BuilderContext, in Paths, implicit, orderOnly, validation Path, + flags []string, out, outDep, outDir, manifestPath WritablePath, - restat, sbox, sboxInputs bool, + restat, sbox, sboxInputs, unescapeNinjaVars bool, rspFile WritablePath, rspFileContents Paths, rspFile2 WritablePath, rspFileContents2 Paths) { - rule := NewRuleBuilder(pctx, ctx) + rule := NewRuleBuilder(pctx_ruleBuilderTest, ctx) if sbox { rule.Sbox(outDir, manifestPath) @@ -564,6 +579,7 @@ func testRuleBuilder_Build(ctx BuilderContext, in Paths, implicit, orderOnly, va rule.Command(). Tool(PathForSource(ctx, "cp")). + Flags(flags). Inputs(in). Implicit(implicit). OrderOnly(orderOnly). @@ -577,7 +593,11 @@ func testRuleBuilder_Build(ctx BuilderContext, in Paths, implicit, orderOnly, va rule.Restat() } - rule.Build("rule", "desc") + if unescapeNinjaVars { + rule.BuildWithUnescapedNinjaVars("rule", "desc") + } else { + rule.Build("rule", "desc") + } } var prepareForRuleBuilderTest = FixtureRegisterWithContext(func(ctx RegistrationContext) { @@ -792,3 +812,47 @@ func TestRuleBuilderHashInputs(t *testing.T) { }) } } + +func TestRuleBuilderWithNinjaVarEscaping(t *testing.T) { + bp := ` + rule_builder_test { + name: "foo_sbox_escaped_ninja", + flags: ["${cmdFlags}"], + sbox: true, + sbox_inputs: true, + } + rule_builder_test { + name: "foo_sbox", + flags: ["${cmdFlags}"], + sbox: true, + sbox_inputs: true, + unescape_ninja_vars: true, + } + ` + result := GroupFixturePreparers( + prepareForRuleBuilderTest, + FixtureWithRootAndroidBp(bp), + ).RunTest(t) + + escapedNinjaMod := result.ModuleForTests("foo_sbox_escaped_ninja", "").Rule("writeFile") + AssertStringDoesContain( + t, + "", + escapedNinjaMod.BuildParams.Args["content"], + "$${cmdFlags}", + ) + + unescapedNinjaMod := result.ModuleForTests("foo_sbox", "").Rule("unescapedWriteFile") + AssertStringDoesContain( + t, + "", + unescapedNinjaMod.BuildParams.Args["content"], + "${cmdFlags}", + ) + AssertStringDoesNotContain( + t, + "", + unescapedNinjaMod.BuildParams.Args["content"], + "$${cmdFlags}", + ) +} diff --git a/android/testing.go b/android/testing.go index 5ad7ad07f..32357db80 100644 --- a/android/testing.go +++ b/android/testing.go @@ -467,12 +467,6 @@ func (ctx *TestContext) RegisterForBazelConversion() { RegisterMutatorsForBazelConversion(ctx.Context, ctx.bp2buildPreArch) } -// RegisterForApiBazelConversion prepares a test context for API bp2build conversion. -func (ctx *TestContext) RegisterForApiBazelConversion() { - ctx.config.BuildMode = ApiBp2build - RegisterMutatorsForApiBazelConversion(ctx.Context, ctx.bp2buildPreArch) -} - func (ctx *TestContext) ParseFileList(rootDir string, filePaths []string) (deps []string, errs []error) { // This function adapts the old style ParseFileList calls that are spread throughout the tests // to the new style that takes a config. diff --git a/android/util.go b/android/util.go index 5375373a6..7f6af2d68 100644 --- a/android/util.go +++ b/android/util.go @@ -33,12 +33,17 @@ func CopyOf[T any](s []T) []T { return append([]T{}, s...) } -// Concat returns a new slice concatenated from the two input slices. It does not change the input +// Concat returns a new slice concatenated from the input slices. It does not change the input // slices. -func Concat[T any](s1, s2 []T) []T { - res := make([]T, 0, len(s1)+len(s2)) - res = append(res, s1...) - res = append(res, s2...) +func Concat[T any](slices ...[]T) []T { + newLength := 0 + for _, s := range slices { + newLength += len(s) + } + res := make([]T, 0, newLength) + for _, s := range slices { + res = append(res, s...) + } return res } diff --git a/android/variable.go b/android/variable.go index 04e407f3c..d33294c16 100644 --- a/android/variable.go +++ b/android/variable.go @@ -315,6 +315,7 @@ type ProductVariables struct { MemtagHeapSyncIncludePaths []string `json:",omitempty"` HWASanIncludePaths []string `json:",omitempty"` + HWASanExcludePaths []string `json:",omitempty"` VendorPath *string `json:",omitempty"` OdmPath *string `json:",omitempty"` @@ -372,17 +373,11 @@ type ProductVariables struct { MultitreeUpdateMeta bool `json:",omitempty"` - BoardVendorSepolicyDirs []string `json:",omitempty"` - BoardOdmSepolicyDirs []string `json:",omitempty"` - BoardReqdMaskPolicy []string `json:",omitempty"` - BoardPlatVendorPolicy []string `json:",omitempty"` - BoardSystemExtPublicPrebuiltDirs []string `json:",omitempty"` - BoardSystemExtPrivatePrebuiltDirs []string `json:",omitempty"` - BoardProductPublicPrebuiltDirs []string `json:",omitempty"` - BoardProductPrivatePrebuiltDirs []string `json:",omitempty"` - SystemExtPublicSepolicyDirs []string `json:",omitempty"` - SystemExtPrivateSepolicyDirs []string `json:",omitempty"` - BoardSepolicyM4Defs []string `json:",omitempty"` + BoardVendorSepolicyDirs []string `json:",omitempty"` + BoardOdmSepolicyDirs []string `json:",omitempty"` + SystemExtPublicSepolicyDirs []string `json:",omitempty"` + SystemExtPrivateSepolicyDirs []string `json:",omitempty"` + BoardSepolicyM4Defs []string `json:",omitempty"` BoardSepolicyVers *string `json:",omitempty"` PlatformSepolicyVersion *string `json:",omitempty"` @@ -443,17 +438,17 @@ type ProductVariables struct { ShippingApiLevel *string `json:",omitempty"` - BuildBrokenPluginValidation []string `json:",omitempty"` - BuildBrokenClangAsFlags bool `json:",omitempty"` - BuildBrokenClangCFlags bool `json:",omitempty"` - BuildBrokenClangProperty bool `json:",omitempty"` - GenruleSandboxing *bool `json:",omitempty"` - BuildBrokenEnforceSyspropOwner bool `json:",omitempty"` - BuildBrokenTrebleSyspropNeverallow bool `json:",omitempty"` - BuildBrokenUsesSoongPython2Modules bool `json:",omitempty"` - BuildBrokenVendorPropertyNamespace bool `json:",omitempty"` - BuildBrokenVendorSeappUsesCoredomain bool `json:",omitempty"` - BuildBrokenInputDirModules []string `json:",omitempty"` + BuildBrokenPluginValidation []string `json:",omitempty"` + BuildBrokenClangAsFlags bool `json:",omitempty"` + BuildBrokenClangCFlags bool `json:",omitempty"` + BuildBrokenClangProperty bool `json:",omitempty"` + GenruleSandboxing *bool `json:",omitempty"` + BuildBrokenEnforceSyspropOwner bool `json:",omitempty"` + BuildBrokenTrebleSyspropNeverallow bool `json:",omitempty"` + BuildBrokenUsesSoongPython2Modules bool `json:",omitempty"` + BuildBrokenVendorPropertyNamespace bool `json:",omitempty"` + BuildBrokenIncorrectPartitionImages bool `json:",omitempty"` + BuildBrokenInputDirModules []string `json:",omitempty"` BuildWarningBadOptionalUsesLibsAllowlist []string `json:",omitempty"` @@ -481,12 +476,20 @@ type ProductVariables struct { ProductBrand string `json:",omitempty"` BuildVersionTags []string `json:",omitempty"` - ReleaseVersion string `json:",omitempty"` - ReleaseAconfigValueSets []string `json:",omitempty"` + ReleaseVersion string `json:",omitempty"` + ReleaseAconfigValueSets string `json:",omitempty"` ReleaseAconfigFlagDefaultPermission string `json:",omitempty"` KeepVndk *bool `json:",omitempty"` + + CheckVendorSeappViolations *bool `json:",omitempty"` + + // PartitionsVars are extra variables that are used to define the partition images. They should + // not be read from soong modules. + PartitionVars struct { + ProductDirectory string `json:",omitempty"` + } `json:",omitempty"` } func boolPtr(v bool) *bool { @@ -672,7 +675,8 @@ type ProductConfigProperties map[string]map[ProductConfigOrSoongConfigProperty]i // ProductVariableProperties returns a ProductConfigProperties containing only the properties which // have been set for the given module. -func ProductVariableProperties(ctx ArchVariantContext, module Module) ProductConfigProperties { +func ProductVariableProperties(ctx ArchVariantContext, module Module) (ProductConfigProperties, []error) { + var errs []error moduleBase := module.base() productConfigProperties := ProductConfigProperties{} @@ -696,12 +700,15 @@ func ProductVariableProperties(ctx ArchVariantContext, module Module) ProductCon for namespace, namespacedVariableProps := range m.namespacedVariableProps() { for _, namespacedVariableProp := range namespacedVariableProps { variableValues := reflect.ValueOf(namespacedVariableProp).Elem().FieldByName(soongconfig.SoongConfigProperty) - productConfigProperties.AddSoongConfigProperties(namespace, variableValues) + err := productConfigProperties.AddSoongConfigProperties(namespace, variableValues) + if err != nil { + errs = append(errs, err) + } } } } - return productConfigProperties + return productConfigProperties, errs } func (p *ProductConfigProperties) AddProductConfigProperty( @@ -823,7 +830,7 @@ func (productConfigProperties *ProductConfigProperties) AddProductConfigProperti } -func (productConfigProperties *ProductConfigProperties) AddSoongConfigProperties(namespace string, soongConfigVariablesStruct reflect.Value) { +func (productConfigProperties *ProductConfigProperties) AddSoongConfigProperties(namespace string, soongConfigVariablesStruct reflect.Value) error { // // Example of soong_config_variables: // @@ -920,7 +927,7 @@ func (productConfigProperties *ProductConfigProperties) AddSoongConfigProperties if propertyName == "Target" { productConfigProperties.AddSoongConfigPropertiesFromTargetStruct(namespace, variableName, proptools.PropertyNameForField(propertyOrValueName), field.Field(k)) } else if propertyName == "Arch" || propertyName == "Multilib" { - panic("Arch/Multilib are not currently supported in soong config variable structs") + return fmt.Errorf("Arch/Multilib are not currently supported in soong config variable structs") } else { productConfigProperties.AddSoongConfigProperty(propertyName, namespace, variableName, proptools.PropertyNameForField(propertyOrValueName), "", field.Field(k).Interface()) } @@ -931,13 +938,14 @@ func (productConfigProperties *ProductConfigProperties) AddSoongConfigProperties if propertyOrValueName == "Target" { productConfigProperties.AddSoongConfigPropertiesFromTargetStruct(namespace, variableName, "", propertyOrStruct) } else if propertyOrValueName == "Arch" || propertyOrValueName == "Multilib" { - panic("Arch/Multilib are not currently supported in soong config variable structs") + return fmt.Errorf("Arch/Multilib are not currently supported in soong config variable structs") } else { productConfigProperties.AddSoongConfigProperty(propertyOrValueName, namespace, variableName, "", "", propertyOrStruct.Interface()) } } } } + return nil } func (productConfigProperties *ProductConfigProperties) AddSoongConfigPropertiesFromTargetStruct(namespace, soongConfigVariableName string, soongConfigVariableValue string, targetStruct reflect.Value) { diff --git a/apex/androidmk.go b/apex/androidmk.go index f4690620c..2f5d8d4f3 100644 --- a/apex/androidmk.go +++ b/apex/androidmk.go @@ -42,7 +42,7 @@ func (class apexFileClass) nameInMake() string { return "ETC" case nativeSharedLib: return "SHARED_LIBRARIES" - case nativeExecutable, shBinary, pyBinary, goBinary: + case nativeExecutable, shBinary: return "EXECUTABLES" case javaSharedLib: return "JAVA_LIBRARIES" @@ -67,7 +67,7 @@ func (a *apexBundle) fullModuleName(apexBundleName string, linkToSystemLib bool, if linkToSystemLib { return fi.androidMkModuleName } - return fi.androidMkModuleName + "." + apexBundleName + a.suffix + return fi.androidMkModuleName + "." + apexBundleName } // androidMkForFiles generates Make definitions for the contents of an @@ -85,11 +85,6 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, moduleDir st // conflicts between two apexes with the same apexName. moduleNames := []string{} - // To avoid creating duplicate build rules, run this function only when primaryApexType is true - // to install symbol files in $(PRODUCT_OUT}/apex. - if !a.primaryApexType { - return moduleNames - } for _, fi := range a.filesInfo { linkToSystemLib := a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() @@ -140,32 +135,9 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, moduleDir st fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", fi.class.nameInMake()) if fi.module != nil { // This apexFile's module comes from Soong - archStr := fi.module.Target().Arch.ArchType.String() - host := false - switch fi.module.Target().Os.Class { - case android.Host: - if fi.module.Target().HostCross { - if fi.module.Target().Arch.ArchType != android.Common { - fmt.Fprintln(w, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr) - } - } else { - if fi.module.Target().Arch.ArchType != android.Common { - fmt.Fprintln(w, "LOCAL_MODULE_HOST_ARCH :=", archStr) - } - } - host = true - case android.Device: - if fi.module.Target().Arch.ArchType != android.Common { - fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr) - } - } - if host { - makeOs := fi.module.Target().Os.String() - if fi.module.Target().Os == android.Linux || fi.module.Target().Os == android.LinuxBionic || fi.module.Target().Os == android.LinuxMusl { - makeOs = "linux" - } - fmt.Fprintln(w, "LOCAL_MODULE_HOST_OS :=", makeOs) - fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true") + if fi.module.Target().Arch.ArchType != android.Common { + archStr := fi.module.Target().Arch.ArchType.String() + fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr) } } else if fi.isBazelPrebuilt && fi.arch != "" { // This apexFile comes from Bazel @@ -237,7 +209,7 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, moduleDir st } // m <module_name> will build <module_name>.<apex_name> as well. - if fi.androidMkModuleName != moduleName && a.primaryApexType { + if fi.androidMkModuleName != moduleName { fmt.Fprintf(w, ".PHONY: %s\n", fi.androidMkModuleName) fmt.Fprintf(w, "%s: %s\n", fi.androidMkModuleName, moduleName) } @@ -266,19 +238,18 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData { return android.AndroidMkData{ Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { moduleNames := []string{} - apexType := a.properties.ApexType if a.installable() { moduleNames = a.androidMkForFiles(w, name, moduleDir, data) } fmt.Fprintln(w, "\ninclude $(CLEAR_VARS) # apex.apexBundle") fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) - fmt.Fprintln(w, "LOCAL_MODULE :=", name+a.suffix) + fmt.Fprintln(w, "LOCAL_MODULE :=", name) data.Entries.WriteLicenseVariables(w) fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") // do we need a new class? fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", a.outputFile.String()) fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", a.installDir.String()) - stemSuffix := apexType.suffix() + stemSuffix := imageApexSuffix if a.isCompressed { stemSuffix = imageCapexSuffix } @@ -287,6 +258,7 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData { if a.installable() { fmt.Fprintln(w, "LOCAL_SOONG_INSTALLED_MODULE :=", a.installedFile.String()) fmt.Fprintln(w, "LOCAL_SOONG_INSTALL_PAIRS :=", a.outputFile.String()+":"+a.installedFile.String()) + fmt.Fprintln(w, "LOCAL_SOONG_INSTALL_SYMLINKS := ", strings.Join(a.compatSymlinks.Strings(), " ")) } // Because apex writes .mk with Custom(), we need to write manually some common properties @@ -306,10 +278,7 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData { a.writeRequiredModules(w, moduleNames) fmt.Fprintln(w, "include $(BUILD_PREBUILT)") - - if apexType == imageApex { - fmt.Fprintln(w, "ALL_MODULES.$(my_register_name).BUNDLE :=", a.bundleModuleFile.String()) - } + fmt.Fprintln(w, "ALL_MODULES.$(my_register_name).BUNDLE :=", a.bundleModuleFile.String()) android.AndroidMkEmitAssignList(w, "ALL_MODULES.$(my_register_name).LINT_REPORTS", a.lintReports.Strings()) if a.installedFilesFile != nil { diff --git a/apex/apex.go b/apex/apex.go index 8c21d3d7c..090d9c4fe 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -18,6 +18,7 @@ package apex import ( "fmt" + "log" "path/filepath" "regexp" "sort" @@ -26,7 +27,6 @@ import ( "android/soong/bazel/cquery" "github.com/google/blueprint" - "github.com/google/blueprint/bootstrap" "github.com/google/blueprint/proptools" "android/soong/android" @@ -37,7 +37,6 @@ import ( "android/soong/filesystem" "android/soong/java" "android/soong/multitree" - "android/soong/python" "android/soong/rust" "android/soong/sh" ) @@ -79,7 +78,6 @@ func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) { ctx.BottomUp("mark_platform_availability", markPlatformAvailability).Parallel() ctx.BottomUp("apex", apexMutator).Parallel() ctx.BottomUp("apex_directly_in_any", apexDirectlyInAnyMutator).Parallel() - ctx.BottomUp("apex_packaging", apexPackagingMutator).Parallel() ctx.BottomUp("apex_dcla_deps", apexDCLADepsMutator).Parallel() // Register after apex_info mutator so that it can use ApexVariationName ctx.TopDown("apex_strict_updatability_lint", apexStrictUpdatibilityLintMutator).Parallel() @@ -166,15 +164,7 @@ type apexBundleProperties struct { // Should be only used in non-system apexes (e.g. vendor: true). Default is false. Use_vndk_as_stable *bool - // The type of APEX to build. Controls what the APEX payload is. Either 'image', 'zip' or - // 'both'. When set to image, contents are stored in a filesystem image inside a zip - // container. When set to zip, contents are stored in a zip container directly. This type is - // mostly for host-side debugging. When set to both, the two types are both built. Default - // is 'image'. - Payload_type *string - - // The type of filesystem to use when the payload_type is 'image'. Either 'ext4', 'f2fs' - // or 'erofs'. Default 'ext4'. + // The type of filesystem to use. Either 'ext4', 'f2fs' or 'erofs'. Default 'ext4'. Payload_fs_type *string // For telling the APEX to ignore special handling for system libraries such as bionic. @@ -216,9 +206,6 @@ type apexBundleProperties struct { HideFromMake bool `blueprint:"mutated"` - // Internal package method for this APEX. - ApexType apexPackaging `blueprint:"mutated"` - // Name that dependencies can specify in their apex_available properties to refer to this module. // If not specified, this defaults to Soong module name. This must be the name of a Soong module. Apex_available_name *string @@ -421,13 +408,6 @@ type apexBundle struct { testApex bool vndkApex bool - // Tells whether this variant of the APEX bundle is the primary one or not. Only the primary - // one gets installed to the device. - primaryApexType bool - - // Suffix of module name in Android.mk ".apex", ".zipapex", or "" - suffix string - // File system type of apex_payload.img payloadFsType fsType @@ -506,12 +486,10 @@ const ( app apexFileClass = iota appSet etc - goBinary javaSharedLib nativeExecutable nativeSharedLib nativeTest - pyBinary shBinary ) @@ -520,12 +498,10 @@ var ( "app": app, "appSet": appSet, "etc": etc, - "goBinary": goBinary, "javaSharedLib": javaSharedLib, "nativeExecutable": nativeExecutable, "nativeSharedLib": nativeSharedLib, "nativeTest": nativeTest, - "pyBinary": pyBinary, "shBinary": shBinary, } ) @@ -716,11 +692,10 @@ func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, nativeM libVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"}) rustLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "rust_libraries", Variation: "dylib"}) - if ctx.Device() { - binVariations = append(binVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation}) - libVariations = append(libVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation}) - rustLibVariations = append(rustLibVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation}) - } + // Append "image" variation + binVariations = append(binVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation}) + libVariations = append(libVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation}) + rustLibVariations = append(rustLibVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation}) // Use *FarVariation* to be able to depend on modules having conflicting variations with // this module. This is required since arch variant of an APEX bundle is 'common' but it is @@ -740,16 +715,7 @@ func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, nativeM } func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) { - if ctx.Device() { - proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Android.Multilib, nil) - } else { - proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Host.Multilib, nil) - if ctx.Os().Bionic() { - proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Linux_bionic.Multilib, nil) - } else { - proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Linux_glibc.Multilib, nil) - } - } + proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Android.Multilib, nil) } // getImageVariationPair returns a pair for the image variation name as its @@ -807,12 +773,6 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) { } } for i, target := range targets { - // Don't include artifacts for the host cross targets because there is no way for us - // to run those artifacts natively on host - if target.HostCross { - continue - } - var deps ApexNativeDependencies // Add native modules targeting both ABIs. When multilib.* is omitted for @@ -1032,6 +992,13 @@ func (a *apexBundle) ApexInfoMutator(mctx android.TopDownMutatorContext) { return false } } + + //TODO: b/296491928 Vendor APEX should use libbinder.ndk instead of libbinder once VNDK is fully deprecated. + if useVndk && mctx.Config().IsVndkDeprecated() && child.Name() == "libbinder" { + log.Print("Libbinder is linked from Vendor APEX ", a.Name(), " with module ", parent.Name()) + return false + } + // By default, all the transitive dependencies are collected, unless filtered out // above. return true @@ -1249,8 +1216,8 @@ func apexTestForMutator(mctx android.BottomUpMutatorContext) { // be) available to platform // TODO(jiyong): move this to android/apex.go? func markPlatformAvailability(mctx android.BottomUpMutatorContext) { - // Host and recovery are not considered as platform - if mctx.Host() || mctx.Module().InstallInRecovery() { + // Recovery is not considered as platform + if mctx.Module().InstallInRecovery() { return } @@ -1353,95 +1320,19 @@ func apexDirectlyInAnyMutator(mctx android.BottomUpMutatorContext) { } } -// apexPackaging represents a specific packaging method for an APEX. -type apexPackaging int - -const ( - // imageApex is a packaging method where contents are included in a filesystem image which - // is then included in a zip container. This is the most typical way of packaging. - imageApex apexPackaging = iota - - // zipApex is a packaging method where contents are directly included in the zip container. - // This is used for host-side testing - because the contents are easily accessible by - // unzipping the container. - // TODO(b/279835185) deprecate zipApex - zipApex -) - const ( // File extensions of an APEX for different packaging methods imageApexSuffix = ".apex" imageCapexSuffix = ".capex" - zipApexSuffix = ".zipapex" // variant names each of which is for a packaging method imageApexType = "image" - zipApexType = "zip" ext4FsType = "ext4" f2fsFsType = "f2fs" erofsFsType = "erofs" ) -// The suffix for the output "file", not the module -func (a apexPackaging) suffix() string { - switch a { - case imageApex: - return imageApexSuffix - case zipApex: - return zipApexSuffix - default: - panic(fmt.Errorf("unknown APEX type %d", a)) - } -} - -func (a apexPackaging) name() string { - switch a { - case imageApex: - return imageApexType - case zipApex: - return zipApexType - default: - panic(fmt.Errorf("unknown APEX type %d", a)) - } -} - -// apexPackagingMutator creates one or more variations each of which is for a packaging method. -func apexPackagingMutator(mctx android.BottomUpMutatorContext) { - if !mctx.Module().Enabled() { - return - } - if ab, ok := mctx.Module().(*apexBundle); ok { - var variants []string - switch proptools.StringDefault(ab.properties.Payload_type, "image") { - case "image": - variants = append(variants, imageApexType) - case "zip": - variants = append(variants, zipApexType) - case "both": - variants = append(variants, imageApexType, zipApexType) - default: - mctx.PropertyErrorf("payload_type", "%q is not one of \"image\", \"zip\", or \"both\".", *ab.properties.Payload_type) - return - } - - modules := mctx.CreateLocalVariations(variants...) - - for i, v := range variants { - switch v { - case imageApexType: - modules[i].(*apexBundle).properties.ApexType = imageApex - case zipApexType: - modules[i].(*apexBundle).properties.ApexType = zipApex - } - } - } else if _, ok := mctx.Module().(*OverrideApex); ok { - // payload_type is forcibly overridden to "image" - // TODO(jiyong): is this the right decision? - mctx.CreateVariations(imageApexType) - } -} - var _ android.DepIsInSameApex = (*apexBundle)(nil) // Implements android.DepInInSameApex @@ -1486,7 +1377,7 @@ var _ cc.Coverage = (*apexBundle)(nil) // Implements cc.Coverage func (a *apexBundle) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool { - return ctx.Device() && ctx.DeviceConfig().NativeCoverageEnabled() + return ctx.DeviceConfig().NativeCoverageEnabled() } // Implements cc.Coverage @@ -1597,13 +1488,9 @@ func (a *apexBundle) IsSanitizerEnabled(config android.Config, sanitizerName str // Then follow the global setting var globalSanitizerNames []string - if a.Host() { - globalSanitizerNames = config.SanitizeHost() - } else { - arches := config.SanitizeDeviceArch() - if len(arches) == 0 || android.InList(a.Arch().ArchType.Name, arches) { - globalSanitizerNames = config.SanitizeDevice() - } + arches := config.SanitizeDeviceArch() + if len(arches) == 0 || android.InList(a.Arch().ArchType.Name, arches) { + globalSanitizerNames = config.SanitizeDevice() } return android.InList(sanitizerName, globalSanitizerNames) } @@ -1611,7 +1498,7 @@ func (a *apexBundle) IsSanitizerEnabled(config android.Config, sanitizerName str func (a *apexBundle) AddSanitizerDependencies(ctx android.BottomUpMutatorContext, sanitizerName string) { // TODO(jiyong): move this info (the sanitizer name, the lib name, etc.) to cc/sanitize.go // Keep only the mechanism here. - if ctx.Device() && sanitizerName == "hwaddress" && strings.HasPrefix(a.Name(), "com.android.runtime") { + if sanitizerName == "hwaddress" && strings.HasPrefix(a.Name(), "com.android.runtime") { imageVariation := a.getImageVariation(ctx) for _, target := range ctx.MultiTargets() { if target.Arch.ArchType.Multilib == "lib64" { @@ -1711,22 +1598,6 @@ func apexFileForRustLibrary(ctx android.BaseModuleContext, rustm *rust.Module) a return newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeSharedLib, rustm) } -func apexFileForPyBinary(ctx android.BaseModuleContext, py *python.PythonBinaryModule) apexFile { - dirInApex := "bin" - fileToCopy := py.HostToolPath().Path() - return newApexFile(ctx, fileToCopy, py.BaseModuleName(), dirInApex, pyBinary, py) -} - -func apexFileForGoBinary(ctx android.BaseModuleContext, depName string, gb bootstrap.GoBinaryTool) apexFile { - dirInApex := "bin" - fileToCopy := android.PathForGoBinary(ctx, gb) - // NB: Since go binaries are static we don't need the module for anything here, which is - // good since the go tool is a blueprint.Module not an android.Module like we would - // normally use. - // - return newApexFile(ctx, fileToCopy, depName, dirInApex, goBinary, nil) -} - func apexFileForShBinary(ctx android.BaseModuleContext, sh *sh.ShBinary) apexFile { dirInApex := filepath.Join("bin", sh.SubDir()) if sh.Target().NativeBridge == android.NativeBridgeEnabled { @@ -1945,7 +1816,7 @@ func (f fsType) string() string { var _ android.MixedBuildBuildable = (*apexBundle)(nil) func (a *apexBundle) IsMixedBuildSupported(ctx android.BaseModuleContext) bool { - return a.properties.ApexType == imageApex + return true } func (a *apexBundle) QueueBazelCall(ctx android.BaseModuleContext) { @@ -1966,13 +1837,9 @@ func (a *apexBundle) ProcessBazelQueryResponse(ctx android.ModuleContext) { return } - a.setApexTypeAndSuffix(ctx) a.setPayloadFsType(ctx) a.setSystemLibLink(ctx) - - if a.properties.ApexType != zipApex { - a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx, a.primaryApexType) - } + a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx) bazelCtx := ctx.Config().BazelContext outputs, err := bazelCtx.GetApexInfo(a.GetBazelLabel(ctx, a), android.GetConfigKey(ctx)) @@ -2007,24 +1874,18 @@ func (a *apexBundle) ProcessBazelQueryResponse(ctx android.ModuleContext) { // part of a bundled build. a.makeModulesToInstall = append(a.makeModulesToInstall, outputs.MakeModulesToInstall...) - apexType := a.properties.ApexType - switch apexType { - case imageApex: - a.bundleModuleFile = android.PathForBazelOut(ctx, outputs.BundleFile) - a.nativeApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.SymbolsUsedByApex)) - a.nativeApisBackedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.BackingLibs)) - // TODO(b/239084755): Generate the java api using.xml file from Bazel. - a.javaApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.JavaSymbolsUsedByApex)) - a.installedFilesFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.InstalledFiles)) - installSuffix := imageApexSuffix - if a.isCompressed { - installSuffix = imageCapexSuffix - } - a.installedFile = ctx.InstallFile(a.installDir, a.Name()+installSuffix, a.outputFile, - a.compatSymlinks.Paths()...) - default: - panic(fmt.Errorf("internal error: unexpected apex_type for the ProcessBazelQueryResponse: %v", a.properties.ApexType)) + a.bundleModuleFile = android.PathForBazelOut(ctx, outputs.BundleFile) + a.nativeApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.SymbolsUsedByApex)) + a.nativeApisBackedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.BackingLibs)) + // TODO(b/239084755): Generate the java api using.xml file from Bazel. + a.javaApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.JavaSymbolsUsedByApex)) + a.installedFilesFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.InstalledFiles)) + installSuffix := imageApexSuffix + if a.isCompressed { + installSuffix = imageCapexSuffix } + a.installedFile = ctx.InstallFile(a.installDir, a.Name()+installSuffix, a.outputFile, + a.compatSymlinks.Paths()...) // filesInfo in mixed mode must retrieve all information about the apex's // contents completely from the Starlark providers. It should never rely on @@ -2065,9 +1926,7 @@ func (a *apexBundle) ProcessBazelQueryResponse(ctx android.ModuleContext) { } func (a *apexBundle) setCompression(ctx android.ModuleContext) { - if a.properties.ApexType != imageApex { - a.isCompressed = false - } else if a.testOnlyShouldForceCompression() { + if a.testOnlyShouldForceCompression() { a.isCompressed = true } else { a.isCompressed = ctx.Config().ApexCompressionEnabled() && a.isCompressable() @@ -2093,12 +1952,7 @@ func (a *apexBundle) setSystemLibLink(ctx android.ModuleContext) { // We don't need the optimization for updatable APEXes, as it might give false signal // to the system health when the APEXes are still bundled (b/149805758). - if !forced && updatable && a.properties.ApexType == imageApex { - a.linkToSystemLib = false - } - - // We also don't want the optimization for host APEXes, because it doesn't make sense. - if ctx.Host() { + if !forced && updatable { a.linkToSystemLib = false } } @@ -2116,22 +1970,6 @@ func (a *apexBundle) setPayloadFsType(ctx android.ModuleContext) { } } -func (a *apexBundle) setApexTypeAndSuffix(ctx android.ModuleContext) { - // Set suffix and primaryApexType depending on the ApexType - switch a.properties.ApexType { - case imageApex: - a.suffix = "" - a.primaryApexType = true - case zipApex: - if proptools.String(a.properties.Payload_type) == "zip" { - a.suffix = "" - a.primaryApexType = true - } else { - a.suffix = zipApexSuffix - } - } -} - func (a *apexBundle) isCompressable() bool { return proptools.BoolDefault(a.overridableProperties.Compressible, false) && !a.testApex } @@ -2178,6 +2016,9 @@ func (vctx *visitorContext) normalizeFileInfo(mctx android.ModuleContext) { // If a module is directly included and also transitively depended on // consider it as directly included. e.transitiveDep = e.transitiveDep && f.transitiveDep + // If a module is added as both a JNI library and a regular shared library, consider it as a + // JNI library. + e.isJniLib = e.isJniLib || f.isJniLib encountered[dest] = e } } @@ -2234,14 +2075,6 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, case *cc.Module: vctx.filesInfo = append(vctx.filesInfo, apexFileForExecutable(ctx, ch)) return true // track transitive dependencies - case *python.PythonBinaryModule: - if ch.HostToolPath().Valid() { - vctx.filesInfo = append(vctx.filesInfo, apexFileForPyBinary(ctx, ch)) - } - case bootstrap.GoBinaryTool: - if a.Host() { - vctx.filesInfo = append(vctx.filesInfo, apexFileForGoBinary(ctx, depName, ch)) - } case *rust.Module: vctx.filesInfo = append(vctx.filesInfo, apexFileForRustExecutable(ctx, ch)) return true // track transitive dependencies @@ -2400,14 +2233,13 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, vctx.requireNativeLibs = append(vctx.requireNativeLibs, ":vndk") return false } - af := apexFileForNativeLibrary(ctx, ch, vctx.handleSpecialLibs) - af.transitiveDep = true - // Always track transitive dependencies for host. - if a.Host() { - vctx.filesInfo = append(vctx.filesInfo, af) - return true + //TODO: b/296491928 Vendor APEX should use libbinder.ndk instead of libbinder once VNDK is fully deprecated. + if ch.UseVndk() && ctx.Config().IsVndkDeprecated() && child.Name() == "libbinder" { + return false } + af := apexFileForNativeLibrary(ctx, ch, vctx.handleSpecialLibs) + af.transitiveDep = true abInfo := ctx.Provider(ApexBundleInfoProvider).(ApexBundleInfo) if !abInfo.Contents.DirectlyInApex(depName) && (ch.IsStubs() || ch.HasStubsVariants()) { @@ -2539,11 +2371,7 @@ func (a *apexBundle) shouldCheckDuplicate(ctx android.ModuleContext) bool { if a.testApex { return false } - // TODO(b/263309864) remove this - if a.Host() { - return false - } - if a.Device() && ctx.DeviceConfig().DeviceArch() == "" { + if ctx.DeviceConfig().DeviceArch() == "" { return false } return true @@ -2621,12 +2449,9 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.installDir = android.PathForModuleInstall(ctx, "apex") a.filesInfo = vctx.filesInfo - a.setApexTypeAndSuffix(ctx) a.setPayloadFsType(ctx) a.setSystemLibLink(ctx) - if a.properties.ApexType != zipApex { - a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx, a.primaryApexType) - } + a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx) //////////////////////////////////////////////////////////////////////////////////////////// // 4) generate the build rules to create the APEX. This is done in builder.go. @@ -2727,7 +2552,7 @@ func newApexBundle() *apexBundle { module.AddProperties(&module.archProperties) module.AddProperties(&module.overridableProperties) - android.InitAndroidMultiTargetsArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon) + android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) android.InitOverridableModule(module, &module.overridableProperties.Overrides) android.InitBazelModule(module) @@ -2798,7 +2623,7 @@ func OverrideApexFactory() android.Module { return m } -func (o *OverrideApex) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (o *OverrideApex) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { if ctx.ModuleType() != "override_apex" { return } @@ -2918,13 +2743,13 @@ func (a *apexBundle) minSdkVersionValue(ctx android.EarlyModuleContext) string { // Only override the minSdkVersion value on Apexes which already specify // a min_sdk_version (it's optional for non-updatable apexes), and that its // min_sdk_version value is lower than the one to override with. - minApiLevel := minSdkVersionFromValue(ctx, proptools.String(a.properties.Min_sdk_version)) + minApiLevel := android.MinSdkVersionFromValue(ctx, proptools.String(a.properties.Min_sdk_version)) if minApiLevel.IsNone() { return "" } overrideMinSdkValue := ctx.DeviceConfig().ApexGlobalMinSdkVersionOverride() - overrideApiLevel := minSdkVersionFromValue(ctx, overrideMinSdkValue) + overrideApiLevel := android.MinSdkVersionFromValue(ctx, overrideMinSdkValue) if !overrideApiLevel.IsNone() && overrideApiLevel.CompareTo(minApiLevel) > 0 { minApiLevel = overrideApiLevel } @@ -2939,26 +2764,13 @@ func (a *apexBundle) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLe // Returns apex's min_sdk_version ApiLevel, honoring overrides func (a *apexBundle) minSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { - return minSdkVersionFromValue(ctx, a.minSdkVersionValue(ctx)) -} - -// Construct ApiLevel object from min_sdk_version string value -func minSdkVersionFromValue(ctx android.EarlyModuleContext, value string) android.ApiLevel { - if value == "" { - return android.NoneApiLevel - } - apiLevel, err := android.ApiLevelFromUser(ctx, value) - if err != nil { - ctx.PropertyErrorf("min_sdk_version", "%s", err.Error()) - return android.NoneApiLevel - } - return apiLevel + return android.MinSdkVersionFromValue(ctx, a.minSdkVersionValue(ctx)) } // Ensures that a lib providing stub isn't statically linked func (a *apexBundle) checkStaticLinkingToStubLibraries(ctx android.ModuleContext) { // Practically, we only care about regular APEXes on the device. - if ctx.Host() || a.testApex || a.vndkApex { + if a.testApex || a.vndkApex { return } @@ -3053,7 +2865,7 @@ func (a *apexBundle) checkJavaStableSdkVersion(ctx android.ModuleContext) { // checkApexAvailability ensures that the all the dependencies are marked as available for this APEX. func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) { // Let's be practical. Availability for test, host, and the VNDK apex isn't important - if ctx.Host() || a.testApex || a.vndkApex { + if a.testApex || a.vndkApex { return } @@ -3111,11 +2923,6 @@ func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) { // checkStaticExecutable ensures that executables in an APEX are not static. func (a *apexBundle) checkStaticExecutables(ctx android.ModuleContext) { - // No need to run this for host APEXes - if ctx.Host() { - return - } - ctx.VisitDirectDepsBlueprint(func(module blueprint.Module) { if ctx.OtherModuleDependencyTag(module) != executableTag { return @@ -3454,7 +3261,7 @@ const ( ) // ConvertWithBp2build performs bp2build conversion of an apex -func (a *apexBundle) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (a *apexBundle) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { // We only convert apex and apex_test modules at this time if ctx.ModuleType() != "apex" && ctx.ModuleType() != "apex_test" { return @@ -3465,7 +3272,7 @@ func (a *apexBundle) ConvertWithBp2build(ctx android.TopDownMutatorContext) { ctx.CreateBazelTargetModule(props, commonAttrs, &attrs) } -func convertWithBp2build(a *apexBundle, ctx android.TopDownMutatorContext) (bazelApexBundleAttributes, bazel.BazelTargetModuleProperties, android.CommonAttributes) { +func convertWithBp2build(a *apexBundle, ctx android.Bp2buildMutatorContext) (bazelApexBundleAttributes, bazel.BazelTargetModuleProperties, android.CommonAttributes) { var manifestLabelAttribute bazel.LabelAttribute manifestLabelAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))) @@ -3491,7 +3298,10 @@ func convertWithBp2build(a *apexBundle, ctx android.TopDownMutatorContext) (baze cannedFsConfigAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *a.properties.Canned_fs_config)) } - productVariableProps := android.ProductVariableProperties(ctx, a) + productVariableProps, errs := android.ProductVariableProperties(ctx, a) + for _, err := range errs { + ctx.ModuleErrorf("ProductVariableProperties error: %s", err) + } // TODO(b/219503907) this would need to be set to a.MinSdkVersionValue(ctx) but // given it's coming via config, we probably don't want to put it in here. var minSdkVersion bazel.StringAttribute @@ -3622,7 +3432,7 @@ func convertWithBp2build(a *apexBundle, ctx android.TopDownMutatorContext) (baze // both, 32/32, 64/none, 32&64/32, 64/32 // first, 32/32, 64/none, 64/32, 64/32 -func convert32Libs(ctx android.TopDownMutatorContext, compileMultilb string, +func convert32Libs(ctx android.Bp2buildMutatorContext, compileMultilb string, libs []string, nativeSharedLibs *convertedNativeSharedLibs) { libsLabelList := android.BazelLabelForModuleDeps(ctx, libs) switch compileMultilb { @@ -3637,7 +3447,7 @@ func convert32Libs(ctx android.TopDownMutatorContext, compileMultilb string, } } -func convert64Libs(ctx android.TopDownMutatorContext, compileMultilb string, +func convert64Libs(ctx android.Bp2buildMutatorContext, compileMultilb string, libs []string, nativeSharedLibs *convertedNativeSharedLibs) { libsLabelList := android.BazelLabelForModuleDeps(ctx, libs) switch compileMultilb { @@ -3650,7 +3460,7 @@ func convert64Libs(ctx android.TopDownMutatorContext, compileMultilb string, } } -func convertBothLibs(ctx android.TopDownMutatorContext, compileMultilb string, +func convertBothLibs(ctx android.Bp2buildMutatorContext, compileMultilb string, libs []string, nativeSharedLibs *convertedNativeSharedLibs) { libsLabelList := android.BazelLabelForModuleDeps(ctx, libs) switch compileMultilb { @@ -3668,7 +3478,7 @@ func convertBothLibs(ctx android.TopDownMutatorContext, compileMultilb string, } } -func convertFirstLibs(ctx android.TopDownMutatorContext, compileMultilb string, +func convertFirstLibs(ctx android.Bp2buildMutatorContext, compileMultilb string, libs []string, nativeSharedLibs *convertedNativeSharedLibs) { libsLabelList := android.BazelLabelForModuleDeps(ctx, libs) switch compileMultilb { @@ -3711,7 +3521,7 @@ func makeSharedLibsAttributes(config string, libsLabelList bazel.LabelList, labelListAttr.Append(list) } -func invalidCompileMultilib(ctx android.TopDownMutatorContext, value string) { +func invalidCompileMultilib(ctx android.Bp2buildMutatorContext, value string) { ctx.PropertyErrorf("compile_multilib", "Invalid value: %s", value) } diff --git a/apex/apex_test.go b/apex/apex_test.go index da059eb0a..3a6af1e44 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -518,10 +518,10 @@ func TestBasicApex(t *testing.T) { } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") // Make sure that Android.mk is created - ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + ab := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) data := android.AndroidMkDataForTest(t, ctx, ab) var builder strings.Builder data.Custom(&builder, ab.BaseModuleName(), "TARGET_", "", data) @@ -533,7 +533,7 @@ func TestBasicApex(t *testing.T) { optFlags := apexRule.Args["opt_flags"] ensureContains(t, optFlags, "--pubkey vendor/foo/devkeys/testkey.avbpubkey") // Ensure that the NOTICE output is being packaged as an asset. - ensureContains(t, optFlags, "--assets_dir out/soong/.intermediates/myapex/android_common_myapex_image/NOTICE") + ensureContains(t, optFlags, "--assets_dir out/soong/.intermediates/myapex/android_common_myapex/NOTICE") copyCmds := apexRule.Args["copy_commands"] @@ -595,13 +595,13 @@ func TestBasicApex(t *testing.T) { t.Errorf("Could not find all expected symlinks! foo: %t, foo_link_64: %t. Command was %s", found_foo, found_foo_link_64, copyCmds) } - fullDepsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("depsinfo/fulllist.txt").Args["content"], "\\n") + fullDepsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex").Output("depsinfo/fulllist.txt").Args["content"], "\\n") ensureListContains(t, fullDepsInfo, " myjar(minSdkVersion:(no version)) <- myapex") ensureListContains(t, fullDepsInfo, " mylib2(minSdkVersion:(no version)) <- mylib") ensureListContains(t, fullDepsInfo, " myotherjar(minSdkVersion:(no version)) <- myjar") ensureListContains(t, fullDepsInfo, " mysharedjar(minSdkVersion:(no version)) (external) <- myjar") - flatDepsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("depsinfo/flatlist.txt").Args["content"], "\\n") + flatDepsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex").Output("depsinfo/flatlist.txt").Args["content"], "\\n") ensureListContains(t, flatDepsInfo, "myjar(minSdkVersion:(no version))") ensureListContains(t, flatDepsInfo, "mylib2(minSdkVersion:(no version))") ensureListContains(t, flatDepsInfo, "myotherjar(minSdkVersion:(no version))") @@ -678,7 +678,7 @@ func TestDefaults(t *testing.T) { } `) - ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{ "etc/myetc", "javalib/myjar.jar", "lib64/mylib.so", @@ -705,7 +705,7 @@ func TestApexManifest(t *testing.T) { } `) - module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + module := ctx.ModuleForTests("myapex", "android_common_myapex") args := module.Rule("apexRule").Args if manifest := args["manifest"]; manifest != module.Output("apex_manifest.pb").Output.String() { t.Error("manifest should be apex_manifest.pb, but " + manifest) @@ -776,7 +776,7 @@ func TestApexManifestMinSdkVersion(t *testing.T) { }, } for _, tc := range testCases { - module := ctx.ModuleForTests(tc.module, "android_common_"+tc.module+"_image") + module := ctx.ModuleForTests(tc.module, "android_common_"+tc.module) args := module.Rule("apexRule").Args optFlags := args["opt_flags"] if !strings.Contains(optFlags, "--min_sdk_version "+tc.minSdkVersion) { @@ -806,7 +806,7 @@ func TestFileContexts(t *testing.T) { } `) - rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("file_contexts") + rule := ctx.ModuleForTests("myapex", "android_common_myapex").Output("file_contexts") if vendor { android.AssertStringDoesContain(t, "should force-label as vendor_apex_metadata_file", rule.RuleParams.Command, @@ -819,57 +819,6 @@ func TestFileContexts(t *testing.T) { } } -func TestBasicZipApex(t *testing.T) { - ctx := testApex(t, ` - apex { - name: "myapex", - key: "myapex.key", - payload_type: "zip", - native_shared_libs: ["mylib"], - updatable: false, - } - - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } - - cc_library { - name: "mylib", - srcs: ["mylib.cpp"], - shared_libs: ["mylib2"], - system_shared_libs: [], - stl: "none", - apex_available: [ "myapex" ], - } - - cc_library { - name: "mylib2", - srcs: ["mylib.cpp"], - system_shared_libs: [], - stl: "none", - apex_available: [ "myapex" ], - } - `) - - zipApexRule := ctx.ModuleForTests("myapex", "android_common_myapex_zip").Rule("zipApexRule") - copyCmds := zipApexRule.Args["copy_commands"] - - // Ensure that main rule creates an output - ensureContains(t, zipApexRule.Output.String(), "myapex.zipapex.unsigned") - - // Ensure that APEX variant is created for the direct dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000") - - // Ensure that APEX variant is created for the indirect dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000") - - // Ensure that both direct and indirect deps are copied into apex - ensureContains(t, copyCmds, "image.zipapex/lib64/mylib.so") - ensureContains(t, copyCmds, "image.zipapex/lib64/mylib2.so") -} - func TestApexWithStubs(t *testing.T) { ctx := testApex(t, ` apex { @@ -946,7 +895,7 @@ func TestApexWithStubs(t *testing.T) { `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that direct non-stubs dep is always included @@ -987,7 +936,7 @@ func TestApexWithStubs(t *testing.T) { // Ensure that genstub for apex-provided lib is invoked with --apex ensureContains(t, ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_shared_12").Rule("genStubSrc").Args["flags"], "--apex") - ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{ "lib64/mylib.so", "lib64/mylib3.so", "lib64/mylib4.so", @@ -999,11 +948,11 @@ func TestApexWithStubs(t *testing.T) { // Ensure that stub dependency from a rust module is not included ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.shared_from_rust.so") // The rust module is linked to the stub cc library - rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustLink").Args["linkFlags"] + rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").RuleParams.Command ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so") ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so") - apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule") + apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule") ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo.shared_from_rust.so") } @@ -1063,7 +1012,7 @@ func TestApexCanUsePrivateApis(t *testing.T) { } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that indirect stubs dep is not included @@ -1075,7 +1024,7 @@ func TestApexCanUsePrivateApis(t *testing.T) { mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_current/mylib2.so") ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so") - rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustLink").Args["linkFlags"] + rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").RuleParams.Command ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so") ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so") } @@ -1141,7 +1090,7 @@ func TestApexWithStubsWithMinSdkVersion(t *testing.T) { } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that direct non-stubs dep is always included @@ -1172,7 +1121,7 @@ func TestApexWithStubsWithMinSdkVersion(t *testing.T) { // Ensure that genstub is invoked with --systemapi ensureContains(t, ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("genStubSrc").Args["flags"], "--systemapi") - ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{ "lib64/mylib.so", "lib64/mylib3.so", "lib64/mylib4.so", @@ -1308,7 +1257,7 @@ func TestApexWithExplicitStubsDependency(t *testing.T) { `) - apexRule := ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex2", "android_common_myapex2").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that direct non-stubs dep is always included @@ -1332,10 +1281,10 @@ func TestApexWithExplicitStubsDependency(t *testing.T) { // Ensure that libfoo stubs is not linking to libbar (since it is a stubs) ensureNotContains(t, libFooStubsLdFlags, "libbar.so") - fullDepsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Output("depsinfo/fulllist.txt").Args["content"], "\\n") + fullDepsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2").Output("depsinfo/fulllist.txt").Args["content"], "\\n") ensureListContains(t, fullDepsInfo, " libfoo(minSdkVersion:(no version)) (external) <- mylib") - flatDepsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Output("depsinfo/flatlist.txt").Args["content"], "\\n") + flatDepsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2").Output("depsinfo/flatlist.txt").Args["content"], "\\n") ensureListContains(t, flatDepsInfo, "libfoo(minSdkVersion:(no version)) (external)") } @@ -1426,7 +1375,7 @@ func TestApexWithRuntimeLibsDependency(t *testing.T) { } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that direct non-stubs dep is always included @@ -1442,7 +1391,7 @@ func TestApexWithRuntimeLibsDependency(t *testing.T) { ensureNotContains(t, copyCmds, "image.apex/lib64/libstatic_to_runtime.so") - apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule") + apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule") ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"])) ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo.so") } @@ -1503,7 +1452,7 @@ func TestRuntimeApexShouldInstallHwasanIfLibcDependsOnIt(t *testing.T) { } `) ctx := result.TestContext - ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime_image", []string{ + ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime", []string{ "lib64/bionic/libc.so", "lib64/bionic/libclang_rt.hwasan-aarch64-android.so", }) @@ -1556,7 +1505,7 @@ func TestRuntimeApexShouldInstallHwasanIfHwaddressSanitized(t *testing.T) { `) ctx := result.TestContext - ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime_image", []string{ + ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime", []string{ "lib64/bionic/libc.so", "lib64/bionic/libclang_rt.hwasan-aarch64-android.so", }) @@ -1637,12 +1586,12 @@ func TestApexDependsOnLLNDKTransitively(t *testing.T) { ) // Ensure that LLNDK dep is not included - ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{ "lib64/mylib.so", }) // Ensure that LLNDK dep is required - apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule") + apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule") ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"])) ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libbar.so") @@ -1702,7 +1651,7 @@ func TestApexWithSystemLibsStubs(t *testing.T) { } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that mylib, libm, libdl are included. @@ -2076,11 +2025,11 @@ func TestTrackAllowedDeps(t *testing.T) { depsinfo := ctx.SingletonForTests("apex_depsinfo_singleton") inputs := depsinfo.Rule("generateApexDepsInfoFilesRule").BuildParams.Inputs.Strings() android.AssertStringListContains(t, "updatable myapex should generate depsinfo file", inputs, - "out/soong/.intermediates/myapex/android_common_myapex_image/depsinfo/flatlist.txt") + "out/soong/.intermediates/myapex/android_common_myapex/depsinfo/flatlist.txt") android.AssertStringListDoesNotContain(t, "non-updatable myapex2 should not generate depsinfo file", inputs, - "out/soong/.intermediates/myapex2/android_common_myapex2_image/depsinfo/flatlist.txt") + "out/soong/.intermediates/myapex2/android_common_myapex2/depsinfo/flatlist.txt") - myapex := ctx.ModuleForTests("myapex", "android_common_myapex_image") + myapex := ctx.ModuleForTests("myapex", "android_common_myapex") flatlist := strings.Split(myapex.Output("depsinfo/flatlist.txt").BuildParams.Args["content"], "\\n") android.AssertStringListContains(t, "deps with stubs should be tracked in depsinfo as external dep", flatlist, "libbar(minSdkVersion:(no version)) (external)") @@ -2838,7 +2787,7 @@ func TestFilesInSubDir(t *testing.T) { } `) - generateFsRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("generateFsConfig") + generateFsRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("generateFsConfig") cmd := generateFsRule.RuleParams.Command // Ensure that the subdirectories are all listed @@ -2903,7 +2852,7 @@ func TestFilesInSubDirWhenNativeBridgeEnabled(t *testing.T) { }, } `, withNativeBridgeEnabled) - ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{ "bin/foo/bar/mybin", "bin/foo/bar/mybin64", "bin/arm/foo/bar/mybin", @@ -2943,14 +2892,14 @@ func TestVendorApex(t *testing.T) { } `) - ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{ + ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex", []string{ "bin/mybin", "lib64/libfoo.so", // TODO(b/159195575): Add an option to use VNDK libs from VNDK APEX "lib64/libc++.so", }) - apexBundle := result.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + apexBundle := result.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) data := android.AndroidMkDataForTest(t, result.TestContext, apexBundle) name := apexBundle.BaseModuleName() prefix := "TARGET_" @@ -2960,7 +2909,7 @@ func TestVendorApex(t *testing.T) { installPath := "out/target/product/test_device/vendor/apex" ensureContains(t, androidMk, "LOCAL_MODULE_PATH := "+installPath) - apexManifestRule := result.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule") + apexManifestRule := result.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule") requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"]) ensureListNotContains(t, requireNativeLibs, ":vndk") } @@ -3103,10 +3052,10 @@ func TestVendorApex_use_vndk_as_stable(t *testing.T) { ensureListContains(t, libs, lib) } // Check apex contents - ensureExactContents(t, ctx, tc.apexName, "android_common_"+tc.apexName+"_image", tc.contents) + ensureExactContents(t, ctx, tc.apexName, "android_common_"+tc.apexName, tc.contents) // Check "requireNativeLibs" - apexManifestRule := ctx.ModuleForTests(tc.apexName, "android_common_"+tc.apexName+"_image").Rule("apexManifestRule") + apexManifestRule := ctx.ModuleForTests(tc.apexName, "android_common_"+tc.apexName).Rule("apexManifestRule") requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"]) if tc.requireVndkNamespace { ensureListContains(t, requireNativeLibs, ":vndk") @@ -3182,7 +3131,7 @@ func TestApex_withPrebuiltFirmware(t *testing.T) { `+tc.additionalProp+` } `) - ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{ "etc/firmware/myfirmware.bin", }) }) @@ -3211,7 +3160,7 @@ func TestAndroidMk_VendorApexRequired(t *testing.T) { } `) - apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) data := android.AndroidMkDataForTest(t, ctx, apexBundle) name := apexBundle.BaseModuleName() prefix := "TARGET_" @@ -3240,7 +3189,7 @@ func TestAndroidMkWritesCommonProperties(t *testing.T) { } `) - apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) data := android.AndroidMkDataForTest(t, ctx, apexBundle) name := apexBundle.BaseModuleName() prefix := "TARGET_" @@ -3343,7 +3292,7 @@ func TestKeys(t *testing.T) { } // check the APK certs. It should be overridden to myapex.certificate.override - certs := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest_image").Rule("signapk").Args["certificates"] + certs := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest").Rule("signapk").Args["certificates"] if certs != "testkey.override.x509.pem testkey.override.pk8" { t.Errorf("cert and private key %q are not %q", certs, "testkey.override.509.pem testkey.override.pk8") @@ -3363,7 +3312,7 @@ func TestCertificate(t *testing.T) { public_key: "testkey.avbpubkey", private_key: "testkey.pem", }`) - rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("signapk") + rule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk") expected := "vendor/foo/devkeys/test.x509.pem vendor/foo/devkeys/test.pk8" if actual := rule.Args["certificates"]; actual != expected { t.Errorf("certificates should be %q, not %q", expected, actual) @@ -3386,7 +3335,7 @@ func TestCertificate(t *testing.T) { name: "myapex.certificate.override", certificate: "testkey.override", }`) - rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest_image").Rule("signapk") + rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest").Rule("signapk") expected := "testkey.override.x509.pem testkey.override.pk8" if actual := rule.Args["certificates"]; actual != expected { t.Errorf("certificates should be %q, not %q", expected, actual) @@ -3409,7 +3358,7 @@ func TestCertificate(t *testing.T) { name: "myapex.certificate", certificate: "testkey", }`) - rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("signapk") + rule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk") expected := "testkey.x509.pem testkey.pk8" if actual := rule.Args["certificates"]; actual != expected { t.Errorf("certificates should be %q, not %q", expected, actual) @@ -3433,7 +3382,7 @@ func TestCertificate(t *testing.T) { name: "myapex.certificate.override", certificate: "testkey.override", }`) - rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest_image").Rule("signapk") + rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest").Rule("signapk") expected := "testkey.override.x509.pem testkey.override.pk8" if actual := rule.Args["certificates"]; actual != expected { t.Errorf("certificates should be %q, not %q", expected, actual) @@ -3452,7 +3401,7 @@ func TestCertificate(t *testing.T) { public_key: "testkey.avbpubkey", private_key: "testkey.pem", }`) - rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("signapk") + rule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk") expected := "vendor/foo/devkeys/testkey.x509.pem vendor/foo/devkeys/testkey.pk8" if actual := rule.Args["certificates"]; actual != expected { t.Errorf("certificates should be %q, not %q", expected, actual) @@ -3476,7 +3425,7 @@ func TestCertificate(t *testing.T) { name: "myapex.certificate.override", certificate: "testkey.override", }`) - rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest_image").Rule("signapk") + rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest").Rule("signapk") expected := "testkey.override.x509.pem testkey.override.pk8" if actual := rule.Args["certificates"]; actual != expected { t.Errorf("certificates should be %q, not %q", expected, actual) @@ -3657,10 +3606,6 @@ func getFiles(t *testing.T, ctx *android.TestContext, moduleName, variant string module := ctx.ModuleForTests(moduleName, variant) apexRule := module.MaybeRule("apexRule") apexDir := "/image.apex/" - if apexRule.Rule == nil { - apexRule = module.Rule("zipApexRule") - apexDir = "/image.zipapex/" - } copyCmds := apexRule.Args["copy_commands"] var ret []fileInApex for _, cmd := range strings.Split(copyCmds, "&&") { @@ -3872,7 +3817,7 @@ func TestVndkApexCurrent(t *testing.T) { variables.DeviceVndkVersion = proptools.StringPtr(tc.vndkVersion) variables.KeepVndk = proptools.BoolPtr(true) })) - ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", tc.expectedFiles) + ensureExactContents(t, ctx, "com.android.vndk.current", "android_common", tc.expectedFiles) }) } } @@ -3927,7 +3872,7 @@ func TestVndkApexWithPrebuilt(t *testing.T) { "libvndk.so": nil, "libvndk.arm.so": nil, })) - ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{ + ensureExactContents(t, ctx, "com.android.vndk.current", "android_common", []string{ "lib/libvndk.so", "lib/libvndk.arm.so", "lib64/libvndk.so", @@ -4023,7 +3968,7 @@ func TestVndkApexVersion(t *testing.T) { "libvndk27_x86_64.so": nil, })) - ensureExactContents(t, ctx, "com.android.vndk.v27", "android_common_image", []string{ + ensureExactContents(t, ctx, "com.android.vndk.v27", "android_common", []string{ "lib/libvndk27_arm.so", "lib64/libvndk27_arm64.so", "etc/*", @@ -4052,7 +3997,7 @@ func TestVndkApexNameRule(t *testing.T) { }`+vndkLibrariesTxtFiles("28", "current")) assertApexName := func(expected, moduleName string) { - module := ctx.ModuleForTests(moduleName, "android_common_image") + module := ctx.ModuleForTests(moduleName, "android_common") apexManifestRule := module.Rule("apexManifestRule") ensureContains(t, apexManifestRule.Args["opt"], "-v name "+expected) } @@ -4093,7 +4038,7 @@ func TestVndkApexSkipsNativeBridgeSupportedModules(t *testing.T) { `+vndkLibrariesTxtFiles("current"), withNativeBridgeEnabled) - ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{ + ensureExactContents(t, ctx, "com.android.vndk.current", "android_common", []string{ "lib/libvndk.so", "lib64/libvndk.so", "lib/libc++.so", @@ -4196,7 +4141,7 @@ func TestVndkApexWithBinder32(t *testing.T) { }), ) - ensureExactContents(t, ctx, "com.android.vndk.v27", "android_common_image", []string{ + ensureExactContents(t, ctx, "com.android.vndk.v27", "android_common", []string{ "lib/libvndk27binder32.so", "etc/*", }) @@ -4233,10 +4178,10 @@ func TestVndkApexShouldNotProvideNativeLibs(t *testing.T) { "libz.map.txt": nil, })) - apexManifestRule := ctx.ModuleForTests("com.android.vndk.current", "android_common_image").Rule("apexManifestRule") + apexManifestRule := ctx.ModuleForTests("com.android.vndk.current", "android_common").Rule("apexManifestRule") provideNativeLibs := names(apexManifestRule.Args["provideNativeLibs"]) ensureListEmpty(t, provideNativeLibs) - ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{ + ensureExactContents(t, ctx, "com.android.vndk.current", "android_common", []string{ "out/soong/.intermediates/libz/android_vendor.29_arm64_armv8-a_shared/libz.so:lib64/libz.so", "out/soong/.intermediates/libz/android_vendor.29_arm_armv7-a-neon_shared/libz.so:lib/libz.so", "*/*", @@ -4392,7 +4337,7 @@ func TestVendorApexWithVndkPrebuilts(t *testing.T) { })) // Should embed the prebuilt VNDK libraries in the apex - ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{ "bin/foo", "prebuilts/vndk/libc++.so:lib64/libc++.so", "prebuilts/vndk/libvndk.so:lib64/libvndk.so", @@ -4406,7 +4351,7 @@ func TestVendorApexWithVndkPrebuilts(t *testing.T) { android.AssertStringDoesContain(t, "should link to prebuilt libunwind", ldRule.Args["libFlags"], "prebuilts/vndk/libunwind.a") // Should declare the LLNDK library as a "required" external dependency - manifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule") + manifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule") requireNativeLibs := names(manifestRule.Args["requireNativeLibs"]) ensureListContains(t, requireNativeLibs, "libllndk.so") } @@ -4519,25 +4464,25 @@ func TestDependenciesInApexManifest(t *testing.T) { var apexManifestRule android.TestingBuildParams var provideNativeLibs, requireNativeLibs []string - apexManifestRule = ctx.ModuleForTests("myapex_nodep", "android_common_myapex_nodep_image").Rule("apexManifestRule") + apexManifestRule = ctx.ModuleForTests("myapex_nodep", "android_common_myapex_nodep").Rule("apexManifestRule") provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"]) requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"]) ensureListEmpty(t, provideNativeLibs) ensureListEmpty(t, requireNativeLibs) - apexManifestRule = ctx.ModuleForTests("myapex_dep", "android_common_myapex_dep_image").Rule("apexManifestRule") + apexManifestRule = ctx.ModuleForTests("myapex_dep", "android_common_myapex_dep").Rule("apexManifestRule") provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"]) requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"]) ensureListEmpty(t, provideNativeLibs) ensureListContains(t, requireNativeLibs, "libfoo.so") - apexManifestRule = ctx.ModuleForTests("myapex_provider", "android_common_myapex_provider_image").Rule("apexManifestRule") + apexManifestRule = ctx.ModuleForTests("myapex_provider", "android_common_myapex_provider").Rule("apexManifestRule") provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"]) requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"]) ensureListContains(t, provideNativeLibs, "libfoo.so") ensureListEmpty(t, requireNativeLibs) - apexManifestRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained_image").Rule("apexManifestRule") + apexManifestRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained").Rule("apexManifestRule") provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"]) requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"]) ensureListContains(t, provideNativeLibs, "libbar.so") @@ -4573,7 +4518,7 @@ func TestOverrideApexManifestDefaultVersion(t *testing.T) { "OVERRIDE_APEX_MANIFEST_DEFAULT_VERSION": "1234", })) - module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + module := ctx.ModuleForTests("myapex", "android_common_myapex") apexManifestRule := module.Rule("apexManifestRule") ensureContains(t, apexManifestRule.Args["default_version"], "1234") } @@ -4636,7 +4581,7 @@ func TestCompileMultilibProp(t *testing.T) { } `, testCase.compileMultiLibProp), ) - module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + module := ctx.ModuleForTests("myapex", "android_common_myapex") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] for _, containedLib := range testCase.containedLibs { @@ -4675,7 +4620,7 @@ func TestNonTestApex(t *testing.T) { } `) - module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + module := ctx.ModuleForTests("myapex", "android_common_myapex") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] @@ -4729,7 +4674,7 @@ func TestTestApex(t *testing.T) { } `) - module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + module := ctx.ModuleForTests("myapex", "android_common_myapex") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] @@ -4819,7 +4764,7 @@ func TestApexWithTarget(t *testing.T) { } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that main rule creates an output @@ -4903,7 +4848,7 @@ func TestApexWithArch(t *testing.T) { } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that apex variant is created for the direct dep @@ -4939,7 +4884,7 @@ func TestApexWithShBinary(t *testing.T) { } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] ensureContains(t, copyCmds, "image.apex/bin/script/myscript.sh") @@ -4973,7 +4918,7 @@ func TestApexInVariousPartition(t *testing.T) { } `) - apex := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + apex := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) expected := "out/soong/target/product/test_device/" + tc.partition + "/apex" actual := apex.installDir.RelativeToTop().String() if actual != expected { @@ -4997,7 +4942,7 @@ func TestFileContexts_FindInDefaultLocationIfNotSet(t *testing.T) { private_key: "testkey.pem", } `) - module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + module := ctx.ModuleForTests("myapex", "android_common_myapex") rule := module.Output("file_contexts") ensureContains(t, rule.RuleParams.Command, "cat system/sepolicy/apex/myapex-file_contexts") } @@ -5055,7 +5000,7 @@ func TestFileContexts_ProductSpecificApexes(t *testing.T) { `, withFiles(map[string][]byte{ "product_specific_file_contexts": nil, })) - module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + module := ctx.ModuleForTests("myapex", "android_common_myapex") rule := module.Output("file_contexts") ensureContains(t, rule.RuleParams.Command, "cat product_specific_file_contexts") } @@ -5083,7 +5028,7 @@ func TestFileContexts_SetViaFileGroup(t *testing.T) { `, withFiles(map[string][]byte{ "product_specific_file_contexts": nil, })) - module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + module := ctx.ModuleForTests("myapex", "android_common_myapex") rule := module.Output("file_contexts") ensureContains(t, rule.RuleParams.Command, "cat product_specific_file_contexts") } @@ -6141,7 +6086,7 @@ func TestApexWithTests(t *testing.T) { } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that test dep (and their transitive dependencies) are copied into apex. @@ -6158,7 +6103,7 @@ func TestApexWithTests(t *testing.T) { ensureContains(t, copyCmds, "image.apex/bin/test/mytest3") // Ensure the module is correctly translated. - bundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + bundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) data := android.AndroidMkDataForTest(t, ctx, bundle) name := bundle.BaseModuleName() prefix := "TARGET_" @@ -6241,7 +6186,7 @@ func TestApexWithJavaImport(t *testing.T) { } `) - module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + module := ctx.ModuleForTests("myapex", "android_common_myapex") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] ensureContains(t, copyCmds, "image.apex/javalib/myjavaimport.jar") @@ -6305,7 +6250,7 @@ func TestApexWithApps(t *testing.T) { } `) - module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + module := ctx.ModuleForTests("myapex", "android_common_myapex") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] @@ -6411,7 +6356,7 @@ func TestApexWithAppImports(t *testing.T) { } `) - module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + module := ctx.ModuleForTests("myapex", "android_common_myapex") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] @@ -6456,7 +6401,7 @@ func TestApexWithAppImportsPrefer(t *testing.T) { "AppFooPrebuilt.apk": nil, })) - ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{ "app/AppFoo@TEST.BUILD_ID/AppFooPrebuilt.apk", }) } @@ -6486,7 +6431,7 @@ func TestApexWithTestHelperApp(t *testing.T) { `) - module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + module := ctx.ModuleForTests("myapex", "android_common_myapex") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] @@ -6809,14 +6754,14 @@ func TestApexAvailable_ApexAvailableNameWithVersionCode(t *testing.T) { } `) - fooManifestRule := result.ModuleForTests("foo", "android_common_foo_image").Rule("apexManifestRule") + fooManifestRule := result.ModuleForTests("foo", "android_common_foo").Rule("apexManifestRule") fooExpectedDefaultVersion := android.DefaultUpdatableModuleVersion fooActualDefaultVersion := fooManifestRule.Args["default_version"] if fooActualDefaultVersion != fooExpectedDefaultVersion { t.Errorf("expected to find defaultVersion %q; got %q", fooExpectedDefaultVersion, fooActualDefaultVersion) } - barManifestRule := result.ModuleForTests("bar", "android_common_bar_image").Rule("apexManifestRule") + barManifestRule := result.ModuleForTests("bar", "android_common_bar").Rule("apexManifestRule") defaultVersionInt, _ := strconv.Atoi(android.DefaultUpdatableModuleVersion) barExpectedDefaultVersion := fmt.Sprint(defaultVersionInt + 3) barActualDefaultVersion := barManifestRule.Args["default_version"] @@ -6824,7 +6769,7 @@ func TestApexAvailable_ApexAvailableNameWithVersionCode(t *testing.T) { t.Errorf("expected to find defaultVersion %q; got %q", barExpectedDefaultVersion, barActualDefaultVersion) } - overrideBarManifestRule := result.ModuleForTests("bar", "android_common_myoverrideapex_bar_image").Rule("apexManifestRule") + overrideBarManifestRule := result.ModuleForTests("bar", "android_common_myoverrideapex_bar").Rule("apexManifestRule") overrideBarActualDefaultVersion := overrideBarManifestRule.Args["default_version"] if overrideBarActualDefaultVersion != barExpectedDefaultVersion { t.Errorf("expected to find defaultVersion %q; got %q", barExpectedDefaultVersion, barActualDefaultVersion) @@ -7184,8 +7129,8 @@ func TestOverrideApex(t *testing.T) { } `, withManifestPackageNameOverrides([]string{"myapex:com.android.myapex"})) - originalVariant := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(android.OverridableModule) - overriddenVariant := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex_image").Module().(android.OverridableModule) + originalVariant := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(android.OverridableModule) + overriddenVariant := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex").Module().(android.OverridableModule) if originalVariant.GetOverriddenBy() != "" { t.Errorf("GetOverriddenBy should be empty, but was %q", originalVariant.GetOverriddenBy()) } @@ -7193,7 +7138,7 @@ func TestOverrideApex(t *testing.T) { t.Errorf("GetOverriddenBy should be \"override_myapex\", but was %q", overriddenVariant.GetOverriddenBy()) } - module := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex_image") + module := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] @@ -7283,7 +7228,7 @@ func TestMinSdkVersionOverride(t *testing.T) { `, withApexGlobalMinSdkVersionOverride(&minSdkOverride31)) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that direct non-stubs dep is always included @@ -7342,7 +7287,7 @@ func TestMinSdkVersionOverrideToLowerVersionNoOp(t *testing.T) { `, withApexGlobalMinSdkVersionOverride(&minSdkOverride29)) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that direct non-stubs dep is always included @@ -7380,7 +7325,7 @@ func TestLegacyAndroid10Support(t *testing.T) { } `, withUnbundledBuild) - module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + module := ctx.ModuleForTests("myapex", "android_common_myapex") args := module.Rule("apexRule").Args ensureContains(t, args["opt_flags"], "--manifest_json "+module.Output("apex_manifest.json").Output.String()) ensureNotContains(t, args["opt_flags"], "--no_hashtree") @@ -7444,7 +7389,7 @@ func TestJavaSDKLibrary(t *testing.T) { `, withFiles(filesForSdkLibrary)) // java_sdk_library installs both impl jar and permission XML - ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{ "javalib/foo.jar", "etc/permissions/foo.xml", }) @@ -7493,7 +7438,7 @@ func TestJavaSDKLibrary_WithinApex(t *testing.T) { `, withFiles(filesForSdkLibrary)) // java_sdk_library installs both impl jar and permission XML - ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{ "javalib/bar.jar", "javalib/foo.jar", "etc/permissions/foo.xml", @@ -7545,7 +7490,7 @@ func TestJavaSDKLibrary_CrossBoundary(t *testing.T) { `, withFiles(filesForSdkLibrary)) // java_sdk_library installs both impl jar and permission XML - ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{ "javalib/foo.jar", "etc/permissions/foo.xml", }) @@ -7634,7 +7579,7 @@ func TestJavaSDKLibrary_ImportPreferred(t *testing.T) { ) // java_sdk_library installs both impl jar and permission XML - ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{ "javalib/bar.jar", "javalib/foo.jar", "etc/permissions/foo.xml", @@ -7714,7 +7659,7 @@ func TestCompatConfig(t *testing.T) { } `) ctx := result.TestContext - ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{ "etc/compatconfig/myjar-platform-compat-config.xml", "javalib/myjar.jar", }) @@ -7809,7 +7754,7 @@ func TestCarryRequiredModuleNames(t *testing.T) { } `) - apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) data := android.AndroidMkDataForTest(t, ctx, apexBundle) name := apexBundle.BaseModuleName() prefix := "TARGET_" @@ -7948,13 +7893,13 @@ func TestSymlinksFromApexToSystem(t *testing.T) { // For unbundled build, symlink shouldn't exist regardless of whether an APEX // is updatable or not ctx := testApex(t, bp, withUnbundledBuild) - files := getFiles(t, ctx, "myapex", "android_common_myapex_image") + files := getFiles(t, ctx, "myapex", "android_common_myapex") ensureRealfileExists(t, files, "javalib/myjar.jar") ensureRealfileExists(t, files, "lib64/mylib.so") ensureRealfileExists(t, files, "lib64/myotherlib.so") ensureRealfileExists(t, files, "lib64/myotherlib_ext.so") - files = getFiles(t, ctx, "myapex.updatable", "android_common_myapex.updatable_image") + files = getFiles(t, ctx, "myapex.updatable", "android_common_myapex.updatable") ensureRealfileExists(t, files, "javalib/myjar.jar") ensureRealfileExists(t, files, "lib64/mylib.so") ensureRealfileExists(t, files, "lib64/myotherlib.so") @@ -7962,13 +7907,13 @@ func TestSymlinksFromApexToSystem(t *testing.T) { // For bundled build, symlink to the system for the non-updatable APEXes only ctx = testApex(t, bp) - files = getFiles(t, ctx, "myapex", "android_common_myapex_image") + files = getFiles(t, ctx, "myapex", "android_common_myapex") ensureRealfileExists(t, files, "javalib/myjar.jar") ensureRealfileExists(t, files, "lib64/mylib.so") ensureSymlinkExists(t, files, "lib64/myotherlib.so", "/system/lib64/myotherlib.so") // this is symlink ensureSymlinkExists(t, files, "lib64/myotherlib_ext.so", "/system_ext/lib64/myotherlib_ext.so") // this is symlink - files = getFiles(t, ctx, "myapex.updatable", "android_common_myapex.updatable_image") + files = getFiles(t, ctx, "myapex.updatable", "android_common_myapex.updatable") ensureRealfileExists(t, files, "javalib/myjar.jar") ensureRealfileExists(t, files, "lib64/mylib.so") ensureRealfileExists(t, files, "lib64/myotherlib.so") // this is a real file @@ -8014,7 +7959,7 @@ func TestSymlinksFromApexToSystemRequiredModuleNames(t *testing.T) { } `) - apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) data := android.AndroidMkDataForTest(t, ctx, apexBundle) var builder strings.Builder data.Custom(&builder, apexBundle.BaseModuleName(), "TARGET_", "", data) @@ -8032,7 +7977,8 @@ func TestApexWithJniLibs(t *testing.T) { apex { name: "myapex", key: "myapex.key", - jni_libs: ["mylib", "libfoo.rust"], + binaries: ["mybin"], + jni_libs: ["mylib", "mylib3", "libfoo.rust"], updatable: false, } @@ -8059,6 +8005,24 @@ func TestApexWithJniLibs(t *testing.T) { apex_available: [ "myapex" ], } + // Used as both a JNI library and a regular shared library. + cc_library { + name: "mylib3", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + apex_available: [ "myapex" ], + } + + cc_binary { + name: "mybin", + srcs: ["mybin.cpp"], + shared_libs: ["mylib3"], + system_shared_libs: [], + stl: "none", + apex_available: [ "myapex" ], + } + rust_ffi_shared { name: "libfoo.rust", crate_name: "foo", @@ -8080,12 +8044,14 @@ func TestApexWithJniLibs(t *testing.T) { `) - rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule") + rule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule") // Notice mylib2.so (transitive dep) is not added as a jni_lib - ensureEquals(t, rule.Args["opt"], "-a jniLibs libfoo.rust.so mylib.so") - ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + ensureEquals(t, rule.Args["opt"], "-a jniLibs libfoo.rust.so mylib.so mylib3.so") + ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{ + "bin/mybin", "lib64/mylib.so", "lib64/mylib2.so", + "lib64/mylib3.so", "lib64/libfoo.rust.so", "lib64/libc++.so", // auto-added to libfoo.rust by Soong "lib64/liblog.so", // auto-added to libfoo.rust by Soong @@ -8143,7 +8109,7 @@ func TestAppBundle(t *testing.T) { } `, withManifestPackageNameOverrides([]string{"AppFoo:com.android.foo"})) - bundleConfigRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("bundle_config.json") + bundleConfigRule := ctx.ModuleForTests("myapex", "android_common_myapex").Output("bundle_config.json") content := bundleConfigRule.Args["content"] ensureContains(t, content, `"compression":{"uncompressed_glob":["apex_payload.img","apex_manifest.*"]}`) @@ -8169,7 +8135,7 @@ func TestAppSetBundle(t *testing.T) { name: "AppSet", set: "AppSet.apks", }`) - mod := ctx.ModuleForTests("myapex", "android_common_myapex_image") + mod := ctx.ModuleForTests("myapex", "android_common_myapex") bundleConfigRule := mod.Output("bundle_config.json") content := bundleConfigRule.Args["content"] ensureContains(t, content, `"compression":{"uncompressed_glob":["apex_payload.img","apex_manifest.*"]}`) @@ -9207,12 +9173,12 @@ func TestAllowedFiles(t *testing.T) { `), })) - rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("diffApexContentRule") + rule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("diffApexContentRule") if expected, actual := "allowed.txt", rule.Args["allowed_files_file"]; expected != actual { t.Errorf("allowed_files_file: expected %q but got %q", expected, actual) } - rule2 := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex_image").Rule("diffApexContentRule") + rule2 := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex").Rule("diffApexContentRule") if expected, actual := "sub/allowed.txt", rule2.Args["allowed_files_file"]; expected != actual { t.Errorf("allowed_files_file: expected %q but got %q", expected, actual) } @@ -9273,14 +9239,14 @@ func TestCompressedApex(t *testing.T) { }), ) - compressRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("compressRule") + compressRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("compressRule") ensureContains(t, compressRule.Output.String(), "myapex.capex.unsigned") - signApkRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Description("sign compressedApex") + signApkRule := ctx.ModuleForTests("myapex", "android_common_myapex").Description("sign compressedApex") ensureEquals(t, signApkRule.Input.String(), compressRule.Output.String()) // Make sure output of bundle is .capex - ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + ab := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) ensureContains(t, ab.outputFile.String(), "myapex.capex") // Verify android.mk rules @@ -9332,7 +9298,7 @@ func TestPreferredPrebuiltSharedLibDep(t *testing.T) { } `) - ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + ab := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) data := android.AndroidMkDataForTest(t, ctx, ab) var builder strings.Builder data.Custom(&builder, ab.BaseModuleName(), "TARGET_", "", data) @@ -9389,7 +9355,7 @@ func TestExcludeDependency(t *testing.T) { ensureNotContains(t, ldFlags, "mylib2/android_arm64_armv8-a_shared_apex10000/mylib2.so") // It shouldn't appear in the copy cmd as well. - copyCmds := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule").Args["copy_commands"] + copyCmds := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule").Args["copy_commands"] ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so") } @@ -9554,28 +9520,6 @@ func TestPrebuiltStubLibDep(t *testing.T) { } } -func TestHostApexInHostOnlyBuild(t *testing.T) { - testApex(t, ` - apex { - name: "myapex", - host_supported: true, - key: "myapex.key", - updatable: false, - payload_type: "zip", - } - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } - `, - android.FixtureModifyConfig(func(config android.Config) { - // We may not have device targets in all builds, e.g. in - // prebuilts/build-tools/build-prebuilts.sh - config.Targets[android.Android] = []android.Target{} - })) -} - func TestApexJavaCoverage(t *testing.T) { bp := ` apex { @@ -9729,7 +9673,7 @@ func TestAndroidMk_DexpreoptBuiltInstalledForApex(t *testing.T) { dexpreopt.FixtureSetApexSystemServerJars("myapex:foo"), ) - apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) data := android.AndroidMkDataForTest(t, ctx, apexBundle) var builder strings.Builder data.Custom(&builder, apexBundle.BaseModuleName(), "TARGET_", "", data) @@ -9805,7 +9749,7 @@ func TestAndroidMk_RequiredModules(t *testing.T) { } `) - apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) data := android.AndroidMkDataForTest(t, ctx, apexBundle) var builder strings.Builder data.Custom(&builder, apexBundle.BaseModuleName(), "TARGET_", "", data) @@ -9828,7 +9772,7 @@ func TestAndroidMk_RequiredDeps(t *testing.T) { } `) - bundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + bundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) bundle.makeModulesToInstall = append(bundle.makeModulesToInstall, "foo") data := android.AndroidMkDataForTest(t, ctx, bundle) var builder strings.Builder @@ -9846,12 +9790,12 @@ func TestApexOutputFileProducer(t *testing.T) { { name: "test_using_output", ref: ":myapex", - expected_data: []string{"out/soong/.intermediates/myapex/android_common_myapex_image/myapex.capex:myapex.capex"}, + expected_data: []string{"out/soong/.intermediates/myapex/android_common_myapex/myapex.capex:myapex.capex"}, }, { name: "test_using_apex", ref: ":myapex{.apex}", - expected_data: []string{"out/soong/.intermediates/myapex/android_common_myapex_image/myapex.apex:myapex.apex"}, + expected_data: []string{"out/soong/.intermediates/myapex/android_common_myapex/myapex.apex:myapex.apex"}, }, } { t.Run(tc.name, func(t *testing.T) { @@ -10587,14 +10531,14 @@ func TestTrimmedApex(t *testing.T) { } ` ctx := testApex(t, bp) - module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + module := ctx.ModuleForTests("myapex", "android_common_myapex") apexRule := module.MaybeRule("apexRule") if apexRule.Rule == nil { t.Errorf("Expecting regular apex rule but a non regular apex rule found") } ctx = testApex(t, bp, android.FixtureModifyConfig(android.SetTrimmedApexEnabledForTests)) - trimmedApexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("TrimmedApexRule") + trimmedApexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("TrimmedApexRule") libs_to_trim := trimmedApexRule.Args["libs_to_trim"] android.AssertStringDoesContain(t, "missing lib to trim", libs_to_trim, "libfoo") android.AssertStringDoesContain(t, "missing lib to trim", libs_to_trim, "libbar") @@ -10614,7 +10558,7 @@ func TestCannedFsConfig(t *testing.T) { public_key: "testkey.avbpubkey", private_key: "testkey.pem", }`) - mod := ctx.ModuleForTests("myapex", "android_common_myapex_image") + mod := ctx.ModuleForTests("myapex", "android_common_myapex") generateFsRule := mod.Rule("generateFsConfig") cmd := generateFsRule.RuleParams.Command @@ -10635,7 +10579,7 @@ func TestCannedFsConfig_HasCustomConfig(t *testing.T) { public_key: "testkey.avbpubkey", private_key: "testkey.pem", }`) - mod := ctx.ModuleForTests("myapex", "android_common_myapex_image") + mod := ctx.ModuleForTests("myapex", "android_common_myapex") generateFsRule := mod.Rule("generateFsConfig") cmd := generateFsRule.RuleParams.Command diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go index f30f7f666..89ea004b3 100644 --- a/apex/bootclasspath_fragment_test.go +++ b/apex/bootclasspath_fragment_test.go @@ -302,14 +302,14 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { java.FixtureSetBootImageInstallDirOnDevice("art", "apex/com.android.art/javalib"), ).RunTest(t) - ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{ + ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{ "etc/boot-image.prof", "etc/classpaths/bootclasspath.pb", "javalib/bar.jar", "javalib/foo.jar", }) - java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{ + java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{ `art-bootclasspath-fragment`, `com.android.art.key`, }) @@ -332,7 +332,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { dexpreopt.FixtureDisableDexpreoptBootImages(true), ).RunTest(t) - ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{ + ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{ "etc/boot-image.prof", "etc/classpaths/bootclasspath.pb", "javalib/bar.jar", @@ -351,7 +351,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { dexpreopt.FixtureDisableGenerateProfile(true), ).RunTest(t) - files := getFiles(t, result.TestContext, "com.android.art", "android_common_com.android.art_image") + files := getFiles(t, result.TestContext, "com.android.art", "android_common_com.android.art") for _, file := range files { matched, _ := path.Match("etc/boot-image.prof", file.path) android.AssertBoolEquals(t, "\"etc/boot-image.prof\" should not be in the APEX", matched, false) @@ -380,7 +380,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { "javalib/foo.jar", }) - java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{ + java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{ `art-bootclasspath-fragment`, `com.android.art.key`, `prebuilt_com.android.art`, @@ -635,7 +635,7 @@ func TestBootclasspathFragmentContentsNoName(t *testing.T) { } `) - ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{ + ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex", []string{ // This does not include art, oat or vdex files as they are only included for the art boot // image. "etc/classpaths/bootclasspath.pb", @@ -643,12 +643,12 @@ func TestBootclasspathFragmentContentsNoName(t *testing.T) { "javalib/foo.jar", }) - java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex_image", []string{ + java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex", []string{ `myapex.key`, `mybootclasspathfragment`, }) - apex := result.ModuleForTests("myapex", "android_common_myapex_image") + apex := result.ModuleForTests("myapex", "android_common_myapex") apexRule := apex.Rule("apexRule") copyCommands := apexRule.Args["copy_commands"] @@ -665,7 +665,7 @@ func TestBootclasspathFragmentContentsNoName(t *testing.T) { } android.AssertPathRelativeToTopEquals(t, name+" dex", expectedDexJar, dexJar) - expectedCopyCommand := fmt.Sprintf("&& cp -f %s out/soong/.intermediates/myapex/android_common_myapex_image/image.apex/javalib/%s.jar", expectedDexJar, name) + expectedCopyCommand := fmt.Sprintf("&& cp -f %s out/soong/.intermediates/myapex/android_common_myapex/image.apex/javalib/%s.jar", expectedDexJar, name) android.AssertStringDoesContain(t, name+" apex copy command", copyCommands, expectedCopyCommand) } diff --git a/apex/bp2build_test.go b/apex/bp2build_test.go index b1b6a75e8..6bab67dbe 100644 --- a/apex/bp2build_test.go +++ b/apex/bp2build_test.go @@ -80,7 +80,7 @@ apex { }), ).RunTestWithBp(t, bp) - m := result.ModuleForTests("foo", "android_common_foo_image").Module() + m := result.ModuleForTests("foo", "android_common_foo").Module() ab, ok := m.(*apexBundle) if !ok { @@ -206,7 +206,7 @@ apex { }), ).RunTestWithBp(t, bp) - m := result.ModuleForTests("foo", "android_common_foo_image").Module() + m := result.ModuleForTests("foo", "android_common_foo").Module() ab, ok := m.(*apexBundle) if !ok { @@ -299,7 +299,7 @@ apex { }), ).RunTestWithBp(t, bp) - m := result.ModuleForTests("foo", "android_common_foo_image").Module() + m := result.ModuleForTests("foo", "android_common_foo").Module() ab, ok := m.(*apexBundle) if !ok { t.Fatalf("Expected module to be an apexBundle, was not") @@ -483,7 +483,7 @@ override_apex { }), ).RunTest(t) - m := result.ModuleForTests("foo", "android_common_override_foo_foo_image").Module() + m := result.ModuleForTests("foo", "android_common_override_foo_foo").Module() ab, ok := m.(*apexBundle) if !ok { t.Fatalf("Expected module to be an apexBundle, was not") diff --git a/apex/builder.go b/apex/builder.go index db66a72ce..1204dbb97 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -75,6 +75,8 @@ func init() { pctx.HostBinToolVariable("deapexer", "deapexer") pctx.HostBinToolVariable("debugfs_static", "debugfs_static") pctx.SourcePathVariable("genNdkUsedbyApexPath", "build/soong/scripts/gen_ndk_usedby_apex.sh") + pctx.HostBinToolVariable("conv_linker_config", "conv_linker_config") + pctx.HostBinToolVariable("assemble_vintf", "assemble_vintf") } var ( @@ -179,19 +181,6 @@ var ( }, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", "opt_flags", "manifest", "libs_to_trim") - zipApexRule = pctx.StaticRule("zipApexRule", blueprint.RuleParams{ - Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` + - `(. ${out}.copy_commands) && ` + - `APEXER_TOOL_PATH=${tool_path} ` + - `${apexer} --force --manifest ${manifest} ` + - `--payload_type zip ` + - `${image_dir} ${out} `, - CommandDeps: []string{"${apexer}", "${merge_zips}", "${soong_zip}", "${zipalign}", "${aapt2}"}, - Rspfile: "${out}.copy_commands", - RspfileContent: "${copy_commands}", - Description: "ZipAPEX ${image_dir} => ${out}", - }, "tool_path", "image_dir", "copy_commands", "manifest") - apexProtoConvertRule = pctx.AndroidStaticRule("apexProtoConvertRule", blueprint.RuleParams{ Command: `${aapt2} convert --output-format proto $in -o $out`, @@ -235,6 +224,18 @@ var ( CommandDeps: []string{"${apex_sepolicy_tests}", "${deapexer}", "${debugfs_static}"}, Description: "run apex_sepolicy_tests", }) + + apexLinkerconfigValidationRule = pctx.StaticRule("apexLinkerconfigValidationRule", blueprint.RuleParams{ + Command: `${conv_linker_config} validate --type apex ${image_dir} && touch ${out}`, + CommandDeps: []string{"${conv_linker_config}"}, + Description: "run apex_linkerconfig_validation", + }, "image_dir") + + apexVintfFragmentsValidationRule = pctx.StaticRule("apexVintfFragmentsValidationRule", blueprint.RuleParams{ + Command: `/bin/bash -c '(shopt -s nullglob; for f in ${image_dir}/etc/vintf/*.xml; do VINTF_IGNORE_TARGET_FCM_VERSION=true ${assemble_vintf} -i "$$f" > /dev/null; done)' && touch ${out}`, + CommandDeps: []string{"${assemble_vintf}"}, + Description: "run apex_vintf_validation", + }, "image_dir") ) // buildManifest creates buile rules to modify the input apex_manifest.json to add information @@ -369,21 +370,16 @@ func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) android.Output // even though VNDK APEX is supposed to be installed on /system. (See com.android.vndk.current.on_vendor) forceLabel = "u:object_r:vendor_apex_metadata_file:s0" } - switch a.properties.ApexType { - case imageApex: - // remove old file - rule.Command().Text("rm").FlagWithOutput("-f ", output) - // copy file_contexts - rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output) - // new line - rule.Command().Text("echo").Text(">>").Output(output) - if !useFileContextsAsIs { - // force-label /apex_manifest.pb and / - rule.Command().Text("echo").Text("/apex_manifest\\\\.pb").Text(forceLabel).Text(">>").Output(output) - rule.Command().Text("echo").Text("/").Text(forceLabel).Text(">>").Output(output) - } - default: - panic(fmt.Errorf("unsupported type %v", a.properties.ApexType)) + // remove old file + rule.Command().Text("rm").FlagWithOutput("-f ", output) + // copy file_contexts + rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output) + // new line + rule.Command().Text("echo").Text(">>").Output(output) + if !useFileContextsAsIs { + // force-label /apex_manifest.pb and / + rule.Command().Text("echo").Text("/apex_manifest\\\\.pb").Text(forceLabel).Text(">>").Output(output) + rule.Command().Text("echo").Text("/").Text(forceLabel).Text(">>").Output(output) } rule.Build("file_contexts."+a.Name(), "Generate file_contexts") @@ -464,8 +460,7 @@ func markManifestTestOnly(ctx android.ModuleContext, androidManifestFile android // buildApex creates build rules to build an APEX using apexer. func (a *apexBundle) buildApex(ctx android.ModuleContext) { - apexType := a.properties.ApexType - suffix := apexType.suffix() + suffix := imageApexSuffix apexName := a.BaseModuleName() //////////////////////////////////////////////////////////////////////////////////////////// @@ -604,263 +599,247 @@ func (a *apexBundle) buildApex(ctx android.ModuleContext) { outHostBinDir := ctx.Config().HostToolPath(ctx, "").String() prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin") - if apexType == imageApex { - - //////////////////////////////////////////////////////////////////////////////////// - // Step 2: create canned_fs_config which encodes filemode,uid,gid of each files - // in this APEX. The file will be used by apexer in later steps. - cannedFsConfig := a.buildCannedFsConfig(ctx) - implicitInputs = append(implicitInputs, cannedFsConfig) - - //////////////////////////////////////////////////////////////////////////////////// - // Step 3: Prepare option flags for apexer and invoke it to create an unsigned APEX. - // TODO(jiyong): use the RuleBuilder - optFlags := []string{} + //////////////////////////////////////////////////////////////////////////////////// + // Step 2: create canned_fs_config which encodes filemode,uid,gid of each files + // in this APEX. The file will be used by apexer in later steps. + cannedFsConfig := a.buildCannedFsConfig(ctx) + implicitInputs = append(implicitInputs, cannedFsConfig) - fileContexts := a.buildFileContexts(ctx) - implicitInputs = append(implicitInputs, fileContexts) + //////////////////////////////////////////////////////////////////////////////////// + // Step 3: Prepare option flags for apexer and invoke it to create an unsigned APEX. + // TODO(jiyong): use the RuleBuilder + optFlags := []string{} - implicitInputs = append(implicitInputs, a.privateKeyFile, a.publicKeyFile) - optFlags = append(optFlags, "--pubkey "+a.publicKeyFile.String()) + fileContexts := a.buildFileContexts(ctx) + implicitInputs = append(implicitInputs, fileContexts) - manifestPackageName := a.getOverrideManifestPackageName(ctx) - if manifestPackageName != "" { - optFlags = append(optFlags, "--override_apk_package_name "+manifestPackageName) - } + implicitInputs = append(implicitInputs, a.privateKeyFile, a.publicKeyFile) + optFlags = append(optFlags, "--pubkey "+a.publicKeyFile.String()) - if a.properties.AndroidManifest != nil { - androidManifestFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.AndroidManifest)) + manifestPackageName := a.getOverrideManifestPackageName(ctx) + if manifestPackageName != "" { + optFlags = append(optFlags, "--override_apk_package_name "+manifestPackageName) + } - if a.testApex { - androidManifestFile = markManifestTestOnly(ctx, androidManifestFile) - } + if a.properties.AndroidManifest != nil { + androidManifestFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.AndroidManifest)) - implicitInputs = append(implicitInputs, androidManifestFile) - optFlags = append(optFlags, "--android_manifest "+androidManifestFile.String()) - } else if a.testApex { - optFlags = append(optFlags, "--test_only") + if a.testApex { + androidManifestFile = markManifestTestOnly(ctx, androidManifestFile) } - // Determine target/min sdk version from the context - // TODO(jiyong): make this as a function - moduleMinSdkVersion := a.minSdkVersion(ctx) - minSdkVersion := moduleMinSdkVersion.String() + implicitInputs = append(implicitInputs, androidManifestFile) + optFlags = append(optFlags, "--android_manifest "+androidManifestFile.String()) + } else if a.testApex { + optFlags = append(optFlags, "--test_only") + } - // bundletool doesn't understand what "current" is. We need to transform it to - // codename - if moduleMinSdkVersion.IsCurrent() || moduleMinSdkVersion.IsNone() { - minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String() + // Determine target/min sdk version from the context + // TODO(jiyong): make this as a function + moduleMinSdkVersion := a.minSdkVersion(ctx) + minSdkVersion := moduleMinSdkVersion.String() - if java.UseApiFingerprint(ctx) { - minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String()) - implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx)) - } - } - // apex module doesn't have a concept of target_sdk_version, hence for the time - // being targetSdkVersion == default targetSdkVersion of the branch. - targetSdkVersion := strconv.Itoa(ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt()) + // bundletool doesn't understand what "current" is. We need to transform it to + // codename + if moduleMinSdkVersion.IsCurrent() || moduleMinSdkVersion.IsNone() { + minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String() if java.UseApiFingerprint(ctx) { - targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String()) + minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String()) implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx)) } - optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion) - optFlags = append(optFlags, "--min_sdk_version "+minSdkVersion) - - if a.overridableProperties.Logging_parent != "" { - optFlags = append(optFlags, "--logging_parent ", a.overridableProperties.Logging_parent) - } - - // Create a NOTICE file, and embed it as an asset file in the APEX. - htmlGzNotice := android.PathForModuleOut(ctx, "NOTICE.html.gz") - android.BuildNoticeHtmlOutputFromLicenseMetadata( - ctx, htmlGzNotice, "", "", - []string{ - android.PathForModuleInstall(ctx).String() + "/", - android.PathForModuleInPartitionInstall(ctx, "apex").String() + "/", - }) - noticeAssetPath := android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz") - builder := android.NewRuleBuilder(pctx, ctx) - builder.Command().Text("cp"). - Input(htmlGzNotice). - Output(noticeAssetPath) - builder.Build("notice_dir", "Building notice dir") - implicitInputs = append(implicitInputs, noticeAssetPath) - optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeAssetPath.String())) - - // Apexes which are supposed to be installed in builtin dirs(/system, etc) - // don't need hashtree for activation. Therefore, by removing hashtree from - // apex bundle (filesystem image in it, to be specific), we can save storage. - needHashTree := moduleMinSdkVersion.LessThanOrEqualTo(android.SdkVersion_Android10) || - a.shouldGenerateHashtree() - if ctx.Config().ApexCompressionEnabled() && a.isCompressable() { - needHashTree = true - } - if !needHashTree { - optFlags = append(optFlags, "--no_hashtree") - } + } + // apex module doesn't have a concept of target_sdk_version, hence for the time + // being targetSdkVersion == default targetSdkVersion of the branch. + targetSdkVersion := strconv.Itoa(ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt()) - if a.testOnlyShouldSkipPayloadSign() { - optFlags = append(optFlags, "--unsigned_payload") - } + if java.UseApiFingerprint(ctx) { + targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String()) + implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx)) + } + optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion) + optFlags = append(optFlags, "--min_sdk_version "+minSdkVersion) - if moduleMinSdkVersion == android.SdkVersion_Android10 { - implicitInputs = append(implicitInputs, a.manifestJsonOut) - optFlags = append(optFlags, "--manifest_json "+a.manifestJsonOut.String()) - } + if a.overridableProperties.Logging_parent != "" { + optFlags = append(optFlags, "--logging_parent ", a.overridableProperties.Logging_parent) + } - optFlags = append(optFlags, "--payload_fs_type "+a.payloadFsType.string()) - - if a.dynamic_common_lib_apex() { - ctx.Build(pctx, android.BuildParams{ - Rule: DCLAApexRule, - Implicits: implicitInputs, - Output: unsignedOutputFile, - Description: "apex (" + apexType.name() + ")", - Args: map[string]string{ - "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir, - "image_dir": imageDir.String(), - "copy_commands": strings.Join(copyCommands, " && "), - "manifest": a.manifestPbOut.String(), - "file_contexts": fileContexts.String(), - "canned_fs_config": cannedFsConfig.String(), - "key": a.privateKeyFile.String(), - "opt_flags": strings.Join(optFlags, " "), - }, - }) - } else if ctx.Config().ApexTrimEnabled() && len(a.libs_to_trim(ctx)) > 0 { - ctx.Build(pctx, android.BuildParams{ - Rule: TrimmedApexRule, - Implicits: implicitInputs, - Output: unsignedOutputFile, - Description: "apex (" + apexType.name() + ")", - Args: map[string]string{ - "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir, - "image_dir": imageDir.String(), - "copy_commands": strings.Join(copyCommands, " && "), - "manifest": a.manifestPbOut.String(), - "file_contexts": fileContexts.String(), - "canned_fs_config": cannedFsConfig.String(), - "key": a.privateKeyFile.String(), - "opt_flags": strings.Join(optFlags, " "), - "libs_to_trim": strings.Join(a.libs_to_trim(ctx), ","), - }, - }) - } else { - ctx.Build(pctx, android.BuildParams{ - Rule: apexRule, - Implicits: implicitInputs, - Output: unsignedOutputFile, - Description: "apex (" + apexType.name() + ")", - Args: map[string]string{ - "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir, - "image_dir": imageDir.String(), - "copy_commands": strings.Join(copyCommands, " && "), - "manifest": a.manifestPbOut.String(), - "file_contexts": fileContexts.String(), - "canned_fs_config": cannedFsConfig.String(), - "key": a.privateKeyFile.String(), - "opt_flags": strings.Join(optFlags, " "), - }, - }) - } + // Create a NOTICE file, and embed it as an asset file in the APEX. + htmlGzNotice := android.PathForModuleOut(ctx, "NOTICE.html.gz") + android.BuildNoticeHtmlOutputFromLicenseMetadata( + ctx, htmlGzNotice, "", "", + []string{ + android.PathForModuleInstall(ctx).String() + "/", + android.PathForModuleInPartitionInstall(ctx, "apex").String() + "/", + }) + noticeAssetPath := android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz") + builder := android.NewRuleBuilder(pctx, ctx) + builder.Command().Text("cp"). + Input(htmlGzNotice). + Output(noticeAssetPath) + builder.Build("notice_dir", "Building notice dir") + implicitInputs = append(implicitInputs, noticeAssetPath) + optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeAssetPath.String())) + + // Apexes which are supposed to be installed in builtin dirs(/system, etc) + // don't need hashtree for activation. Therefore, by removing hashtree from + // apex bundle (filesystem image in it, to be specific), we can save storage. + needHashTree := moduleMinSdkVersion.LessThanOrEqualTo(android.SdkVersion_Android10) || + a.shouldGenerateHashtree() + if ctx.Config().ApexCompressionEnabled() && a.isCompressable() { + needHashTree = true + } + if !needHashTree { + optFlags = append(optFlags, "--no_hashtree") + } - // TODO(jiyong): make the two rules below as separate functions - apexProtoFile := android.PathForModuleOut(ctx, a.Name()+".pb"+suffix) - bundleModuleFile := android.PathForModuleOut(ctx, a.Name()+suffix+"-base.zip") - a.bundleModuleFile = bundleModuleFile + if a.testOnlyShouldSkipPayloadSign() { + optFlags = append(optFlags, "--unsigned_payload") + } - ctx.Build(pctx, android.BuildParams{ - Rule: apexProtoConvertRule, - Input: unsignedOutputFile, - Output: apexProtoFile, - Description: "apex proto convert", - }) + if moduleMinSdkVersion == android.SdkVersion_Android10 { + implicitInputs = append(implicitInputs, a.manifestJsonOut) + optFlags = append(optFlags, "--manifest_json "+a.manifestJsonOut.String()) + } - implicitInputs = append(implicitInputs, unsignedOutputFile) + optFlags = append(optFlags, "--payload_fs_type "+a.payloadFsType.string()) - // Run coverage analysis - apisUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.txt") + if a.dynamic_common_lib_apex() { ctx.Build(pctx, android.BuildParams{ - Rule: generateAPIsUsedbyApexRule, + Rule: DCLAApexRule, Implicits: implicitInputs, - Description: "coverage", - Output: apisUsedbyOutputFile, + Output: unsignedOutputFile, + Description: "apex", Args: map[string]string{ - "image_dir": imageDir.String(), - "readelf": "${config.ClangBin}/llvm-readelf", + "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir, + "image_dir": imageDir.String(), + "copy_commands": strings.Join(copyCommands, " && "), + "manifest": a.manifestPbOut.String(), + "file_contexts": fileContexts.String(), + "canned_fs_config": cannedFsConfig.String(), + "key": a.privateKeyFile.String(), + "opt_flags": strings.Join(optFlags, " "), }, }) - a.nativeApisUsedByModuleFile = apisUsedbyOutputFile - - var nativeLibNames []string - for _, f := range a.filesInfo { - if f.class == nativeSharedLib { - nativeLibNames = append(nativeLibNames, f.stem()) - } - } - apisBackedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_backing.txt") - rule := android.NewRuleBuilder(pctx, ctx) - rule.Command(). - Tool(android.PathForSource(ctx, "build/soong/scripts/gen_ndk_backedby_apex.sh")). - Output(apisBackedbyOutputFile). - Flags(nativeLibNames) - rule.Build("ndk_backedby_list", "Generate API libraries backed by Apex") - a.nativeApisBackedByModuleFile = apisBackedbyOutputFile - - var javaLibOrApkPath []android.Path - for _, f := range a.filesInfo { - if f.class == javaSharedLib || f.class == app { - javaLibOrApkPath = append(javaLibOrApkPath, f.builtFile) - } - } - javaApiUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.xml") - javaUsedByRule := android.NewRuleBuilder(pctx, ctx) - javaUsedByRule.Command(). - Tool(android.PathForSource(ctx, "build/soong/scripts/gen_java_usedby_apex.sh")). - BuiltTool("dexdeps"). - Output(javaApiUsedbyOutputFile). - Inputs(javaLibOrApkPath) - javaUsedByRule.Build("java_usedby_list", "Generate Java APIs used by Apex") - a.javaApisUsedByModuleFile = javaApiUsedbyOutputFile - - bundleConfig := a.buildBundleConfig(ctx) - - var abis []string - for _, target := range ctx.MultiTargets() { - if len(target.Arch.Abi) > 0 { - abis = append(abis, target.Arch.Abi[0]) - } - } - - abis = android.FirstUniqueStrings(abis) - + } else if ctx.Config().ApexTrimEnabled() && len(a.libs_to_trim(ctx)) > 0 { ctx.Build(pctx, android.BuildParams{ - Rule: apexBundleRule, - Input: apexProtoFile, - Implicit: bundleConfig, - Output: a.bundleModuleFile, - Description: "apex bundle module", + Rule: TrimmedApexRule, + Implicits: implicitInputs, + Output: unsignedOutputFile, + Description: "apex", Args: map[string]string{ - "abi": strings.Join(abis, "."), - "config": bundleConfig.String(), + "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir, + "image_dir": imageDir.String(), + "copy_commands": strings.Join(copyCommands, " && "), + "manifest": a.manifestPbOut.String(), + "file_contexts": fileContexts.String(), + "canned_fs_config": cannedFsConfig.String(), + "key": a.privateKeyFile.String(), + "opt_flags": strings.Join(optFlags, " "), + "libs_to_trim": strings.Join(a.libs_to_trim(ctx), ","), }, }) - } else { // zipApex + } else { ctx.Build(pctx, android.BuildParams{ - Rule: zipApexRule, + Rule: apexRule, Implicits: implicitInputs, Output: unsignedOutputFile, - Description: "apex (" + apexType.name() + ")", + Description: "apex", Args: map[string]string{ - "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir, - "image_dir": imageDir.String(), - "copy_commands": strings.Join(copyCommands, " && "), - "manifest": a.manifestPbOut.String(), + "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir, + "image_dir": imageDir.String(), + "copy_commands": strings.Join(copyCommands, " && "), + "manifest": a.manifestPbOut.String(), + "file_contexts": fileContexts.String(), + "canned_fs_config": cannedFsConfig.String(), + "key": a.privateKeyFile.String(), + "opt_flags": strings.Join(optFlags, " "), }, }) } + // TODO(jiyong): make the two rules below as separate functions + apexProtoFile := android.PathForModuleOut(ctx, a.Name()+".pb"+suffix) + bundleModuleFile := android.PathForModuleOut(ctx, a.Name()+suffix+"-base.zip") + a.bundleModuleFile = bundleModuleFile + + ctx.Build(pctx, android.BuildParams{ + Rule: apexProtoConvertRule, + Input: unsignedOutputFile, + Output: apexProtoFile, + Description: "apex proto convert", + }) + + implicitInputs = append(implicitInputs, unsignedOutputFile) + + // Run coverage analysis + apisUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.txt") + ctx.Build(pctx, android.BuildParams{ + Rule: generateAPIsUsedbyApexRule, + Implicits: implicitInputs, + Description: "coverage", + Output: apisUsedbyOutputFile, + Args: map[string]string{ + "image_dir": imageDir.String(), + "readelf": "${config.ClangBin}/llvm-readelf", + }, + }) + a.nativeApisUsedByModuleFile = apisUsedbyOutputFile + + var nativeLibNames []string + for _, f := range a.filesInfo { + if f.class == nativeSharedLib { + nativeLibNames = append(nativeLibNames, f.stem()) + } + } + apisBackedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_backing.txt") + rb := android.NewRuleBuilder(pctx, ctx) + rb.Command(). + Tool(android.PathForSource(ctx, "build/soong/scripts/gen_ndk_backedby_apex.sh")). + Output(apisBackedbyOutputFile). + Flags(nativeLibNames) + rb.Build("ndk_backedby_list", "Generate API libraries backed by Apex") + a.nativeApisBackedByModuleFile = apisBackedbyOutputFile + + var javaLibOrApkPath []android.Path + for _, f := range a.filesInfo { + if f.class == javaSharedLib || f.class == app { + javaLibOrApkPath = append(javaLibOrApkPath, f.builtFile) + } + } + javaApiUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.xml") + javaUsedByRule := android.NewRuleBuilder(pctx, ctx) + javaUsedByRule.Command(). + Tool(android.PathForSource(ctx, "build/soong/scripts/gen_java_usedby_apex.sh")). + BuiltTool("dexdeps"). + Output(javaApiUsedbyOutputFile). + Inputs(javaLibOrApkPath) + javaUsedByRule.Build("java_usedby_list", "Generate Java APIs used by Apex") + a.javaApisUsedByModuleFile = javaApiUsedbyOutputFile + + bundleConfig := a.buildBundleConfig(ctx) + + var abis []string + for _, target := range ctx.MultiTargets() { + if len(target.Arch.Abi) > 0 { + abis = append(abis, target.Arch.Abi[0]) + } + } + + abis = android.FirstUniqueStrings(abis) + + ctx.Build(pctx, android.BuildParams{ + Rule: apexBundleRule, + Input: apexProtoFile, + Implicit: bundleConfig, + Output: a.bundleModuleFile, + Description: "apex bundle module", + Args: map[string]string{ + "abi": strings.Join(abis, "."), + "config": bundleConfig.String(), + }, + }) + //////////////////////////////////////////////////////////////////////////////////// // Step 4: Sign the APEX using signapk signedOutputFile := android.PathForModuleOut(ctx, a.Name()+suffix) @@ -878,6 +857,10 @@ func (a *apexBundle) buildApex(ctx android.ModuleContext) { args["outCommaList"] = signedOutputFile.String() } var validations android.Paths + validations = append(validations, runApexLinkerconfigValidation(ctx, unsignedOutputFile.OutputPath, imageDir.OutputPath)) + if !a.testApex && a.SocSpecific() { + validations = append(validations, runApexVintfFragmentsValidation(ctx, unsignedOutputFile.OutputPath, imageDir.OutputPath)) + } // TODO(b/279688635) deapexer supports [ext4] if suffix == imageApexSuffix && ext4 == a.payloadFsType { validations = append(validations, runApexSepolicyTests(ctx, unsignedOutputFile.OutputPath)) @@ -987,21 +970,12 @@ func (a *apexBundle) getOverrideManifestPackageName(ctx android.ModuleContext) s } func (a *apexBundle) buildApexDependencyInfo(ctx android.ModuleContext) { - if !a.primaryApexType { - return - } - if a.properties.IsCoverageVariant { // Otherwise, we will have duplicated rules for coverage and // non-coverage variants of the same APEX return } - if ctx.Host() { - // No need to generate dependency info for host variant - return - } - depInfos := android.DepNameToDepInfoMap{} a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { if from.Name() == to.Name() { @@ -1141,6 +1115,32 @@ func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext) android.Outp return cannedFsConfig.OutputPath } +func runApexLinkerconfigValidation(ctx android.ModuleContext, apexFile android.OutputPath, imageDir android.OutputPath) android.Path { + timestamp := android.PathForModuleOut(ctx, "apex_linkerconfig_validation.timestamp") + ctx.Build(pctx, android.BuildParams{ + Rule: apexLinkerconfigValidationRule, + Input: apexFile, + Output: timestamp, + Args: map[string]string{ + "image_dir": imageDir.String(), + }, + }) + return timestamp +} + +func runApexVintfFragmentsValidation(ctx android.ModuleContext, apexFile android.OutputPath, imageDir android.OutputPath) android.Path { + timestamp := android.PathForModuleOut(ctx, "apex_vintf_fragments_validation.timestamp") + ctx.Build(pctx, android.BuildParams{ + Rule: apexVintfFragmentsValidationRule, + Input: apexFile, + Output: timestamp, + Args: map[string]string{ + "image_dir": imageDir.String(), + }, + }) + return timestamp +} + // Runs apex_sepolicy_tests // // $ deapexer list -Z {apex_file} > {file_contexts} diff --git a/apex/key.go b/apex/key.go index 3010d76be..fc1456b96 100644 --- a/apex/key.go +++ b/apex/key.go @@ -60,7 +60,7 @@ type apexKeyProperties struct { func ApexKeyFactory() android.Module { module := &apexKey{} module.AddProperties(&module.properties) - android.InitAndroidArchModule(module, android.HostAndDeviceDefault, android.MultilibCommon) + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) android.InitBazelModule(module) return module } @@ -208,11 +208,11 @@ type bazelApexKeyAttributes struct { } // ConvertWithBp2build performs conversion apexKey for bp2build -func (m *apexKey) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (m *apexKey) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { apexKeyBp2BuildInternal(ctx, m) } -func apexKeyBp2BuildInternal(ctx android.TopDownMutatorContext, module *apexKey) { +func apexKeyBp2BuildInternal(ctx android.Bp2buildMutatorContext, module *apexKey) { privateKeyLabelAttribute, privateKeyNameAttribute := android.BazelStringOrLabelFromProp(ctx, module.properties.Private_key) diff --git a/apex/prebuilt.go b/apex/prebuilt.go index 3509e6cbe..1a90c3a73 100644 --- a/apex/prebuilt.go +++ b/apex/prebuilt.go @@ -235,6 +235,7 @@ func (p *prebuiltCommon) AndroidMkEntries() []android.AndroidMkEntries { entries.SetString("LOCAL_MODULE_STEM", p.installFilename) entries.SetPath("LOCAL_SOONG_INSTALLED_MODULE", p.installedFile) entries.SetString("LOCAL_SOONG_INSTALL_PAIRS", p.outputApex.String()+":"+p.installedFile.String()) + entries.AddStrings("LOCAL_SOONG_INSTALL_SYMLINKS", p.compatSymlinks.Strings()...) entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !p.installable()) entries.AddStrings("LOCAL_OVERRIDES_MODULES", p.prebuiltCommonProperties.Overrides...) p.addRequiredModules(entries) @@ -781,10 +782,10 @@ func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) { p.initApexFilesForAndroidMk(ctx) // in case that prebuilt_apex replaces source apex (using prefer: prop) - p.compatSymlinks = makeCompatSymlinks(p.BaseModuleName(), ctx, true) + p.compatSymlinks = makeCompatSymlinks(p.BaseModuleName(), ctx) // or that prebuilt_apex overrides other apexes (using overrides: prop) for _, overridden := range p.prebuiltCommonProperties.Overrides { - p.compatSymlinks = append(p.compatSymlinks, makeCompatSymlinks(overridden, ctx, true)...) + p.compatSymlinks = append(p.compatSymlinks, makeCompatSymlinks(overridden, ctx)...) } if p.installable() { @@ -876,12 +877,7 @@ func (e *ApexExtractorProperties) prebuiltSrcs(ctx android.BaseModuleContext) [] srcs = append(srcs, *e.Set) } - var sanitizers []string - if ctx.Host() { - sanitizers = ctx.Config().SanitizeHost() - } else { - sanitizers = ctx.Config().SanitizeDevice() - } + sanitizers := ctx.Config().SanitizeDevice() if android.InList("address", sanitizers) && e.Sanitized.Address.Set != nil { srcs = append(srcs, *e.Sanitized.Address.Set) @@ -1006,10 +1002,10 @@ func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { } // in case that apex_set replaces source apex (using prefer: prop) - a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx, true) + a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx) // or that apex_set overrides other apexes (using overrides: prop) for _, overridden := range a.prebuiltCommonProperties.Overrides { - a.compatSymlinks = append(a.compatSymlinks, makeCompatSymlinks(overridden, ctx, true)...) + a.compatSymlinks = append(a.compatSymlinks, makeCompatSymlinks(overridden, ctx)...) } } diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go index f94e50f4f..40d05814e 100644 --- a/apex/systemserver_classpath_fragment_test.go +++ b/apex/systemserver_classpath_fragment_test.go @@ -97,7 +97,7 @@ func TestSystemserverclasspathFragmentContents(t *testing.T) { ctx := result.TestContext - ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{ "etc/classpaths/systemserverclasspath.pb", "javalib/foo.jar", "javalib/bar.jar", @@ -105,7 +105,7 @@ func TestSystemserverclasspathFragmentContents(t *testing.T) { "javalib/baz.jar", }) - java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex_image", []string{ + java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex", []string{ `myapex.key`, `mysystemserverclasspathfragment`, }) @@ -157,11 +157,11 @@ func TestSystemserverclasspathFragmentNoGeneratedProto(t *testing.T) { } `) - ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{ + ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex", []string{ "javalib/foo.jar", }) - java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex_image", []string{ + java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex", []string{ `myapex.key`, `mysystemserverclasspathfragment`, }) @@ -361,7 +361,7 @@ func TestSystemserverclasspathFragmentStandaloneContents(t *testing.T) { ctx := result.TestContext - ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{ "etc/classpaths/systemserverclasspath.pb", "javalib/foo.jar", "javalib/bar.jar", diff --git a/apex/vndk.go b/apex/vndk.go index 68b3a4000..26c60edc8 100644 --- a/apex/vndk.go +++ b/apex/vndk.go @@ -112,14 +112,10 @@ func apexVndkDepsMutator(mctx android.BottomUpMutatorContext) { } // name is module.BaseModuleName() which is used as LOCAL_MODULE_NAME and also LOCAL_OVERRIDES_* -func makeCompatSymlinks(name string, ctx android.ModuleContext, primaryApex bool) (symlinks android.InstallPaths) { +func makeCompatSymlinks(name string, ctx android.ModuleContext) (symlinks android.InstallPaths) { // small helper to add symlink commands addSymlink := func(target string, dir android.InstallPath, linkName string) { - if primaryApex { - symlinks = append(symlinks, ctx.InstallAbsoluteSymlink(dir, linkName, target)) - } else { - symlinks = append(symlinks, dir.Join(ctx, linkName)) - } + symlinks = append(symlinks, ctx.InstallAbsoluteSymlink(dir, linkName, target)) } // TODO(b/142911355): [VNDK APEX] Fix hard-coded references to /system/lib/vndk diff --git a/apex/vndk_test.go b/apex/vndk_test.go index 4327a61f8..2b86e5347 100644 --- a/apex/vndk_test.go +++ b/apex/vndk_test.go @@ -55,7 +55,7 @@ func TestVndkApexForVndkLite(t *testing.T) { }), ) // VNDK-Lite contains only core variants of VNDK-Sp libraries - ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{ + ensureExactContents(t, ctx, "com.android.vndk.current", "android_common", []string{ "lib/libvndksp.so", "lib/libc++.so", "lib64/libvndksp.so", @@ -110,7 +110,7 @@ func TestVndkApexUsesVendorVariant(t *testing.T) { } // VNDK APEX doesn't create apex variant - files := getFiles(t, ctx, "com.android.vndk.current", "android_common_image") + files := getFiles(t, ctx, "com.android.vndk.current", "android_common") ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared/libfoo.so") }) @@ -122,7 +122,7 @@ func TestVndkApexUsesVendorVariant(t *testing.T) { }), ) - files := getFiles(t, ctx, "com.android.vndk.current", "android_common_image") + files := getFiles(t, ctx, "com.android.vndk.current", "android_common") ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared/libfoo.so") }) @@ -134,10 +134,10 @@ func TestVndkApexUsesVendorVariant(t *testing.T) { }), ) - files := getFiles(t, ctx, "com.android.vndk.current", "android_common_image") + files := getFiles(t, ctx, "com.android.vndk.current", "android_common") ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared/libfoo.so") - files = getFiles(t, ctx, "com.android.vndk.current", "android_common_cov_image") + files = getFiles(t, ctx, "com.android.vndk.current", "android_common_cov") ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared_cov/libfoo.so") }) } diff --git a/bazel/aquery.go b/bazel/aquery.go index d77d59acf..c35571239 100644 --- a/bazel/aquery.go +++ b/bazel/aquery.go @@ -123,6 +123,7 @@ type BuildStatement struct { // Unlike most properties in BuildStatement, these paths must be relative to the root of // the whole out/ folder, instead of relative to ctx.Config().BazelContext.OutputBase() ImplicitDeps []string + IsExecutable bool } // A helper type for aquery processing which facilitates retrieval of path IDs from their @@ -176,6 +177,21 @@ func newAqueryHandler(aqueryResult *analysis_v2_proto.ActionGraphContainer) (*aq if err != nil { return nil, err } + if artifact.IsTreeArtifact && + !strings.HasPrefix(artifactPath, "bazel-out/io_bazel_rules_go/") && + !strings.HasPrefix(artifactPath, "bazel-out/rules_java_builtin/") { + // Since we're using ninja as an executor, we can't use tree artifacts. Ninja only + // considers a file/directory "dirty" when it's mtime changes. Directories' mtimes will + // only change when a file in the directory is added/removed, but not when files in + // the directory are changed, or when files in subdirectories are changed/added/removed. + // Bazel handles this by walking the directory and generating a hash for it after the + // action runs, which we would have to do as well if we wanted to support these + // artifacts in mixed builds. + // + // However, there are some bazel built-in rules that use tree artifacts. Allow those, + // but keep in mind that they'll have incrementality issues. + return nil, fmt.Errorf("tree artifacts are currently not supported in mixed builds: " + artifactPath) + } artifactIdToPath[artifactId(artifact.Id)] = artifactPath } @@ -560,6 +576,7 @@ func (a *aqueryArtifactHandler) fileWriteActionBuildStatement(actionEntry *analy Mnemonic: actionEntry.Mnemonic, InputDepsetHashes: depsetHashes, FileContents: actionEntry.FileContents, + IsExecutable: actionEntry.IsExecutable, }, nil } diff --git a/bazel/configurability.go b/bazel/configurability.go index aa58fdc7e..a28432c01 100644 --- a/bazel/configurability.go +++ b/bazel/configurability.go @@ -39,7 +39,7 @@ const ( // Targets in arch.go osArchAndroidArm = "android_arm" - osArchAndroidArm64 = "android_arm64" + OsArchAndroidArm64 = "android_arm64" osArchAndroidRiscv64 = "android_riscv64" osArchAndroidX86 = "android_x86" osArchAndroidX86_64 = "android_x86_64" @@ -71,6 +71,7 @@ const ( AndroidAndInApex = "android-in_apex" AndroidPlatform = "system" + Unbundled_app = "unbundled_app" InApex = "in_apex" NonApex = "non_apex" @@ -170,7 +171,7 @@ var ( platformOsArchMap = map[string]string{ osArchAndroidArm: "//build/bazel/platforms/os_arch:android_arm", - osArchAndroidArm64: "//build/bazel/platforms/os_arch:android_arm64", + OsArchAndroidArm64: "//build/bazel/platforms/os_arch:android_arm64", osArchAndroidRiscv64: "//build/bazel/platforms/os_arch:android_riscv64", osArchAndroidX86: "//build/bazel/platforms/os_arch:android_x86", osArchAndroidX86_64: "//build/bazel/platforms/os_arch:android_x86_64", @@ -207,6 +208,7 @@ var ( osAndInApexMap = map[string]string{ AndroidAndInApex: "//build/bazel/rules/apex:android-in_apex", AndroidPlatform: "//build/bazel/rules/apex:system", + Unbundled_app: "//build/bazel/rules/apex:unbundled_app", OsDarwin: "//build/bazel/platforms/os:darwin", OsLinux: "//build/bazel/platforms/os:linux_glibc", osLinuxMusl: "//build/bazel/platforms/os:linux_musl", diff --git a/bp2build/Android.bp b/bp2build/Android.bp index 4a3786feb..e30e53d86 100644 --- a/bp2build/Android.bp +++ b/bp2build/Android.bp @@ -32,6 +32,7 @@ bootstrap_go_package { "soong-genrule", "soong-linkerconfig", "soong-python", + "soong-rust", "soong-sh", "soong-shared", "soong-starlark-format", @@ -43,6 +44,7 @@ bootstrap_go_package { "aidl_library_conversion_test.go", "android_app_certificate_conversion_test.go", "android_app_conversion_test.go", + "android_test_conversion_test.go", "apex_conversion_test.go", "apex_key_conversion_test.go", "build_conversion_test.go", @@ -61,7 +63,8 @@ bootstrap_go_package { "cc_test_conversion_test.go", "cc_yasm_conversion_test.go", "conversion_test.go", - "droidstubs_conversion_test.go", + "droiddoc_exported_dir_conversion_test.go", + "fdo_profile_conversion_test.go", "filegroup_conversion_test.go", "genrule_conversion_test.go", "gensrcs_conversion_test.go", @@ -72,6 +75,8 @@ bootstrap_go_package { "java_library_host_conversion_test.go", "java_plugin_conversion_test.go", "java_proto_conversion_test.go", + "java_sdk_library_conversion_test.go", + "java_sdk_library_import_conversion_test.go", "license_conversion_test.go", "license_kind_conversion_test.go", "linker_config_conversion_test.go", @@ -82,7 +87,12 @@ bootstrap_go_package { "python_binary_conversion_test.go", "python_library_conversion_test.go", "python_test_conversion_test.go", + "rust_binary_conversion_test.go", + "rust_library_conversion_test.go", + "rust_proc_macro_conversion_test.go", + "rust_protobuf_conversion_test.go", "sh_conversion_test.go", + "sh_test_conversion_test.go", "soong_config_module_type_conversion_test.go", ], pluginFor: [ diff --git a/bp2build/aar_conversion_test.go b/bp2build/aar_conversion_test.go index 09d9dc103..59aacbb15 100644 --- a/bp2build/aar_conversion_test.go +++ b/bp2build/aar_conversion_test.go @@ -15,11 +15,10 @@ package bp2build import ( + "testing" + "android/soong/android" "android/soong/java" - "fmt" - - "testing" ) func TestConvertAndroidLibrary(t *testing.T) { @@ -35,21 +34,22 @@ func TestConvertAndroidLibrary(t *testing.T) { "res/res.png": "", "manifest/AndroidManifest.xml": "", }, - Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + ` + StubbedBuildDefinitions: []string{"static_lib_dep"}, + Blueprint: simpleModule("android_library", "static_lib_dep") + ` android_library { - name: "TestLib", - srcs: ["lib.java"], - arch: { - arm: { - srcs: ["arm.java"], - }, - x86: { - srcs: ["x86.java"], - } + name: "TestLib", + srcs: ["lib.java"], + arch: { + arm: { + srcs: ["arm.java"], }, - manifest: "manifest/AndroidManifest.xml", - static_libs: ["static_lib_dep"], - java_version: "7", + x86: { + srcs: ["x86.java"], + } + }, + manifest: "manifest/AndroidManifest.xml", + static_libs: ["static_lib_dep"], + sdk_version: "current", } `, ExpectedBazelTargets: []string{ @@ -66,12 +66,9 @@ android_library { "resource_files": `["res/res.png"]`, "deps": `[":static_lib_dep"]`, "exports": `[":static_lib_dep"]`, - "java_version": `"7"`, + "sdk_version": `"current"`, // use as default }), - MakeNeverlinkDuplicateTargetWithAttrs( - "android_library", - "TestLib", - AttrNameToString{"java_version": `"7"`}), + MakeNeverlinkDuplicateTarget("android_library", "TestLib"), }}) } @@ -85,15 +82,15 @@ func TestConvertAndroidLibraryWithNoSources(t *testing.T) { "res/res.png": "", "AndroidManifest.xml": "", }, - Blueprint: simpleModuleDoNotConvertBp2build("android_library", "lib_dep") + ` + Blueprint: simpleModule("android_library", "lib_dep") + ` android_library { - name: "TestLib", - srcs: [], - manifest: "AndroidManifest.xml", - libs: ["lib_dep"], + name: "TestLib", + srcs: [], + manifest: "AndroidManifest.xml", + libs: ["lib_dep"], + sdk_version: "current", } `, - ExpectedErr: fmt.Errorf("Module has direct dependencies but no sources. Bazel will not allow this."), ExpectedBazelTargets: []string{}, }) } @@ -111,16 +108,23 @@ func TestConvertAndroidLibraryImport(t *testing.T) { ModuleTypeUnderTestFactory: java.AARImportFactory, Filesystem: map[string]string{ "import.aar": "", + "dep.aar": "", }, + StubbedBuildDefinitions: []string{"static_lib_dep", "prebuilt_static_import_dep"}, // Bazel's aar_import can only export *_import targets, so we expect // only "static_import_dep" in exports, but both "static_lib_dep" and // "static_import_dep" in deps - Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + - simpleModuleDoNotConvertBp2build("android_library_import", "static_import_dep") + ` + Blueprint: simpleModule("android_library", "static_lib_dep") + ` android_library_import { name: "TestImport", aars: ["import.aar"], static_libs: ["static_lib_dep", "static_import_dep"], + sdk_version: "current", +} + +// TODO: b/301007952 - This dep is needed because android_library_import must have aars set. +android_library_import { + name: "static_import_dep", } `, ExpectedBazelTargets: []string{ @@ -133,7 +137,8 @@ android_library_import { ":static_lib_dep", ":static_import_dep", ]`, - "exports": `[":static_import_dep"]`, + "exports": `[":static_import_dep"]`, + "sdk_version": `"current"`, // use as default }, ), MakeNeverlinkDuplicateTarget("android_library", "TestImport"), @@ -153,9 +158,10 @@ func TestConvertAndroidLibraryKotlin(t *testing.T) { }, Blueprint: ` android_library { - name: "TestLib", - srcs: ["a.java", "b.kt"], - common_srcs: ["c.kt"], + name: "TestLib", + srcs: ["a.java", "b.kt"], + common_srcs: ["c.kt"], + sdk_version: "current", } `, ExpectedBazelTargets: []string{ @@ -170,6 +176,7 @@ android_library { "common_srcs": `["c.kt"]`, "manifest": `"AndroidManifest.xml"`, "resource_files": `[]`, + "sdk_version": `"current"`, // use as default }), MakeNeverlinkDuplicateTarget("android_library", "TestLib"), }}) @@ -186,9 +193,10 @@ func TestConvertAndroidLibraryKotlinCflags(t *testing.T) { }, Blueprint: ` android_library { - name: "TestLib", - srcs: ["a.java", "b.kt"], - kotlincflags: ["-flag1", "-flag2"], + name: "TestLib", + srcs: ["a.java", "b.kt"], + kotlincflags: ["-flag1", "-flag2"], + sdk_version: "current", } `, ExpectedBazelTargets: []string{ @@ -206,6 +214,7 @@ android_library { ]`, "manifest": `"AndroidManifest.xml"`, "resource_files": `[]`, + "sdk_version": `"current"`, // use as default }), MakeNeverlinkDuplicateTarget("android_library", "TestLib"), }}) diff --git a/bp2build/aconfig_conversion_test.go b/bp2build/aconfig_conversion_test.go new file mode 100644 index 000000000..cbf42ac06 --- /dev/null +++ b/bp2build/aconfig_conversion_test.go @@ -0,0 +1,137 @@ +// Copyright 2023 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 ( + "testing" + + "android/soong/aconfig" + "android/soong/android" + "android/soong/cc" +) + +func registerAconfigModuleTypes(ctx android.RegistrationContext) { + aconfig.RegisterBuildComponents(ctx) + ctx.RegisterModuleType("cc_library", cc.LibraryFactory) +} + +func TestAconfigDeclarations(t *testing.T) { + bp := ` + aconfig_declarations { + name: "foo", + srcs: [ + "foo1.aconfig", + "test/foo2.aconfig", + ], + package: "com.android.foo", + } + ` + expectedBazelTarget := MakeBazelTargetNoRestrictions( + "aconfig_declarations", + "foo", + AttrNameToString{ + "srcs": `[ + "foo1.aconfig", + "test/foo2.aconfig", + ]`, + "package": `"com.android.foo"`, + }, + ) + RunBp2BuildTestCase(t, registerAconfigModuleTypes, Bp2buildTestCase{ + Blueprint: bp, + ExpectedBazelTargets: []string{expectedBazelTarget}, + }) +} + +func TestAconfigValues(t *testing.T) { + bp := ` + aconfig_values { + name: "foo", + srcs: [ + "foo1.textproto", + ], + package: "com.android.foo", + } + aconfig_value_set { + name: "bar", + values: [ + "foo" + ] + } + ` + expectedBazelTargets := []string{ + MakeBazelTargetNoRestrictions( + "aconfig_values", + "foo", + AttrNameToString{ + "srcs": `["foo1.textproto"]`, + "package": `"com.android.foo"`, + }, + ), + MakeBazelTargetNoRestrictions( + "aconfig_value_set", + "bar", + AttrNameToString{ + "values": `[":foo"]`, + }, + )} + RunBp2BuildTestCase(t, registerAconfigModuleTypes, Bp2buildTestCase{ + Blueprint: bp, + ExpectedBazelTargets: expectedBazelTargets, + }) +} + +func TestCcAconfigLibrary(t *testing.T) { + bp := ` + aconfig_declarations { + name: "foo_aconfig_declarations", + srcs: [ + "foo1.aconfig", + ], + package: "com.android.foo", + } + cc_library { + name: "server_configurable_flags", + srcs: ["bar.cc"], + bazel_module: { bp2build_available: false }, + } + cc_aconfig_library { + name: "foo", + aconfig_declarations: "foo_aconfig_declarations", + } + ` + expectedBazelTargets := []string{ + MakeBazelTargetNoRestrictions( + "aconfig_declarations", + "foo_aconfig_declarations", + AttrNameToString{ + "srcs": `["foo1.aconfig"]`, + "package": `"com.android.foo"`, + }, + ), + MakeBazelTargetNoRestrictions( + "cc_aconfig_library", + "foo", + AttrNameToString{ + "aconfig_declarations": `":foo_aconfig_declarations"`, + "dynamic_deps": `[":server_configurable_flags"]`, + "target_compatible_with": `["//build/bazel/platforms/os:android"]`, + }, + )} + RunBp2BuildTestCase(t, registerAconfigModuleTypes, Bp2buildTestCase{ + Blueprint: bp, + ExpectedBazelTargets: expectedBazelTargets, + }) +} diff --git a/bp2build/android_app_conversion_test.go b/bp2build/android_app_conversion_test.go index 8ed94b498..7f04e2ac2 100644 --- a/bp2build/android_app_conversion_test.go +++ b/bp2build/android_app_conversion_test.go @@ -16,6 +16,7 @@ package bp2build import ( "android/soong/android" + "android/soong/cc" "android/soong/java" "testing" @@ -29,6 +30,7 @@ func runAndroidAppTestCase(t *testing.T, tc Bp2buildTestCase) { func registerAndroidAppModuleTypes(ctx android.RegistrationContext) { ctx.RegisterModuleType("filegroup", android.FileGroupFactory) ctx.RegisterModuleType("java_library", java.LibraryFactory) + ctx.RegisterModuleType("cc_library_shared", cc.LibrarySharedFactory) } func TestMinimalAndroidApp(t *testing.T) { @@ -44,9 +46,14 @@ func TestMinimalAndroidApp(t *testing.T) { }, Blueprint: ` android_app { - name: "TestApp", - srcs: ["app.java"], - sdk_version: "current", + name: "TestApp", + srcs: ["app.java"], + sdk_version: "current", + optimize: { + shrink: true, + optimize: true, + obfuscate: true, + }, } `, ExpectedBazelTargets: []string{ @@ -73,19 +80,30 @@ func TestAndroidAppAllSupportedFields(t *testing.T) { "manifest/AndroidManifest.xml": "", "assets_/asset.png": "", }, - Blueprint: simpleModuleDoNotConvertBp2build("android_app", "static_lib_dep") + ` + StubbedBuildDefinitions: []string{"static_lib_dep", "jni_lib"}, + Blueprint: simpleModule("android_app", "static_lib_dep") + + simpleModule("cc_library_shared", "jni_lib") + ` android_app { - name: "TestApp", - srcs: ["app.java"], - sdk_version: "current", - package_name: "com.google", - resource_dirs: ["resa", "resb"], - manifest: "manifest/AndroidManifest.xml", - static_libs: ["static_lib_dep"], - java_version: "7", - certificate: "foocert", - required: ["static_lib_dep"], - asset_dirs: ["assets_"], + name: "TestApp", + srcs: ["app.java"], + sdk_version: "current", + package_name: "com.google", + resource_dirs: ["resa", "resb"], + manifest: "manifest/AndroidManifest.xml", + static_libs: ["static_lib_dep"], + java_version: "7", + certificate: "foocert", + required: ["static_lib_dep"], + asset_dirs: ["assets_"], + optimize: { + enabled: true, + optimize: false, + proguard_flags_files: ["proguard.flags"], + shrink: false, + obfuscate: false, + ignore_warnings: true, + }, + jni_libs: ["jni_lib"], } `, ExpectedBazelTargets: []string{ @@ -96,13 +114,24 @@ android_app { "resa/res.png", "resb/res.png", ]`, - "assets": `["assets_/asset.png"]`, - "assets_dir": `"assets_"`, - "custom_package": `"com.google"`, - "deps": `[":static_lib_dep"]`, + "assets": `["assets_/asset.png"]`, + "assets_dir": `"assets_"`, + "custom_package": `"com.google"`, + "deps": `[ + ":static_lib_dep", + ":jni_lib", + ]`, "java_version": `"7"`, "sdk_version": `"current"`, "certificate_name": `"foocert"`, + "proguard_specs": `[ + "proguard.flags", + ":TestApp_proguard_flags", + ]`, + }), + MakeBazelTarget("genrule", "TestApp_proguard_flags", AttrNameToString{ + "outs": `["TestApp_proguard.flags"]`, + "cmd": `"echo -ignorewarning -dontshrink -dontoptimize -dontobfuscate > $(OUTS)"`, }), }}) } @@ -120,16 +149,19 @@ func TestAndroidAppArchVariantSrcs(t *testing.T) { }, Blueprint: ` android_app { - name: "TestApp", - sdk_version: "current", - arch: { - arm: { - srcs: ["arm.java"], - }, - x86: { - srcs: ["x86.java"], - } + name: "TestApp", + sdk_version: "current", + arch: { + arm: { + srcs: ["arm.java"], + }, + x86: { + srcs: ["x86.java"], } + }, + optimize: { + enabled: false, + }, } `, ExpectedBazelTargets: []string{ @@ -142,6 +174,7 @@ android_app { "manifest": `"AndroidManifest.xml"`, "resource_files": `["res/res.png"]`, "sdk_version": `"current"`, + "optimize": `False`, }), }}) } @@ -152,10 +185,15 @@ func TestAndroidAppCertIsModule(t *testing.T) { ModuleTypeUnderTest: "android_app", ModuleTypeUnderTestFactory: java.AndroidAppFactory, Filesystem: map[string]string{}, - Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + ` + StubbedBuildDefinitions: []string{"foocert"}, + Blueprint: simpleModule("filegroup", "foocert") + ` android_app { - name: "TestApp", - certificate: ":foocert", + name: "TestApp", + certificate: ":foocert", + sdk_version: "current", + optimize: { + enabled: false, + }, } `, ExpectedBazelTargets: []string{ @@ -163,6 +201,8 @@ android_app { "certificate": `":foocert"`, "manifest": `"AndroidManifest.xml"`, "resource_files": `[]`, + "sdk_version": `"current"`, // use as default + "optimize": `False`, }), }}) } @@ -177,8 +217,12 @@ func TestAndroidAppCertIsSrcFile(t *testing.T) { }, Blueprint: ` android_app { - name: "TestApp", - certificate: "foocert", + name: "TestApp", + certificate: "foocert", + sdk_version: "current", + optimize: { + enabled: false, + }, } `, ExpectedBazelTargets: []string{ @@ -186,6 +230,8 @@ android_app { "certificate": `"foocert"`, "manifest": `"AndroidManifest.xml"`, "resource_files": `[]`, + "sdk_version": `"current"`, // use as default + "optimize": `False`, }), }}) } @@ -200,8 +246,12 @@ func TestAndroidAppCertIsNotSrcOrModule(t *testing.T) { }, Blueprint: ` android_app { - name: "TestApp", - certificate: "foocert", + name: "TestApp", + certificate: "foocert", + sdk_version: "current", + optimize: { + enabled: false, + }, } `, ExpectedBazelTargets: []string{ @@ -209,6 +259,8 @@ android_app { "certificate_name": `"foocert"`, "manifest": `"AndroidManifest.xml"`, "resource_files": `[]`, + "sdk_version": `"current"`, // use as default + "optimize": `False`, }), }}) } @@ -219,22 +271,24 @@ func TestAndroidAppLibs(t *testing.T) { ModuleTypeUnderTest: "android_app", ModuleTypeUnderTestFactory: java.AndroidAppFactory, Filesystem: map[string]string{}, - Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + ` + StubbedBuildDefinitions: []string{"barLib"}, + Blueprint: simpleModule("java_library", "barLib") + ` android_app { - name: "foo", - libs: ["barLib"] -} -java_library{ - name: "barLib", + name: "foo", + libs: ["barLib"], + sdk_version: "current", + optimize: { + enabled: false, + }, } `, ExpectedBazelTargets: []string{ - MakeBazelTarget("java_library", "barLib", AttrNameToString{}), - MakeNeverlinkDuplicateTarget("java_library", "barLib"), MakeBazelTarget("android_binary", "foo", AttrNameToString{ "manifest": `"AndroidManifest.xml"`, "resource_files": `[]`, "deps": `[":barLib-neverlink"]`, + "sdk_version": `"current"`, // use as default + "optimize": `False`, }), }}) } @@ -247,21 +301,22 @@ func TestAndroidAppKotlinSrcs(t *testing.T) { Filesystem: map[string]string{ "res/res.png": "", }, - Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + ` + StubbedBuildDefinitions: []string{"foocert", "barLib"}, + Blueprint: simpleModule("filegroup", "foocert") + + simpleModule("java_library", "barLib") + ` android_app { - name: "foo", - srcs: ["a.java", "b.kt"], - certificate: ":foocert", - manifest: "fooManifest.xml", - libs: ["barLib"] -} -java_library{ - name: "barLib", + name: "foo", + srcs: ["a.java", "b.kt"], + certificate: ":foocert", + manifest: "fooManifest.xml", + libs: ["barLib"], + sdk_version: "current", + optimize: { + enabled: false, + }, } `, ExpectedBazelTargets: []string{ - MakeBazelTarget("java_library", "barLib", AttrNameToString{}), - MakeNeverlinkDuplicateTarget("java_library", "barLib"), MakeBazelTarget("android_library", "foo_kt", AttrNameToString{ "srcs": `[ "a.java", @@ -270,11 +325,14 @@ java_library{ "manifest": `"fooManifest.xml"`, "resource_files": `["res/res.png"]`, "deps": `[":barLib-neverlink"]`, + "sdk_version": `"current"`, // use as default }), MakeBazelTarget("android_binary", "foo", AttrNameToString{ "deps": `[":foo_kt"]`, "certificate": `":foocert"`, "manifest": `"fooManifest.xml"`, + "sdk_version": `"current"`, // use as default + "optimize": `False`, }), }}) } @@ -287,33 +345,37 @@ func TestAndroidAppCommonSrcs(t *testing.T) { Filesystem: map[string]string{ "res/res.png": "", }, - Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + ` + StubbedBuildDefinitions: []string{"barLib"}, + Blueprint: ` android_app { - name: "foo", - srcs: ["a.java"], - common_srcs: ["b.kt"], - certificate: "foocert", - manifest: "fooManifest.xml", - libs: ["barLib"], + name: "foo", + srcs: ["a.java"], + common_srcs: ["b.kt"], + manifest: "fooManifest.xml", + libs: ["barLib"], + sdk_version: "current", + optimize: { + enabled: false, + }, } java_library{ - name: "barLib", + name: "barLib", } `, ExpectedBazelTargets: []string{ - MakeBazelTarget("java_library", "barLib", AttrNameToString{}), - MakeNeverlinkDuplicateTarget("java_library", "barLib"), MakeBazelTarget("android_library", "foo_kt", AttrNameToString{ "srcs": `["a.java"]`, "common_srcs": `["b.kt"]`, "manifest": `"fooManifest.xml"`, "resource_files": `["res/res.png"]`, "deps": `[":barLib-neverlink"]`, + "sdk_version": `"current"`, // use as default }), MakeBazelTarget("android_binary", "foo", AttrNameToString{ - "deps": `[":foo_kt"]`, - "certificate_name": `"foocert"`, - "manifest": `"fooManifest.xml"`, + "deps": `[":foo_kt"]`, + "manifest": `"fooManifest.xml"`, + "sdk_version": `"current"`, // use as default + "optimize": `False`, }), }}) } @@ -326,13 +388,16 @@ func TestAndroidAppKotlinCflags(t *testing.T) { Filesystem: map[string]string{ "res/res.png": "", }, - Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + ` + Blueprint: ` android_app { - name: "foo", - srcs: ["a.java", "b.kt"], - certificate: ":foocert", - manifest: "fooManifest.xml", - kotlincflags: ["-flag1", "-flag2"], + name: "foo", + srcs: ["a.java", "b.kt"], + manifest: "fooManifest.xml", + kotlincflags: ["-flag1", "-flag2"], + sdk_version: "current", + optimize: { + enabled: false, + }, } `, ExpectedBazelTargets: []string{ @@ -347,11 +412,13 @@ android_app { "-flag1", "-flag2", ]`, + "sdk_version": `"current"`, // use as default }), MakeBazelTarget("android_binary", "foo", AttrNameToString{ "deps": `[":foo_kt"]`, - "certificate": `":foocert"`, "manifest": `"fooManifest.xml"`, + "sdk_version": `"current"`, + "optimize": `False`, }), }}) } @@ -362,13 +429,16 @@ func TestAndroidAppManifestSdkVersionsProvided(t *testing.T) { ModuleTypeUnderTest: "android_app", ModuleTypeUnderTestFactory: java.AndroidAppFactory, Filesystem: map[string]string{}, - Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + ` + Blueprint: ` android_app { - name: "foo", - sdk_version: "current", - min_sdk_version: "24", - max_sdk_version: "30", - target_sdk_version: "29", + name: "foo", + sdk_version: "current", + min_sdk_version: "24", + max_sdk_version: "30", + target_sdk_version: "29", + optimize: { + enabled: false, + }, } `, ExpectedBazelTargets: []string{ @@ -381,6 +451,7 @@ android_app { "targetSdkVersion": "29", }`, "sdk_version": `"current"`, + "optimize": `False`, }), }}) } @@ -391,10 +462,13 @@ func TestAndroidAppMinAndTargetSdkDefaultToSdkVersion(t *testing.T) { ModuleTypeUnderTest: "android_app", ModuleTypeUnderTestFactory: java.AndroidAppFactory, Filesystem: map[string]string{}, - Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + ` + Blueprint: ` android_app { - name: "foo", - sdk_version: "30", + name: "foo", + sdk_version: "30", + optimize: { + enabled: false, + }, } `, ExpectedBazelTargets: []string{ @@ -406,6 +480,7 @@ android_app { "targetSdkVersion": "30", }`, "sdk_version": `"30"`, + "optimize": `False`, }), }}) } diff --git a/bp2build/android_test_conversion_test.go b/bp2build/android_test_conversion_test.go new file mode 100644 index 000000000..52413fad5 --- /dev/null +++ b/bp2build/android_test_conversion_test.go @@ -0,0 +1,103 @@ +// Copyright 2023 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/java" + + "testing" +) + +func runAndroidTestTestCase(t *testing.T, tc Bp2buildTestCase) { + t.Helper() + RunBp2BuildTestCase(t, registerAndroidTestModuleTypes, tc) +} + +func registerAndroidTestModuleTypes(ctx android.RegistrationContext) { + ctx.RegisterModuleType("filegroup", android.FileGroupFactory) + ctx.RegisterModuleType("java_library", java.LibraryFactory) +} + +func TestMinimalAndroidTest(t *testing.T) { + runAndroidAppTestCase(t, Bp2buildTestCase{ + Description: "Android test - simple example", + ModuleTypeUnderTest: "android_test", + ModuleTypeUnderTestFactory: java.AndroidTestFactory, + Filesystem: map[string]string{ + "app.java": "", + "res/res.png": "", + "AndroidManifest.xml": "", + "assets/asset.png": "", + }, + Blueprint: ` +android_test { + name: "TestApp", + srcs: ["app.java"], + sdk_version: "current", + optimize: { + shrink: true, + optimize: true, + obfuscate: true, + }, +} +`, + ExpectedBazelTargets: []string{ + MakeBazelTarget("android_test", "TestApp", AttrNameToString{ + "srcs": `["app.java"]`, + "manifest": `"AndroidManifest.xml"`, + "resource_files": `["res/res.png"]`, + "sdk_version": `"current"`, + "assets": `["assets/asset.png"]`, + "assets_dir": `"assets"`, + }), + }}) +} + +func TestMinimalAndroidTestHelperApp(t *testing.T) { + runAndroidAppTestCase(t, Bp2buildTestCase{ + Description: "Android test helper app - simple example", + ModuleTypeUnderTest: "android_test_helper_app", + ModuleTypeUnderTestFactory: java.AndroidTestHelperAppFactory, + Filesystem: map[string]string{ + "app.java": "", + "res/res.png": "", + "AndroidManifest.xml": "", + "assets/asset.png": "", + }, + Blueprint: ` +android_test_helper_app { + name: "TestApp", + srcs: ["app.java"], + sdk_version: "current", + optimize: { + shrink: true, + optimize: true, + obfuscate: true, + }, +} +`, + ExpectedBazelTargets: []string{ + MakeBazelTarget("android_binary", "TestApp", AttrNameToString{ + "srcs": `["app.java"]`, + "manifest": `"AndroidManifest.xml"`, + "resource_files": `["res/res.png"]`, + "sdk_version": `"current"`, + "assets": `["assets/asset.png"]`, + "assets_dir": `"assets"`, + "testonly": `True`, + }), + }}) +} diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go index 238324761..2a58d0103 100644 --- a/bp2build/apex_conversion_test.go +++ b/bp2build/apex_conversion_test.go @@ -74,38 +74,34 @@ func TestApexBundleSimple(t *testing.T) { ModuleTypeUnderTest: "apex", ModuleTypeUnderTestFactory: apex.BundleFactory, Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"com.android.apogee.key", "com.android.apogee.certificate", "native_shared_lib_1", "native_shared_lib_2", + "prebuilt_1", "prebuilt_2", "com.android.apogee-file_contexts", "cc_binary_1", "sh_binary_2"}, Blueprint: ` apex_key { name: "com.android.apogee.key", public_key: "com.android.apogee.avbpubkey", private_key: "com.android.apogee.pem", - bazel_module: { bp2build_available: false }, } android_app_certificate { name: "com.android.apogee.certificate", certificate: "com.android.apogee", - bazel_module: { bp2build_available: false }, } cc_library { name: "native_shared_lib_1", - bazel_module: { bp2build_available: false }, } cc_library { name: "native_shared_lib_2", - bazel_module: { bp2build_available: false }, } prebuilt_etc { name: "prebuilt_1", - bazel_module: { bp2build_available: false }, } prebuilt_etc { name: "prebuilt_2", - bazel_module: { bp2build_available: false }, } filegroup { @@ -113,11 +109,10 @@ filegroup { srcs: [ "com.android.apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, } -cc_binary { name: "cc_binary_1", bazel_module: { bp2build_available: false } } -sh_binary { name: "sh_binary_2", bazel_module: { bp2build_available: false } } +cc_binary { name: "cc_binary_1"} +sh_binary { name: "sh_binary_2"} apex { name: "com.android.apogee", @@ -202,6 +197,7 @@ func TestApexBundleSimple_fileContextsInAnotherAndroidBp(t *testing.T) { Description: "apex - file contexts is a module in another Android.bp", ModuleTypeUnderTest: "apex", ModuleTypeUnderTestFactory: apex.BundleFactory, + StubbedBuildDefinitions: []string{"//a/b:com.android.apogee-file_contexts"}, Filesystem: map[string]string{ "a/b/Android.bp": ` filegroup { @@ -209,7 +205,6 @@ filegroup { srcs: [ "com.android.apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, } `, }, @@ -252,6 +247,7 @@ func TestApexBundleSimple_fileContextsIsNotSpecified(t *testing.T) { Description: "apex - file contexts is not specified", ModuleTypeUnderTest: "apex", ModuleTypeUnderTestFactory: apex.BundleFactory, + StubbedBuildDefinitions: []string{"//system/sepolicy/apex:com.android.apogee-file_contexts"}, Filesystem: map[string]string{ "system/sepolicy/apex/Android.bp": ` filegroup { @@ -259,7 +255,6 @@ filegroup { srcs: [ "com.android.apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, } `, }, @@ -281,12 +276,12 @@ func TestApexBundleCompileMultilibBoth(t *testing.T) { Description: "apex - example with compile_multilib=both", ModuleTypeUnderTest: "apex", ModuleTypeUnderTestFactory: apex.BundleFactory, + StubbedBuildDefinitions: append(multilibStubNames(), "//system/sepolicy/apex:com.android.apogee-file_contexts"), Filesystem: map[string]string{ "system/sepolicy/apex/Android.bp": ` filegroup { name: "com.android.apogee-file_contexts", srcs: [ "apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, } `, }, @@ -373,12 +368,12 @@ func TestApexBundleCompileMultilibFirstAndDefaultValue(t *testing.T) { Description: "apex - example with " + compileMultiLibProp, ModuleTypeUnderTest: "apex", ModuleTypeUnderTestFactory: apex.BundleFactory, + StubbedBuildDefinitions: append(multilibStubNames(), "//system/sepolicy/apex:com.android.apogee-file_contexts"), Filesystem: map[string]string{ "system/sepolicy/apex/Android.bp": ` filegroup { name: "com.android.apogee-file_contexts", srcs: [ "apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, } `, }, @@ -393,12 +388,12 @@ func TestApexBundleCompileMultilib32(t *testing.T) { Description: "apex - example with compile_multilib=32", ModuleTypeUnderTest: "apex", ModuleTypeUnderTestFactory: apex.BundleFactory, + StubbedBuildDefinitions: append(multilibStubNames(), "//system/sepolicy/apex:com.android.apogee-file_contexts"), Filesystem: map[string]string{ "system/sepolicy/apex/Android.bp": ` filegroup { name: "com.android.apogee-file_contexts", srcs: [ "apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, } `, }, @@ -425,12 +420,12 @@ func TestApexBundleCompileMultilib64(t *testing.T) { Description: "apex - example with compile_multilib=64", ModuleTypeUnderTest: "apex", ModuleTypeUnderTestFactory: apex.BundleFactory, + StubbedBuildDefinitions: append(multilibStubNames(), "//system/sepolicy/apex:com.android.apogee-file_contexts"), Filesystem: map[string]string{ "system/sepolicy/apex/Android.bp": ` filegroup { name: "com.android.apogee-file_contexts", srcs: [ "apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, } `, }, @@ -458,31 +453,31 @@ filegroup { }}) } +func multilibStubNames() []string { + return []string{"native_shared_lib_for_both", "native_shared_lib_for_first", "native_shared_lib_for_lib32", "native_shared_lib_for_lib64", + "native_shared_lib_for_lib64", "unnested_native_shared_lib"} +} + func createMultilibBlueprint(compile_multilib string) string { return fmt.Sprintf(` cc_library { name: "native_shared_lib_for_both", - bazel_module: { bp2build_available: false }, } cc_library { name: "native_shared_lib_for_first", - bazel_module: { bp2build_available: false }, } cc_library { name: "native_shared_lib_for_lib32", - bazel_module: { bp2build_available: false }, } cc_library { name: "native_shared_lib_for_lib64", - bazel_module: { bp2build_available: false }, } cc_library { name: "unnested_native_shared_lib", - bazel_module: { bp2build_available: false }, } apex { @@ -519,12 +514,12 @@ func TestApexBundleDefaultPropertyValues(t *testing.T) { Description: "apex - default property values", ModuleTypeUnderTest: "apex", ModuleTypeUnderTestFactory: apex.BundleFactory, + StubbedBuildDefinitions: []string{"//system/sepolicy/apex:com.android.apogee-file_contexts"}, Filesystem: map[string]string{ "system/sepolicy/apex/Android.bp": ` filegroup { name: "com.android.apogee-file_contexts", srcs: [ "apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, } `, }, @@ -546,12 +541,12 @@ func TestApexBundleHasBazelModuleProps(t *testing.T) { Description: "apex - has bazel module props", ModuleTypeUnderTest: "apex", ModuleTypeUnderTestFactory: apex.BundleFactory, + StubbedBuildDefinitions: []string{"//system/sepolicy/apex:apogee-file_contexts"}, Filesystem: map[string]string{ "system/sepolicy/apex/Android.bp": ` filegroup { name: "apogee-file_contexts", srcs: [ "apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, } `, }, @@ -575,38 +570,35 @@ func TestBp2BuildOverrideApex(t *testing.T) { ModuleTypeUnderTest: "override_apex", ModuleTypeUnderTestFactory: apex.OverrideApexFactory, Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"com.android.apogee.key", "com.android.apogee.certificate", "native_shared_lib_1", + "native_shared_lib_2", "prebuilt_1", "prebuilt_2", "com.android.apogee-file_contexts", "cc_binary_1", + "sh_binary_2", "com.android.apogee", "com.google.android.apogee.key", "com.google.android.apogee.certificate"}, Blueprint: ` apex_key { name: "com.android.apogee.key", public_key: "com.android.apogee.avbpubkey", private_key: "com.android.apogee.pem", - bazel_module: { bp2build_available: false }, } android_app_certificate { name: "com.android.apogee.certificate", certificate: "com.android.apogee", - bazel_module: { bp2build_available: false }, } cc_library { name: "native_shared_lib_1", - bazel_module: { bp2build_available: false }, } cc_library { name: "native_shared_lib_2", - bazel_module: { bp2build_available: false }, } prebuilt_etc { name: "prebuilt_1", - bazel_module: { bp2build_available: false }, } prebuilt_etc { name: "prebuilt_2", - bazel_module: { bp2build_available: false }, } filegroup { @@ -614,11 +606,10 @@ filegroup { srcs: [ "com.android.apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, } -cc_binary { name: "cc_binary_1", bazel_module: { bp2build_available: false } } -sh_binary { name: "sh_binary_2", bazel_module: { bp2build_available: false } } +cc_binary { name: "cc_binary_1" } +sh_binary { name: "sh_binary_2" } apex { name: "com.android.apogee", @@ -643,20 +634,17 @@ apex { "prebuilt_1", "prebuilt_2", ], - bazel_module: { bp2build_available: false }, } apex_key { name: "com.google.android.apogee.key", public_key: "com.google.android.apogee.avbpubkey", private_key: "com.google.android.apogee.pem", - bazel_module: { bp2build_available: false }, } android_app_certificate { name: "com.google.android.apogee.certificate", certificate: "com.google.android.apogee", - bazel_module: { bp2build_available: false }, } override_apex { @@ -717,28 +705,27 @@ func TestOverrideApexTest(t *testing.T) { ModuleTypeUnderTest: "override_apex", ModuleTypeUnderTestFactory: apex.OverrideApexFactory, Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"com.android.apogee.certificate", "native_shared_lib_1", + "prebuilt_1", "com.android.apogee-file_contexts", "cc_binary_1", "sh_binary_2", + "com.android.apogee", "com.google.android.apogee.key", "com.google.android.apogee.certificate", "com.android.apogee.key"}, Blueprint: ` apex_key { name: "com.android.apogee.key", public_key: "com.android.apogee.avbpubkey", private_key: "com.android.apogee.pem", - bazel_module: { bp2build_available: false }, } android_app_certificate { name: "com.android.apogee.certificate", certificate: "com.android.apogee", - bazel_module: { bp2build_available: false }, } cc_library { name: "native_shared_lib_1", - bazel_module: { bp2build_available: false }, } prebuilt_etc { name: "prebuilt_1", - bazel_module: { bp2build_available: false }, } filegroup { @@ -746,11 +733,10 @@ filegroup { srcs: [ "com.android.apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, } -cc_binary { name: "cc_binary_1", bazel_module: { bp2build_available: false } } -sh_binary { name: "sh_binary_2", bazel_module: { bp2build_available: false } } +cc_binary { name: "cc_binary_1"} +sh_binary { name: "sh_binary_2"} apex_test { name: "com.android.apogee", @@ -773,20 +759,17 @@ apex_test { prebuilts: [ "prebuilt_1", ], - bazel_module: { bp2build_available: false }, } apex_key { name: "com.google.android.apogee.key", public_key: "com.google.android.apogee.avbpubkey", private_key: "com.google.android.apogee.pem", - bazel_module: { bp2build_available: false }, } android_app_certificate { name: "com.google.android.apogee.certificate", certificate: "com.google.android.apogee", - bazel_module: { bp2build_available: false }, } override_apex { @@ -835,12 +818,12 @@ func TestApexBundleSimple_manifestIsEmpty_baseApexOverrideApexInDifferentAndroid Description: "override_apex - manifest of base apex is empty, base apex and override_apex is in different Android.bp", ModuleTypeUnderTest: "override_apex", ModuleTypeUnderTestFactory: apex.OverrideApexFactory, + StubbedBuildDefinitions: []string{"//system/sepolicy/apex:com.android.apogee-file_contexts"}, Filesystem: map[string]string{ "system/sepolicy/apex/Android.bp": ` filegroup { name: "com.android.apogee-file_contexts", srcs: [ "apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, }`, "a/b/Android.bp": ` apex { @@ -869,12 +852,12 @@ func TestApexBundleSimple_manifestIsSet_baseApexOverrideApexInDifferentAndroidBp Description: "override_apex - manifest of base apex is set, base apex and override_apex is in different Android.bp", ModuleTypeUnderTest: "override_apex", ModuleTypeUnderTestFactory: apex.OverrideApexFactory, + StubbedBuildDefinitions: []string{"//system/sepolicy/apex:com.android.apogee-file_contexts"}, Filesystem: map[string]string{ "system/sepolicy/apex/Android.bp": ` filegroup { name: "com.android.apogee-file_contexts", srcs: [ "apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, }`, "a/b/Android.bp": ` apex { @@ -904,12 +887,12 @@ func TestApexBundleSimple_manifestIsEmpty_baseApexOverrideApexInSameAndroidBp(t Description: "override_apex - manifest of base apex is empty, base apex and override_apex is in same Android.bp", ModuleTypeUnderTest: "override_apex", ModuleTypeUnderTestFactory: apex.OverrideApexFactory, + StubbedBuildDefinitions: []string{"//system/sepolicy/apex:com.android.apogee-file_contexts"}, Filesystem: map[string]string{ "system/sepolicy/apex/Android.bp": ` filegroup { name: "com.android.apogee-file_contexts", srcs: [ "apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, }`, }, Blueprint: ` @@ -937,12 +920,12 @@ func TestApexBundleSimple_manifestIsSet_baseApexOverrideApexInSameAndroidBp(t *t Description: "override_apex - manifest of base apex is set, base apex and override_apex is in same Android.bp", ModuleTypeUnderTest: "override_apex", ModuleTypeUnderTestFactory: apex.OverrideApexFactory, + StubbedBuildDefinitions: []string{"//system/sepolicy/apex:com.android.apogee-file_contexts"}, Filesystem: map[string]string{ "system/sepolicy/apex/Android.bp": ` filegroup { name: "com.android.apogee-file_contexts", srcs: [ "apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, }`, }, Blueprint: ` @@ -971,12 +954,12 @@ func TestApexBundleSimple_packageNameOverride(t *testing.T) { Description: "override_apex - override package name", ModuleTypeUnderTest: "override_apex", ModuleTypeUnderTestFactory: apex.OverrideApexFactory, + StubbedBuildDefinitions: []string{"//system/sepolicy/apex:com.android.apogee-file_contexts"}, Filesystem: map[string]string{ "system/sepolicy/apex/Android.bp": ` filegroup { name: "com.android.apogee-file_contexts", srcs: [ "apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, }`, }, Blueprint: ` @@ -1006,24 +989,22 @@ func TestApexBundleSimple_NoPrebuiltsOverride(t *testing.T) { Description: "override_apex - no override", ModuleTypeUnderTest: "override_apex", ModuleTypeUnderTestFactory: apex.OverrideApexFactory, + StubbedBuildDefinitions: []string{"prebuilt_file", "com.android.apogee", "//system/sepolicy/apex:com.android.apogee-file_contexts"}, Filesystem: map[string]string{ "system/sepolicy/apex/Android.bp": ` filegroup { name: "com.android.apogee-file_contexts", srcs: [ "apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, }`, }, Blueprint: ` prebuilt_etc { name: "prebuilt_file", - bazel_module: { bp2build_available: false }, } apex { name: "com.android.apogee", - bazel_module: { bp2build_available: false }, - prebuilts: ["prebuilt_file"] + prebuilts: ["prebuilt_file"] } override_apex { @@ -1046,35 +1027,32 @@ func TestApexBundleSimple_PrebuiltsOverride(t *testing.T) { Description: "override_apex - ooverride", ModuleTypeUnderTest: "override_apex", ModuleTypeUnderTestFactory: apex.OverrideApexFactory, + StubbedBuildDefinitions: []string{"prebuilt_file", "prebuilt_file2", "com.android.apogee", "//system/sepolicy/apex:com.android.apogee-file_contexts"}, Filesystem: map[string]string{ "system/sepolicy/apex/Android.bp": ` filegroup { name: "com.android.apogee-file_contexts", srcs: [ "apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, }`, }, Blueprint: ` prebuilt_etc { name: "prebuilt_file", - bazel_module: { bp2build_available: false }, } prebuilt_etc { name: "prebuilt_file2", - bazel_module: { bp2build_available: false }, } apex { name: "com.android.apogee", - bazel_module: { bp2build_available: false }, - prebuilts: ["prebuilt_file"] + prebuilts: ["prebuilt_file"] } override_apex { name: "com.google.android.apogee", base: ":com.android.apogee", - prebuilts: ["prebuilt_file2"] + prebuilts: ["prebuilt_file2"] } `, ExpectedBazelTargets: []string{ @@ -1092,24 +1070,22 @@ func TestApexBundleSimple_PrebuiltsOverrideEmptyList(t *testing.T) { Description: "override_apex - override with empty list", ModuleTypeUnderTest: "override_apex", ModuleTypeUnderTestFactory: apex.OverrideApexFactory, + StubbedBuildDefinitions: []string{"prebuilt_file", "com.android.apogee", "//system/sepolicy/apex:com.android.apogee-file_contexts"}, Filesystem: map[string]string{ "system/sepolicy/apex/Android.bp": ` filegroup { name: "com.android.apogee-file_contexts", srcs: [ "apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, }`, }, Blueprint: ` prebuilt_etc { name: "prebuilt_file", - bazel_module: { bp2build_available: false }, } apex { name: "com.android.apogee", - bazel_module: { bp2build_available: false }, - prebuilts: ["prebuilt_file"] + prebuilts: ["prebuilt_file"] } override_apex { @@ -1133,12 +1109,12 @@ func TestApexBundleSimple_NoLoggingParentOverride(t *testing.T) { Description: "override_apex - logging_parent - no override", ModuleTypeUnderTest: "override_apex", ModuleTypeUnderTestFactory: apex.OverrideApexFactory, + StubbedBuildDefinitions: []string{"//system/sepolicy/apex:com.android.apogee-file_contexts"}, Filesystem: map[string]string{ "system/sepolicy/apex/Android.bp": ` filegroup { name: "com.android.apogee-file_contexts", srcs: [ "apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, }`, }, Blueprint: ` @@ -1168,12 +1144,12 @@ func TestApexBundleSimple_LoggingParentOverride(t *testing.T) { Description: "override_apex - logging_parent - override", ModuleTypeUnderTest: "override_apex", ModuleTypeUnderTestFactory: apex.OverrideApexFactory, + StubbedBuildDefinitions: []string{"//system/sepolicy/apex:com.android.apogee-file_contexts"}, Filesystem: map[string]string{ "system/sepolicy/apex/Android.bp": ` filegroup { name: "com.android.apogee-file_contexts", srcs: [ "apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, }`, }, Blueprint: ` @@ -1205,11 +1181,11 @@ func TestBp2BuildOverrideApex_CertificateNil(t *testing.T) { ModuleTypeUnderTest: "override_apex", ModuleTypeUnderTestFactory: apex.OverrideApexFactory, Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"com.android.apogee.certificate", "com.android.apogee-file_contexts", "com.android.apogee"}, Blueprint: ` android_app_certificate { name: "com.android.apogee.certificate", certificate: "com.android.apogee", - bazel_module: { bp2build_available: false }, } filegroup { @@ -1217,7 +1193,6 @@ filegroup { srcs: [ "com.android.apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, } apex { @@ -1225,7 +1200,6 @@ apex { manifest: "apogee_manifest.json", file_contexts: ":com.android.apogee-file_contexts", certificate: ":com.android.apogee.certificate", - bazel_module: { bp2build_available: false }, } override_apex { @@ -1250,11 +1224,11 @@ func TestApexCertificateIsModule(t *testing.T) { ModuleTypeUnderTest: "apex", ModuleTypeUnderTestFactory: apex.BundleFactory, Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"com.android.apogee-file_contexts", "com.android.apogee.certificate"}, Blueprint: ` android_app_certificate { name: "com.android.apogee.certificate", certificate: "com.android.apogee", - bazel_module: { bp2build_available: false }, } apex { @@ -1263,7 +1237,7 @@ apex { file_contexts: ":com.android.apogee-file_contexts", certificate: ":com.android.apogee.certificate", } -` + simpleModuleDoNotConvertBp2build("filegroup", "com.android.apogee-file_contexts"), +` + simpleModule("filegroup", "com.android.apogee-file_contexts"), ExpectedBazelTargets: []string{ MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{ "certificate": `":com.android.apogee.certificate"`, @@ -1279,6 +1253,7 @@ func TestApexWithStubLib(t *testing.T) { ModuleTypeUnderTest: "apex", ModuleTypeUnderTestFactory: apex.BundleFactory, Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"myapex-file_contexts"}, Blueprint: ` cc_library{ name: "foo", @@ -1299,7 +1274,7 @@ apex { binaries: ["bar"], native_shared_libs: ["foo"], } -` + simpleModuleDoNotConvertBp2build("filegroup", "myapex-file_contexts"), +` + simpleModule("filegroup", "myapex-file_contexts"), ExpectedBazelTargets: []string{ MakeBazelTarget("cc_binary", "bar", AttrNameToString{ "local_includes": `["."]`, @@ -1315,6 +1290,7 @@ apex { "tags": `["apex_available=myapex"]`, }), MakeBazelTarget("cc_stub_suite", "foo_stub_libs", AttrNameToString{ + "api_surface": `"module-libapi"`, "soname": `"foo.so"`, "source_library_label": `"//:foo"`, "symbol_file": `"foo.map.txt"`, @@ -1349,6 +1325,7 @@ func TestApexCertificateIsSrc(t *testing.T) { ModuleTypeUnderTest: "apex", ModuleTypeUnderTestFactory: apex.BundleFactory, Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"com.android.apogee-file_contexts"}, Blueprint: ` apex { name: "com.android.apogee", @@ -1356,7 +1333,7 @@ apex { file_contexts: ":com.android.apogee-file_contexts", certificate: "com.android.apogee.certificate", } -` + simpleModuleDoNotConvertBp2build("filegroup", "com.android.apogee-file_contexts"), +` + simpleModule("filegroup", "com.android.apogee-file_contexts"), ExpectedBazelTargets: []string{ MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{ "certificate_name": `"com.android.apogee.certificate"`, @@ -1372,11 +1349,12 @@ func TestBp2BuildOverrideApex_CertificateIsModule(t *testing.T) { ModuleTypeUnderTest: "override_apex", ModuleTypeUnderTestFactory: apex.OverrideApexFactory, Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"com.android.apogee.certificate", "com.android.apogee-file_contexts", + "com.android.apogee", "com.google.android.apogee.certificate"}, Blueprint: ` android_app_certificate { name: "com.android.apogee.certificate", certificate: "com.android.apogee", - bazel_module: { bp2build_available: false }, } filegroup { @@ -1384,7 +1362,6 @@ filegroup { srcs: [ "com.android.apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, } apex { @@ -1392,13 +1369,11 @@ apex { manifest: "apogee_manifest.json", file_contexts: ":com.android.apogee-file_contexts", certificate: ":com.android.apogee.certificate", - bazel_module: { bp2build_available: false }, } android_app_certificate { name: "com.google.android.apogee.certificate", certificate: "com.google.android.apogee", - bazel_module: { bp2build_available: false }, } override_apex { @@ -1423,11 +1398,11 @@ func TestBp2BuildOverrideApex_CertificateIsSrc(t *testing.T) { ModuleTypeUnderTest: "override_apex", ModuleTypeUnderTestFactory: apex.OverrideApexFactory, Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"com.android.apogee.certificate", "com.android.apogee", "com.android.apogee-file_contexts"}, Blueprint: ` android_app_certificate { name: "com.android.apogee.certificate", certificate: "com.android.apogee", - bazel_module: { bp2build_available: false }, } filegroup { @@ -1435,7 +1410,6 @@ filegroup { srcs: [ "com.android.apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, } apex { @@ -1468,8 +1442,9 @@ func TestApexTestBundleSimple(t *testing.T) { ModuleTypeUnderTest: "apex_test", ModuleTypeUnderTestFactory: apex.TestApexBundleFactory, Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"cc_test_1"}, Blueprint: ` -cc_test { name: "cc_test_1", bazel_module: { bp2build_available: false } } +cc_test { name: "cc_test_1"} apex_test { name: "test_com.android.apogee", @@ -1496,6 +1471,7 @@ func TestApexBundle_overridePlusProductVars(t *testing.T) { Description: "apex - overriding a module that uses product vars", ModuleTypeUnderTest: "override_apex", ModuleTypeUnderTestFactory: apex.OverrideApexFactory, + StubbedBuildDefinitions: []string{"foo-file_contexts"}, Blueprint: ` soong_config_string_variable { name: "library_linking_strategy", @@ -1534,7 +1510,6 @@ filegroup { srcs: [ "com.android.apogee-file_contexts", ], - bazel_module: { bp2build_available: false }, } apex { diff --git a/bp2build/apex_key_conversion_test.go b/bp2build/apex_key_conversion_test.go index f9a68c918..140afb76a 100644 --- a/bp2build/apex_key_conversion_test.go +++ b/bp2build/apex_key_conversion_test.go @@ -47,8 +47,9 @@ apex_key { } `, ExpectedBazelTargets: []string{MakeBazelTargetNoRestrictions("apex_key", "com.android.apogee.key", AttrNameToString{ - "private_key": `"com.android.apogee.pem"`, - "public_key": `"com.android.apogee.avbpubkey"`, + "private_key": `"com.android.apogee.pem"`, + "public_key": `"com.android.apogee.avbpubkey"`, + "target_compatible_with": `["//build/bazel/platforms/os:android"]`, }), }}) } @@ -69,8 +70,9 @@ apex_key { } `, ExpectedBazelTargets: []string{MakeBazelTargetNoRestrictions("apex_key", "com.android.apogee.key", AttrNameToString{ - "private_key_name": `"com.android.apogee.pem"`, - "public_key_name": `"com.android.apogee.avbpubkey"`, + "private_key_name": `"com.android.apogee.pem"`, + "public_key_name": `"com.android.apogee.avbpubkey"`, + "target_compatible_with": `["//build/bazel/platforms/os:android"]`, }), }}) } @@ -81,17 +83,19 @@ func TestApexKey_KeysAreModules(t *testing.T) { ModuleTypeUnderTest: "apex_key", ModuleTypeUnderTestFactory: apex.ApexKeyFactory, Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"com.android.apogee.avbpubkey", "com.android.apogee.pem"}, Blueprint: ` apex_key { name: "com.android.apogee.key", public_key: ":com.android.apogee.avbpubkey", private_key: ":com.android.apogee.pem", } -` + simpleModuleDoNotConvertBp2build("filegroup", "com.android.apogee.avbpubkey") + - simpleModuleDoNotConvertBp2build("filegroup", "com.android.apogee.pem"), +` + simpleModule("filegroup", "com.android.apogee.avbpubkey") + + simpleModule("filegroup", "com.android.apogee.pem"), ExpectedBazelTargets: []string{MakeBazelTargetNoRestrictions("apex_key", "com.android.apogee.key", AttrNameToString{ - "private_key": `":com.android.apogee.pem"`, - "public_key": `":com.android.apogee.avbpubkey"`, + "private_key": `":com.android.apogee.pem"`, + "public_key": `":com.android.apogee.avbpubkey"`, + "target_compatible_with": `["//build/bazel/platforms/os:android"]`, }), }}) } diff --git a/bp2build/api_domain_conversion_test.go b/bp2build/api_domain_conversion_test.go deleted file mode 100644 index 224008fef..000000000 --- a/bp2build/api_domain_conversion_test.go +++ /dev/null @@ -1,68 +0,0 @@ -// 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 ( - "testing" - - "android/soong/android" - "android/soong/cc" -) - -func registerApiDomainModuleTypes(ctx android.RegistrationContext) { - android.RegisterApiDomainBuildComponents(ctx) - cc.RegisterNdkModuleTypes(ctx) - cc.RegisterLibraryBuildComponents(ctx) -} - -func TestApiDomainContributionsTest(t *testing.T) { - bp := ` - api_domain { - name: "system", - cc_api_contributions: [ - "libfoo.ndk", - "libbar", - ], - } - ` - fs := map[string]string{ - "libfoo/Android.bp": ` - ndk_library { - name: "libfoo", - } - `, - "libbar/Android.bp": ` - cc_library { - name: "libbar", - } - `, - } - expectedBazelTarget := MakeBazelTargetNoRestrictions( - "api_domain", - "system", - AttrNameToString{ - "cc_api_contributions": `[ - "//libfoo:libfoo.ndk.contribution", - "//libbar:libbar.contribution", - ]`, - "target_compatible_with": `["//build/bazel/platforms/os:android"]`, - }, - ) - RunApiBp2BuildTestCase(t, registerApiDomainModuleTypes, Bp2buildTestCase{ - Blueprint: bp, - ExpectedBazelTargets: []string{expectedBazelTarget}, - Filesystem: fs, - }) -} diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go index 5f7b382f0..6c9d90330 100644 --- a/bp2build/bp2build.go +++ b/bp2build/bp2build.go @@ -82,15 +82,25 @@ func Codegen(ctx *CodegenContext) *CodegenMetrics { os.Exit(1) } var bp2buildFiles []BazelFile + productConfig, err := createProductConfigFiles(ctx, res.metrics) ctx.Context().EventHandler.Do("CreateBazelFile", func() { - bp2buildFiles = CreateBazelFiles(nil, res.buildFileToTargets, ctx.mode) + allTargets := make(map[string]BazelTargets) + for k, v := range res.buildFileToTargets { + allTargets[k] = append(allTargets[k], v...) + } + for k, v := range productConfig.bp2buildTargets { + allTargets[k] = append(allTargets[k], v...) + } + bp2buildFiles = CreateBazelFiles(nil, allTargets, ctx.mode) }) - injectionFiles, additionalBp2buildFiles, err := CreateSoongInjectionDirFiles(ctx, res.metrics) + bp2buildFiles = append(bp2buildFiles, productConfig.bp2buildFiles...) + injectionFiles, err := createSoongInjectionDirFiles(ctx, res.metrics) if err != nil { fmt.Printf("%s\n", err.Error()) os.Exit(1) } - bp2buildFiles = append(bp2buildFiles, additionalBp2buildFiles...) + injectionFiles = append(injectionFiles, productConfig.injectionFiles...) + writeFiles(ctx, bp2buildDir, bp2buildFiles) // Delete files under the bp2build root which weren't just written. An // alternative would have been to delete the whole directory and write these @@ -109,26 +119,6 @@ func Codegen(ctx *CodegenContext) *CodegenMetrics { return &res.metrics } -// Wrapper function that will be responsible for all files in soong_injection directory -// This includes -// 1. config value(s) that are hardcoded in Soong -// 2. product_config variables -func CreateSoongInjectionDirFiles(ctx *CodegenContext, metrics CodegenMetrics) ([]BazelFile, []BazelFile, error) { - var ret []BazelFile - - productConfigInjectionFiles, productConfigBp2BuildDirFiles, err := CreateProductConfigFiles(ctx, metrics) - if err != nil { - return nil, nil, err - } - ret = append(ret, productConfigInjectionFiles...) - injectionFiles, err := soongInjectionFiles(ctx.Config(), metrics) - if err != nil { - return nil, nil, err - } - ret = append(injectionFiles, ret...) - return ret, productConfigBp2BuildDirFiles, nil -} - // Get the output directory and create it if it doesn't exist. func getOrCreateOutputDir(outputDir android.OutputPath, ctx android.PathContext, dir string) android.OutputPath { dirPath := outputDir.Join(ctx, dir) diff --git a/bp2build/bp2build_product_config.go b/bp2build/bp2build_product_config.go index e8c2ef7e0..3d9cae069 100644 --- a/bp2build/bp2build_product_config.go +++ b/bp2build/bp2build_product_config.go @@ -1,9 +1,6 @@ package bp2build import ( - "android/soong/android" - "android/soong/android/soongconfig" - "android/soong/starlark_import" "encoding/json" "fmt" "os" @@ -11,13 +8,23 @@ import ( "reflect" "strings" + "android/soong/android" + "android/soong/android/soongconfig" + "android/soong/starlark_import" + "github.com/google/blueprint/proptools" "go.starlark.net/starlark" ) -func CreateProductConfigFiles( +type createProductConfigFilesResult struct { + injectionFiles []BazelFile + bp2buildFiles []BazelFile + bp2buildTargets map[string]BazelTargets +} + +func createProductConfigFiles( ctx *CodegenContext, - metrics CodegenMetrics) ([]BazelFile, []BazelFile, error) { + metrics CodegenMetrics) (createProductConfigFilesResult, error) { cfg := &ctx.config targetProduct := "unknown" if cfg.HasDeviceProduct() { @@ -30,68 +37,85 @@ func CreateProductConfigFiles( targetBuildVariant = "userdebug" } + var res createProductConfigFilesResult + productVariablesFileName := cfg.ProductVariablesFileName if !strings.HasPrefix(productVariablesFileName, "/") { productVariablesFileName = filepath.Join(ctx.topDir, productVariablesFileName) } productVariablesBytes, err := os.ReadFile(productVariablesFileName) if err != nil { - return nil, nil, err + return res, err } productVariables := android.ProductVariables{} err = json.Unmarshal(productVariablesBytes, &productVariables) if err != nil { - return nil, nil, err + return res, err } - // TODO(b/249685973): the name is product_config_platforms because product_config - // was already used for other files. Deduplicate them. - currentProductFolder := fmt.Sprintf("product_config_platforms/products/%s-%s", targetProduct, targetBuildVariant) + currentProductFolder := fmt.Sprintf("build/bazel/products/%s-%s", targetProduct, targetBuildVariant) + if len(productVariables.PartitionVars.ProductDirectory) > 0 { + currentProductFolder = fmt.Sprintf("%s%s-%s", productVariables.PartitionVars.ProductDirectory, targetProduct, targetBuildVariant) + } productReplacer := strings.NewReplacer( "{PRODUCT}", targetProduct, "{VARIANT}", targetBuildVariant, "{PRODUCT_FOLDER}", currentProductFolder) - platformMappingContent, err := platformMappingContent( - productReplacer.Replace("@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}"), - &productVariables, - ctx.Config().Bp2buildSoongConfigDefinitions, - metrics.convertedModulePathMap) - if err != nil { - return nil, nil, err - } - productsForTestingMap, err := starlark_import.GetStarlarkValue[map[string]map[string]starlark.Value]("products_for_testing") if err != nil { - return nil, nil, err + return res, err } productsForTesting := android.SortedKeys(productsForTestingMap) for i := range productsForTesting { productsForTesting[i] = fmt.Sprintf(" \"@//build/bazel/tests/products:%s\",", productsForTesting[i]) } - injectionDirFiles := []BazelFile{ - newFile( - currentProductFolder, - "soong.variables.bzl", - `variables = json.decode("""`+strings.ReplaceAll(string(productVariablesBytes), "\\", "\\\\")+`""")`), - newFile( - currentProductFolder, - "BUILD", - productReplacer.Replace(` -package(default_visibility=[ - "@soong_injection//product_config_platforms:__subpackages__", - "@//build/bazel/product_config:__subpackages__", -]) -load(":soong.variables.bzl", _soong_variables = "variables") -load("@//build/bazel/product_config:android_product.bzl", "android_product") + productLabelsToVariables := make(map[string]*android.ProductVariables) + productLabelsToVariables[productReplacer.Replace("@//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}")] = &productVariables + for product, productVariablesStarlark := range productsForTestingMap { + productVariables, err := starlarkMapToProductVariables(productVariablesStarlark) + if err != nil { + return res, err + } + productLabelsToVariables["@//build/bazel/tests/products:"+product] = &productVariables + } -android_product( + res.bp2buildTargets = make(map[string]BazelTargets) + res.bp2buildTargets[currentProductFolder] = append(res.bp2buildTargets[currentProductFolder], BazelTarget{ + name: productReplacer.Replace("{PRODUCT}-{VARIANT}"), + packageName: currentProductFolder, + content: productReplacer.Replace(`android_product( name = "{PRODUCT}-{VARIANT}", soong_variables = _soong_variables, -) -`)), +)`), + ruleClass: "android_product", + loads: []BazelLoad{ + { + file: ":soong.variables.bzl", + symbols: []BazelLoadSymbol{{ + symbol: "variables", + alias: "_soong_variables", + }}, + }, + { + file: "//build/bazel/product_config:android_product.bzl", + symbols: []BazelLoadSymbol{{symbol: "android_product"}}, + }, + }, + }) + createTargets(productLabelsToVariables, res.bp2buildTargets) + + platformMappingContent, err := platformMappingContent( + productLabelsToVariables, + ctx.Config().Bp2buildSoongConfigDefinitions, + metrics.convertedModulePathMap) + if err != nil { + return res, err + } + + res.injectionFiles = []BazelFile{ newFile( "product_config_platforms", "BUILD.bazel", @@ -101,7 +125,7 @@ package(default_visibility = [ "@soong_injection//product_config_platforms:__subpackages__", ]) -load("//{PRODUCT_FOLDER}:soong.variables.bzl", _soong_variables = "variables") +load("@//{PRODUCT_FOLDER}:soong.variables.bzl", _soong_variables = "variables") load("@//build/bazel/product_config:android_product.bzl", "android_product") # Bazel will qualify its outputs by the platform name. When switching between products, this @@ -125,53 +149,53 @@ android_product( # currently lunched product, they should all be listed here product_labels = [ "@soong_injection//product_config_platforms:mixed_builds_product-{VARIANT}", - "@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}", + "@//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}", `)+strings.Join(productsForTesting, "\n")+"\n]\n"), newFile( "product_config_platforms", "common.bazelrc", productReplacer.Replace(` build --platform_mappings=platform_mappings -build --platforms @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64 - -build:android --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT} -build:linux_x86 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86 -build:linux_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64 -build:linux_bionic_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_bionic_x86_64 -build:linux_musl_x86 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_musl_x86 -build:linux_musl_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_musl_x86_64 +build --platforms @//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64 + +build:android --platforms=@//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT} +build:linux_x86 --platforms=@//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86 +build:linux_x86_64 --platforms=@//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64 +build:linux_bionic_x86_64 --platforms=@//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_bionic_x86_64 +build:linux_musl_x86 --platforms=@//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_musl_x86 +build:linux_musl_x86_64 --platforms=@//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_musl_x86_64 `)), newFile( "product_config_platforms", "linux.bazelrc", productReplacer.Replace(` -build --host_platform @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64 +build --host_platform @//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64 `)), newFile( "product_config_platforms", "darwin.bazelrc", productReplacer.Replace(` -build --host_platform @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_darwin_x86_64 +build --host_platform @//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_darwin_x86_64 `)), } - bp2buildDirFiles := []BazelFile{ + res.bp2buildFiles = []BazelFile{ newFile( "", "platform_mappings", platformMappingContent), + newFile( + currentProductFolder, + "soong.variables.bzl", + `variables = json.decode("""`+strings.ReplaceAll(string(productVariablesBytes), "\\", "\\\\")+`""")`), } - return injectionDirFiles, bp2buildDirFiles, nil + + return res, nil } func platformMappingContent( - mainProductLabel string, - mainProductVariables *android.ProductVariables, + productLabelToVariables map[string]*android.ProductVariables, soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions, convertedModulePathMap map[string]string) (string, error) { - productsForTesting, err := starlark_import.GetStarlarkValue[map[string]map[string]starlark.Value]("products_for_testing") - if err != nil { - return "", err - } var result strings.Builder mergedConvertedModulePathMap := make(map[string]string) @@ -187,13 +211,8 @@ func platformMappingContent( } result.WriteString("platforms:\n") - platformMappingSingleProduct(mainProductLabel, mainProductVariables, soongConfigDefinitions, mergedConvertedModulePathMap, &result) - for product, productVariablesStarlark := range productsForTesting { - productVariables, err := starlarkMapToProductVariables(productVariablesStarlark) - if err != nil { - return "", err - } - platformMappingSingleProduct("@//build/bazel/tests/products:"+product, &productVariables, soongConfigDefinitions, mergedConvertedModulePathMap, &result) + for productLabel, productVariables := range productLabelToVariables { + platformMappingSingleProduct(productLabel, productVariables, soongConfigDefinitions, mergedConvertedModulePathMap, &result) } return result.String(), nil } @@ -232,7 +251,7 @@ func platformMappingSingleProduct( defaultAppCertificateFilegroup := "//build/bazel/utils:empty_filegroup" if proptools.String(productVariables.DefaultAppCertificate) != "" { - defaultAppCertificateFilegroup = "@//" + filepath.Dir(proptools.String(productVariables.DefaultAppCertificate)) + ":android_certificate_directory" + defaultAppCertificateFilegroup = "@//" + filepath.Dir(proptools.String(productVariables.DefaultAppCertificate)) + ":generated_android_certificate_directory" } for _, suffix := range bazelPlatformSuffixes { @@ -245,6 +264,7 @@ func platformMappingSingleProduct( result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:apex_global_min_sdk_version_override=%s\n", proptools.String(productVariables.ApexGlobalMinSdkVersionOverride))) result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:binder32bit=%t\n", proptools.Bool(productVariables.Binder32bit))) result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:build_from_text_stub=%t\n", proptools.Bool(productVariables.Build_from_text_stub))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:build_broken_incorrect_partition_images=%t\n", productVariables.BuildBrokenIncorrectPartitionImages)) result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:build_id=%s\n", proptools.String(productVariables.BuildId))) result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:build_version_tags=%s\n", strings.Join(productVariables.BuildVersionTags, ","))) result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:cfi_exclude_paths=%s\n", strings.Join(productVariables.CFIExcludePaths, ","))) @@ -258,17 +278,27 @@ func platformMappingSingleProduct( result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_name=%s\n", proptools.String(productVariables.DeviceName))) result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_page_size_agnostic=%t\n", proptools.Bool(productVariables.DevicePageSizeAgnostic))) result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_product=%s\n", proptools.String(productVariables.DeviceProduct))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_platform=%s\n", label)) result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:enable_cfi=%t\n", proptools.BoolDefault(productVariables.EnableCFI, true))) result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:enforce_vintf_manifest=%t\n", proptools.Bool(productVariables.Enforce_vintf_manifest))) result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:eng=%t\n", proptools.Bool(productVariables.Eng))) result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:malloc_not_svelte=%t\n", proptools.Bool(productVariables.Malloc_not_svelte))) result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:malloc_pattern_fill_contents=%t\n", proptools.Bool(productVariables.Malloc_pattern_fill_contents))) result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:malloc_zero_contents=%t\n", proptools.Bool(productVariables.Malloc_zero_contents))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:memtag_heap_exclude_paths=%s\n", strings.Join(productVariables.MemtagHeapExcludePaths, ","))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:memtag_heap_async_include_paths=%s\n", strings.Join(productVariables.MemtagHeapAsyncIncludePaths, ","))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:memtag_heap_sync_include_paths=%s\n", strings.Join(productVariables.MemtagHeapSyncIncludePaths, ","))) result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:manifest_package_name_overrides=%s\n", strings.Join(productVariables.ManifestPackageNameOverrides, ","))) result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:native_coverage=%t\n", proptools.Bool(productVariables.Native_coverage))) result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:platform_version_name=%s\n", proptools.String(productVariables.Platform_version_name))) result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:product_brand=%s\n", productVariables.ProductBrand)) result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:product_manufacturer=%s\n", productVariables.ProductManufacturer)) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:release_aconfig_flag_default_permission=%s\n", productVariables.ReleaseAconfigFlagDefaultPermission)) + // Empty string can't be used as label_flag on the bazel side + if len(productVariables.ReleaseAconfigValueSets) > 0 { + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:release_aconfig_value_sets=%s\n", productVariables.ReleaseAconfigValueSets)) + } + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:release_version=%s\n", productVariables.ReleaseVersion)) result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:platform_sdk_version=%d\n", platform_sdk_version)) result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:safestack=%t\n", proptools.Bool(productVariables.Safestack))) result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:target_build_variant=%s\n", targetBuildVariant)) @@ -398,3 +428,36 @@ func starlarkMapToProductVariables(in map[string]starlark.Value) (android.Produc return result, nil } + +func createTargets(productLabelsToVariables map[string]*android.ProductVariables, res map[string]BazelTargets) { + createGeneratedAndroidCertificateDirectories(productLabelsToVariables, res) +} + +func createGeneratedAndroidCertificateDirectories(productLabelsToVariables map[string]*android.ProductVariables, targets map[string]BazelTargets) { + var allDefaultAppCertificateDirs []string + for _, productVariables := range productLabelsToVariables { + if proptools.String(productVariables.DefaultAppCertificate) != "" { + d := filepath.Dir(proptools.String(productVariables.DefaultAppCertificate)) + if !android.InList(d, allDefaultAppCertificateDirs) { + allDefaultAppCertificateDirs = append(allDefaultAppCertificateDirs, d) + } + } + } + for _, dir := range allDefaultAppCertificateDirs { + content := `filegroup( + name = "generated_android_certificate_directory", + srcs = glob([ + "*.pk8", + "*.pem", + "*.avbpubkey", + ]), + visibility = ["//visibility:public"], +)` + targets[dir] = append(targets[dir], BazelTarget{ + name: "generated_android_certificate_directory", + packageName: dir, + content: content, + ruleClass: "filegroup", + }) + } +} diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go index cd1bc7f19..15b77669c 100644 --- a/bp2build/build_conversion.go +++ b/bp2build/build_conversion.go @@ -39,18 +39,24 @@ type BazelAttributes struct { Attrs map[string]string } -type BazelTarget struct { - name string - packageName string - content string - ruleClass string - bzlLoadLocation string +type BazelLoadSymbol struct { + // The name of the symbol in the file being loaded + symbol string + // The name the symbol wil have in this file. Can be left blank to use the same name as symbol. + alias string } -// IsLoadedFromStarlark determines if the BazelTarget's rule class is loaded from a .bzl file, -// as opposed to a native rule built into Bazel. -func (t BazelTarget) IsLoadedFromStarlark() bool { - return t.bzlLoadLocation != "" +type BazelLoad struct { + file string + symbols []BazelLoadSymbol +} + +type BazelTarget struct { + name string + packageName string + content string + ruleClass string + loads []BazelLoad } // Label is the fully qualified Bazel label constructed from the BazelTarget's @@ -110,30 +116,62 @@ func (targets BazelTargets) String() string { // LoadStatements return the string representation of the sorted and deduplicated // Starlark rule load statements needed by a group of BazelTargets. func (targets BazelTargets) LoadStatements() string { - bzlToLoadedSymbols := map[string][]string{} + // First, merge all the load statements from all the targets onto one list + bzlToLoadedSymbols := map[string][]BazelLoadSymbol{} for _, target := range targets { - if target.IsLoadedFromStarlark() { - bzlToLoadedSymbols[target.bzlLoadLocation] = - append(bzlToLoadedSymbols[target.bzlLoadLocation], target.ruleClass) + for _, load := range target.loads { + outer: + for _, symbol := range load.symbols { + alias := symbol.alias + if alias == "" { + alias = symbol.symbol + } + for _, otherSymbol := range bzlToLoadedSymbols[load.file] { + otherAlias := otherSymbol.alias + if otherAlias == "" { + otherAlias = otherSymbol.symbol + } + if symbol.symbol == otherSymbol.symbol && alias == otherAlias { + continue outer + } else if alias == otherAlias { + panic(fmt.Sprintf("Conflicting destination (%s) for loads of %s and %s", alias, symbol.symbol, otherSymbol.symbol)) + } + } + bzlToLoadedSymbols[load.file] = append(bzlToLoadedSymbols[load.file], symbol) + } } } - var loadStatements []string - for bzl, ruleClasses := range bzlToLoadedSymbols { - loadStatement := "load(\"" - loadStatement += bzl - loadStatement += "\", " - ruleClasses = android.SortedUniqueStrings(ruleClasses) - for i, ruleClass := range ruleClasses { - loadStatement += "\"" + ruleClass + "\"" - if i != len(ruleClasses)-1 { - loadStatement += ", " + var loadStatements strings.Builder + for i, bzl := range android.SortedKeys(bzlToLoadedSymbols) { + symbols := bzlToLoadedSymbols[bzl] + loadStatements.WriteString("load(\"") + loadStatements.WriteString(bzl) + loadStatements.WriteString("\", ") + sort.Slice(symbols, func(i, j int) bool { + if symbols[i].symbol < symbols[j].symbol { + return true + } + return symbols[i].alias < symbols[j].alias + }) + for j, symbol := range symbols { + if symbol.alias != "" && symbol.alias != symbol.symbol { + loadStatements.WriteString(symbol.alias) + loadStatements.WriteString(" = ") + } + loadStatements.WriteString("\"") + loadStatements.WriteString(symbol.symbol) + loadStatements.WriteString("\"") + if j != len(symbols)-1 { + loadStatements.WriteString(", ") } } - loadStatement += ")" - loadStatements = append(loadStatements, loadStatement) + loadStatements.WriteString(")") + if i != len(bzlToLoadedSymbols)-1 { + loadStatements.WriteString("\n") + } } - return strings.Join(android.SortedUniqueStrings(loadStatements), "\n") + return loadStatements.String() } type bpToBuildContext interface { @@ -175,9 +213,6 @@ const ( // This mode is used for discovering and introspecting the existing Soong // module graph. QueryView - - // ApiBp2build - generate BUILD files for API contribution targets - ApiBp2build ) type unconvertedDepsMode int @@ -196,8 +231,6 @@ func (mode CodegenMode) String() string { return "Bp2Build" case QueryView: return "QueryView" - case ApiBp2build: - return "ApiBp2build" default: return fmt.Sprintf("%d", mode) } @@ -774,10 +807,6 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (convers errs = append(errs, err) } targets = append(targets, t) - case ApiBp2build: - if aModule, ok := m.(android.Module); ok && aModule.IsConvertedByBp2build() { - targets, errs = generateBazelTargets(bpCtx, aModule) - } default: errs = append(errs, fmt.Errorf("Unknown code-generation mode: %s", ctx.Mode())) return @@ -808,7 +837,7 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (convers for dir := range dirs { buildFileToTargets[dir] = append(buildFileToTargets[dir], BazelTarget{ name: "bp2build_all_srcs", - content: `filegroup(name = "bp2build_all_srcs", srcs = glob(["**/*"]))`, + content: `filegroup(name = "bp2build_all_srcs", srcs = glob(["**/*"]), tags = ["manual"])`, ruleClass: "filegroup", }) } @@ -866,12 +895,19 @@ func generateBazelTarget(ctx bpToBuildContext, m bp2buildModule) (BazelTarget, e } else { content = fmt.Sprintf(unnamedRuleTargetTemplate, ruleClass, attributes) } + var loads []BazelLoad + if bzlLoadLocation != "" { + loads = append(loads, BazelLoad{ + file: bzlLoadLocation, + symbols: []BazelLoadSymbol{{symbol: ruleClass}}, + }) + } return BazelTarget{ - name: targetName, - packageName: m.TargetPackage(), - ruleClass: ruleClass, - bzlLoadLocation: bzlLoadLocation, - content: content, + name: targetName, + packageName: m.TargetPackage(), + ruleClass: ruleClass, + loads: loads, + content: content, }, nil } diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go index 8ee0439c0..329c907f8 100644 --- a/bp2build/build_conversion_test.go +++ b/bp2build/build_conversion_test.go @@ -773,9 +773,12 @@ func TestLoadStatements(t *testing.T) { { bazelTargets: BazelTargets{ BazelTarget{ - name: "foo", - ruleClass: "cc_library", - bzlLoadLocation: "//build/bazel/rules:cc.bzl", + name: "foo", + ruleClass: "cc_library", + loads: []BazelLoad{{ + file: "//build/bazel/rules:cc.bzl", + symbols: []BazelLoadSymbol{{symbol: "cc_library"}}, + }}, }, }, expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_library")`, @@ -783,14 +786,20 @@ func TestLoadStatements(t *testing.T) { { bazelTargets: BazelTargets{ BazelTarget{ - name: "foo", - ruleClass: "cc_library", - bzlLoadLocation: "//build/bazel/rules:cc.bzl", + name: "foo", + ruleClass: "cc_library", + loads: []BazelLoad{{ + file: "//build/bazel/rules:cc.bzl", + symbols: []BazelLoadSymbol{{symbol: "cc_library"}}, + }}, }, BazelTarget{ - name: "bar", - ruleClass: "cc_library", - bzlLoadLocation: "//build/bazel/rules:cc.bzl", + name: "bar", + ruleClass: "cc_library", + loads: []BazelLoad{{ + file: "//build/bazel/rules:cc.bzl", + symbols: []BazelLoadSymbol{{symbol: "cc_library"}}, + }}, }, }, expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_library")`, @@ -798,14 +807,20 @@ func TestLoadStatements(t *testing.T) { { bazelTargets: BazelTargets{ BazelTarget{ - name: "foo", - ruleClass: "cc_library", - bzlLoadLocation: "//build/bazel/rules:cc.bzl", + name: "foo", + ruleClass: "cc_library", + loads: []BazelLoad{{ + file: "//build/bazel/rules:cc.bzl", + symbols: []BazelLoadSymbol{{symbol: "cc_library"}}, + }}, }, BazelTarget{ - name: "bar", - ruleClass: "cc_binary", - bzlLoadLocation: "//build/bazel/rules:cc.bzl", + name: "bar", + ruleClass: "cc_binary", + loads: []BazelLoad{{ + file: "//build/bazel/rules:cc.bzl", + symbols: []BazelLoadSymbol{{symbol: "cc_binary"}}, + }}, }, }, expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary", "cc_library")`, @@ -813,19 +828,28 @@ func TestLoadStatements(t *testing.T) { { bazelTargets: BazelTargets{ BazelTarget{ - name: "foo", - ruleClass: "cc_library", - bzlLoadLocation: "//build/bazel/rules:cc.bzl", + name: "foo", + ruleClass: "cc_library", + loads: []BazelLoad{{ + file: "//build/bazel/rules:cc.bzl", + symbols: []BazelLoadSymbol{{symbol: "cc_library"}}, + }}, }, BazelTarget{ - name: "bar", - ruleClass: "cc_binary", - bzlLoadLocation: "//build/bazel/rules:cc.bzl", + name: "bar", + ruleClass: "cc_binary", + loads: []BazelLoad{{ + file: "//build/bazel/rules:cc.bzl", + symbols: []BazelLoadSymbol{{symbol: "cc_binary"}}, + }}, }, BazelTarget{ - name: "baz", - ruleClass: "java_binary", - bzlLoadLocation: "//build/bazel/rules:java.bzl", + name: "baz", + ruleClass: "java_binary", + loads: []BazelLoad{{ + file: "//build/bazel/rules:java.bzl", + symbols: []BazelLoadSymbol{{symbol: "java_binary"}}, + }}, }, }, expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary", "cc_library") @@ -834,19 +858,25 @@ load("//build/bazel/rules:java.bzl", "java_binary")`, { bazelTargets: BazelTargets{ BazelTarget{ - name: "foo", - ruleClass: "cc_binary", - bzlLoadLocation: "//build/bazel/rules:cc.bzl", + name: "foo", + ruleClass: "cc_binary", + loads: []BazelLoad{{ + file: "//build/bazel/rules:cc.bzl", + symbols: []BazelLoadSymbol{{symbol: "cc_binary"}}, + }}, }, BazelTarget{ - name: "bar", - ruleClass: "java_binary", - bzlLoadLocation: "//build/bazel/rules:java.bzl", + name: "bar", + ruleClass: "java_binary", + loads: []BazelLoad{{ + file: "//build/bazel/rules:java.bzl", + symbols: []BazelLoadSymbol{{symbol: "java_binary"}}, + }}, }, BazelTarget{ name: "baz", ruleClass: "genrule", - // Note: no bzlLoadLocation for native rules + // Note: no loads for native rules }, }, expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary") @@ -1743,7 +1773,8 @@ func TestCommonBp2BuildModuleAttrs(t *testing.T) { Description: "Required into data test", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, - Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + ` + StubbedBuildDefinitions: []string{"reqd"}, + Blueprint: simpleModule("filegroup", "reqd") + ` filegroup { name: "fg_foo", required: ["reqd"], @@ -1759,7 +1790,8 @@ filegroup { Description: "Required into data test, cyclic self reference is filtered out", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, - Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + ` + StubbedBuildDefinitions: []string{"reqd"}, + Blueprint: simpleModule("filegroup", "reqd") + ` filegroup { name: "fg_foo", required: ["reqd", "fg_foo"], @@ -1775,8 +1807,9 @@ filegroup { Description: "Required via arch into data test", ModuleTypeUnderTest: "python_library", ModuleTypeUnderTestFactory: python.PythonLibraryFactory, - Blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqdx86") + - simpleModuleDoNotConvertBp2build("python_library", "reqdarm") + ` + StubbedBuildDefinitions: []string{"reqdx86", "reqdarm"}, + Blueprint: simpleModule("python_library", "reqdx86") + + simpleModule("python_library", "reqdarm") + ` python_library { name: "fg_foo", arch: { @@ -1809,7 +1842,8 @@ python_library { "data.bin": "", "src.py": "", }, - Blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqd") + ` + StubbedBuildDefinitions: []string{"reqd"}, + Blueprint: simpleModule("python_library", "reqd") + ` python_library { name: "fg_foo", data: ["data.bin"], @@ -1831,7 +1865,8 @@ python_library { Description: "All props-to-attrs at once together test", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, - Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + ` + StubbedBuildDefinitions: []string{"reqd"}, + Blueprint: simpleModule("filegroup", "reqd") + ` filegroup { name: "fg_foo", required: ["reqd"], @@ -1879,30 +1914,6 @@ filegroup { }) } -func TestGenerateApiBazelTargets(t *testing.T) { - bp := ` - custom { - name: "foo", - api: "foo.txt", - } - ` - expectedBazelTarget := MakeBazelTarget( - "custom_api_contribution", - "foo", - AttrNameToString{ - "api": `"foo.txt"`, - }, - ) - registerCustomModule := func(ctx android.RegistrationContext) { - ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice) - } - RunApiBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{ - Blueprint: bp, - ExpectedBazelTargets: []string{expectedBazelTarget}, - Description: "Generating API contribution Bazel targets for custom module", - }) -} - func TestGenerateConfigSetting(t *testing.T) { bp := ` custom { @@ -1950,6 +1961,69 @@ func TestPrettyPrintSelectMapEqualValues(t *testing.T) { android.AssertStringEquals(t, "Print the common value if all keys in an axis have the same value", `[":libfoo.impl"]`, actual) } +func TestAlreadyPresentBuildTarget(t *testing.T) { + bp := ` + custom { + name: "foo", + } + custom { + name: "bar", + } + ` + alreadyPresentBuildFile := + MakeBazelTarget( + "custom", + "foo", + AttrNameToString{}, + ) + expectedBazelTargets := []string{ + MakeBazelTarget( + "custom", + "bar", + AttrNameToString{}, + ), + } + registerCustomModule := func(ctx android.RegistrationContext) { + ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice) + } + RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{ + AlreadyExistingBuildContents: alreadyPresentBuildFile, + Blueprint: bp, + ExpectedBazelTargets: expectedBazelTargets, + Description: "Not duplicating work for an already-present BUILD target.", + }) +} + +// Verifies that if a module is defined in pkg1/Android.bp, that a target present +// in pkg2/BUILD.bazel does not result in the module being labeled "already defined +// in a BUILD file". +func TestBuildTargetPresentOtherDirectory(t *testing.T) { + bp := ` + custom { + name: "foo", + } + ` + expectedBazelTargets := []string{ + MakeBazelTarget( + "custom", + "foo", + AttrNameToString{}, + ), + } + registerCustomModule := func(ctx android.RegistrationContext) { + ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice) + } + RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{ + KeepBuildFileForDirs: []string{"other_pkg"}, + Filesystem: map[string]string{ + "other_pkg/BUILD.bazel": MakeBazelTarget("custom", "foo", AttrNameToString{}), + }, + Blueprint: bp, + ExpectedBazelTargets: expectedBazelTargets, + Description: "Not treating a BUILD target as the bazel definition for a module in another package", + }) +} + // If CommonAttributes.Dir is set, the bazel target should be created in that dir func TestCreateBazelTargetInDifferentDir(t *testing.T) { t.Parallel() diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go index 90db36573..c67970375 100644 --- a/bp2build/cc_binary_conversion_test.go +++ b/bp2build/cc_binary_conversion_test.go @@ -44,10 +44,11 @@ func generateBazelTargetsForTest(targets []testBazelTarget, hod android.HostOrDe } type ccBinaryBp2buildTestCase struct { - description string - filesystem map[string]string - blueprint string - targets []testBazelTarget + description string + filesystem map[string]string + blueprint string + targets []testBazelTarget + stubbedBuildDefinitions []string } func registerCcBinaryModuleTypes(ctx android.RegistrationContext) { @@ -81,6 +82,7 @@ func runCcBinaryTestCase(t *testing.T, testCase ccBinaryBp2buildTestCase) { Description: description, Blueprint: binaryReplacer.Replace(testCase.blueprint), Filesystem: testCase.filesystem, + StubbedBuildDefinitions: testCase.stubbedBuildDefinitions, }) }) } @@ -97,6 +99,7 @@ func runCcHostBinaryTestCase(t *testing.T, testCase ccBinaryBp2buildTestCase) { Description: description, Blueprint: hostBinaryReplacer.Replace(testCase.blueprint), Filesystem: testCase.filesystem, + StubbedBuildDefinitions: testCase.stubbedBuildDefinitions, }) }) } @@ -107,6 +110,7 @@ func TestBasicCcBinary(t *testing.T) { filesystem: map[string]string{ soongCcVersionLibBpPath: soongCcVersionLibBp, }, + stubbedBuildDefinitions: []string{"//build/soong/cc/libbuildversion:libbuildversion"}, blueprint: ` {rule_name} { name: "foo", @@ -264,7 +268,8 @@ func TestCcBinaryLdflagsSplitBySpaceExceptSoongAdded(t *testing.T) { func TestCcBinarySplitSrcsByLang(t *testing.T) { runCcHostBinaryTestCase(t, ccBinaryBp2buildTestCase{ - description: "split srcs by lang", + description: "split srcs by lang", + stubbedBuildDefinitions: []string{"fg_foo"}, blueprint: ` {rule_name} { name: "foo", @@ -276,7 +281,7 @@ func TestCcBinarySplitSrcsByLang(t *testing.T) { ], include_build_directory: false, } -` + simpleModuleDoNotConvertBp2build("filegroup", "fg_foo"), +` + simpleModule("filegroup", "fg_foo"), targets: []testBazelTarget{ {"cc_binary", "foo", AttrNameToString{ "srcs": `[ @@ -300,17 +305,17 @@ func TestCcBinarySplitSrcsByLang(t *testing.T) { func TestCcBinaryDoNotDistinguishBetweenDepsAndImplementationDeps(t *testing.T) { runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{ description: "no implementation deps", + stubbedBuildDefinitions: []string{"generated_hdr", "export_generated_hdr", "static_dep", "implementation_static_dep", + "whole_static_dep", "not_explicitly_exported_whole_static_dep", "shared_dep", "implementation_shared_dep"}, blueprint: ` genrule { name: "generated_hdr", cmd: "nothing to see here", - bazel_module: { bp2build_available: false }, } genrule { name: "export_generated_hdr", cmd: "nothing to see here", - bazel_module: { bp2build_available: false }, } {rule_name} { @@ -326,12 +331,12 @@ genrule { export_generated_headers: ["export_generated_hdr"], } ` + - simpleModuleDoNotConvertBp2build("cc_library_static", "static_dep") + - simpleModuleDoNotConvertBp2build("cc_library_static", "implementation_static_dep") + - simpleModuleDoNotConvertBp2build("cc_library_static", "whole_static_dep") + - simpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep") + - simpleModuleDoNotConvertBp2build("cc_library", "shared_dep") + - simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep"), + simpleModule("cc_library_static", "static_dep") + + simpleModule("cc_library_static", "implementation_static_dep") + + simpleModule("cc_library_static", "whole_static_dep") + + simpleModule("cc_library_static", "not_explicitly_exported_whole_static_dep") + + simpleModule("cc_library", "shared_dep") + + simpleModule("cc_library", "implementation_shared_dep"), targets: []testBazelTarget{ {"cc_binary", "foo", AttrNameToString{ "deps": `[ @@ -502,6 +507,7 @@ func TestCcBinaryPropertiesToFeatures(t *testing.T) { func TestCcBinarySharedProto(t *testing.T) { runCcBinaryTests(t, ccBinaryBp2buildTestCase{ + stubbedBuildDefinitions: []string{"libprotobuf-cpp-full", "libprotobuf-cpp-lite"}, blueprint: soongCcProtoLibraries + `{rule_name} { name: "foo", srcs: ["foo.proto"], @@ -524,6 +530,7 @@ func TestCcBinarySharedProto(t *testing.T) { func TestCcBinaryStaticProto(t *testing.T) { runCcBinaryTests(t, ccBinaryBp2buildTestCase{ + stubbedBuildDefinitions: []string{"libprotobuf-cpp-full", "libprotobuf-cpp-lite"}, blueprint: soongCcProtoLibraries + `{rule_name} { name: "foo", srcs: ["foo.proto"], @@ -1224,13 +1231,13 @@ func TestCCBinaryRscriptSrc(t *testing.T) { func TestCcBinaryStatic_SystemSharedLibUsedAsDep(t *testing.T) { runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{ - description: "cc_library_static system_shared_lib empty for linux_bionic variant", + stubbedBuildDefinitions: []string{"libm", "libc"}, + description: "cc_library_static system_shared_lib empty for linux_bionic variant", blueprint: soongCcLibraryStaticPreamble + - simpleModuleDoNotConvertBp2build("cc_library", "libc") + ` + simpleModule("cc_library", "libc") + ` cc_library { name: "libm", - bazel_module: { bp2build_available: false }, } cc_binary { diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go index 28dbf7ead..ec603c294 100644 --- a/bp2build/cc_library_conversion_test.go +++ b/bp2build/cc_library_conversion_test.go @@ -35,19 +35,16 @@ cc_defaults { soongCcVersionLibBp = ` cc_library_static { name: "libbuildversion", - bazel_module: { bp2build_available: false }, } ` soongCcProtoLibraries = ` cc_library { name: "libprotobuf-cpp-lite", - bazel_module: { bp2build_available: false }, } cc_library { name: "libprotobuf-cpp-full", - bazel_module: { bp2build_available: false }, }` soongCcProtoPreamble = soongCcLibraryPreamble + soongCcProtoLibraries @@ -55,6 +52,7 @@ cc_library { func runCcLibraryTestCase(t *testing.T, tc Bp2buildTestCase) { t.Helper() + tc.StubbedBuildDefinitions = append(tc.StubbedBuildDefinitions, "libprotobuf-cpp-lite", "libprotobuf-cpp-full") RunBp2BuildTestCase(t, registerCcLibraryModuleTypes, tc) } @@ -65,6 +63,7 @@ func registerCcLibraryModuleTypes(ctx android.RegistrationContext) { ctx.RegisterModuleType("cc_prebuilt_library_static", cc.PrebuiltStaticLibraryFactory) ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory) ctx.RegisterModuleType("aidl_library", aidl_library.AidlLibraryFactory) + ctx.RegisterModuleType("ndk_library", cc.NdkLibraryFactory) } func TestCcLibrarySimple(t *testing.T) { @@ -72,6 +71,7 @@ func TestCcLibrarySimple(t *testing.T) { Description: "cc_library - simple example", ModuleTypeUnderTest: "cc_library", ModuleTypeUnderTestFactory: cc.LibraryFactory, + StubbedBuildDefinitions: []string{"//build/soong/cc/libbuildversion:libbuildversion", "some-headers"}, Filesystem: map[string]string{ soongCcVersionLibBpPath: soongCcVersionLibBp, "android.cpp": "", @@ -94,7 +94,7 @@ func TestCcLibrarySimple(t *testing.T) { "foo-dir/a.h": "", }, Blueprint: soongCcLibraryPreamble + - simpleModuleDoNotConvertBp2build("cc_library_headers", "some-headers") + ` + simpleModule("cc_library_headers", "some-headers") + ` cc_library { name: "foo-lib", srcs: ["impl.cpp"], @@ -168,6 +168,7 @@ func TestCcLibraryTrimmedLdAndroid(t *testing.T) { Description: "cc_library - trimmed example of //bionic/linker:ld-android", ModuleTypeUnderTest: "cc_library", ModuleTypeUnderTestFactory: cc.LibraryFactory, + StubbedBuildDefinitions: []string{"libc_headers"}, Filesystem: map[string]string{ "ld-android.cpp": "", "linked_list.h": "", @@ -176,7 +177,7 @@ func TestCcLibraryTrimmedLdAndroid(t *testing.T) { "linker_cfi.h": "", }, Blueprint: soongCcLibraryPreamble + - simpleModuleDoNotConvertBp2build("cc_library_headers", "libc_headers") + ` + simpleModule("cc_library_headers", "libc_headers") + ` cc_library { name: "fake-ld-android", srcs: ["ld_android.cpp"], @@ -319,54 +320,49 @@ cc_library { cc_library_static { name: "static_dep_for_shared", - bazel_module: { bp2build_available: false }, } cc_library_static { name: "static_dep_for_static", - bazel_module: { bp2build_available: false }, } cc_library_static { name: "static_dep_for_both", - bazel_module: { bp2build_available: false }, } cc_library_static { name: "whole_static_lib_for_shared", - bazel_module: { bp2build_available: false }, } cc_library_static { name: "whole_static_lib_for_static", - bazel_module: { bp2build_available: false }, } cc_library_static { name: "whole_static_lib_for_both", - bazel_module: { bp2build_available: false }, } cc_library_static { name: "whole_and_static_lib_for_both", - bazel_module: { bp2build_available: false }, } cc_library { name: "shared_dep_for_shared", - bazel_module: { bp2build_available: false }, } cc_library { name: "shared_dep_for_static", - bazel_module: { bp2build_available: false }, } cc_library { name: "shared_dep_for_both", - bazel_module: { bp2build_available: false }, } `, + StubbedBuildDefinitions: []string{"static_dep_for_shared", "static_dep_for_static", + "static_dep_for_both", "whole_static_lib_for_shared", "whole_static_lib_for_static", + "whole_static_lib_for_both", "whole_and_static_lib_for_both", "shared_dep_for_shared", + "shared_dep_for_static", "shared_dep_for_both", + }, ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{ "copts": `[ @@ -457,24 +453,34 @@ cc_library { }, include_build_directory: false, } -` + simpleModuleDoNotConvertBp2build("cc_library_static", "static_dep_for_shared") + - simpleModuleDoNotConvertBp2build("cc_library_static", "implementation_static_dep_for_shared") + - simpleModuleDoNotConvertBp2build("cc_library_static", "static_dep_for_static") + - simpleModuleDoNotConvertBp2build("cc_library_static", "implementation_static_dep_for_static") + - simpleModuleDoNotConvertBp2build("cc_library_static", "static_dep_for_both") + - simpleModuleDoNotConvertBp2build("cc_library_static", "implementation_static_dep_for_both") + - simpleModuleDoNotConvertBp2build("cc_library_static", "whole_static_dep_for_shared") + - simpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep_for_shared") + - simpleModuleDoNotConvertBp2build("cc_library_static", "whole_static_dep_for_static") + - simpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep_for_static") + - simpleModuleDoNotConvertBp2build("cc_library_static", "whole_static_dep_for_both") + - simpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep_for_both") + - simpleModuleDoNotConvertBp2build("cc_library", "shared_dep_for_shared") + - simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_shared") + - simpleModuleDoNotConvertBp2build("cc_library", "shared_dep_for_static") + - simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_static") + - simpleModuleDoNotConvertBp2build("cc_library", "shared_dep_for_both") + - simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_both"), +` + simpleModule("cc_library_static", "static_dep_for_shared") + + simpleModule("cc_library_static", "implementation_static_dep_for_shared") + + simpleModule("cc_library_static", "static_dep_for_static") + + simpleModule("cc_library_static", "implementation_static_dep_for_static") + + simpleModule("cc_library_static", "static_dep_for_both") + + simpleModule("cc_library_static", "implementation_static_dep_for_both") + + simpleModule("cc_library_static", "whole_static_dep_for_shared") + + simpleModule("cc_library_static", "not_explicitly_exported_whole_static_dep_for_shared") + + simpleModule("cc_library_static", "whole_static_dep_for_static") + + simpleModule("cc_library_static", "not_explicitly_exported_whole_static_dep_for_static") + + simpleModule("cc_library_static", "whole_static_dep_for_both") + + simpleModule("cc_library_static", "not_explicitly_exported_whole_static_dep_for_both") + + simpleModule("cc_library", "shared_dep_for_shared") + + simpleModule("cc_library", "implementation_shared_dep_for_shared") + + simpleModule("cc_library", "shared_dep_for_static") + + simpleModule("cc_library", "implementation_shared_dep_for_static") + + simpleModule("cc_library", "shared_dep_for_both") + + simpleModule("cc_library", "implementation_shared_dep_for_both"), + StubbedBuildDefinitions: []string{"static_dep_for_shared", "implementation_static_dep_for_shared", + "static_dep_for_static", "implementation_static_dep_for_static", "static_dep_for_both", + "implementation_static_dep_for_both", "whole_static_dep_for_shared", + "not_explicitly_exported_whole_static_dep_for_shared", "whole_static_dep_for_static", + "not_explicitly_exported_whole_static_dep_for_static", "whole_static_dep_for_both", + "not_explicitly_exported_whole_static_dep_for_both", "shared_dep_for_shared", + "implementation_shared_dep_for_shared", "shared_dep_for_static", + "implementation_shared_dep_for_static", "shared_dep_for_both", + "implementation_shared_dep_for_both", + }, ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{ "copts": `[ @@ -549,6 +555,8 @@ func TestCcLibraryWholeStaticLibsAlwaysLink(t *testing.T) { ModuleTypeUnderTest: "cc_library", ModuleTypeUnderTestFactory: cc.LibraryFactory, Dir: "foo/bar", + StubbedBuildDefinitions: []string{"//foo/bar:prebuilt_whole_static_lib_for_shared", "//foo/bar:prebuilt_whole_static_lib_for_static", + "//foo/bar:prebuilt_whole_static_lib_for_both"}, Filesystem: map[string]string{ "foo/bar/Android.bp": ` cc_library { @@ -665,6 +673,10 @@ cc_library_static { name: "x86_dep_for_static" } cc_library_static { name: "android_dep_for_shared" } `, }, + StubbedBuildDefinitions: []string{"//foo/bar:static_dep_for_shared", "//foo/bar:static_dep_for_static", + "//foo/bar:static_dep_for_both", "//foo/bar:arm_static_dep_for_shared", "//foo/bar:arm_whole_static_dep_for_shared", + "//foo/bar:arm_shared_dep_for_shared", "//foo/bar:x86_dep_for_static", "//foo/bar:android_dep_for_shared", + }, Blueprint: soongCcLibraryPreamble, ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{ @@ -746,6 +758,7 @@ func TestCcLibrarySharedStaticPropsWithMixedSources(t *testing.T) { ModuleTypeUnderTest: "cc_library", ModuleTypeUnderTestFactory: cc.LibraryFactory, Dir: "foo/bar", + StubbedBuildDefinitions: []string{"//foo/bar:shared_filegroup", "//foo/bar:static_filegroup", "//foo/bar:both_filegroup"}, Filesystem: map[string]string{ "foo/bar/both_source.cpp": "", "foo/bar/both_source.cc": "", @@ -1017,10 +1030,10 @@ func TestCcLibrarySharedLibs(t *testing.T) { Description: "cc_library shared_libs", ModuleTypeUnderTest: "cc_library", ModuleTypeUnderTestFactory: cc.LibraryFactory, + StubbedBuildDefinitions: []string{"mylib"}, Blueprint: soongCcLibraryPreamble + ` cc_library { name: "mylib", - bazel_module: { bp2build_available: false }, } cc_library { @@ -1181,6 +1194,10 @@ func TestCcLibraryExcludeLibs(t *testing.T) { ModuleTypeUnderTest: "cc_library", ModuleTypeUnderTestFactory: cc.LibraryFactory, Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"arm_whole_static_lib_excludes", "malloc_not_svelte_whole_static_lib", + "arm_static_lib_excludes", "malloc_not_svelte_whole_static_lib_excludes", "arm_shared_lib_excludes", + "malloc_not_svelte_static_lib_excludes", "arm_shared_lib_excludes", "malloc_not_svelte_shared_lib", + }, Blueprint: soongCcLibraryStaticPreamble + ` cc_library { name: "foo_static", @@ -1222,37 +1239,30 @@ cc_library { cc_library { name: "arm_whole_static_lib_excludes", - bazel_module: { bp2build_available: false }, } cc_library { name: "malloc_not_svelte_whole_static_lib", - bazel_module: { bp2build_available: false }, } cc_library { name: "malloc_not_svelte_whole_static_lib_excludes", - bazel_module: { bp2build_available: false }, } cc_library { name: "arm_static_lib_excludes", - bazel_module: { bp2build_available: false }, } cc_library { name: "malloc_not_svelte_static_lib_excludes", - bazel_module: { bp2build_available: false }, } cc_library { name: "arm_shared_lib_excludes", - bazel_module: { bp2build_available: false }, } cc_library { name: "malloc_not_svelte_shared_lib", - bazel_module: { bp2build_available: false }, } `, ExpectedBazelTargets: makeCcLibraryTargets("foo_static", AttrNameToString{ @@ -1288,6 +1298,7 @@ func TestCcLibraryProductVariablesHeaderLibs(t *testing.T) { ModuleTypeUnderTest: "cc_library", ModuleTypeUnderTestFactory: cc.LibraryFactory, Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"malloc_not_svelte_header_lib"}, Blueprint: soongCcLibraryStaticPreamble + ` cc_library { name: "foo_static", @@ -1302,7 +1313,6 @@ cc_library { cc_library { name: "malloc_not_svelte_header_lib", - bazel_module: { bp2build_available: false }, } `, ExpectedBazelTargets: makeCcLibraryTargets("foo_static", AttrNameToString{ @@ -1812,10 +1822,10 @@ func TestCcLibrary_SystemSharedLibsLinuxBionicEmpty(t *testing.T) { Description: "cc_library system_shared_libs empty for linux_bionic variant", ModuleTypeUnderTest: "cc_library", ModuleTypeUnderTestFactory: cc.LibraryFactory, + StubbedBuildDefinitions: []string{"libc_musl"}, Blueprint: soongCcLibraryPreamble + ` cc_library { name: "libc_musl", - bazel_module: { bp2build_available: false }, } cc_library { @@ -1843,6 +1853,7 @@ func TestCcLibrary_SystemSharedLibsBionicEmpty(t *testing.T) { Description: "cc_library system_shared_libs empty for bionic variant", ModuleTypeUnderTest: "cc_library", ModuleTypeUnderTestFactory: cc.LibraryFactory, + StubbedBuildDefinitions: []string{"libc_musl"}, Blueprint: soongCcLibraryPreamble + ` cc_library { name: "libc_musl", @@ -1874,10 +1885,10 @@ func TestCcLibrary_SystemSharedLibsMuslEmpty(t *testing.T) { Description: "cc_library system_shared_lib empty for musl variant", ModuleTypeUnderTest: "cc_library", ModuleTypeUnderTestFactory: cc.LibraryFactory, + StubbedBuildDefinitions: []string{"libc_musl"}, Blueprint: soongCcLibraryPreamble + ` cc_library { name: "libc_musl", - bazel_module: { bp2build_available: false }, } cc_library { @@ -1927,14 +1938,13 @@ func TestCcLibrary_SystemSharedLibsSharedAndRoot(t *testing.T) { Description: "cc_library system_shared_libs set for shared and root", ModuleTypeUnderTest: "cc_library", ModuleTypeUnderTestFactory: cc.LibraryFactory, + StubbedBuildDefinitions: []string{"libc", "libm"}, Blueprint: soongCcLibraryPreamble + ` cc_library { name: "libc", - bazel_module: { bp2build_available: false }, } cc_library { name: "libm", - bazel_module: { bp2build_available: false }, } cc_library { @@ -2505,6 +2515,7 @@ func TestCcLibraryExternalConvertedProtoFilegroups(t *testing.T) { runCcLibraryTestCase(t, Bp2buildTestCase{ ModuleTypeUnderTest: "cc_library", ModuleTypeUnderTestFactory: cc.LibraryFactory, + StubbedBuildDefinitions: []string{"//path/to/A:a_fg_proto"}, Filesystem: map[string]string{ "path/to/A/Android.bp": ` filegroup { @@ -2548,11 +2559,12 @@ func TestCcLibraryProtoFilegroups(t *testing.T) { runCcLibraryTestCase(t, Bp2buildTestCase{ ModuleTypeUnderTest: "cc_library", ModuleTypeUnderTestFactory: cc.LibraryFactory, + StubbedBuildDefinitions: []string{"a_fg_proto", "b_protos", "c-proto-srcs", "proto-srcs-d"}, Blueprint: soongCcProtoPreamble + - simpleModuleDoNotConvertBp2build("filegroup", "a_fg_proto") + - simpleModuleDoNotConvertBp2build("filegroup", "b_protos") + - simpleModuleDoNotConvertBp2build("filegroup", "c-proto-srcs") + - simpleModuleDoNotConvertBp2build("filegroup", "proto-srcs-d") + ` + simpleModule("filegroup", "a_fg_proto") + + simpleModule("filegroup", "b_protos") + + simpleModule("filegroup", "c-proto-srcs") + + simpleModule("filegroup", "proto-srcs-d") + ` cc_library { name: "a", srcs: [":a_fg_proto"], @@ -2809,6 +2821,7 @@ func TestCcLibraryStubs(t *testing.T) { "stubs_symbol_file": `"a.map.txt"`, }) expectedBazelTargets = append(expectedBazelTargets, makeCcStubSuiteTargets("a", AttrNameToString{ + "api_surface": `"module-libapi"`, "soname": `"a.so"`, "source_library_label": `"//foo/bar:a"`, "stubs_symbol_file": `"a.map.txt"`, @@ -2839,205 +2852,6 @@ cc_library { ) } -func TestCcApiContributionsWithHdrs(t *testing.T) { - bp := ` - cc_library { - name: "libfoo", - stubs: { symbol_file: "libfoo.map.txt", versions: ["28", "29", "current"] }, - llndk: { symbol_file: "libfoo.map.txt", override_export_include_dirs: ["dir2"]}, - export_include_dirs: ["dir1"], - } - ` - expectedBazelTargets := []string{ - MakeBazelTarget( - "cc_api_library_headers", - "libfoo.module-libapi.headers", - AttrNameToString{ - "export_includes": `["dir1"]`, - }), - MakeBazelTarget( - "cc_api_library_headers", - "libfoo.vendorapi.headers", - AttrNameToString{ - "export_includes": `["dir2"]`, - }), - MakeBazelTarget( - "cc_api_contribution", - "libfoo.contribution", - AttrNameToString{ - "api": `"libfoo.map.txt"`, - "library_name": `"libfoo"`, - "api_surfaces": `[ - "module-libapi", - "vendorapi", - ]`, - "hdrs": `[ - ":libfoo.module-libapi.headers", - ":libfoo.vendorapi.headers", - ]`, - }), - } - RunApiBp2BuildTestCase(t, cc.RegisterLibraryBuildComponents, Bp2buildTestCase{ - Blueprint: bp, - Description: "cc API contributions to module-libapi and vendorapi", - ExpectedBazelTargets: expectedBazelTargets, - }) -} - -func TestCcApiSurfaceCombinations(t *testing.T) { - testCases := []struct { - bp string - expectedApi string - expectedApiSurfaces string - description string - }{ - { - bp: ` - cc_library { - name: "a", - stubs: {symbol_file: "a.map.txt"}, - }`, - expectedApi: `"a.map.txt"`, - expectedApiSurfaces: `["module-libapi"]`, - description: "Library that contributes to module-libapi", - }, - { - bp: ` - cc_library { - name: "a", - llndk: {symbol_file: "a.map.txt"}, - }`, - expectedApi: `"a.map.txt"`, - expectedApiSurfaces: `["vendorapi"]`, - description: "Library that contributes to vendorapi", - }, - { - bp: ` - cc_library { - name: "a", - llndk: {symbol_file: "a.map.txt"}, - stubs: {symbol_file: "a.map.txt"}, - }`, - expectedApi: `"a.map.txt"`, - expectedApiSurfaces: `[ - "module-libapi", - "vendorapi", - ]`, - description: "Library that contributes to module-libapi and vendorapi", - }, - } - for _, testCase := range testCases { - expectedBazelTargets := []string{ - MakeBazelTarget( - "cc_api_contribution", - "a.contribution", - AttrNameToString{ - "library_name": `"a"`, - "hdrs": `[]`, - "api": testCase.expectedApi, - "api_surfaces": testCase.expectedApiSurfaces, - }, - ), - } - RunApiBp2BuildTestCase(t, cc.RegisterLibraryBuildComponents, Bp2buildTestCase{ - Blueprint: testCase.bp, - Description: testCase.description, - ExpectedBazelTargets: expectedBazelTargets, - }) - } -} - -// llndk struct property in Soong provides users with several options to configure the exported include dirs -// Test the generated bazel targets for the different configurations -func TestCcVendorApiHeaders(t *testing.T) { - testCases := []struct { - bp string - expectedIncludes string - expectedSystemIncludes string - description string - }{ - { - bp: ` - cc_library { - name: "a", - export_include_dirs: ["include"], - export_system_include_dirs: ["base_system_include"], - llndk: { - symbol_file: "a.map.txt", - export_headers_as_system: true, - }, - } - `, - expectedIncludes: "", - expectedSystemIncludes: `[ - "base_system_include", - "include", - ]`, - description: "Headers are exported as system to API surface", - }, - { - bp: ` - cc_library { - name: "a", - export_include_dirs: ["include"], - export_system_include_dirs: ["base_system_include"], - llndk: { - symbol_file: "a.map.txt", - override_export_include_dirs: ["llndk_include"], - }, - } - `, - expectedIncludes: `["llndk_include"]`, - expectedSystemIncludes: `["base_system_include"]`, - description: "Non-system Headers are ovverriden before export to API surface", - }, - { - bp: ` - cc_library { - name: "a", - export_include_dirs: ["include"], - export_system_include_dirs: ["base_system_include"], - llndk: { - symbol_file: "a.map.txt", - override_export_include_dirs: ["llndk_include"], - export_headers_as_system: true, - }, - } - `, - expectedIncludes: "", // includes are set to nil - expectedSystemIncludes: `[ - "base_system_include", - "llndk_include", - ]`, - description: "System Headers are extended before export to API surface", - }, - } - for _, testCase := range testCases { - attrs := AttrNameToString{} - if testCase.expectedIncludes != "" { - attrs["export_includes"] = testCase.expectedIncludes - } - if testCase.expectedSystemIncludes != "" { - attrs["export_system_includes"] = testCase.expectedSystemIncludes - } - - expectedBazelTargets := []string{ - MakeBazelTarget("cc_api_library_headers", "a.vendorapi.headers", attrs), - // Create a target for cc_api_contribution target - MakeBazelTarget("cc_api_contribution", "a.contribution", AttrNameToString{ - "api": `"a.map.txt"`, - "api_surfaces": `["vendorapi"]`, - "hdrs": `[":a.vendorapi.headers"]`, - "library_name": `"a"`, - }), - } - RunApiBp2BuildTestCase(t, cc.RegisterLibraryBuildComponents, Bp2buildTestCase{ - Blueprint: testCase.bp, - ExpectedBazelTargets: expectedBazelTargets, - }) - } -} - func TestCcLibraryStubsAcrossConfigsDuplicatesRemoved(t *testing.T) { runCcLibraryTestCase(t, Bp2buildTestCase{ Description: "stub target generation of the same lib across configs should not result in duplicates", @@ -3046,11 +2860,11 @@ func TestCcLibraryStubsAcrossConfigsDuplicatesRemoved(t *testing.T) { Filesystem: map[string]string{ "bar.map.txt": "", }, + StubbedBuildDefinitions: []string{"barlib"}, Blueprint: ` cc_library { name: "barlib", stubs: { symbol_file: "bar.map.txt", versions: ["28", "29", "current"] }, - bazel_module: { bp2build_available: false }, } cc_library { name: "foolib", @@ -3066,7 +2880,6 @@ cc_library { ExpectedBazelTargets: makeCcLibraryTargets("foolib", AttrNameToString{ "implementation_dynamic_deps": `select({ "//build/bazel/rules/apex:foo": ["@api_surfaces//module-libapi/current:barlib"], - "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:barlib"], "//conditions:default": [":barlib"], })`, "local_includes": `["."]`, @@ -3082,16 +2895,15 @@ func TestCcLibraryExcludesLibsHost(t *testing.T) { Filesystem: map[string]string{ "bar.map.txt": "", }, - Blueprint: simpleModuleDoNotConvertBp2build("cc_library", "bazlib") + ` + StubbedBuildDefinitions: []string{"bazlib", "quxlib", "barlib"}, + Blueprint: simpleModule("cc_library", "bazlib") + ` cc_library { name: "quxlib", stubs: { symbol_file: "bar.map.txt", versions: ["current"] }, - bazel_module: { bp2build_available: false }, } cc_library { name: "barlib", stubs: { symbol_file: "bar.map.txt", versions: ["28", "29", "current"] }, - bazel_module: { bp2build_available: false }, } cc_library { name: "foolib", @@ -3124,10 +2936,6 @@ cc_library { "@api_surfaces//module-libapi/current:barlib", "@api_surfaces//module-libapi/current:quxlib", ], - "//build/bazel/rules/apex:system": [ - "@api_surfaces//module-libapi/current:barlib", - "@api_surfaces//module-libapi/current:quxlib", - ], "//conditions:default": [ ":barlib", ":quxlib", @@ -3209,18 +3017,18 @@ func TestCCLibraryRuntimeDeps(t *testing.T) { cc_library { name: "foo", - runtime_libs: ["foo"], + runtime_libs: ["bar"], }`, ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_shared", "bar", AttrNameToString{ "local_includes": `["."]`, }), MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{ - "runtime_deps": `[":foo"]`, + "runtime_deps": `[":bar"]`, "local_includes": `["."]`, }), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{ - "runtime_deps": `[":foo"]`, + "runtime_deps": `[":bar"]`, "local_includes": `["."]`, }), }, @@ -3431,6 +3239,7 @@ func TestCcLibraryWithNonAdjacentAidlFilegroup(t *testing.T) { Description: "cc_library with non aidl filegroup", ModuleTypeUnderTest: "cc_library", ModuleTypeUnderTestFactory: cc.LibraryFactory, + StubbedBuildDefinitions: []string{"//path/to/A:A_aidl"}, Filesystem: map[string]string{ "path/to/A/Android.bp": ` filegroup { @@ -3720,6 +3529,7 @@ func TestCcLibraryWithAidlAndLibs(t *testing.T) { Description: "cc_aidl_library depends on libs from parent cc_library_static", ModuleTypeUnderTest: "cc_library", ModuleTypeUnderTestFactory: cc.LibraryFactory, + StubbedBuildDefinitions: []string{"bar-static", "baz-static", "bar-shared", "baz-shared"}, Blueprint: ` cc_library_static { name: "foo", @@ -3741,10 +3551,10 @@ cc_library_static { "baz-shared", ], }` + - simpleModuleDoNotConvertBp2build("cc_library_static", "bar-static") + - simpleModuleDoNotConvertBp2build("cc_library_static", "baz-static") + - simpleModuleDoNotConvertBp2build("cc_library", "bar-shared") + - simpleModuleDoNotConvertBp2build("cc_library", "baz-shared"), + simpleModule("cc_library_static", "bar-static") + + simpleModule("cc_library_static", "baz-static") + + simpleModule("cc_library", "bar-shared") + + simpleModule("cc_library", "baz-shared"), ExpectedBazelTargets: []string{ MakeBazelTarget("aidl_library", "foo_aidl_library", AttrNameToString{ "srcs": `["Foo.aidl"]`, @@ -3843,8 +3653,8 @@ cc_library { { description: "cc_library with afdo enabled and existing profile", filesystem: map[string]string{ - "vendor/google_data/pgo_profile/sampling/BUILD": "", - "vendor/google_data/pgo_profile/sampling/foo.afdo": "", + "vendor/google_data/pgo_profile/sampling/Android.bp": "", + "vendor/google_data/pgo_profile/sampling/foo.afdo": "", }, expectedBazelTargets: []string{ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{}), @@ -3856,8 +3666,8 @@ cc_library { { description: "cc_library with afdo enabled and existing profile in AOSP", filesystem: map[string]string{ - "toolchain/pgo-profiles/sampling/BUILD": "", - "toolchain/pgo-profiles/sampling/foo.afdo": "", + "toolchain/pgo-profiles/sampling/Android.bp": "", + "toolchain/pgo-profiles/sampling/foo.afdo": "", }, expectedBazelTargets: []string{ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{}), @@ -3869,8 +3679,8 @@ cc_library { { description: "cc_library with afdo enabled but profile filename doesn't match with module name", filesystem: map[string]string{ - "toolchain/pgo-profiles/sampling/BUILD": "", - "toolchain/pgo-profiles/sampling/bar.afdo": "", + "toolchain/pgo-profiles/sampling/Android.bp": "", + "toolchain/pgo-profiles/sampling/bar.afdo": "", }, expectedBazelTargets: []string{ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{}), @@ -4288,17 +4098,16 @@ func TestCcLibraryInApexWithStubSharedLibs(t *testing.T) { Description: "cc_library with in apex with stub shared_libs and export_shared_lib_headers", ModuleTypeUnderTest: "cc_library", ModuleTypeUnderTestFactory: cc.LibraryFactory, + StubbedBuildDefinitions: []string{"barlib", "bazlib"}, Blueprint: ` cc_library { name: "barlib", stubs: { symbol_file: "bar.map.txt", versions: ["28", "29", "current"] }, - bazel_module: { bp2build_available: false }, apex_available: ["//apex_available:platform",], } cc_library { name: "bazlib", stubs: { symbol_file: "bar.map.txt", versions: ["28", "29", "current"] }, - bazel_module: { bp2build_available: false }, apex_available: ["//apex_available:platform",], } cc_library { @@ -4674,6 +4483,7 @@ func TestCcLibraryYaccConversion(t *testing.T) { Description: "cc_library is built from .y/.yy files", ModuleTypeUnderTest: "cc_library", ModuleTypeUnderTestFactory: cc.LibraryFactory, + StubbedBuildDefinitions: []string{"staticlib", "sharedlib"}, Blueprint: soongCcLibraryPreamble + `cc_library { name: "a", srcs: [ @@ -4690,11 +4500,9 @@ func TestCcLibraryYaccConversion(t *testing.T) { } cc_library_static { name: "staticlib", - bazel_module: { bp2build_available: false }, } cc_library { name: "sharedlib", - bazel_module: { bp2build_available: false }, } `, ExpectedBazelTargets: []string{ @@ -4948,7 +4756,7 @@ cc_library_static { canonical_path_from_root: true, } } -` + simpleModuleDoNotConvertBp2build("cc_library", "libprotobuf-cpp-lite"), +` + simpleModule("cc_library", "libprotobuf-cpp-lite"), Filesystem: map[string]string{ "bar/Android.bp": "", "baz/subbaz/Android.bp": "", @@ -4965,6 +4773,7 @@ cc_library_static { }), MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{ "srcs": `["foo.proto"]`, + "tags": `["manual"]`, }), MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{ "deps": `[ @@ -5015,7 +4824,7 @@ cc_library_static { canonical_path_from_root: false, } } -` + simpleModuleDoNotConvertBp2build("cc_library", "libprotobuf-cpp-lite"), +` + simpleModule("cc_library", "libprotobuf-cpp-lite"), Filesystem: map[string]string{ "bar/Android.bp": "", "baz/subbaz/Android.bp": "", @@ -5033,6 +4842,7 @@ cc_library_static { MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{ "srcs": `["foo.proto"]`, "strip_import_prefix": `""`, + "tags": `["manual"]`, }), MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{ "deps": `[ @@ -5084,7 +4894,7 @@ cc_library_static { include_dirs: ["bar"], } } -` + simpleModuleDoNotConvertBp2build("cc_library", "libprotobuf-cpp-lite"), +` + simpleModule("cc_library", "libprotobuf-cpp-lite"), Filesystem: map[string]string{ "bar/Android.bp": "", "bar/bar.proto": "", @@ -5103,6 +4913,7 @@ cc_library_static { }), MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{ "srcs": `["foo.proto"]`, + "tags": `["manual"]`, }), MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{ "deps": `[":foo_proto"]`, @@ -5117,7 +4928,7 @@ cc_library_static { // bar dir tc.Dir = "bar" tc.ExpectedBazelTargets = []string{ - MakeBazelTarget("proto_library", "bar.include_dir_bp2build_generated_proto", AttrNameToString{ + MakeBazelTargetNoRestrictions("proto_library", "bar.include_dir_bp2build_generated_proto", AttrNameToString{ "srcs": `["bar.proto"]`, "strip_import_prefix": `""`, "tags": `["manual"]`, @@ -5128,7 +4939,7 @@ cc_library_static { // bar/baz dir tc.Dir = "bar/baz" tc.ExpectedBazelTargets = []string{ - MakeBazelTarget("proto_library", "bar.include_dir_bp2build_generated_proto", AttrNameToString{ + MakeBazelTargetNoRestrictions("proto_library", "bar.include_dir_bp2build_generated_proto", AttrNameToString{ "srcs": `["//bar/baz:baz.proto"]`, "strip_import_prefix": `""`, "import_prefix": `"baz"`, @@ -5137,3 +4948,239 @@ cc_library_static { } runCcLibraryTestCase(t, tc) } + +func TestProtoIncludeDirsWithSrcsInMultiplePackages(t *testing.T) { + tc := Bp2buildTestCase{ + Description: "cc_library has srcs in multiple bazel packages and uses proto.include_dirs", + ModuleTypeUnderTest: "cc_library", + ModuleTypeUnderTestFactory: cc.LibraryFactory, + Blueprint: ` +cc_library_static { + name: "foo", + srcs: [ + "foo.proto", + "bar/bar.proto", + ], + proto: { + include_dirs: ["baz"], + } +} +` + simpleModule("cc_library", "libprotobuf-cpp-lite"), + Filesystem: map[string]string{ + "bar/Android.bp": "", // package boundary + "baz/Android.bp": "", + "baz/baz.proto": "", + }, + } + + tc.ExpectedBazelTargets = []string{ + MakeBazelTarget("cc_library_static", "foo", AttrNameToString{ + "local_includes": `["."]`, + "deps": `[":libprotobuf-cpp-lite"]`, + "implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`, + }), + MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{ + "srcs": `["foo.proto"]`, + "tags": `["manual"]`, + }), + MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{ + "deps": `[ + ":foo_proto", + "//bar:foo_proto", + ]`, + "transitive_deps": `["//baz:baz.include_dir_bp2build_generated_proto"]`, + }), + } + runCcLibraryTestCase(t, tc) + +} + +func TestProtoLocalIncludeDirs(t *testing.T) { + tc := Bp2buildTestCase{ + Description: "cc_library depends on .proto files using proto.local_include_dirs", + ModuleTypeUnderTest: "cc_library", + ModuleTypeUnderTestFactory: cc.LibraryFactory, + Blueprint: ` +cc_library { + name: "libprotobuf-cpp-lite", + // TODO: b/285631638 - A stubbed proto library dependency does not work as a protolib + // dependency of cc_library_static. + bazel_module: { bp2build_available: false }, +} +`, + Filesystem: map[string]string{ + "foo/Android.bp": `cc_library_static { + name: "foo", + srcs: [ + "foo.proto", + ], + proto: { + local_include_dirs: ["foo_subdir"], + }, + bazel_module: { bp2build_available: true }, +}`, + "foo/foo.proto": "", + "foo/foo_subdir/Android.bp": "", + "foo/foo_subdir/foo_subdir.proto": "", + }, + } + + // We will run the test 2 times and check in foo and foo/foo_subdir directories + // foo dir + tc.Dir = "foo" + tc.ExpectedBazelTargets = []string{ + MakeBazelTarget("cc_library_static", "foo", AttrNameToString{ + "local_includes": `["."]`, + "deps": `["//:libprotobuf-cpp-lite"]`, + "implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`, + }), + MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{ + "srcs": `["foo.proto"]`, + "tags": `["manual"]`, + }), + MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{ + "deps": `[":foo_proto"]`, + "transitive_deps": `["//foo/foo_subdir:foo.foo_subdir.include_dir_bp2build_generated_proto"]`, + }), + } + runCcLibraryTestCase(t, tc) + + // foo/foo_subdir + tc.Dir = "foo/foo_subdir" + tc.ExpectedBazelTargets = []string{ + MakeBazelTargetNoRestrictions("proto_library", "foo.foo_subdir.include_dir_bp2build_generated_proto", AttrNameToString{ + "srcs": `["foo_subdir.proto"]`, + "strip_import_prefix": `""`, + "tags": `["manual"]`, + }), + } + runCcLibraryTestCase(t, tc) +} + +// `foo_device` and `bar_host` can depend on .proto files of a specific dir, +// the dynamically generated proto_library should not have any target_compatible_with +func TestProtoLibraryForIncludeDirsIsOsAgnostic(t *testing.T) { + tc := Bp2buildTestCase{ + Description: "proto_library generated for proto.include_dirs is compatible for all axes", + ModuleTypeUnderTest: "cc_library", + ModuleTypeUnderTestFactory: cc.LibraryFactory, + Blueprint: simpleModule("cc_library", "libprotobuf-cpp-lite") + ` +cc_library { + name: "foo_device", + device_supported: true, // this is the default behavior, but added explicitly here for illustration + host_supported: false, + proto: {include_dirs: ["dir"]}, +} +cc_library { + name: "bar_host", + device_supported: false, + host_supported: true, + srcs: ["bar.proto"], + proto: {include_dirs: ["dir"]}, +} +`, + Filesystem: map[string]string{ + "dir/Android.bp": "", + "dir/dir.proto": "", + }, + Dir: "dir", // check for the generated proto_library + ExpectedBazelTargets: []string{ + MakeBazelTargetNoRestrictions("proto_library", "dir.include_dir_bp2build_generated_proto", AttrNameToString{ + "srcs": `["dir.proto"]`, + "strip_import_prefix": `""`, + "tags": `["manual"]`, + }), + }, + } + runCcLibraryTestCase(t, tc) +} + +func TestCcCompileMultilibConversion(t *testing.T) { + tc := Bp2buildTestCase{ + Description: "cc_library with compile_multilib", + ModuleTypeUnderTest: "cc_library", + ModuleTypeUnderTestFactory: cc.LibraryFactory, + Blueprint: ` +cc_library { + name: "lib32", + compile_multilib: "32", +} +cc_library { + name: "lib64", + compile_multilib: "64", +} +`, + ExpectedBazelTargets: []string{ + MakeBazelTargetNoRestrictions("cc_library_shared", "lib32", AttrNameToString{ + "local_includes": `["."]`, + "target_compatible_with": `["//build/bazel/platforms/os:android"] + select({ + "//build/bazel/platforms/arch:arm64": ["@platforms//:incompatible"], + "//build/bazel/platforms/arch:riscv64": ["@platforms//:incompatible"], + "//build/bazel/platforms/arch:x86_64": ["@platforms//:incompatible"], + "//conditions:default": [], + })`, + }), + MakeBazelTargetNoRestrictions("cc_library_static", "lib32_bp2build_cc_library_static", AttrNameToString{ + "local_includes": `["."]`, + "target_compatible_with": `["//build/bazel/platforms/os:android"] + select({ + "//build/bazel/platforms/arch:arm64": ["@platforms//:incompatible"], + "//build/bazel/platforms/arch:riscv64": ["@platforms//:incompatible"], + "//build/bazel/platforms/arch:x86_64": ["@platforms//:incompatible"], + "//conditions:default": [], + })`, + }), + MakeBazelTargetNoRestrictions("cc_library_shared", "lib64", AttrNameToString{ + "local_includes": `["."]`, + "target_compatible_with": `["//build/bazel/platforms/os:android"] + select({ + "//build/bazel/platforms/arch:arm": ["@platforms//:incompatible"], + "//build/bazel/platforms/arch:x86": ["@platforms//:incompatible"], + "//conditions:default": [], + })`, + }), + MakeBazelTargetNoRestrictions("cc_library_static", "lib64_bp2build_cc_library_static", AttrNameToString{ + "local_includes": `["."]`, + "target_compatible_with": `["//build/bazel/platforms/os:android"] + select({ + "//build/bazel/platforms/arch:arm": ["@platforms//:incompatible"], + "//build/bazel/platforms/arch:x86": ["@platforms//:incompatible"], + "//conditions:default": [], + })`, + }), + }, + } + runCcLibraryTestCase(t, tc) +} + +func TestNdkLibraryConversion(t *testing.T) { + tc := Bp2buildTestCase{ + Description: "ndk_library conversion", + ModuleTypeUnderTest: "cc_library", + ModuleTypeUnderTestFactory: cc.LibraryFactory, + Blueprint: ` +cc_library { + name: "libfoo", + bazel_module: { bp2build_available: false }, +} +ndk_library { + name: "libfoo", + first_version: "29", + symbol_file: "libfoo.map.txt", +} +`, + ExpectedBazelTargets: []string{ + MakeBazelTarget("cc_stub_suite", "libfoo.ndk_stub_libs", AttrNameToString{ + "api_surface": `"publicapi"`, + "soname": `"libfoo.so"`, + "source_library_label": `"//:libfoo"`, + "symbol_file": `"libfoo.map.txt"`, + "versions": `[ + "29", + "30", + "S", + "Tiramisu", + "current", + ]`, + }), + }, + } + runCcLibraryTestCase(t, tc) +} diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go index 072f5b3b4..fde4c973e 100644 --- a/bp2build/cc_library_headers_conversion_test.go +++ b/bp2build/cc_library_headers_conversion_test.go @@ -57,6 +57,8 @@ func TestCcLibraryHeadersLoadStatement(t *testing.T) { func registerCcLibraryHeadersModuleTypes(ctx android.RegistrationContext) { cc.RegisterCCBuildComponents(ctx) + cc.RegisterLibraryHeadersBuildComponents(ctx) + ctx.RegisterModuleType("cc_library_shared", cc.LibrarySharedFactory) } func runCcLibraryHeadersTestCase(t *testing.T, tc Bp2buildTestCase) { @@ -66,9 +68,7 @@ func runCcLibraryHeadersTestCase(t *testing.T, tc Bp2buildTestCase) { func TestCcLibraryHeadersSimple(t *testing.T) { runCcLibraryHeadersTestCase(t, Bp2buildTestCase{ - Description: "cc_library_headers test", - ModuleTypeUnderTest: "cc_library_headers", - ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory, + Description: "cc_library_headers test", Filesystem: map[string]string{ "lib-1/lib1a.h": "", "lib-1/lib1b.h": "", @@ -123,101 +123,32 @@ cc_library_headers { }) } -func TestCcApiHeaders(t *testing.T) { - fs := map[string]string{ - "bar/Android.bp": `cc_library_headers { name: "bar_headers", }`, - } - bp := ` - cc_library_headers { - name: "foo_headers", - export_include_dirs: ["dir1", "dir2"], - export_header_lib_headers: ["bar_headers"], - - arch: { - arm: { - export_include_dirs: ["dir_arm"], - }, - x86: { - export_include_dirs: ["dir_x86"], - }, - }, - - target: { - android: { - export_include_dirs: ["dir1", "dir_android"], - }, - windows: { - export_include_dirs: ["dir_windows"], - }, - } - } - ` - expectedBazelTargets := []string{ - MakeBazelTarget("cc_api_library_headers", "foo_headers.contribution.arm", AttrNameToString{ - "export_includes": `["dir_arm"]`, - "arch": `"arm"`, - }), - MakeBazelTarget("cc_api_library_headers", "foo_headers.contribution.x86", AttrNameToString{ - "export_includes": `["dir_x86"]`, - "arch": `"x86"`, - }), - MakeBazelTarget("cc_api_library_headers", "foo_headers.contribution.androidos", AttrNameToString{ - "export_includes": `["dir_android"]`, // common includes are deduped - }), - // Windows headers are not exported - MakeBazelTarget("cc_api_library_headers", "foo_headers.contribution", AttrNameToString{ - "export_includes": `[ - "dir1", - "dir2", - ]`, - "deps": `[ - "//bar:bar_headers.contribution", - ":foo_headers.contribution.arm", - ":foo_headers.contribution.x86", - ":foo_headers.contribution.androidos", - ]`, - }), - } - RunApiBp2BuildTestCase(t, cc.RegisterLibraryHeadersBuildComponents, Bp2buildTestCase{ - Blueprint: bp, - Description: "Header library contributions to API surfaces", - ExpectedBazelTargets: expectedBazelTargets, - Filesystem: fs, - }) -} - // header_libs has "variant_prepend" tag. In bp2build output, // variant info(select) should go before general info. func TestCcLibraryHeadersOsSpecificHeader(t *testing.T) { runCcLibraryHeadersTestCase(t, Bp2buildTestCase{ - Description: "cc_library_headers test with os-specific header_libs props", - ModuleTypeUnderTest: "cc_library_headers", - ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory, - Filesystem: map[string]string{}, + Description: "cc_library_headers test with os-specific header_libs props", + Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"android-lib", "base-lib", "darwin-lib", + "linux-lib", "linux_bionic-lib", "windows-lib"}, Blueprint: soongCcLibraryPreamble + ` cc_library_headers { name: "android-lib", - bazel_module: { bp2build_available: false }, } cc_library_headers { name: "base-lib", - bazel_module: { bp2build_available: false }, } cc_library_headers { name: "darwin-lib", - bazel_module: { bp2build_available: false }, } cc_library_headers { name: "linux-lib", - bazel_module: { bp2build_available: false }, } cc_library_headers { name: "linux_bionic-lib", - bazel_module: { bp2build_available: false }, } cc_library_headers { name: "windows-lib", - bazel_module: { bp2build_available: false }, } cc_library_headers { name: "foo_headers", @@ -264,18 +195,15 @@ cc_library_headers { func TestCcLibraryHeadersOsSpecficHeaderLibsExportHeaderLibHeaders(t *testing.T) { runCcLibraryHeadersTestCase(t, Bp2buildTestCase{ - Description: "cc_library_headers test with os-specific header_libs and export_header_lib_headers props", - ModuleTypeUnderTest: "cc_library_headers", - ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory, - Filesystem: map[string]string{}, + Description: "cc_library_headers test with os-specific header_libs and export_header_lib_headers props", + Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"android-lib", "exported-lib"}, Blueprint: soongCcLibraryPreamble + ` cc_library_headers { name: "android-lib", - bazel_module: { bp2build_available: false }, } cc_library_headers { name: "exported-lib", - bazel_module: { bp2build_available: false }, } cc_library_headers { name: "foo_headers", @@ -300,10 +228,8 @@ cc_library_headers { func TestCcLibraryHeadersArchAndTargetExportSystemIncludes(t *testing.T) { runCcLibraryHeadersTestCase(t, Bp2buildTestCase{ - Description: "cc_library_headers test with arch-specific and target-specific export_system_include_dirs props", - ModuleTypeUnderTest: "cc_library_headers", - ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory, - Filesystem: map[string]string{}, + Description: "cc_library_headers test with arch-specific and target-specific export_system_include_dirs props", + Filesystem: map[string]string{}, Blueprint: soongCcLibraryPreamble + `cc_library_headers { name: "foo_headers", export_system_include_dirs: [ @@ -359,9 +285,7 @@ func TestCcLibraryHeadersArchAndTargetExportSystemIncludes(t *testing.T) { func TestCcLibraryHeadersNoCrtIgnored(t *testing.T) { runCcLibraryHeadersTestCase(t, Bp2buildTestCase{ - Description: "cc_library_headers test", - ModuleTypeUnderTest: "cc_library_headers", - ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory, + Description: "cc_library_headers test", Filesystem: map[string]string{ "lib-1/lib1a.h": "", "lib-1/lib1b.h": "", @@ -392,10 +316,9 @@ cc_library_headers { func TestCcLibraryHeadersExportedStaticLibHeadersReexported(t *testing.T) { runCcLibraryHeadersTestCase(t, Bp2buildTestCase{ - Description: "cc_library_headers exported_static_lib_headers is reexported", - ModuleTypeUnderTest: "cc_library_headers", - ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory, - Filesystem: map[string]string{}, + Description: "cc_library_headers exported_static_lib_headers is reexported", + Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"foo_export"}, Blueprint: soongCcLibraryHeadersPreamble + ` cc_library_headers { name: "foo_headers", @@ -403,7 +326,7 @@ cc_library_headers { static_libs: ["foo_export", "foo_no_reexport"], bazel_module: { bp2build_available: true }, } -` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"), +` + simpleModule("cc_library_headers", "foo_export"), ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{ "deps": `[":foo_export"]`, @@ -414,10 +337,9 @@ cc_library_headers { func TestCcLibraryHeadersExportedSharedLibHeadersReexported(t *testing.T) { runCcLibraryHeadersTestCase(t, Bp2buildTestCase{ - Description: "cc_library_headers exported_shared_lib_headers is reexported", - ModuleTypeUnderTest: "cc_library_headers", - ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory, - Filesystem: map[string]string{}, + Description: "cc_library_headers exported_shared_lib_headers is reexported", + Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"foo_export"}, Blueprint: soongCcLibraryHeadersPreamble + ` cc_library_headers { name: "foo_headers", @@ -425,7 +347,7 @@ cc_library_headers { shared_libs: ["foo_export", "foo_no_reexport"], bazel_module: { bp2build_available: true }, } -` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"), +` + simpleModule("cc_library_headers", "foo_export"), ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{ "deps": `[":foo_export"]`, @@ -436,10 +358,9 @@ cc_library_headers { func TestCcLibraryHeadersExportedHeaderLibHeadersReexported(t *testing.T) { runCcLibraryHeadersTestCase(t, Bp2buildTestCase{ - Description: "cc_library_headers exported_header_lib_headers is reexported", - ModuleTypeUnderTest: "cc_library_headers", - ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory, - Filesystem: map[string]string{}, + Description: "cc_library_headers exported_header_lib_headers is reexported", + Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"foo_export"}, Blueprint: soongCcLibraryHeadersPreamble + ` cc_library_headers { name: "foo_headers", @@ -447,7 +368,7 @@ cc_library_headers { header_libs: ["foo_export", "foo_no_reexport"], bazel_module: { bp2build_available: true }, } -` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"), +` + simpleModule("cc_library_headers", "foo_export"), ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{ "deps": `[":foo_export"]`, @@ -458,17 +379,16 @@ cc_library_headers { func TestCcLibraryHeadersWholeStaticLibsReexported(t *testing.T) { runCcLibraryHeadersTestCase(t, Bp2buildTestCase{ - Description: "cc_library_headers whole_static_libs is reexported", - ModuleTypeUnderTest: "cc_library_headers", - ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory, - Filesystem: map[string]string{}, + Description: "cc_library_headers whole_static_libs is reexported", + Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"foo_export"}, Blueprint: soongCcLibraryHeadersPreamble + ` cc_library_headers { name: "foo_headers", whole_static_libs: ["foo_export"], bazel_module: { bp2build_available: true }, } -` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"), +` + simpleModule("cc_library_headers", "foo_export"), ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{ "deps": `[":foo_export"]`, @@ -476,3 +396,89 @@ cc_library_headers { }, }) } + +func TestPrebuiltCcLibraryHeadersWholeStaticLibsReexported(t *testing.T) { + runCcLibraryHeadersTestCase(t, Bp2buildTestCase{ + Description: "cc_library_headers whole_static_libs is reexported", + Filesystem: map[string]string{ + "foo/bar/Android.bp": simpleModule("cc_library_headers", "foo_headers"), + }, + StubbedBuildDefinitions: []string{"foo_export"}, + Blueprint: soongCcLibraryHeadersPreamble + ` +cc_prebuilt_library_headers { + name: "foo_headers", + whole_static_libs: ["foo_export"], + bazel_module: { bp2build_available: true }, +} +` + simpleModule("cc_library_headers", "foo_export"), + ExpectedBazelTargets: []string{ + MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{ + "deps": `[":foo_export"]`, + }), + }, + }) +} + +func TestPrebuiltCcLibraryHeadersPreferredRdepUpdated(t *testing.T) { + runCcLibraryHeadersTestCase(t, Bp2buildTestCase{ + Description: "cc_library_headers prebuilt preferred is used as rdep", + StubbedBuildDefinitions: []string{"foo_export"}, + Filesystem: map[string]string{ + "foo/bar/Android.bp": simpleModule("cc_library_headers", "foo_headers"), + }, + Blueprint: soongCcLibraryHeadersPreamble + ` +cc_prebuilt_library_headers { + name: "foo_headers", + whole_static_libs: ["foo_export"], + bazel_module: { bp2build_available: true }, + prefer: true, +} + +cc_library_shared { + name: "foo", + header_libs: ["foo_headers"], + include_build_directory: false, +} +` + simpleModule("cc_library_headers", "foo_export"), + ExpectedBazelTargets: []string{ + MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{ + "deps": `[":foo_export"]`, + }), + MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{ + "implementation_deps": `[":foo_headers"]`, + }), + }, + }) +} + +func TestPrebuiltCcLibraryHeadersRdepUpdated(t *testing.T) { + runCcLibraryHeadersTestCase(t, Bp2buildTestCase{ + Description: "cc_library_headers not preferred is not used for rdep", + StubbedBuildDefinitions: []string{"foo_export"}, + Filesystem: map[string]string{ + "foo/bar/Android.bp": simpleModule("cc_library_headers", "foo_headers"), + }, + Blueprint: soongCcLibraryHeadersPreamble + ` +cc_prebuilt_library_headers { + name: "foo_headers", + whole_static_libs: ["foo_export"], + bazel_module: { bp2build_available: true }, + prefer: false, +} + +cc_library_shared { + name: "foo", + header_libs: ["foo_headers"], + include_build_directory: false, +} +` + simpleModule("cc_library_headers", "foo_export"), + ExpectedBazelTargets: []string{ + MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{ + "deps": `[":foo_export"]`, + }), + MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{ + "implementation_deps": `["//foo/bar:foo_headers"]`, + }), + }, + }) +} diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go index 90b13b03f..345c22632 100644 --- a/bp2build/cc_library_shared_conversion_test.go +++ b/bp2build/cc_library_shared_conversion_test.go @@ -32,11 +32,13 @@ func registerCcLibrarySharedModuleTypes(ctx android.RegistrationContext) { ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory) ctx.RegisterModuleType("cc_library_static", cc.LibraryStaticFactory) ctx.RegisterModuleType("cc_library", cc.LibraryFactory) + ctx.RegisterModuleType("ndk_library", cc.NdkLibraryFactory) } func runCcLibrarySharedTestCase(t *testing.T, tc Bp2buildTestCase) { t.Helper() t.Parallel() + tc.StubbedBuildDefinitions = append(tc.StubbedBuildDefinitions, "libbuildversion", "libprotobuf-cpp-lite", "libprotobuf-cpp-full") (&tc).ModuleTypeUnderTest = "cc_library_shared" (&tc).ModuleTypeUnderTestFactory = cc.LibrarySharedFactory RunBp2BuildTestCase(t, registerCcLibrarySharedModuleTypes, tc) @@ -44,7 +46,8 @@ func runCcLibrarySharedTestCase(t *testing.T, tc Bp2buildTestCase) { func TestCcLibrarySharedSimple(t *testing.T) { runCcLibrarySharedTestCase(t, Bp2buildTestCase{ - Description: "cc_library_shared simple overall test", + Description: "cc_library_shared simple overall test", + StubbedBuildDefinitions: []string{"header_lib_1", "header_lib_2", "whole_static_lib_1", "whole_static_lib_2", "shared_lib_1", "shared_lib_2"}, Filesystem: map[string]string{ // NOTE: include_dir headers *should not* appear in Bazel hdrs later (?) "include_dir_1/include_dir_1_a.h": "", @@ -69,37 +72,31 @@ func TestCcLibrarySharedSimple(t *testing.T) { cc_library_headers { name: "header_lib_1", export_include_dirs: ["header_lib_1"], - bazel_module: { bp2build_available: false }, } cc_library_headers { name: "header_lib_2", export_include_dirs: ["header_lib_2"], - bazel_module: { bp2build_available: false }, } cc_library_shared { name: "shared_lib_1", srcs: ["shared_lib_1.cc"], - bazel_module: { bp2build_available: false }, } cc_library_shared { name: "shared_lib_2", srcs: ["shared_lib_2.cc"], - bazel_module: { bp2build_available: false }, } cc_library_static { name: "whole_static_lib_1", srcs: ["whole_static_lib_1.cc"], - bazel_module: { bp2build_available: false }, } cc_library_static { name: "whole_static_lib_2", srcs: ["whole_static_lib_2.cc"], - bazel_module: { bp2build_available: false }, } cc_library_shared { @@ -185,16 +182,15 @@ cc_library_shared { func TestCcLibrarySharedArchSpecificSharedLib(t *testing.T) { runCcLibrarySharedTestCase(t, Bp2buildTestCase{ - Description: "cc_library_shared arch-specific shared_libs with whole_static_libs", - Filesystem: map[string]string{}, + Description: "cc_library_shared arch-specific shared_libs with whole_static_libs", + Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"static_dep", "shared_dep"}, Blueprint: soongCcLibrarySharedPreamble + ` cc_library_static { name: "static_dep", - bazel_module: { bp2build_available: false }, } cc_library_shared { name: "shared_dep", - bazel_module: { bp2build_available: false }, } cc_library_shared { name: "foo_shared", @@ -218,12 +214,12 @@ cc_library_shared { func TestCcLibrarySharedOsSpecificSharedLib(t *testing.T) { runCcLibrarySharedTestCase(t, Bp2buildTestCase{ - Description: "cc_library_shared os-specific shared_libs", - Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"shared_dep"}, + Description: "cc_library_shared os-specific shared_libs", + Filesystem: map[string]string{}, Blueprint: soongCcLibrarySharedPreamble + ` cc_library_shared { name: "shared_dep", - bazel_module: { bp2build_available: false }, } cc_library_shared { name: "foo_shared", @@ -243,20 +239,18 @@ cc_library_shared { func TestCcLibrarySharedBaseArchOsSpecificSharedLib(t *testing.T) { runCcLibrarySharedTestCase(t, Bp2buildTestCase{ - Description: "cc_library_shared base, arch, and os-specific shared_libs", - Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"shared_dep", "shared_dep2", "shared_dep3"}, + Description: "cc_library_shared base, arch, and os-specific shared_libs", + Filesystem: map[string]string{}, Blueprint: soongCcLibrarySharedPreamble + ` cc_library_shared { name: "shared_dep", - bazel_module: { bp2build_available: false }, } cc_library_shared { name: "shared_dep2", - bazel_module: { bp2build_available: false }, } cc_library_shared { name: "shared_dep3", - bazel_module: { bp2build_available: false }, } cc_library_shared { name: "foo_shared", @@ -511,6 +505,7 @@ func TestCcLibrarySharedUseVersionLib(t *testing.T) { Filesystem: map[string]string{ soongCcVersionLibBpPath: soongCcVersionLibBp, }, + StubbedBuildDefinitions: []string{"//build/soong/cc/libbuildversion:libbuildversion"}, Blueprint: soongCcProtoPreamble + `cc_library_shared { name: "foo", use_version_lib: true, @@ -543,6 +538,7 @@ cc_library_shared { }, Blueprint: soongCcLibraryPreamble, ExpectedBazelTargets: []string{makeCcStubSuiteTargets("a", AttrNameToString{ + "api_surface": `"module-libapi"`, "soname": `"a.so"`, "source_library_label": `"//foo/bar:a"`, "stubs_symbol_file": `"a.map.txt"`, @@ -564,11 +560,11 @@ func TestCcLibrarySharedStubs_UseImplementationInSameApex(t *testing.T) { Description: "cc_library_shared stubs", ModuleTypeUnderTest: "cc_library_shared", ModuleTypeUnderTestFactory: cc.LibrarySharedFactory, + StubbedBuildDefinitions: []string{"a"}, Blueprint: soongCcLibrarySharedPreamble + ` cc_library_shared { name: "a", stubs: { symbol_file: "a.map.txt", versions: ["28", "29", "current"] }, - bazel_module: { bp2build_available: false }, include_build_directory: false, apex_available: ["made_up_apex"], } @@ -593,11 +589,11 @@ func TestCcLibrarySharedStubs_UseStubsInDifferentApex(t *testing.T) { Description: "cc_library_shared stubs", ModuleTypeUnderTest: "cc_library_shared", ModuleTypeUnderTestFactory: cc.LibrarySharedFactory, + StubbedBuildDefinitions: []string{"a"}, Blueprint: soongCcLibrarySharedPreamble + ` cc_library_shared { name: "a", stubs: { symbol_file: "a.map.txt", versions: ["28", "29", "current"] }, - bazel_module: { bp2build_available: false }, include_build_directory: false, apex_available: ["apex_a"], } @@ -627,19 +623,18 @@ func TestCcLibrarySharedStubs_UseStubsFromMultipleApiDomains(t *testing.T) { Description: "cc_library_shared stubs", ModuleTypeUnderTest: "cc_library_shared", ModuleTypeUnderTestFactory: cc.LibrarySharedFactory, + StubbedBuildDefinitions: []string{"libplatform_stable", "libapexfoo_stable"}, Blueprint: soongCcLibrarySharedPreamble + ` cc_library_shared { name: "libplatform_stable", stubs: { symbol_file: "libplatform_stable.map.txt", versions: ["28", "29", "current"] }, apex_available: ["//apex_available:platform"], - bazel_module: { bp2build_available: false }, include_build_directory: false, } cc_library_shared { name: "libapexfoo_stable", stubs: { symbol_file: "libapexfoo_stable.map.txt", versions: ["28", "29", "current"] }, apex_available: ["apexfoo"], - bazel_module: { bp2build_available: false }, include_build_directory: false, } cc_library_shared { @@ -661,7 +656,7 @@ cc_library_shared { ":libapexfoo_stable", ], "//build/bazel/rules/apex:system": [ - "@api_surfaces//module-libapi/current:libplatform_stable", + ":libplatform_stable", "@api_surfaces//module-libapi/current:libapexfoo_stable", ], "//conditions:default": [ @@ -684,11 +679,11 @@ func TestCcLibrarySharedStubs_IgnorePlatformAvailable(t *testing.T) { Description: "cc_library_shared stubs", ModuleTypeUnderTest: "cc_library_shared", ModuleTypeUnderTestFactory: cc.LibrarySharedFactory, + StubbedBuildDefinitions: []string{"a"}, Blueprint: soongCcLibrarySharedPreamble + ` cc_library_shared { name: "a", stubs: { symbol_file: "a.map.txt", versions: ["28", "29", "current"] }, - bazel_module: { bp2build_available: false }, include_build_directory: false, apex_available: ["//apex_available:platform", "apex_a"], } @@ -720,11 +715,11 @@ func TestCcLibraryDoesNotDropStubDepIfNoVariationAcrossAxis(t *testing.T) { Description: "cc_library depeends on impl for all configurations", ModuleTypeUnderTest: "cc_library_shared", ModuleTypeUnderTestFactory: cc.LibrarySharedFactory, + StubbedBuildDefinitions: []string{"a"}, Blueprint: soongCcLibrarySharedPreamble + ` cc_library_shared { name: "a", stubs: { symbol_file: "a.map.txt", versions: ["28", "29", "current"] }, - bazel_module: { bp2build_available: false }, apex_available: ["//apex_available:platform"], } cc_library_shared { @@ -747,11 +742,11 @@ func TestCcLibrarySharedStubs_MultipleApexAvailable(t *testing.T) { runCcLibrarySharedTestCase(t, Bp2buildTestCase{ ModuleTypeUnderTest: "cc_library_shared", ModuleTypeUnderTestFactory: cc.LibrarySharedFactory, + StubbedBuildDefinitions: []string{"a"}, Blueprint: soongCcLibrarySharedPreamble + ` cc_library_shared { name: "a", stubs: { symbol_file: "a.map.txt", versions: ["28", "29", "current"] }, - bazel_module: { bp2build_available: false }, include_build_directory: false, apex_available: ["//apex_available:platform", "apex_a", "apex_b"], } @@ -929,14 +924,14 @@ func TestCCLibrarySharedRuntimeDeps(t *testing.T) { cc_library_shared { name: "foo", - runtime_libs: ["foo"], + runtime_libs: ["bar"], }`, ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_shared", "bar", AttrNameToString{ "local_includes": `["."]`, }), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{ - "runtime_deps": `[":foo"]`, + "runtime_deps": `[":bar"]`, "local_includes": `["."]`, }), }, @@ -1442,6 +1437,7 @@ cc_library_shared { `, ExpectedBazelTargets: []string{ makeCcStubSuiteTargets("a", AttrNameToString{ + "api_surface": `"module-libapi"`, "soname": `"a.so"`, "source_library_label": `"//:a"`, "stubs_symbol_file": `"a.map.txt"`, @@ -1456,6 +1452,7 @@ cc_library_shared { "stubs_symbol_file": `"a.map.txt"`, }), makeCcStubSuiteTargets("b", AttrNameToString{ + "api_surface": `"module-libapi"`, "soname": `"b.so"`, "source_library_label": `"//:b"`, "stubs_symbol_file": `"b.map.txt"`, @@ -1592,3 +1589,62 @@ cc_library_shared{ ]`, })}}) } + +func TestCcLibrarySdkVariantUsesStubs(t *testing.T) { + runCcLibrarySharedTestCase(t, Bp2buildTestCase{ + Description: "cc_library_shared stubs", + ModuleTypeUnderTest: "cc_library_shared", + ModuleTypeUnderTestFactory: cc.LibrarySharedFactory, + Blueprint: soongCcLibrarySharedPreamble + ` +cc_library_shared { + name: "libUsesSdk", + sdk_version: "current", + shared_libs: [ + "libNoStubs", + "libHasApexStubs", + "libHasApexAndNdkStubs", + ] +} +cc_library_shared { + name: "libNoStubs", + bazel_module: { bp2build_available: false }, +} +cc_library_shared { + name: "libHasApexStubs", + stubs: { symbol_file: "a.map.txt", versions: ["28", "29", "current"] }, + bazel_module: { bp2build_available: false }, + apex_available: ["apex_a"], +} +cc_library_shared { + name: "libHasApexAndNdkStubs", + stubs: { symbol_file: "b.map.txt", versions: ["28", "29", "current"] }, + bazel_module: { bp2build_available: false }, + apex_available: ["apex_b"], +} +ndk_library { + name: "libHasApexAndNdkStubs", + bazel_module: { bp2build_available: false }, +} +`, + ExpectedBazelTargets: []string{ + MakeBazelTarget("cc_library_shared", "libUsesSdk", AttrNameToString{ + "implementation_dynamic_deps": `[":libNoStubs"] + select({ + "//build/bazel/rules/apex:system": [ + "@api_surfaces//module-libapi/current:libHasApexStubs", + "@api_surfaces//module-libapi/current:libHasApexAndNdkStubs", + ], + "//build/bazel/rules/apex:unbundled_app": [ + ":libHasApexStubs", + "//.:libHasApexAndNdkStubs.ndk_stub_libs-current", + ], + "//conditions:default": [ + ":libHasApexStubs", + ":libHasApexAndNdkStubs", + ], + })`, + "local_includes": `["."]`, + "sdk_version": `"current"`, + }), + }, + }) +} diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go index 89ec8f9a7..0587aaea1 100644 --- a/bp2build/cc_library_static_conversion_test.go +++ b/bp2build/cc_library_static_conversion_test.go @@ -96,41 +96,37 @@ func TestCcLibraryStaticSimple(t *testing.T) { "implicit_include_1.h": "", "implicit_include_2.h": "", }, + StubbedBuildDefinitions: []string{"header_lib_1", "header_lib_2", + "static_lib_1", "static_lib_2", "whole_static_lib_1", "whole_static_lib_2"}, Blueprint: soongCcLibraryStaticPreamble + ` cc_library_headers { name: "header_lib_1", export_include_dirs: ["header_lib_1"], - bazel_module: { bp2build_available: false }, } cc_library_headers { name: "header_lib_2", export_include_dirs: ["header_lib_2"], - bazel_module: { bp2build_available: false }, } cc_library_static { name: "static_lib_1", srcs: ["static_lib_1.cc"], - bazel_module: { bp2build_available: false }, } cc_library_static { name: "static_lib_2", srcs: ["static_lib_2.cc"], - bazel_module: { bp2build_available: false }, } cc_library_static { name: "whole_static_lib_1", srcs: ["whole_static_lib_1.cc"], - bazel_module: { bp2build_available: false }, } cc_library_static { name: "whole_static_lib_2", srcs: ["whole_static_lib_2.cc"], - bazel_module: { bp2build_available: false }, } cc_library_static { @@ -392,16 +388,15 @@ cc_library_static { func TestCcLibraryStaticArchSpecificStaticLib(t *testing.T) { runCcLibraryStaticTestCase(t, Bp2buildTestCase{ - Description: "cc_library_static arch-specific static_libs", - Filesystem: map[string]string{}, + Description: "cc_library_static arch-specific static_libs", + Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"static_dep", "static_dep2"}, Blueprint: soongCcLibraryStaticPreamble + ` cc_library_static { name: "static_dep", - bazel_module: { bp2build_available: false }, } cc_library_static { name: "static_dep2", - bazel_module: { bp2build_available: false }, } cc_library_static { name: "foo_static", @@ -425,16 +420,15 @@ cc_library_static { func TestCcLibraryStaticOsSpecificStaticLib(t *testing.T) { runCcLibraryStaticTestCase(t, Bp2buildTestCase{ - Description: "cc_library_static os-specific static_libs", - Filesystem: map[string]string{}, + Description: "cc_library_static os-specific static_libs", + Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"static_dep", "static_dep2"}, Blueprint: soongCcLibraryStaticPreamble + ` cc_library_static { name: "static_dep", - bazel_module: { bp2build_available: false }, } cc_library_static { name: "static_dep2", - bazel_module: { bp2build_available: false }, } cc_library_static { name: "foo_static", @@ -460,22 +454,20 @@ func TestCcLibraryStaticBaseArchOsSpecificStaticLib(t *testing.T) { runCcLibraryStaticTestCase(t, Bp2buildTestCase{ Description: "cc_library_static base, arch and os-specific static_libs", Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"static_dep", "static_dep2", "static_dep3", + "static_dep4"}, Blueprint: soongCcLibraryStaticPreamble + ` cc_library_static { name: "static_dep", - bazel_module: { bp2build_available: false }, } cc_library_static { name: "static_dep2", - bazel_module: { bp2build_available: false }, } cc_library_static { name: "static_dep3", - bazel_module: { bp2build_available: false }, } cc_library_static { name: "static_dep4", - bazel_module: { bp2build_available: false }, } cc_library_static { name: "foo_static", @@ -756,12 +748,12 @@ cc_library_static { func TestCcLibraryStaticMultipleDepSameName(t *testing.T) { runCcLibraryStaticTestCase(t, Bp2buildTestCase{ - Description: "cc_library_static multiple dep same name panic", - Filesystem: map[string]string{}, + Description: "cc_library_static multiple dep same name panic", + Filesystem: map[string]string{}, + StubbedBuildDefinitions: []string{"static_dep"}, Blueprint: soongCcLibraryStaticPreamble + ` cc_library_static { name: "static_dep", - bazel_module: { bp2build_available: false }, } cc_library_static { name: "foo_static", @@ -961,17 +953,16 @@ cc_library_static { func TestCcLibraryStaticGeneratedHeadersAllPartitions(t *testing.T) { runCcLibraryStaticTestCase(t, Bp2buildTestCase{ + StubbedBuildDefinitions: []string{"generated_hdr", "export_generated_hdr"}, Blueprint: soongCcLibraryStaticPreamble + ` genrule { name: "generated_hdr", cmd: "nothing to see here", - bazel_module: { bp2build_available: false }, } genrule { name: "export_generated_hdr", cmd: "nothing to see here", - bazel_module: { bp2build_available: false }, } cc_library_static { @@ -1005,19 +996,18 @@ cc_library_static { func TestCcLibraryStaticGeneratedHeadersMultipleExports(t *testing.T) { runCcLibraryStaticTestCase(t, Bp2buildTestCase{ + StubbedBuildDefinitions: []string{"generated_hdr", "export_generated_hdr"}, Blueprint: soongCcLibraryStaticPreamble + ` genrule { name: "generated_hdr", cmd: "nothing to see here", export_include_dirs: ["foo", "bar"], - bazel_module: { bp2build_available: false }, } genrule { name: "export_generated_hdr", cmd: "nothing to see here", export_include_dirs: ["a", "b"], - bazel_module: { bp2build_available: false }, } cc_library_static { @@ -1040,22 +1030,26 @@ cc_library_static { func TestCcLibraryStaticArchSrcsExcludeSrcsGeneratedFiles(t *testing.T) { runCcLibraryStaticTestCase(t, Bp2buildTestCase{ Description: "cc_library_static arch srcs/exclude_srcs with generated files", + StubbedBuildDefinitions: []string{"//dep:generated_src_other_pkg", "//dep:generated_hdr_other_pkg", + "//dep:generated_src_other_pkg_x86", "//dep:generated_hdr_other_pkg_x86", "//dep:generated_hdr_other_pkg_android", + "generated_src", "generated_src_not_x86", "generated_src_android", "generated_hdr", + }, Filesystem: map[string]string{ "common.cpp": "", "for-x86.cpp": "", "not-for-x86.cpp": "", "not-for-everything.cpp": "", - "dep/Android.bp": simpleModuleDoNotConvertBp2build("genrule", "generated_src_other_pkg") + - simpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg") + - simpleModuleDoNotConvertBp2build("genrule", "generated_src_other_pkg_x86") + - simpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg_x86") + - simpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg_android"), + "dep/Android.bp": simpleModule("genrule", "generated_src_other_pkg") + + simpleModule("genrule", "generated_hdr_other_pkg") + + simpleModule("genrule", "generated_src_other_pkg_x86") + + simpleModule("genrule", "generated_hdr_other_pkg_x86") + + simpleModule("genrule", "generated_hdr_other_pkg_android"), }, Blueprint: soongCcLibraryStaticPreamble + - simpleModuleDoNotConvertBp2build("genrule", "generated_src") + - simpleModuleDoNotConvertBp2build("genrule", "generated_src_not_x86") + - simpleModuleDoNotConvertBp2build("genrule", "generated_src_android") + - simpleModuleDoNotConvertBp2build("genrule", "generated_hdr") + ` + simpleModule("genrule", "generated_src") + + simpleModule("genrule", "generated_src_not_x86") + + simpleModule("genrule", "generated_src_android") + + simpleModule("genrule", "generated_hdr") + ` cc_library_static { name: "foo_static", srcs: ["common.cpp", "not-for-*.cpp"], @@ -1340,11 +1334,11 @@ cc_library_static { func TestStaticLibrary_SystemSharedLibsBionicEmpty(t *testing.T) { runCcLibraryStaticTestCase(t, Bp2buildTestCase{ - Description: "cc_library_static system_shared_lib empty for bionic variant", + Description: "cc_library_static system_shared_lib empty for bionic variant", + StubbedBuildDefinitions: []string{"libc_musl"}, Blueprint: soongCcLibraryStaticPreamble + ` cc_library { name: "libc_musl", - bazel_module: { bp2build_available: false }, } cc_library_static { @@ -1374,11 +1368,11 @@ func TestStaticLibrary_SystemSharedLibsLinuxBionicEmpty(t *testing.T) { // only for linux_bionic, but `android` had `["libc", "libdl", "libm"]. // b/195791252 tracks the fix. runCcLibraryStaticTestCase(t, Bp2buildTestCase{ - Description: "cc_library_static system_shared_lib empty for linux_bionic variant", + Description: "cc_library_static system_shared_lib empty for linux_bionic variant", + StubbedBuildDefinitions: []string{"libc_musl"}, Blueprint: soongCcLibraryStaticPreamble + ` cc_library { name: "libc_musl", - bazel_module: { bp2build_available: false }, } cc_library_static { @@ -1458,12 +1452,12 @@ cc_library_static { func TestStaticLibrary_SystemSharedLibsBionic(t *testing.T) { runCcLibraryStaticTestCase(t, Bp2buildTestCase{ - Description: "cc_library_static system_shared_libs set for bionic variant", + Description: "cc_library_static system_shared_libs set for bionic variant", + StubbedBuildDefinitions: []string{"libc", "libc_musl"}, Blueprint: soongCcLibraryStaticPreamble + - simpleModuleDoNotConvertBp2build("cc_library", "libc") + ` + simpleModule("cc_library", "libc") + ` cc_library { name: "libc_musl", - bazel_module: { bp2build_available: false }, } cc_library_static { @@ -1491,13 +1485,13 @@ cc_library_static { func TestStaticLibrary_SystemSharedLibsLinuxRootAndLinuxBionic(t *testing.T) { runCcLibraryStaticTestCase(t, Bp2buildTestCase{ - Description: "cc_library_static system_shared_libs set for root and linux_bionic variant", + Description: "cc_library_static system_shared_libs set for root and linux_bionic variant", + StubbedBuildDefinitions: []string{"libc", "libm", "libc_musl"}, Blueprint: soongCcLibraryStaticPreamble + - simpleModuleDoNotConvertBp2build("cc_library", "libc") + - simpleModuleDoNotConvertBp2build("cc_library", "libm") + ` + simpleModule("cc_library", "libc") + + simpleModule("cc_library", "libm") + ` cc_library { name: "libc_musl", - bazel_module: { bp2build_available: false }, } cc_library_static { @@ -1525,9 +1519,10 @@ cc_library_static { func TestCcLibrarystatic_SystemSharedLibUsedAsDep(t *testing.T) { runCcLibraryStaticTestCase(t, Bp2buildTestCase{ - Description: "cc_library_static system_shared_lib empty for linux_bionic variant", + Description: "cc_library_static system_shared_lib empty for linux_bionic variant", + StubbedBuildDefinitions: []string{"libc", "libm"}, Blueprint: soongCcLibraryStaticPreamble + - simpleModuleDoNotConvertBp2build("cc_library", "libc") + ` + simpleModule("cc_library", "libc") + ` cc_library { name: "libm", @@ -1535,7 +1530,6 @@ cc_library { symbol_file: "libm.map.txt", versions: ["current"], }, - bazel_module: { bp2build_available: false }, apex_available: ["com.android.runtime"], } @@ -1613,6 +1607,7 @@ cc_library_static { func TestCcLibraryStaticProto(t *testing.T) { runCcLibraryStaticTestCase(t, Bp2buildTestCase{ + StubbedBuildDefinitions: []string{"libprotobuf-cpp-full", "libprotobuf-cpp-lite"}, Blueprint: soongCcProtoPreamble + `cc_library_static { name: "foo", srcs: ["foo.proto"], @@ -1639,6 +1634,7 @@ func TestCcLibraryStaticUseVersionLib(t *testing.T) { Filesystem: map[string]string{ soongCcVersionLibBpPath: soongCcVersionLibBp, }, + StubbedBuildDefinitions: []string{"//build/soong/cc/libbuildversion:libbuildversion", "libprotobuf-cpp-full", "libprotobuf-cpp-lite"}, Blueprint: soongCcProtoPreamble + `cc_library_static { name: "foo", use_version_lib: true, @@ -1658,6 +1654,8 @@ func TestCcLibraryStaticUseVersionLibHasDep(t *testing.T) { Filesystem: map[string]string{ soongCcVersionLibBpPath: soongCcVersionLibBp, }, + StubbedBuildDefinitions: []string{"//build/soong/cc/libbuildversion:libbuildversion", "libprotobuf-cpp-full", "libprotobuf-cpp-lite"}, + Blueprint: soongCcProtoPreamble + `cc_library_static { name: "foo", use_version_lib: true, @@ -1674,6 +1672,7 @@ func TestCcLibraryStaticUseVersionLibHasDep(t *testing.T) { func TestCcLibraryStaticStdInFlags(t *testing.T) { runCcLibraryStaticTestCase(t, Bp2buildTestCase{ + StubbedBuildDefinitions: []string{"libprotobuf-cpp-full", "libprotobuf-cpp-lite"}, Blueprint: soongCcProtoPreamble + `cc_library_static { name: "foo", cflags: ["-std=candcpp"], @@ -1767,14 +1766,14 @@ func TestCCLibraryStaticRuntimeDeps(t *testing.T) { cc_library_static { name: "foo", - runtime_libs: ["foo"], + runtime_libs: ["bar"], }`, ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_shared", "bar", AttrNameToString{ "local_includes": `["."]`, }), MakeBazelTarget("cc_library_static", "foo", AttrNameToString{ - "runtime_deps": `[":foo"]`, + "runtime_deps": `[":bar"]`, "local_includes": `["."]`, }), }, @@ -2260,6 +2259,7 @@ func TestCcLibraryWithProtoInGeneratedSrcs(t *testing.T) { Description: "cc_library with a .proto file generated from a genrule", ModuleTypeUnderTest: "cc_library_static", ModuleTypeUnderTestFactory: cc.LibraryStaticFactory, + StubbedBuildDefinitions: []string{"libprotobuf-cpp-lite"}, Blueprint: soongCcLibraryPreamble + ` cc_library_static { name: "mylib", @@ -2269,7 +2269,7 @@ genrule { name: "myprotogen", out: ["myproto.proto"], } -` + simpleModuleDoNotConvertBp2build("cc_library", "libprotobuf-cpp-lite"), +` + simpleModule("cc_library", "libprotobuf-cpp-lite"), ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_static", "mylib", AttrNameToString{ "local_includes": `["."]`, diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go index ecfcb5a93..e1e2f43d7 100644 --- a/bp2build/cc_object_conversion_test.go +++ b/bp2build/cc_object_conversion_test.go @@ -317,7 +317,8 @@ func TestCcObjectLinkerScript(t *testing.T) { func TestCcObjectDepsAndLinkerScriptSelects(t *testing.T) { runCcObjectTestCase(t, Bp2buildTestCase{ - Description: "cc_object setting deps and linker_script across archs", + Description: "cc_object setting deps and linker_script across archs", + StubbedBuildDefinitions: []string{"x86_obj", "x86_64_obj", "arm_obj"}, Blueprint: `cc_object { name: "foo", srcs: ["base.cpp"], @@ -343,7 +344,6 @@ cc_object { system_shared_libs: [], srcs: ["x86.cpp"], include_build_directory: false, - bazel_module: { bp2build_available: false }, } cc_object { @@ -351,7 +351,6 @@ cc_object { system_shared_libs: [], srcs: ["x86_64.cpp"], include_build_directory: false, - bazel_module: { bp2build_available: false }, } cc_object { @@ -359,7 +358,6 @@ cc_object { system_shared_libs: [], srcs: ["arm.cpp"], include_build_directory: false, - bazel_module: { bp2build_available: false }, } `, ExpectedBazelTargets: []string{ diff --git a/bp2build/cc_prebuilt_library_conversion_test.go b/bp2build/cc_prebuilt_library_conversion_test.go index b88960e0e..8c33be3c9 100644 --- a/bp2build/cc_prebuilt_library_conversion_test.go +++ b/bp2build/cc_prebuilt_library_conversion_test.go @@ -17,6 +17,7 @@ import ( "fmt" "testing" + "android/soong/android" "android/soong/cc" ) @@ -360,3 +361,52 @@ cc_prebuilt_library { }, }) } + +func TestPrebuiltNdkStlConversion(t *testing.T) { + registerNdkStlModuleTypes := func(ctx android.RegistrationContext) { + ctx.RegisterModuleType("ndk_prebuilt_static_stl", cc.NdkPrebuiltStaticStlFactory) + ctx.RegisterModuleType("ndk_prebuilt_shared_stl", cc.NdkPrebuiltSharedStlFactory) + } + RunBp2BuildTestCase(t, registerNdkStlModuleTypes, Bp2buildTestCase{ + Description: "TODO", + Blueprint: ` +ndk_prebuilt_static_stl { + name: "ndk_libfoo_static", + export_include_dirs: ["dir1", "dir2"], +} +ndk_prebuilt_shared_stl { + name: "ndk_libfoo_shared", + export_include_dirs: ["dir1", "dir2"], +}`, + ExpectedBazelTargets: []string{ + MakeBazelTarget("cc_prebuilt_library_static", "ndk_libfoo_static", AttrNameToString{ + "static_library": `select({ + "//build/bazel/platforms/os_arch:android_arm": "current/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libfoo_static.a", + "//build/bazel/platforms/os_arch:android_arm64": "current/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libfoo_static.a", + "//build/bazel/platforms/os_arch:android_riscv64": "current/sources/cxx-stl/llvm-libc++/libs/riscv64/libfoo_static.a", + "//build/bazel/platforms/os_arch:android_x86": "current/sources/cxx-stl/llvm-libc++/libs/x86/libfoo_static.a", + "//build/bazel/platforms/os_arch:android_x86_64": "current/sources/cxx-stl/llvm-libc++/libs/x86_64/libfoo_static.a", + "//conditions:default": None, + })`, + "export_system_includes": `[ + "dir1", + "dir2", + ]`, + }), + MakeBazelTarget("cc_prebuilt_library_shared", "ndk_libfoo_shared", AttrNameToString{ + "shared_library": `select({ + "//build/bazel/platforms/os_arch:android_arm": "current/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libfoo_shared.so", + "//build/bazel/platforms/os_arch:android_arm64": "current/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libfoo_shared.so", + "//build/bazel/platforms/os_arch:android_riscv64": "current/sources/cxx-stl/llvm-libc++/libs/riscv64/libfoo_shared.so", + "//build/bazel/platforms/os_arch:android_x86": "current/sources/cxx-stl/llvm-libc++/libs/x86/libfoo_shared.so", + "//build/bazel/platforms/os_arch:android_x86_64": "current/sources/cxx-stl/llvm-libc++/libs/x86_64/libfoo_shared.so", + "//conditions:default": None, + })`, + "export_system_includes": `[ + "dir1", + "dir2", + ]`, + }), + }, + }) +} diff --git a/bp2build/cc_test_conversion_test.go b/bp2build/cc_test_conversion_test.go index abceac844..679a36461 100644 --- a/bp2build/cc_test_conversion_test.go +++ b/bp2build/cc_test_conversion_test.go @@ -24,10 +24,11 @@ import ( ) type ccTestBp2buildTestCase struct { - description string - blueprint string - filesystem map[string]string - targets []testBazelTarget + description string + blueprint string + filesystem map[string]string + targets []testBazelTarget + stubbedBuildDefinitions []string } func registerCcTestModuleTypes(ctx android.RegistrationContext) { @@ -52,6 +53,7 @@ func runCcTestTestCase(t *testing.T, testCase ccTestBp2buildTestCase) { ModuleTypeUnderTestFactory: cc.TestFactory, Description: description, Blueprint: testCase.blueprint, + StubbedBuildDefinitions: testCase.stubbedBuildDefinitions, }) }) } @@ -59,6 +61,8 @@ func runCcTestTestCase(t *testing.T, testCase ccTestBp2buildTestCase) { func TestBasicCcTest(t *testing.T) { runCcTestTestCase(t, ccTestBp2buildTestCase{ description: "basic cc_test with commonly used attributes", + stubbedBuildDefinitions: []string{"libbuildversion", "libprotobuf-cpp-lite", "libprotobuf-cpp-full", + "foolib", "hostlib", "data_mod", "cc_bin", "cc_lib", "cc_test_lib2", "libgtest_main", "libgtest"}, blueprint: ` cc_test { name: "mytest", @@ -89,14 +93,14 @@ cc_test_library { host_supported: true, include_build_directory: false, } -` + simpleModuleDoNotConvertBp2build("cc_library", "foolib") + - simpleModuleDoNotConvertBp2build("cc_library_static", "hostlib") + - simpleModuleDoNotConvertBp2build("genrule", "data_mod") + - simpleModuleDoNotConvertBp2build("cc_binary", "cc_bin") + - simpleModuleDoNotConvertBp2build("cc_library", "cc_lib") + - simpleModuleDoNotConvertBp2build("cc_test_library", "cc_test_lib2") + - simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") + - simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"), +` + simpleModule("cc_library", "foolib") + + simpleModule("cc_library_static", "hostlib") + + simpleModule("genrule", "data_mod") + + simpleModule("cc_binary", "cc_bin") + + simpleModule("cc_library", "cc_lib") + + simpleModule("cc_test_library", "cc_test_lib2") + + simpleModule("cc_library_static", "libgtest_main") + + simpleModule("cc_library_static", "libgtest"), targets: []testBazelTarget{ {"cc_library_shared", "cc_test_lib1", AttrNameToString{}}, {"cc_library_static", "cc_test_lib1_bp2build_cc_library_static", AttrNameToString{}}, @@ -139,6 +143,13 @@ cc_test_library { "host_without_device", "device", ]`, + "features": `select({ + "//build/bazel/platforms/os_arch:android_arm64": [ + "memtag_heap", + "diag_memtag_heap", + ], + "//conditions:default": [], + })`, }, }, }, @@ -166,6 +177,13 @@ cc_test { "host_without_device", "device", ]`, + "features": `select({ + "//build/bazel/platforms/os_arch:android_arm64": [ + "memtag_heap", + "diag_memtag_heap", + ], + "//conditions:default": [], + })`, }, }, }, @@ -174,7 +192,8 @@ cc_test { func TestCcTest_TestOptions_Tags(t *testing.T) { runCcTestTestCase(t, ccTestBp2buildTestCase{ - description: "cc test with test_options.tags converted to tags", + description: "cc test with test_options.tags converted to tags", + stubbedBuildDefinitions: []string{"libgtest_main", "libgtest"}, blueprint: ` cc_test { name: "mytest", @@ -182,8 +201,8 @@ cc_test { srcs: ["test.cpp"], test_options: { tags: ["no-remote"] }, } -` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") + - simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"), +` + simpleModule("cc_library_static", "libgtest_main") + + simpleModule("cc_library_static", "libgtest"), targets: []testBazelTarget{ {"cc_test", "mytest", AttrNameToString{ "tags": `["no-remote"]`, @@ -197,6 +216,13 @@ cc_test { "host_without_device", "device", ]`, + "features": `select({ + "//build/bazel/platforms/os_arch:android_arm64": [ + "memtag_heap", + "diag_memtag_heap", + ], + "//conditions:default": [], + })`, }, }, }, @@ -209,14 +235,15 @@ func TestCcTest_TestConfig(t *testing.T) { filesystem: map[string]string{ "test_config.xml": "", }, + stubbedBuildDefinitions: []string{"libgtest_main", "libgtest"}, blueprint: ` cc_test { name: "mytest", srcs: ["test.cpp"], test_config: "test_config.xml", } -` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") + - simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"), +` + simpleModule("cc_library_static", "libgtest_main") + + simpleModule("cc_library_static", "libgtest"), targets: []testBazelTarget{ {"cc_test", "mytest", AttrNameToString{ "local_includes": `["."]`, @@ -228,6 +255,13 @@ cc_test { ":libgtest", ]`, "runs_on": `["device"]`, + "features": `select({ + "//build/bazel/platforms/os_arch:android_arm64": [ + "memtag_heap", + "diag_memtag_heap", + ], + "//conditions:default": [], + })`, }, }, }, @@ -238,26 +272,36 @@ func TestCcTest_TestConfigAndroidTestXML(t *testing.T) { runCcTestTestCase(t, ccTestBp2buildTestCase{ description: "cc test that defaults to test config AndroidTest.xml", filesystem: map[string]string{ - "AndroidTest.xml": "", + "AndroidTest.xml": "", + "DynamicConfig.xml": "", }, + stubbedBuildDefinitions: []string{"libgtest_main", "libgtest"}, blueprint: ` cc_test { name: "mytest", srcs: ["test.cpp"], } -` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") + - simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"), +` + simpleModule("cc_library_static", "libgtest_main") + + simpleModule("cc_library_static", "libgtest"), targets: []testBazelTarget{ {"cc_test", "mytest", AttrNameToString{ "local_includes": `["."]`, "srcs": `["test.cpp"]`, "target_compatible_with": `["//build/bazel/platforms/os:android"]`, "test_config": `"AndroidTest.xml"`, + "dynamic_config": `"DynamicConfig.xml"`, "deps": `[ ":libgtest_main", ":libgtest", ]`, "runs_on": `["device"]`, + "features": `select({ + "//build/bazel/platforms/os_arch:android_arm64": [ + "memtag_heap", + "diag_memtag_heap", + ], + "//conditions:default": [], + })`, }, }, }, @@ -270,6 +314,7 @@ func TestCcTest_TestConfigTemplateOptions(t *testing.T) { filesystem: map[string]string{ "test_config_template.xml": "", }, + stubbedBuildDefinitions: []string{"libgtest_isolated_main", "liblog"}, blueprint: ` cc_test { name: "mytest", @@ -278,8 +323,8 @@ cc_test { auto_gen_config: true, isolated: true, } -` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_isolated_main") + - simpleModuleDoNotConvertBp2build("cc_library", "liblog"), +` + simpleModule("cc_library_static", "libgtest_isolated_main") + + simpleModule("cc_library", "liblog"), targets: []testBazelTarget{ {"cc_test", "mytest", AttrNameToString{ "auto_generate_test_config": "True", @@ -295,6 +340,13 @@ cc_test { "deps": `[":libgtest_isolated_main"]`, "dynamic_deps": `[":liblog"]`, "runs_on": `["device"]`, + "features": `select({ + "//build/bazel/platforms/os_arch:android_arm64": [ + "memtag_heap", + "diag_memtag_heap", + ], + "//conditions:default": [], + })`, }, }, }, @@ -303,15 +355,16 @@ cc_test { func TestCcTest_WithExplicitGTestDepInAndroidBp(t *testing.T) { runCcTestTestCase(t, ccTestBp2buildTestCase{ - description: "cc test that lists libgtest in Android.bp should not have dups of libgtest in BUILD file", + description: "cc test that lists libgtest in Android.bp should not have dups of libgtest in BUILD file", + stubbedBuildDefinitions: []string{"libgtest_main", "libgtest"}, blueprint: ` cc_test { name: "mytest", srcs: ["test.cpp"], static_libs: ["libgtest"], } -` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") + - simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"), +` + simpleModule("cc_library_static", "libgtest_main") + + simpleModule("cc_library_static", "libgtest"), targets: []testBazelTarget{ {"cc_test", "mytest", AttrNameToString{ "local_includes": `["."]`, @@ -322,6 +375,13 @@ cc_test { ":libgtest_main", ]`, "runs_on": `["device"]`, + "features": `select({ + "//build/bazel/platforms/os_arch:android_arm64": [ + "memtag_heap", + "diag_memtag_heap", + ], + "//conditions:default": [], + })`, }, }, }, @@ -331,15 +391,16 @@ cc_test { func TestCcTest_WithIsolatedTurnedOn(t *testing.T) { runCcTestTestCase(t, ccTestBp2buildTestCase{ - description: "cc test that sets `isolated: true` should run with ligtest_isolated_main instead of libgtest_main", + description: "cc test that sets `isolated: true` should run with ligtest_isolated_main instead of libgtest_main", + stubbedBuildDefinitions: []string{"libgtest_isolated_main", "liblog"}, blueprint: ` cc_test { name: "mytest", srcs: ["test.cpp"], isolated: true, } -` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_isolated_main") + - simpleModuleDoNotConvertBp2build("cc_library", "liblog"), +` + simpleModule("cc_library_static", "libgtest_isolated_main") + + simpleModule("cc_library", "liblog"), targets: []testBazelTarget{ {"cc_test", "mytest", AttrNameToString{ "local_includes": `["."]`, @@ -348,6 +409,13 @@ cc_test { "deps": `[":libgtest_isolated_main"]`, "dynamic_deps": `[":liblog"]`, "runs_on": `["device"]`, + "features": `select({ + "//build/bazel/platforms/os_arch:android_arm64": [ + "memtag_heap", + "diag_memtag_heap", + ], + "//conditions:default": [], + })`, }, }, }, @@ -357,7 +425,8 @@ cc_test { func TestCcTest_GtestExplicitlySpecifiedInAndroidBp(t *testing.T) { runCcTestTestCase(t, ccTestBp2buildTestCase{ - description: "If `gtest` is explicit in Android.bp, it should be explicit in BUILD files as well", + description: "If `gtest` is explicit in Android.bp, it should be explicit in BUILD files as well", + stubbedBuildDefinitions: []string{"libgtest_main", "libgtest"}, blueprint: ` cc_test { name: "mytest_with_gtest", @@ -367,8 +436,8 @@ cc_test { name: "mytest_with_no_gtest", gtest: false, } -` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") + - simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"), +` + simpleModule("cc_library_static", "libgtest_main") + + simpleModule("cc_library_static", "libgtest"), targets: []testBazelTarget{ {"cc_test", "mytest_with_gtest", AttrNameToString{ "local_includes": `["."]`, @@ -379,6 +448,13 @@ cc_test { "gtest": "True", "target_compatible_with": `["//build/bazel/platforms/os:android"]`, "runs_on": `["device"]`, + "features": `select({ + "//build/bazel/platforms/os_arch:android_arm64": [ + "memtag_heap", + "diag_memtag_heap", + ], + "//conditions:default": [], + })`, }, }, {"cc_test", "mytest_with_no_gtest", AttrNameToString{ @@ -386,6 +462,170 @@ cc_test { "gtest": "False", "target_compatible_with": `["//build/bazel/platforms/os:android"]`, "runs_on": `["device"]`, + "features": `select({ + "//build/bazel/platforms/os_arch:android_arm64": [ + "memtag_heap", + "diag_memtag_heap", + ], + "//conditions:default": [], + })`, + }, + }, + }, + }) +} + +func TestCcTest_DisableMemtagHeap(t *testing.T) { + runCcTestTestCase(t, ccTestBp2buildTestCase{ + description: "cc test that disable memtag_heap", + stubbedBuildDefinitions: []string{"libgtest_isolated_main", "liblog"}, + blueprint: ` +cc_test { + name: "mytest", + srcs: ["test.cpp"], + isolated: true, + sanitize: { + cfi: true, + memtag_heap: false, + }, +} +` + simpleModule("cc_library_static", "libgtest_isolated_main") + + simpleModule("cc_library", "liblog"), + targets: []testBazelTarget{ + {"cc_test", "mytest", AttrNameToString{ + "local_includes": `["."]`, + "srcs": `["test.cpp"]`, + "target_compatible_with": `["//build/bazel/platforms/os:android"]`, + "deps": `[":libgtest_isolated_main"]`, + "dynamic_deps": `[":liblog"]`, + "runs_on": `["device"]`, + "features": `["android_cfi"] + select({ + "//build/bazel/platforms/os_arch:android_arm64": ["-memtag_heap"], + "//conditions:default": [], + })`, + }, + }, + }, + }) +} + +func TestCcTest_RespectArm64MemtagHeap(t *testing.T) { + runCcTestTestCase(t, ccTestBp2buildTestCase{ + description: "cc test that disable memtag_heap", + stubbedBuildDefinitions: []string{"libgtest_isolated_main", "liblog"}, + blueprint: ` +cc_test { + name: "mytest", + srcs: ["test.cpp"], + isolated: true, + target: { + android_arm64: { + sanitize: { + memtag_heap: false, + } + } + }, +} +` + simpleModule("cc_library_static", "libgtest_isolated_main") + + simpleModule("cc_library", "liblog"), + targets: []testBazelTarget{ + {"cc_test", "mytest", AttrNameToString{ + "local_includes": `["."]`, + "srcs": `["test.cpp"]`, + "target_compatible_with": `["//build/bazel/platforms/os:android"]`, + "deps": `[":libgtest_isolated_main"]`, + "dynamic_deps": `[":liblog"]`, + "runs_on": `["device"]`, + "features": `select({ + "//build/bazel/platforms/os_arch:android_arm64": ["-memtag_heap"], + "//conditions:default": [], + })`, + }, + }, + }, + }) +} + +func TestCcTest_IgnoreNoneArm64MemtagHeap(t *testing.T) { + runCcTestTestCase(t, ccTestBp2buildTestCase{ + description: "cc test that disable memtag_heap", + stubbedBuildDefinitions: []string{"libgtest_isolated_main", "liblog"}, + blueprint: ` +cc_test { + name: "mytest", + srcs: ["test.cpp"], + isolated: true, + arch: { + x86: { + sanitize: { + memtag_heap: false, + } + } + }, +} +` + simpleModule("cc_library_static", "libgtest_isolated_main") + + simpleModule("cc_library", "liblog"), + targets: []testBazelTarget{ + {"cc_test", "mytest", AttrNameToString{ + "local_includes": `["."]`, + "srcs": `["test.cpp"]`, + "target_compatible_with": `["//build/bazel/platforms/os:android"]`, + "deps": `[":libgtest_isolated_main"]`, + "dynamic_deps": `[":liblog"]`, + "runs_on": `["device"]`, + "features": `select({ + "//build/bazel/platforms/os_arch:android_arm64": [ + "memtag_heap", + "diag_memtag_heap", + ], + "//conditions:default": [], + })`, + }, + }, + }, + }) +} + +func TestCcTest_Arm64MemtagHeapOverrideNoConfigOne(t *testing.T) { + runCcTestTestCase(t, ccTestBp2buildTestCase{ + description: "cc test that disable memtag_heap", + stubbedBuildDefinitions: []string{"libgtest_isolated_main", "liblog"}, + blueprint: ` +cc_test { + name: "mytest", + srcs: ["test.cpp"], + isolated: true, + sanitize: { + memtag_heap: true, + }, + target: { + android_arm64: { + sanitize: { + memtag_heap: false, + diag: { + memtag_heap: false, + }, + } + } + }, +} +` + simpleModule("cc_library_static", "libgtest_isolated_main") + + simpleModule("cc_library", "liblog"), + targets: []testBazelTarget{ + {"cc_test", "mytest", AttrNameToString{ + "local_includes": `["."]`, + "srcs": `["test.cpp"]`, + "target_compatible_with": `["//build/bazel/platforms/os:android"]`, + "deps": `[":libgtest_isolated_main"]`, + "dynamic_deps": `[":liblog"]`, + "runs_on": `["device"]`, + "features": `select({ + "//build/bazel/platforms/os_arch:android_arm64": [ + "-memtag_heap", + "-diag_memtag_heap", + ], + "//conditions:default": [], + })`, }, }, }, diff --git a/bp2build/conversion.go b/bp2build/conversion.go index f28092431..c69723587 100644 --- a/bp2build/conversion.go +++ b/bp2build/conversion.go @@ -12,8 +12,10 @@ import ( "android/soong/cc" cc_config "android/soong/cc/config" java_config "android/soong/java/config" + rust_config "android/soong/rust/config" "android/soong/starlark_fmt" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) @@ -23,20 +25,35 @@ type BazelFile struct { Contents string } -// PRIVATE: Use CreateSoongInjectionDirFiles instead -func soongInjectionFiles(cfg android.Config, metrics CodegenMetrics) ([]BazelFile, error) { +// createSoongInjectionDirFiles returns most of the files to write to the soong_injection directory. +// Some other files also come from CreateProductConfigFiles +func createSoongInjectionDirFiles(ctx *CodegenContext, metrics CodegenMetrics) ([]BazelFile, error) { + cfg := ctx.Config() var files []BazelFile files = append(files, newFile("android", GeneratedBuildFileName, "")) // Creates a //cc_toolchain package. files = append(files, newFile("android", "constants.bzl", android.BazelCcToolchainVars(cfg))) + // Visit all modules to determine the list of ndk libraries + // This list will be used to add additional flags for cc stub generation + ndkLibsStringFormatted := []string{} + ctx.Context().VisitAllModules(func(m blueprint.Module) { + if ctx.Context().ModuleType(m) == "ndk_library" { + ndkLibsStringFormatted = append(ndkLibsStringFormatted, fmt.Sprintf(`"%s"`, m.Name())) // name will be `"libc.ndk"` + } + }) + files = append(files, newFile("cc_toolchain", GeneratedBuildFileName, "")) // Creates a //cc_toolchain package. files = append(files, newFile("cc_toolchain", "config_constants.bzl", cc_config.BazelCcToolchainVars(cfg))) files = append(files, newFile("cc_toolchain", "sanitizer_constants.bzl", cc.BazelCcSanitizerToolchainVars(cfg))) + files = append(files, newFile("cc_toolchain", "ndk_libs.bzl", fmt.Sprintf("ndk_libs = [%v]", strings.Join(ndkLibsStringFormatted, ", ")))) files = append(files, newFile("java_toolchain", GeneratedBuildFileName, "")) // Creates a //java_toolchain package. files = append(files, newFile("java_toolchain", "constants.bzl", java_config.BazelJavaToolchainVars(cfg))) + files = append(files, newFile("rust_toolchain", GeneratedBuildFileName, "")) // Creates a //rust_toolchain package. + files = append(files, newFile("rust_toolchain", "constants.bzl", rust_config.BazelRustToolchainVars(cfg))) + files = append(files, newFile("apex_toolchain", GeneratedBuildFileName, "")) // Creates a //apex_toolchain package. apexToolchainVars, err := apex.BazelApexToolchainVars() if err != nil { @@ -44,7 +61,11 @@ func soongInjectionFiles(cfg android.Config, metrics CodegenMetrics) ([]BazelFil } files = append(files, newFile("apex_toolchain", "constants.bzl", apexToolchainVars)) - files = append(files, newFile("metrics", "converted_modules.txt", strings.Join(metrics.Serialize().ConvertedModules, "\n"))) + if buf, err := json.MarshalIndent(metrics.convertedModuleWithType, "", " "); err != nil { + return []BazelFile{}, err + } else { + files = append(files, newFile("metrics", "converted_modules.json", string(buf))) + } convertedModulePathMap, err := json.MarshalIndent(metrics.convertedModulePathMap, "", "\t") if err != nil { @@ -137,7 +158,7 @@ func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) targets.sort() var content string - if mode == Bp2Build || mode == ApiBp2build { + if mode == Bp2Build { content = `# READ THIS FIRST: # This file was automatically generated by bp2build for the Bazel migration project. # Feel free to edit or test it, but do *not* check it into your version control system. diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go index 15284ce03..6b100772c 100644 --- a/bp2build/conversion_test.go +++ b/bp2build/conversion_test.go @@ -83,7 +83,8 @@ func TestCreateBazelFiles_QueryView_AddsTopLevelFiles(t *testing.T) { func TestCreateBazelFiles_Bp2Build_CreatesDefaultFiles(t *testing.T) { testConfig := android.TestConfig("", make(map[string]string), "", make(map[string][]byte)) - files, err := soongInjectionFiles(testConfig, CreateCodegenMetrics()) + codegenCtx := NewCodegenContext(testConfig, android.NewTestContext(testConfig).Context, Bp2Build, "") + files, err := createSoongInjectionDirFiles(codegenCtx, CreateCodegenMetrics()) if err != nil { t.Error(err) } @@ -106,6 +107,10 @@ func TestCreateBazelFiles_Bp2Build_CreatesDefaultFiles(t *testing.T) { }, { dir: "cc_toolchain", + basename: "ndk_libs.bzl", + }, + { + dir: "cc_toolchain", basename: "sanitizer_constants.bzl", }, { @@ -117,6 +122,14 @@ func TestCreateBazelFiles_Bp2Build_CreatesDefaultFiles(t *testing.T) { basename: "constants.bzl", }, { + dir: "rust_toolchain", + basename: GeneratedBuildFileName, + }, + { + dir: "rust_toolchain", + basename: "constants.bzl", + }, + { dir: "apex_toolchain", basename: GeneratedBuildFileName, }, @@ -126,7 +139,7 @@ func TestCreateBazelFiles_Bp2Build_CreatesDefaultFiles(t *testing.T) { }, { dir: "metrics", - basename: "converted_modules.txt", + basename: "converted_modules.json", }, { dir: "metrics", @@ -174,15 +187,45 @@ func TestCreateBazelFiles_Bp2Build_CreatesDefaultFiles(t *testing.T) { }, } - if len(files) != len(expectedFilePaths) { - t.Errorf("Expected %d file, got %d", len(expectedFilePaths), len(files)) + less := func(a bazelFilepath, b bazelFilepath) bool { + return a.dir+"/"+a.basename < b.dir+"/"+b.basename } - for i := range files { - actualFile, expectedFile := files[i], expectedFilePaths[i] + fileToFilepath := func(a BazelFile) bazelFilepath { + return bazelFilepath{basename: a.Basename, dir: a.Dir} + } - if actualFile.Dir != expectedFile.dir || actualFile.Basename != expectedFile.basename { - t.Errorf("Did not find expected file %s/%s", actualFile.Dir, actualFile.Basename) + sort.Slice(expectedFilePaths, func(i, j int) bool { + return less(expectedFilePaths[i], expectedFilePaths[j]) + }) + sort.Slice(files, func(i, j int) bool { + return less(fileToFilepath(files[i]), fileToFilepath(files[j])) + }) + + i := 0 + j := 0 + for i < len(expectedFilePaths) && j < len(files) { + expectedFile, actualFile := expectedFilePaths[i], files[j] + + if actualFile.Dir == expectedFile.dir && actualFile.Basename == expectedFile.basename { + i++ + j++ + } else if less(expectedFile, fileToFilepath(actualFile)) { + t.Errorf("Did not find expected file %s/%s", expectedFile.dir, expectedFile.basename) + i++ + } else { + t.Errorf("Found unexpected file %s/%s", actualFile.Dir, actualFile.Basename) + j++ } } + for i < len(expectedFilePaths) { + expectedFile := expectedFilePaths[i] + t.Errorf("Did not find expected file %s/%s", expectedFile.dir, expectedFile.basename) + i++ + } + for j < len(files) { + actualFile := files[j] + t.Errorf("Found unexpected file %s/%s", actualFile.Dir, actualFile.Basename) + j++ + } } diff --git a/bp2build/droiddoc_exported_dir_conversion_test.go b/bp2build/droiddoc_exported_dir_conversion_test.go new file mode 100644 index 000000000..dee67f4ed --- /dev/null +++ b/bp2build/droiddoc_exported_dir_conversion_test.go @@ -0,0 +1,60 @@ +// Copyright 2023 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 ( + "regexp" + "testing" + + "android/soong/java" +) + +func TestDroiddocExportedDir(t *testing.T) { + bp := ` + droiddoc_exported_dir { + name: "test-module", + path: "docs", + } + ` + p := regexp.MustCompile(`\t*\|`) + dedent := func(s string) string { + return p.ReplaceAllString(s, "") + } + expectedBazelTargets := []string{ + MakeBazelTargetNoRestrictions( + "droiddoc_exported_dir", + "test-module", + AttrNameToString{ + "dir": `"docs"`, + "srcs": dedent(`[ + | "docs/android/1.txt", + | "docs/android/nested-1/2.txt", + | "//docs/android/nested-2:3.txt", + | "//docs/android/nested-2:Android.bp", + | ]`), + }), + //note we are not excluding Android.bp files from subpackages for now + } + RunBp2BuildTestCase(t, java.RegisterDocsBuildComponents, Bp2buildTestCase{ + Blueprint: bp, + ExpectedBazelTargets: expectedBazelTargets, + Filesystem: map[string]string{ + "docs/android/1.txt": "", + "docs/android/nested-1/2.txt": "", + "docs/android/nested-2/Android.bp": "", + "docs/android/nested-2/3.txt": "", + }, + }) +} diff --git a/bp2build/droidstubs_conversion_test.go b/bp2build/droidstubs_conversion_test.go deleted file mode 100644 index 12c1cfe32..000000000 --- a/bp2build/droidstubs_conversion_test.go +++ /dev/null @@ -1,104 +0,0 @@ -// 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 ( - "testing" - - "android/soong/android" - "android/soong/java" -) - -func registerJavaApiModules(ctx android.RegistrationContext) { - java.RegisterSdkLibraryBuildComponents(ctx) - java.RegisterStubsBuildComponents(ctx) -} - -func TestDroidstubsApiContributions(t *testing.T) { - bp := ` - droidstubs { - name: "framework-stubs", - check_api: { - current: { - api_file: "framework.current.txt", - }, - }, - } - - // Modules without check_api should not generate a Bazel API target - droidstubs { - name: "framework-docs", - } - - // java_sdk_library is a macro that creates droidstubs - java_sdk_library { - name: "module-stubs", - srcs: ["A.java"], - - // These api surfaces are added by default, but add them explicitly to make - // this test hermetic - public: { - enabled: true, - }, - system: { - enabled: true, - }, - - // Disable other api surfaces to keep unit test scope limited - module_lib: { - enabled: false, - }, - test: { - enabled: false, - }, - } - ` - expectedBazelTargets := []string{ - MakeBazelTargetNoRestrictions( - "java_api_contribution", - "framework-stubs.contribution", - AttrNameToString{ - "api": `"framework.current.txt"`, - "api_surface": `"publicapi"`, - "target_compatible_with": `["//build/bazel/platforms/os:android"]`, - }), - MakeBazelTargetNoRestrictions( - "java_api_contribution", - "module-stubs.stubs.source.contribution", - AttrNameToString{ - "api": `"api/current.txt"`, - "api_surface": `"publicapi"`, - "target_compatible_with": `["//build/bazel/platforms/os:android"]`, - }), - MakeBazelTargetNoRestrictions( - "java_api_contribution", - "module-stubs.stubs.source.system.contribution", - AttrNameToString{ - "api": `"api/system-current.txt"`, - "api_surface": `"systemapi"`, - "target_compatible_with": `["//build/bazel/platforms/os:android"]`, - }), - } - RunApiBp2BuildTestCase(t, registerJavaApiModules, Bp2buildTestCase{ - Blueprint: bp, - ExpectedBazelTargets: expectedBazelTargets, - Filesystem: map[string]string{ - "api/current.txt": "", - "api/removed.txt": "", - "api/system-current.txt": "", - "api/system-removed.txt": "", - }, - }) -} diff --git a/bp2build/fdo_profile_conversion_test.go b/bp2build/fdo_profile_conversion_test.go new file mode 100644 index 000000000..4d04283ca --- /dev/null +++ b/bp2build/fdo_profile_conversion_test.go @@ -0,0 +1,85 @@ +// Copyright 2023 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 ( + "testing" + + "android/soong/android" + "android/soong/cc" +) + +func runFdoProfileTestCase(t *testing.T, tc Bp2buildTestCase) { + t.Helper() + (&tc).ModuleTypeUnderTest = "fdo_profile" + (&tc).ModuleTypeUnderTestFactory = cc.FdoProfileFactory + RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc) +} + +func TestFdoProfile(t *testing.T) { + testcases := []struct { + name string + bp string + expectedBazelAttrs AttrNameToString + }{ + { + name: "fdo_profile with arch-specific profiles", + bp: ` +fdo_profile { + name: "foo", + arch: { + arm: { + profile: "foo_arm.afdo", + }, + arm64: { + profile: "foo_arm64.afdo", + } + } +}`, + expectedBazelAttrs: AttrNameToString{ + "profile": `select({ + "//build/bazel/platforms/arch:arm": "foo_arm.afdo", + "//build/bazel/platforms/arch:arm64": "foo_arm64.afdo", + "//conditions:default": None, + })`, + }, + }, + { + name: "fdo_profile with arch-agnostic profile", + bp: ` +fdo_profile { + name: "foo", + profile: "foo.afdo", +}`, + expectedBazelAttrs: AttrNameToString{ + "profile": `"foo.afdo"`, + }, + }, + } + + for _, test := range testcases { + t.Run(test.name, func(t *testing.T) { + expectedBazelTargets := []string{ + // TODO(b/276287371): Add device-only restriction back to fdo_profile targets + MakeBazelTargetNoRestrictions("fdo_profile", "foo", test.expectedBazelAttrs), + } + runFdoProfileTestCase(t, Bp2buildTestCase{ + Description: test.name, + Blueprint: test.bp, + ExpectedBazelTargets: expectedBazelTargets, + }) + }) + } +} diff --git a/bp2build/genrule_conversion_test.go b/bp2build/genrule_conversion_test.go index 2a10a14d4..7e9b17bca 100644 --- a/bp2build/genrule_conversion_test.go +++ b/bp2build/genrule_conversion_test.go @@ -93,7 +93,6 @@ func TestGenruleCliVariableReplacement(t *testing.T) { out: ["foo_tool.out"], srcs: ["foo_tool.in"], cmd: "cp $(in) $(out)", - bazel_module: { bp2build_available: false }, } %s { @@ -124,6 +123,7 @@ func TestGenruleCliVariableReplacement(t *testing.T) { ModuleTypeUnderTestFactory: tc.factory, Blueprint: fmt.Sprintf(bp, tc.moduleType, tc.moduleType), ExpectedBazelTargets: expectedBazelTargets, + StubbedBuildDefinitions: []string{"foo.tool", "other.tool"}, }) }) } @@ -262,6 +262,7 @@ func TestGenruleLocationsAbsoluteLabel(t *testing.T) { Blueprint: fmt.Sprintf(bp, tc.moduleType), ExpectedBazelTargets: expectedBazelTargets, Filesystem: otherGenruleBp(tc.moduleType), + StubbedBuildDefinitions: []string{"//other:foo.tool"}, }) }) } @@ -326,6 +327,7 @@ func TestGenruleSrcsLocationsAbsoluteLabel(t *testing.T) { Blueprint: fmt.Sprintf(bp, tc.moduleType), ExpectedBazelTargets: expectedBazelTargets, Filesystem: otherGenruleBp(tc.moduleType), + StubbedBuildDefinitions: []string{"//other:foo.tool", "//other:other.tool"}, }) }) } @@ -390,6 +392,7 @@ func TestGenruleLocationLabelShouldSubstituteFirstToolLabel(t *testing.T) { Blueprint: fmt.Sprintf(bp, tc.moduleType), ExpectedBazelTargets: expectedBazelTargets, Filesystem: otherGenruleBp(tc.moduleType), + StubbedBuildDefinitions: []string{"//other:foo.tool", "//other:other.tool"}, }) }) } @@ -454,6 +457,7 @@ func TestGenruleLocationsLabelShouldSubstituteFirstToolLabel(t *testing.T) { Blueprint: fmt.Sprintf(bp, tc.moduleType), ExpectedBazelTargets: expectedBazelTargets, Filesystem: otherGenruleBp(tc.moduleType), + StubbedBuildDefinitions: []string{"//other:foo.tool", "//other:other.tool"}, }) }) } @@ -948,6 +952,7 @@ genrule { ModuleTypeUnderTest: "genrule", ModuleTypeUnderTestFactory: genrule.GenRuleFactory, ExpectedBazelTargets: expectedBazelTargets, + StubbedBuildDefinitions: []string{"//mynamespace/dir:mymodule"}, }) }) diff --git a/bp2build/java_binary_host_conversion_test.go b/bp2build/java_binary_host_conversion_test.go index 39e55c410..7d8ab635a 100644 --- a/bp2build/java_binary_host_conversion_test.go +++ b/bp2build/java_binary_host_conversion_test.go @@ -26,6 +26,7 @@ func runJavaBinaryHostTestCase(t *testing.T, tc Bp2buildTestCase) { t.Helper() (&tc).ModuleTypeUnderTest = "java_binary_host" (&tc).ModuleTypeUnderTestFactory = java.BinaryHostFactory + tc.StubbedBuildDefinitions = append(tc.StubbedBuildDefinitions, "//other:jni-lib-1") RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) { ctx.RegisterModuleType("cc_library_host_shared", cc.LibraryHostSharedFactory) ctx.RegisterModuleType("java_library", java.LibraryFactory) @@ -81,8 +82,9 @@ func TestJavaBinaryHost(t *testing.T) { func TestJavaBinaryHostRuntimeDeps(t *testing.T) { runJavaBinaryHostTestCase(t, Bp2buildTestCase{ - Description: "java_binary_host with srcs, exclude_srcs, jni_libs, javacflags, and manifest.", - Filesystem: testFs, + Description: "java_binary_host with srcs, exclude_srcs, jni_libs, javacflags, and manifest.", + Filesystem: testFs, + StubbedBuildDefinitions: []string{"java-dep-1"}, Blueprint: `java_binary_host { name: "java-binary-host-1", static_libs: ["java-dep-1"], @@ -93,7 +95,6 @@ func TestJavaBinaryHostRuntimeDeps(t *testing.T) { java_library { name: "java-dep-1", srcs: ["a.java"], - bazel_module: { bp2build_available: false }, } `, ExpectedBazelTargets: []string{ @@ -111,8 +112,9 @@ java_library { func TestJavaBinaryHostLibs(t *testing.T) { runJavaBinaryHostTestCase(t, Bp2buildTestCase{ - Description: "java_binary_host with srcs, libs.", - Filesystem: testFs, + Description: "java_binary_host with srcs, libs.", + Filesystem: testFs, + StubbedBuildDefinitions: []string{"prebuilt_java-lib-dep-1"}, Blueprint: `java_binary_host { name: "java-binary-host-libs", libs: ["java-lib-dep-1"], @@ -123,7 +125,6 @@ func TestJavaBinaryHostLibs(t *testing.T) { java_import_host{ name: "java-lib-dep-1", jars: ["foo.jar"], - bazel_module: { bp2build_available: false }, } `, ExpectedBazelTargets: []string{ diff --git a/bp2build/java_host_for_device_conversion_test.go b/bp2build/java_host_for_device_conversion_test.go index 448cba461..1fa712657 100644 --- a/bp2build/java_host_for_device_conversion_test.go +++ b/bp2build/java_host_for_device_conversion_test.go @@ -48,6 +48,7 @@ java_library { name: "java-lib-2", srcs: ["b.java"], bazel_module: { bp2build_available: true }, + sdk_version: "current", }`, ExpectedBazelTargets: []string{ MakeBazelTarget("java_host_for_device", "java-lib-1", AttrNameToString{ @@ -57,7 +58,8 @@ java_library { "sdk_version": `"none"`, }), MakeBazelTarget("java_library", "java-lib-2", AttrNameToString{ - "srcs": `["b.java"]`, + "srcs": `["b.java"]`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "java-lib-2"), }, diff --git a/bp2build/java_library_conversion_test.go b/bp2build/java_library_conversion_test.go index c501a7bcb..7e4e44ec8 100644 --- a/bp2build/java_library_conversion_test.go +++ b/bp2build/java_library_conversion_test.go @@ -15,7 +15,6 @@ package bp2build import ( - "fmt" "testing" "android/soong/android" @@ -42,22 +41,26 @@ func TestJavaLibrary(t *testing.T) { srcs: ["a.java", "b.java"], exclude_srcs: ["b.java"], libs: ["java-lib-2"], + sdk_version: "current", bazel_module: { bp2build_available: true }, } java_library { name: "java-lib-2", srcs: ["b.java"], + sdk_version: "current", bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{ - "srcs": `["a.java"]`, - "deps": `[":java-lib-2-neverlink"]`, + "srcs": `["a.java"]`, + "deps": `[":java-lib-2-neverlink"]`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"), MakeBazelTarget("java_library", "java-lib-2", AttrNameToString{ - "srcs": `["b.java"]`, + "srcs": `["b.java"]`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "java-lib-2"), }, @@ -66,24 +69,26 @@ java_library { func TestJavaLibraryConvertsStaticLibsToDepsAndExports(t *testing.T) { runJavaLibraryTestCase(t, Bp2buildTestCase{ + StubbedBuildDefinitions: []string{"java-lib-2", "java-lib-3"}, Blueprint: `java_library { name: "java-lib-1", srcs: ["a.java"], libs: ["java-lib-2"], static_libs: ["java-lib-3"], + sdk_version: "current", bazel_module: { bp2build_available: true }, } java_library { name: "java-lib-2", srcs: ["b.java"], - bazel_module: { bp2build_available: false }, + sdk_version: "current", } java_library { name: "java-lib-3", srcs: ["c.java"], - bazel_module: { bp2build_available: false }, + sdk_version: "current", }`, ExpectedBazelTargets: []string{ MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{ @@ -92,7 +97,8 @@ java_library { ":java-lib-2-neverlink", ":java-lib-3", ]`, - "exports": `[":java-lib-3"]`, + "exports": `[":java-lib-3"]`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"), }, @@ -101,60 +107,58 @@ java_library { func TestJavaLibraryConvertsStaticLibsToExportsIfNoSrcs(t *testing.T) { runJavaLibraryTestCase(t, Bp2buildTestCase{ + StubbedBuildDefinitions: []string{"java-lib-2"}, Blueprint: `java_library { name: "java-lib-1", static_libs: ["java-lib-2"], + sdk_version: "current", bazel_module: { bp2build_available: true }, } java_library { name: "java-lib-2", srcs: ["a.java"], - bazel_module: { bp2build_available: false }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{ - "exports": `[":java-lib-2"]`, + "exports": `[":java-lib-2"]`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"), }, }) } -func TestJavaLibraryFailsToConvertLibsWithNoSrcs(t *testing.T) { +func TestJavaLibraryFailsToConvertNoSdkVersion(t *testing.T) { runJavaLibraryTestCase(t, Bp2buildTestCase{ - ExpectedErr: fmt.Errorf("Module has direct dependencies but no sources. Bazel will not allow this."), - Blueprint: `java_library { - name: "java-lib-1", - libs: ["java-lib-2"], + Blueprint: ` +java_library { + name: "lib", bazel_module: { bp2build_available: true }, } - -java_library { - name: "java-lib-2", - srcs: ["a.java"], - bazel_module: { bp2build_available: false }, -}`, - ExpectedBazelTargets: []string{}, +`, + ExpectedBazelTargets: []string{}, // no targets expected because sdk_version is not set }) } func TestJavaLibraryPlugins(t *testing.T) { runJavaLibraryTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{ + StubbedBuildDefinitions: []string{"java-plugin-1"}, Blueprint: `java_library { name: "java-lib-1", plugins: ["java-plugin-1"], + sdk_version: "current", bazel_module: { bp2build_available: true }, } java_plugin { name: "java-plugin-1", srcs: ["a.java"], - bazel_module: { bp2build_available: false }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{ - "plugins": `[":java-plugin-1"]`, + "plugins": `[":java-plugin-1"]`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"), }, @@ -169,26 +173,33 @@ func TestJavaLibraryJavaVersion(t *testing.T) { name: "java-lib-1", srcs: ["a.java"], java_version: "11", + sdk_version: "current", }`, ExpectedBazelTargets: []string{ MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{ "srcs": `["a.java"]`, "java_version": `"11"`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTargetWithAttrs( "java_library", "java-lib-1", - AttrNameToString{"java_version": `"11"`}), + AttrNameToString{ + "java_version": `"11"`, + "sdk_version": `"current"`, + }), }, }) } func TestJavaLibraryErrorproneEnabledManually(t *testing.T) { runJavaLibraryTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{ + StubbedBuildDefinitions: []string{"plugin2"}, Blueprint: `java_library { name: "java-lib-1", srcs: ["a.java"], javacflags: ["-Xsuper-fast"], + sdk_version: "current", errorprone: { enabled: true, javacflags: ["-Xep:SpeedLimit:OFF"], @@ -198,7 +209,6 @@ func TestJavaLibraryErrorproneEnabledManually(t *testing.T) { java_plugin { name: "plugin2", srcs: ["a.java"], - bazel_module: { bp2build_available: false }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{ @@ -209,6 +219,7 @@ java_plugin { "plugins": `[":plugin2"]`, "srcs": `["a.java"]`, "errorprone_force_enable": `True`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"), }, @@ -222,6 +233,7 @@ func TestJavaLibraryErrorproneJavacflagsErrorproneDisabledByDefault(t *testing.T Blueprint: `java_library { name: "java-lib-1", srcs: ["a.java"], + sdk_version: "current", javacflags: ["-Xsuper-fast"], errorprone: { javacflags: ["-Xep:SpeedLimit:OFF"], @@ -229,8 +241,9 @@ func TestJavaLibraryErrorproneJavacflagsErrorproneDisabledByDefault(t *testing.T }`, ExpectedBazelTargets: []string{ MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{ - "javacopts": `["-Xsuper-fast"]`, - "srcs": `["a.java"]`, + "javacopts": `["-Xsuper-fast"]`, + "srcs": `["a.java"]`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"), }, @@ -243,6 +256,7 @@ func TestJavaLibraryErrorproneDisabledManually(t *testing.T) { name: "java-lib-1", srcs: ["a.java"], javacflags: ["-Xsuper-fast"], + sdk_version: "current", errorprone: { enabled: false, }, @@ -253,7 +267,8 @@ func TestJavaLibraryErrorproneDisabledManually(t *testing.T) { "-Xsuper-fast", "-XepDisableAllChecks", ]`, - "srcs": `["a.java"]`, + "srcs": `["a.java"]`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"), }, @@ -266,14 +281,15 @@ func TestJavaLibraryLogTags(t *testing.T) { ModuleTypeUnderTest: "java_library", ModuleTypeUnderTestFactory: java.LibraryFactory, Blueprint: `java_library { - name: "example_lib", - srcs: [ - "a.java", - "b.java", - "a.logtag", - "b.logtag", - ], - bazel_module: { bp2build_available: true }, + name: "example_lib", + srcs: [ + "a.java", + "b.java", + "a.logtag", + "b.logtag", + ], + sdk_version: "current", + bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("event_log_tags", "example_lib_logtags", AttrNameToString{ @@ -288,6 +304,7 @@ func TestJavaLibraryLogTags(t *testing.T) { "b.java", ":example_lib_logtags", ]`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "example_lib"), }}) @@ -301,9 +318,10 @@ func TestJavaLibraryResources(t *testing.T) { "adir/res/b.res": "", "adir/res/dir1/b.res": "", "adir/Android.bp": `java_library { - name: "java-lib-1", - java_resources: ["res/a.res", "res/b.res"], - bazel_module: { bp2build_available: true }, + name: "java-lib-1", + java_resources: ["res/a.res", "res/b.res"], + sdk_version: "current", + bazel_module: { bp2build_available: true }, }`, }, Blueprint: "", @@ -314,6 +332,7 @@ func TestJavaLibraryResources(t *testing.T) { "res/b.res", ]`, "resource_strip_prefix": `"adir"`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"), }, @@ -328,8 +347,9 @@ func TestJavaLibraryResourceDirs(t *testing.T) { "res/dir1/b.res": "", }, Blueprint: `java_library { - name: "java-lib-1", + name: "java-lib-1", java_resource_dirs: ["res"], + sdk_version: "current", }`, ExpectedBazelTargets: []string{ MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{ @@ -339,6 +359,7 @@ func TestJavaLibraryResourceDirs(t *testing.T) { "res/b.res", "res/dir1/b.res", ]`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"), }, @@ -352,14 +373,16 @@ func TestJavaLibraryResourcesExcludeDir(t *testing.T) { "res/exclude/b.res": "", }, Blueprint: `java_library { - name: "java-lib-1", + name: "java-lib-1", java_resource_dirs: ["res"], + sdk_version: "current", exclude_java_resource_dirs: ["res/exclude"], }`, ExpectedBazelTargets: []string{ MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{ "resource_strip_prefix": `"res"`, "resources": `["res/a.res"]`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"), }, @@ -374,8 +397,9 @@ func TestJavaLibraryResourcesExcludeFile(t *testing.T) { "res/dir1/exclude.res": "", }, Blueprint: `java_library { - name: "java-lib-1", + name: "java-lib-1", java_resource_dirs: ["res"], + sdk_version: "current", exclude_java_resources: ["res/dir1/exclude.res"], }`, ExpectedBazelTargets: []string{ @@ -385,24 +409,67 @@ func TestJavaLibraryResourcesExcludeFile(t *testing.T) { "res/a.res", "res/dir1/b.res", ]`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"), }, }) } -func TestJavaLibraryResourcesFailsWithMultipleDirs(t *testing.T) { +func TestJavaLibraryResourcesWithMultipleDirs(t *testing.T) { runJavaLibraryTestCase(t, Bp2buildTestCase{ Filesystem: map[string]string{ "res/a.res": "", - "res1/a.res": "", + "res1/b.res": "", }, Blueprint: `java_library { - name: "java-lib-1", + name: "java-lib-1", java_resource_dirs: ["res", "res1"], + sdk_version: "current", }`, - ExpectedErr: fmt.Errorf("bp2build does not support more than one directory in java_resource_dirs (b/226423379)"), - ExpectedBazelTargets: []string{}, + ExpectedBazelTargets: []string{ + MakeBazelTarget("java_resources", "java-lib-1_resource_dir_res1", AttrNameToString{ + "resource_strip_prefix": `"res1"`, + "resources": `["res1/b.res"]`, + }), + MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{ + "additional_resources": `["java-lib-1_resource_dir_res1"]`, + "resources": `["res/a.res"]`, + "resource_strip_prefix": `"res"`, + "sdk_version": `"current"`, + }), + MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"), + }, + }) +} + +func TestJavaLibraryJavaResourcesAndResourceDirs(t *testing.T) { + runJavaLibraryTestCase(t, Bp2buildTestCase{ + Filesystem: map[string]string{ + "resdir/a.res": "", + }, + Blueprint: `java_library { + name: "java-lib-1", + java_resources: ["res1", "res2"], + java_resource_dirs: ["resdir"], + sdk_version: "current", +}`, + ExpectedBazelTargets: []string{ + MakeBazelTarget("java_resources", "java-lib-1_resource_dir_resdir", AttrNameToString{ + "resource_strip_prefix": `"resdir"`, + "resources": `["resdir/a.res"]`, + }), + MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{ + "additional_resources": `["java-lib-1_resource_dir_resdir"]`, + "resource_strip_prefix": `"."`, + "resources": `[ + "res1", + "res2", + ]`, + "sdk_version": `"current"`, + }), + MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"), + }, }) } @@ -412,14 +479,15 @@ func TestJavaLibraryAidl(t *testing.T) { ModuleTypeUnderTest: "java_library", ModuleTypeUnderTestFactory: java.LibraryFactory, Blueprint: `java_library { - name: "example_lib", - srcs: [ - "a.java", - "b.java", - "a.aidl", - "b.aidl", - ], - bazel_module: { bp2build_available: true }, + name: "example_lib", + srcs: [ + "a.java", + "b.java", + "a.aidl", + "b.aidl", + ], + bazel_module: { bp2build_available: true }, + sdk_version: "current", }`, ExpectedBazelTargets: []string{ MakeBazelTarget("aidl_library", "example_lib_aidl_library", AttrNameToString{ @@ -438,6 +506,7 @@ func TestJavaLibraryAidl(t *testing.T) { "a.java", "b.java", ]`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "example_lib"), }}) @@ -450,12 +519,13 @@ func TestJavaLibraryAidlSrcsNoFileGroup(t *testing.T) { ModuleTypeUnderTestFactory: java.LibraryFactory, Blueprint: ` java_library { - name: "example_lib", - srcs: [ - "a.java", - "b.aidl", - ], - bazel_module: { bp2build_available: true }, + name: "example_lib", + srcs: [ + "a.java", + "b.aidl", + ], + sdk_version: "current", + bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("aidl_library", "example_lib_aidl_library", AttrNameToString{ @@ -465,9 +535,10 @@ java_library { "deps": `[":example_lib_aidl_library"]`, }), MakeBazelTarget("java_library", "example_lib", AttrNameToString{ - "deps": `[":example_lib_java_aidl_library"]`, - "exports": `[":example_lib_java_aidl_library"]`, - "srcs": `["a.java"]`, + "deps": `[":example_lib_java_aidl_library"]`, + "exports": `[":example_lib_java_aidl_library"]`, + "srcs": `["a.java"]`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "example_lib"), }, @@ -497,14 +568,15 @@ filegroup { ], } java_library { - name: "example_lib", - srcs: [ - "a.java", - "b.java", - ":aidl_files", - ":random_other_files", - ], - bazel_module: { bp2build_available: true }, + name: "example_lib", + srcs: [ + "a.java", + "b.java", + ":aidl_files", + ":random_other_files", + ], + sdk_version: "current", + bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("aidl_library", "aidl_files", AttrNameToString{ @@ -525,6 +597,7 @@ java_library { "b.java", ":random_other_files", ]`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "example_lib"), MakeBazelTargetNoRestrictions("filegroup", "random_other_files", AttrNameToString{ @@ -544,27 +617,30 @@ func TestJavaLibraryAidlNonAdjacentAidlFilegroup(t *testing.T) { Description: "java_library with non adjacent aidl filegroup", ModuleTypeUnderTest: "java_library", ModuleTypeUnderTestFactory: java.LibraryFactory, + StubbedBuildDefinitions: []string{"A_aidl"}, Filesystem: map[string]string{ "path/to/A/Android.bp": ` filegroup { - name: "A_aidl", - srcs: ["aidl/A.aidl"], - path: "aidl", + name: "A_aidl", + srcs: ["aidl/A.aidl"], + path: "aidl", }`, }, Blueprint: ` java_library { - name: "foo", - srcs: [ - ":A_aidl", - ], + name: "foo", + srcs: [ + ":A_aidl", + ], + sdk_version: "current", }`, ExpectedBazelTargets: []string{ MakeBazelTarget("java_aidl_library", "foo_java_aidl_library", AttrNameToString{ "deps": `["//path/to/A:A_aidl"]`, }), MakeBazelTarget("java_library", "foo", AttrNameToString{ - "exports": `[":foo_java_aidl_library"]`, + "exports": `[":foo_java_aidl_library"]`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "foo"), }, @@ -579,18 +655,19 @@ func TestConvertArmNeonVariant(t *testing.T) { Description: "Android Library - simple arch feature", ModuleTypeUnderTest: "android_library", ModuleTypeUnderTestFactory: java.AndroidLibraryFactory, - Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + ` + Blueprint: simpleModule("android_library", "static_lib_dep") + ` android_library { - name: "TestLib", - manifest: "manifest/AndroidManifest.xml", - srcs: ["lib.java"], - arch: { - arm: { - neon: { - srcs: ["arm_neon.java"], - }, - }, - }, + name: "TestLib", + manifest: "manifest/AndroidManifest.xml", + srcs: ["lib.java"], + sdk_version: "current", + arch: { + arm: { + neon: { + srcs: ["arm_neon.java"], + }, + }, + }, } `, ExpectedBazelTargets: []string{ @@ -604,6 +681,7 @@ android_library { })`, "manifest": `"manifest/AndroidManifest.xml"`, "resource_files": `[]`, + "sdk_version": `"current"`, // use as default }), MakeNeverlinkDuplicateTarget("android_library", "TestLib"), }}) @@ -615,21 +693,22 @@ func TestConvertMultipleArchFeatures(t *testing.T) { Description: "Android Library - multiple arch features", ModuleTypeUnderTest: "android_library", ModuleTypeUnderTestFactory: java.AndroidLibraryFactory, - Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + ` + Blueprint: simpleModule("android_library", "static_lib_dep") + ` android_library { - name: "TestLib", - manifest: "manifest/AndroidManifest.xml", - srcs: ["lib.java"], - arch: { - x86: { - ssse3: { - srcs: ["ssse3.java"], - }, - sse4_1: { - srcs: ["sse4_1.java"], - }, - }, - }, + name: "TestLib", + manifest: "manifest/AndroidManifest.xml", + srcs: ["lib.java"], + sdk_version: "current", + arch: { + x86: { + ssse3: { + srcs: ["ssse3.java"], + }, + sse4_1: { + srcs: ["sse4_1.java"], + }, + }, + }, } `, ExpectedBazelTargets: []string{ @@ -648,6 +727,7 @@ android_library { })`, "manifest": `"manifest/AndroidManifest.xml"`, "resource_files": `[]`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("android_library", "TestLib"), }}) @@ -659,19 +739,20 @@ func TestConvertExcludeSrcsArchFeature(t *testing.T) { Description: "Android Library - exclude_srcs with arch feature", ModuleTypeUnderTest: "android_library", ModuleTypeUnderTestFactory: java.AndroidLibraryFactory, - Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + ` + Blueprint: simpleModule("android_library", "static_lib_dep") + ` android_library { - name: "TestLib", - manifest: "manifest/AndroidManifest.xml", - srcs: ["lib.java"], - arch: { - arm: { - srcs: ["arm_non_neon.java"], - neon: { - exclude_srcs: ["arm_non_neon.java"], - }, - }, - }, + name: "TestLib", + manifest: "manifest/AndroidManifest.xml", + srcs: ["lib.java"], + arch: { + arm: { + srcs: ["arm_non_neon.java"], + neon: { + exclude_srcs: ["arm_non_neon.java"], + }, + }, + }, + sdk_version: "current", } `, ExpectedBazelTargets: []string{ @@ -686,6 +767,7 @@ android_library { })`, "manifest": `"manifest/AndroidManifest.xml"`, "resource_files": `[]`, + "sdk_version": `"current"`, // use as default }), MakeNeverlinkDuplicateTarget("android_library", "TestLib"), }}) @@ -698,6 +780,7 @@ func TestJavaLibraryKotlinSrcs(t *testing.T) { name: "java-lib-1", srcs: ["a.java", "b.java", "c.kt"], bazel_module: { bp2build_available: true }, + sdk_version: "current", } `, ExpectedBazelTargets: []string{ @@ -707,6 +790,7 @@ func TestJavaLibraryKotlinSrcs(t *testing.T) { "b.java", "c.kt", ]`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("kt_jvm_library", "java-lib-1"), }, @@ -721,6 +805,7 @@ func TestJavaLibraryKotlincflags(t *testing.T) { srcs: [ "a.kt"], kotlincflags: ["-flag1", "-flag2"], bazel_module: { bp2build_available: true }, + sdk_version: "current", } `, ExpectedBazelTargets: []string{ @@ -730,6 +815,7 @@ func TestJavaLibraryKotlincflags(t *testing.T) { "-flag1", "-flag2", ]`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("kt_jvm_library", "java-lib-1"), }, @@ -744,6 +830,7 @@ func TestJavaLibraryKotlinCommonSrcs(t *testing.T) { srcs: ["a.java", "b.java"], common_srcs: ["c.kt"], bazel_module: { bp2build_available: true }, + sdk_version: "current", } `, ExpectedBazelTargets: []string{ @@ -753,6 +840,7 @@ func TestJavaLibraryKotlinCommonSrcs(t *testing.T) { "b.java", ]`, "common_srcs": `["c.kt"]`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("kt_jvm_library", "java-lib-1"), }, @@ -761,11 +849,13 @@ func TestJavaLibraryKotlinCommonSrcs(t *testing.T) { func TestJavaLibraryArchVariantDeps(t *testing.T) { runJavaLibraryTestCase(t, Bp2buildTestCase{ - Description: "java_library with arch variant libs", + Description: "java_library with arch variant libs", + StubbedBuildDefinitions: []string{"java-lib-2", "java-lib-3", "java-lib-4"}, Blueprint: `java_library { name: "java-lib-1", srcs: ["a.java"], libs: ["java-lib-2"], + sdk_version: "current", target: { android: { libs: ["java-lib-3"], @@ -775,16 +865,16 @@ func TestJavaLibraryArchVariantDeps(t *testing.T) { bazel_module: { bp2build_available: true }, } - java_library{ - name: "java-lib-2", + java_library{ + name: "java-lib-2", } - java_library{ - name: "java-lib-3", + java_library{ + name: "java-lib-3", } - java_library{ - name: "java-lib-4", + java_library{ + name: "java-lib-4", } `, ExpectedBazelTargets: []string{ @@ -801,14 +891,9 @@ func TestJavaLibraryArchVariantDeps(t *testing.T) { ], "//conditions:default": [], })`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"), - MakeBazelTarget("java_library", "java-lib-2", AttrNameToString{}), - MakeNeverlinkDuplicateTarget("java_library", "java-lib-2"), - MakeBazelTarget("java_library", "java-lib-3", AttrNameToString{}), - MakeNeverlinkDuplicateTarget("java_library", "java-lib-3"), - MakeBazelTarget("java_library", "java-lib-4", AttrNameToString{}), - MakeNeverlinkDuplicateTarget("java_library", "java-lib-4"), }, }) } @@ -819,6 +904,7 @@ func TestJavaLibraryArchVariantSrcsWithExcludes(t *testing.T) { Blueprint: `java_library { name: "java-lib-1", srcs: ["a.java", "b.java"], + sdk_version: "current", target: { android: { exclude_srcs: ["a.java"], @@ -833,6 +919,7 @@ func TestJavaLibraryArchVariantSrcsWithExcludes(t *testing.T) { "//build/bazel/platforms/os:android": [], "//conditions:default": ["a.java"], })`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"), }, @@ -850,6 +937,7 @@ func TestJavaLibraryJavaResourcesSingleFilegroup(t *testing.T) { Blueprint: `java_library { name: "java-lib-1", srcs: ["a.java"], + sdk_version: "current", java_resources: [":filegroup1"], bazel_module: { bp2build_available: true }, } @@ -866,6 +954,7 @@ filegroup { "srcs": `["a.java"]`, "resources": `[":filegroup1"]`, "resource_strip_prefix": `"foo"`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"), MakeBazelTargetNoRestrictions("filegroup", "filegroup1", AttrNameToString{ @@ -878,3 +967,59 @@ filegroup { ctx.RegisterModuleType("filegroup", android.FileGroupFactory) }) } + +func TestJavaLibraryJavaResourcesMultipleFilegroup(t *testing.T) { + runJavaLibraryTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{ + Filesystem: map[string]string{ + "a.res": "", + }, + Description: "with java_resources that has multiple filegroups", + Blueprint: `java_library { + name: "java-lib-1", + srcs: ["a.java"], + java_resources: ["a.res", ":filegroup1", ":filegroup2"], + sdk_version: "current", + bazel_module: { bp2build_available: true }, +} + +filegroup { + name: "filegroup1", + path: "foo", + srcs: ["foo/a"], +} + +filegroup { + name: "filegroup2", + path: "bar", + srcs: ["bar/a"], +} +`, + ExpectedBazelTargets: []string{ + MakeBazelTarget("java_resources", "java-lib-1_filegroup_resources_filegroup1", AttrNameToString{ + "resource_strip_prefix": `"foo"`, + "resources": `[":filegroup1"]`, + }), + MakeBazelTarget("java_resources", "java-lib-1_filegroup_resources_filegroup2", AttrNameToString{ + "resource_strip_prefix": `"bar"`, + "resources": `[":filegroup2"]`, + }), + MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{ + "srcs": `["a.java"]`, + "resources": `["a.res"]`, + "resource_strip_prefix": `"."`, + "additional_resources": `[ + "java-lib-1_filegroup_resources_filegroup1", + "java-lib-1_filegroup_resources_filegroup2", + ]`, + "sdk_version": `"current"`, + }), + MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"), + MakeBazelTargetNoRestrictions("filegroup", "filegroup1", AttrNameToString{ + "srcs": `["foo/a"]`}), + MakeBazelTargetNoRestrictions("filegroup", "filegroup2", AttrNameToString{ + "srcs": `["bar/a"]`}), + }, + }, func(ctx android.RegistrationContext) { + ctx.RegisterModuleType("filegroup", android.FileGroupFactory) + }) +} diff --git a/bp2build/java_plugin_conversion_test.go b/bp2build/java_plugin_conversion_test.go index f2b6f20a4..b284112c6 100644 --- a/bp2build/java_plugin_conversion_test.go +++ b/bp2build/java_plugin_conversion_test.go @@ -32,7 +32,8 @@ func runJavaPluginTestCase(t *testing.T, tc Bp2buildTestCase) { func TestJavaPlugin(t *testing.T) { runJavaPluginTestCase(t, Bp2buildTestCase{ - Description: "java_plugin with srcs, libs, static_libs", + Description: "java_plugin with srcs, libs, static_libs", + StubbedBuildDefinitions: []string{"java-lib-1", "java-lib-2"}, Blueprint: `java_plugin { name: "java-plug-1", srcs: ["a.java", "b.java"], @@ -45,13 +46,11 @@ func TestJavaPlugin(t *testing.T) { java_library { name: "java-lib-1", srcs: ["b.java"], - bazel_module: { bp2build_available: false }, } java_library { name: "java-lib-2", srcs: ["c.java"], - bazel_module: { bp2build_available: false }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("java_plugin", "java-plug-1", AttrNameToString{ @@ -75,7 +74,8 @@ java_library { func TestJavaPluginNoSrcs(t *testing.T) { runJavaPluginTestCase(t, Bp2buildTestCase{ - Description: "java_plugin without srcs converts (static) libs to deps", + Description: "java_plugin without srcs converts (static) libs to deps", + StubbedBuildDefinitions: []string{"java-lib-1", "java-lib-2"}, Blueprint: `java_plugin { name: "java-plug-1", libs: ["java-lib-1"], diff --git a/bp2build/java_proto_conversion_test.go b/bp2build/java_proto_conversion_test.go index f546cf45d..b25471048 100644 --- a/bp2build/java_proto_conversion_test.go +++ b/bp2build/java_proto_conversion_test.go @@ -68,6 +68,7 @@ func TestJavaProto(t *testing.T) { type: "%s", }, srcs: ["a.proto"], + sdk_version: "current", }` protoLibrary := MakeBazelTarget("proto_library", "java-protos_proto", AttrNameToString{ @@ -86,10 +87,12 @@ func TestJavaProto(t *testing.T) { tc.javaLibraryType, javaLibraryName, AttrNameToString{ - "deps": `[":java-protos_proto"]`, + "deps": `[":java-protos_proto"]`, + "sdk_version": `"current"`, }), MakeBazelTarget("java_library", "java-protos", AttrNameToString{ - "exports": fmt.Sprintf(`[":%s"]`, javaLibraryName), + "exports": fmt.Sprintf(`[":%s"]`, javaLibraryName), + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTarget("java_library", "java-protos"), }, @@ -104,6 +107,7 @@ func TestJavaProtoDefault(t *testing.T) { name: "java-protos", srcs: ["a.proto"], java_version: "7", + sdk_version: "current", } `, ExpectedBazelTargets: []string{ @@ -116,15 +120,64 @@ func TestJavaProtoDefault(t *testing.T) { AttrNameToString{ "deps": `[":java-protos_proto"]`, "java_version": `"7"`, + "sdk_version": `"current"`, }), MakeBazelTarget("java_library", "java-protos", AttrNameToString{ "exports": `[":java-protos_java_proto_lite"]`, "java_version": `"7"`, + "sdk_version": `"current"`, }), MakeNeverlinkDuplicateTargetWithAttrs( "java_library", "java-protos", - AttrNameToString{"java_version": `"7"`}), + AttrNameToString{ + "java_version": `"7"`, + "sdk_version": `"current"`, + }), + }, + }) +} + +func TestJavaLibsAndOnlyProtoSrcs(t *testing.T) { + runJavaProtoTestCase(t, Bp2buildTestCase{ + Description: "java_library that has only proto srcs", + Blueprint: `java_library_static { + name: "java-protos", + srcs: ["a.proto"], + libs: ["java-lib"], + java_version: "7", + sdk_version: "current", +} + +java_library_static { + name: "java-lib", + bazel_module: { bp2build_available: false }, +} +`, + ExpectedBazelTargets: []string{ + MakeBazelTarget("proto_library", "java-protos_proto", AttrNameToString{ + "srcs": `["a.proto"]`, + }), + MakeBazelTarget( + "java_lite_proto_library", + "java-protos_java_proto_lite", + AttrNameToString{ + "deps": `[":java-protos_proto"]`, + "java_version": `"7"`, + "sdk_version": `"current"`, + }), + MakeBazelTarget("java_library", "java-protos", AttrNameToString{ + "exports": `[":java-protos_java_proto_lite"]`, + "java_version": `"7"`, + "sdk_version": `"current"`, + }), + MakeNeverlinkDuplicateTargetWithAttrs( + "java_library", + "java-protos", + AttrNameToString{ + "java_version": `"7"`, + "sdk_version": `"current"`, + }), }, }) } diff --git a/bp2build/java_sdk_library_import_conversion_test.go b/bp2build/java_sdk_library_import_conversion_test.go new file mode 100644 index 000000000..456f87268 --- /dev/null +++ b/bp2build/java_sdk_library_import_conversion_test.go @@ -0,0 +1,84 @@ +// Copyright 2023 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 ( + "testing" + + "android/soong/java" +) + +func runJavaSdkLibraryImportTestCase(t *testing.T, tc Bp2buildTestCase) { + t.Helper() + RunBp2BuildTestCase(t, java.RegisterSdkLibraryBuildComponents, tc) +} + +func TestJavaSdkLibraryImport(t *testing.T) { + runJavaSdkLibraryImportTestCase(t, Bp2buildTestCase{ + Blueprint: ` +java_sdk_library_import { + name : "foo", + public: { + current_api: "foo_current.txt", + }, + system: { + current_api: "system_foo_current.txt", + }, +} +`, + ExpectedBazelTargets: []string{ + MakeBazelTarget("java_sdk_library", "foo", AttrNameToString{ + "public": `"foo_current.txt"`, + "system": `"system_foo_current.txt"`, + }), + }, + }) +} + +func TestJavaSdkLibraryImportPrebuiltPrefixRemoved(t *testing.T) { + runJavaSdkLibraryImportTestCase(t, Bp2buildTestCase{ + Filesystem: map[string]string{ + "foobar/Android.bp": ` +java_sdk_library { + name: "foo", + srcs: ["**/*.java"], +} +`, + "foobar/api/current.txt": "", + "foobar/api/system-current.txt": "", + "foobar/api/test-current.txt": "", + "foobar/api/removed.txt": "", + "foobar/api/system-removed.txt": "", + "foobar/api/test-removed.txt": "", + }, + Blueprint: ` +java_sdk_library_import { + name : "foo", + public: { + current_api: "foo_current.txt", + }, + system: { + current_api: "system_foo_current.txt", + }, +} +`, + ExpectedBazelTargets: []string{ + MakeBazelTarget("java_sdk_library", "foo", AttrNameToString{ + "public": `"foo_current.txt"`, + "system": `"system_foo_current.txt"`, + }), + }, + }) +} diff --git a/bp2build/metrics.go b/bp2build/metrics.go index 00f21c8a7..20002c67f 100644 --- a/bp2build/metrics.go +++ b/bp2build/metrics.go @@ -9,11 +9,17 @@ import ( "android/soong/android" "android/soong/shared" "android/soong/ui/metrics/bp2build_metrics_proto" + "google.golang.org/protobuf/proto" "github.com/google/blueprint" ) +type moduleInfo struct { + Name string `json:"name"` + Type string `json:"type"` +} + // CodegenMetrics represents information about the Blueprint-to-BUILD // conversion process. // Use CreateCodegenMetrics() to get a properly initialized instance @@ -30,6 +36,9 @@ type CodegenMetrics struct { // Map of converted modules and paths to call // NOTE: NOT in the .proto convertedModulePathMap map[string]string + + // Name and type of converted modules + convertedModuleWithType []moduleInfo } func CreateCodegenMetrics() CodegenMetrics { @@ -191,6 +200,10 @@ func (metrics *CodegenMetrics) AddConvertedModule(m blueprint.Module, moduleType // Undo prebuilt_ module name prefix modifications moduleName := android.RemoveOptionalPrebuiltPrefix(m.Name()) metrics.serialized.ConvertedModules = append(metrics.serialized.ConvertedModules, moduleName) + metrics.convertedModuleWithType = append(metrics.convertedModuleWithType, moduleInfo{ + moduleName, + moduleType, + }) metrics.convertedModulePathMap[moduleName] = "//" + dir metrics.serialized.ConvertedModuleTypeCount[moduleType] += 1 metrics.serialized.TotalModuleTypeCount[moduleType] += 1 diff --git a/bp2build/platform_compat_config_conversion_test.go b/bp2build/platform_compat_config_conversion_test.go index 4dfcce3a3..d74db5d0b 100644 --- a/bp2build/platform_compat_config_conversion_test.go +++ b/bp2build/platform_compat_config_conversion_test.go @@ -37,6 +37,7 @@ func TestPlatformCompatConfig(t *testing.T) { name: "foo", src: ":lib", }`, + StubbedBuildDefinitions: []string{"//a/b:lib"}, Filesystem: map[string]string{ "a/b/Android.bp": ` java_library { diff --git a/bp2build/prebuilt_etc_conversion_test.go b/bp2build/prebuilt_etc_conversion_test.go index 5b2d609ac..e2373038a 100644 --- a/bp2build/prebuilt_etc_conversion_test.go +++ b/bp2build/prebuilt_etc_conversion_test.go @@ -346,3 +346,17 @@ prebuilt_etc { ExpectedErr: fmt.Errorf("label attribute could not be collapsed"), }) } + +func TestPrebuiltEtcNoConversionIfSrcEqualsName(t *testing.T) { + runPrebuiltEtcTestCase(t, Bp2buildTestCase{ + Description: "", + Filesystem: map[string]string{}, + Blueprint: ` +prebuilt_etc { + name: "foo", + filename: "fooFilename", + src: "foo", +}`, + ExpectedBazelTargets: []string{}, + }) +} diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go index 1b538d066..b69c4eab7 100644 --- a/bp2build/python_binary_conversion_test.go +++ b/bp2build/python_binary_conversion_test.go @@ -30,6 +30,7 @@ func TestPythonBinaryHostSimple(t *testing.T) { "b/e.py": "", "files/data.txt": "", }, + StubbedBuildDefinitions: []string{"bar"}, Blueprint: `python_binary_host { name: "foo", main: "a.py", @@ -42,7 +43,6 @@ func TestPythonBinaryHostSimple(t *testing.T) { python_library_host { name: "bar", srcs: ["b/e.py"], - bazel_module: { bp2build_available: false }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("py_binary", "foo", AttrNameToString{ @@ -196,6 +196,7 @@ func TestPythonBinaryMainIsLabel(t *testing.T) { Description: "python_binary_host main label in same package", ModuleTypeUnderTest: "python_binary_host", ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory, + StubbedBuildDefinitions: []string{"a"}, Blueprint: `python_binary_host { name: "foo", main: ":a", @@ -204,7 +205,6 @@ func TestPythonBinaryMainIsLabel(t *testing.T) { genrule { name: "a", - bazel_module: { bp2build_available: false }, } `, ExpectedBazelTargets: []string{ @@ -282,6 +282,7 @@ func TestPythonBinaryDuplicatesInRequired(t *testing.T) { Description: "python_binary_host duplicates in required attribute of the module and its defaults", ModuleTypeUnderTest: "python_binary_host", ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory, + StubbedBuildDefinitions: []string{"r1", "r2"}, Blueprint: `python_binary_host { name: "foo", main: "a.py", @@ -298,8 +299,8 @@ python_defaults { "r1", "r2", ], -}` + simpleModuleDoNotConvertBp2build("genrule", "r1") + - simpleModuleDoNotConvertBp2build("genrule", "r2"), +}` + simpleModule("genrule", "r1") + + simpleModule("genrule", "r2"), ExpectedBazelTargets: []string{ MakeBazelTarget("py_binary", "foo", AttrNameToString{ diff --git a/bp2build/python_library_conversion_test.go b/bp2build/python_library_conversion_test.go index a53371d2b..497df8091 100644 --- a/bp2build/python_library_conversion_test.go +++ b/bp2build/python_library_conversion_test.go @@ -13,12 +13,13 @@ import ( type PythonLibBp2Build func(ctx android.TopDownMutatorContext) type pythonLibBp2BuildTestCase struct { - description string - filesystem map[string]string - blueprint string - expectedBazelTargets []testBazelTarget - dir string - expectedError error + description string + filesystem map[string]string + blueprint string + expectedBazelTargets []testBazelTarget + dir string + expectedError error + stubbedBuildDefinitions []string } func convertPythonLibTestCaseToBp2build_Host(tc pythonLibBp2BuildTestCase) Bp2buildTestCase { @@ -44,12 +45,13 @@ func convertPythonLibTestCaseToBp2build(tc pythonLibBp2BuildTestCase) Bp2buildTe filesystemCopy[k] = v } return Bp2buildTestCase{ - Description: tc.description, - Filesystem: filesystemCopy, - Blueprint: tc.blueprint, - ExpectedBazelTargets: bp2BuildTargets, - Dir: tc.dir, - ExpectedErr: tc.expectedError, + Description: tc.description, + Filesystem: filesystemCopy, + Blueprint: tc.blueprint, + ExpectedBazelTargets: bp2BuildTargets, + Dir: tc.dir, + ExpectedErr: tc.expectedError, + StubbedBuildDefinitions: tc.stubbedBuildDefinitions, } } @@ -104,6 +106,7 @@ func TestSimplePythonLib(t *testing.T) { "b/e.py": "", "files/data.txt": "", }, + stubbedBuildDefinitions: []string{"bar"}, blueprint: `%s { name: "foo", srcs: ["**/*.py"], @@ -115,7 +118,6 @@ func TestSimplePythonLib(t *testing.T) { python_library { name: "bar", srcs: ["b/e.py"], - bazel_module: { bp2build_available: false }, }`, expectedBazelTargets: []testBazelTarget{ { @@ -348,3 +350,43 @@ func TestPythonLibraryWithProtobufs(t *testing.T) { }, }) } + +func TestPythonLibraryWithProtobufsAndPkgPath(t *testing.T) { + t.Parallel() + runBp2BuildTestCaseWithPythonLibraries(t, Bp2buildTestCase{ + Description: "test python_library protobuf with pkg_path", + Filesystem: map[string]string{ + "dir/foo.proto": "", + "dir/bar.proto": "", // bar contains "import dir/foo.proto" + "dir/Android.bp": ` +python_library { + name: "foo", + pkg_path: "dir", + srcs: [ + "foo.proto", + "bar.proto", + ], + bazel_module: {bp2build_available: true}, +}`, + }, + Dir: "dir", + ExpectedBazelTargets: []string{ + MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{ + "import_prefix": `"dir"`, + "strip_import_prefix": `""`, + "srcs": `[ + "foo.proto", + "bar.proto", + ]`, + }), + MakeBazelTarget("py_proto_library", "foo_py_proto", AttrNameToString{ + "deps": `[":foo_proto"]`, + }), + MakeBazelTarget("py_library", "foo", AttrNameToString{ + "srcs_version": `"PY3"`, + "imports": `[".."]`, + "deps": `[":foo_py_proto"]`, + }), + }, + }) +} diff --git a/bp2build/python_test_conversion_test.go b/bp2build/python_test_conversion_test.go index 4ff1fa16d..fa2e48507 100644 --- a/bp2build/python_test_conversion_test.go +++ b/bp2build/python_test_conversion_test.go @@ -15,8 +15,9 @@ package bp2build import ( - "android/soong/python" "testing" + + "android/soong/python" ) func TestPythonTestHostSimple(t *testing.T) { @@ -31,6 +32,7 @@ func TestPythonTestHostSimple(t *testing.T) { "b/e.py": "", "files/data.txt": "", }, + StubbedBuildDefinitions: []string{"bar"}, Blueprint: `python_test_host { name: "foo", main: "a.py", @@ -43,7 +45,6 @@ func TestPythonTestHostSimple(t *testing.T) { python_library_host { name: "bar", srcs: ["b/e.py"], - bazel_module: { bp2build_available: false }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("py_test", "foo", AttrNameToString{ diff --git a/bp2build/rust_binary_conversion_test.go b/bp2build/rust_binary_conversion_test.go new file mode 100644 index 000000000..a5abbdb89 --- /dev/null +++ b/bp2build/rust_binary_conversion_test.go @@ -0,0 +1,88 @@ +// Copyright 2023 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/rust" + "testing" +) + +func runRustBinaryTestCase(t *testing.T, tc Bp2buildTestCase) { + t.Helper() + RunBp2BuildTestCase(t, registerRustBinaryModuleTypes, tc) +} + +func registerRustBinaryModuleTypes(ctx android.RegistrationContext) { + ctx.RegisterModuleType("rust_binary_host", rust.RustBinaryHostFactory) + ctx.RegisterModuleType("rust_library_host", rust.RustLibraryHostFactory) + ctx.RegisterModuleType("rust_proc_macro", rust.ProcMacroFactory) + +} + +func TestRustBinaryHost(t *testing.T) { + runRustBinaryTestCase(t, Bp2buildTestCase{ + Dir: "external/rust/crates/foo", + Blueprint: "", + Filesystem: map[string]string{ + "external/rust/crates/foo/src/lib.rs": "", + "external/rust/crates/foo/src/helper.rs": "", + "external/rust/crates/foo/Android.bp": ` +rust_binary_host { + name: "libfoo", + crate_name: "foo", + srcs: ["src/main.rs"], + edition: "2021", + features: ["bah-enabled"], + cfgs: ["baz"], + rustlibs: ["libbar"], + proc_macros: ["libbah"], + bazel_module: { bp2build_available: true }, +} +`, + "external/rust/crates/bar/Android.bp": ` +rust_library_host { + name: "libbar", + crate_name: "bar", + srcs: ["src/lib.rs"], + bazel_module: { bp2build_available: true }, +} +`, + "external/rust/crates/bah/Android.bp": ` +rust_proc_macro { + name: "libbah", + crate_name: "bah", + srcs: ["src/lib.rs"], + bazel_module: { bp2build_available: true }, +} +`, + }, + ExpectedBazelTargets: []string{ + makeBazelTargetHostOrDevice("rust_binary", "libfoo", AttrNameToString{ + "crate_name": `"foo"`, + "srcs": `[ + "src/helper.rs", + "src/lib.rs", + ]`, + "deps": `["//external/rust/crates/bar:libbar"]`, + "proc_macro_deps": `["//external/rust/crates/bah:libbah"]`, + "edition": `"2021"`, + "crate_features": `["bah-enabled"]`, + "rustc_flags": `["--cfg=baz"]`, + }, android.HostSupported), + }, + }, + ) +} diff --git a/bp2build/rust_library_conversion_test.go b/bp2build/rust_library_conversion_test.go new file mode 100644 index 000000000..0bc80dfbb --- /dev/null +++ b/bp2build/rust_library_conversion_test.go @@ -0,0 +1,110 @@ +// Copyright 2023 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/rust" + "testing" +) + +func runRustLibraryTestCase(t *testing.T, tc Bp2buildTestCase) { + t.Helper() + RunBp2BuildTestCase(t, registerRustLibraryModuleTypes, tc) +} + +func registerRustLibraryModuleTypes(ctx android.RegistrationContext) { + ctx.RegisterModuleType("rust_library", rust.RustLibraryFactory) + ctx.RegisterModuleType("rust_library_host", rust.RustLibraryHostFactory) +} + +func TestLibProtobuf(t *testing.T) { + runRustLibraryTestCase(t, Bp2buildTestCase{ + Dir: "external/rust/crates/foo", + Blueprint: "", + Filesystem: map[string]string{ + "external/rust/crates/foo/src/lib.rs": "", + "external/rust/crates/foo/Android.bp": ` +rust_library_host { + name: "libprotobuf", + crate_name: "protobuf", + srcs: ["src/lib.rs"], + bazel_module: { bp2build_available: true }, +} +`, + }, + ExpectedBazelTargets: []string{ + // TODO(b/290790800): Remove the restriction when rust toolchain for android is implemented + makeBazelTargetHostOrDevice("rust_library", "libprotobuf", AttrNameToString{ + "crate_name": `"protobuf"`, + "srcs": `["src/lib.rs"]`, + "deps": `[":libprotobuf_build_script"]`, + }, android.HostSupported), + makeBazelTargetHostOrDevice("cargo_build_script", "libprotobuf_build_script", AttrNameToString{ + "srcs": `["build.rs"]`, + }, android.HostSupported), + }, + }, + ) +} + +func TestRustLibrary(t *testing.T) { + expectedAttrs := AttrNameToString{ + "crate_name": `"foo"`, + "srcs": `[ + "src/helper.rs", + "src/lib.rs", + ]`, + "crate_features": `["bah-enabled"]`, + "edition": `"2021"`, + "rustc_flags": `["--cfg=baz"]`, + } + + runRustLibraryTestCase(t, Bp2buildTestCase{ + Dir: "external/rust/crates/foo", + Blueprint: "", + Filesystem: map[string]string{ + "external/rust/crates/foo/src/lib.rs": "", + "external/rust/crates/foo/src/helper.rs": "", + "external/rust/crates/foo/Android.bp": ` +rust_library { + name: "libfoo", + crate_name: "foo", + host_supported: true, + srcs: ["src/lib.rs"], + edition: "2021", + features: ["bah-enabled"], + cfgs: ["baz"], + bazel_module: { bp2build_available: true }, +} +rust_library_host { + name: "libfoo_host", + crate_name: "foo", + srcs: ["src/lib.rs"], + edition: "2021", + features: ["bah-enabled"], + cfgs: ["baz"], + bazel_module: { bp2build_available: true }, +} +`, + }, + ExpectedBazelTargets: []string{ + // TODO(b/290790800): Remove the restriction when rust toolchain for android is implemented + makeBazelTargetHostOrDevice("rust_library", "libfoo", expectedAttrs, android.HostSupported), + makeBazelTargetHostOrDevice("rust_library", "libfoo_host", expectedAttrs, android.HostSupported), + }, + }, + ) +} diff --git a/bp2build/rust_proc_macro_conversion_test.go b/bp2build/rust_proc_macro_conversion_test.go new file mode 100644 index 000000000..7df37ec4b --- /dev/null +++ b/bp2build/rust_proc_macro_conversion_test.go @@ -0,0 +1,76 @@ +// Copyright 2023 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/rust" + "testing" +) + +func rustRustProcMacroTestCase(t *testing.T, tc Bp2buildTestCase) { + t.Helper() + RunBp2BuildTestCase(t, registerRustProcMacroModuleTypes, tc) +} + +func registerRustProcMacroModuleTypes(ctx android.RegistrationContext) { + ctx.RegisterModuleType("rust_library_host", rust.RustLibraryHostFactory) + ctx.RegisterModuleType("rust_proc_macro", rust.ProcMacroFactory) +} + +func TestRustProcMacroLibrary(t *testing.T) { + rustRustProcMacroTestCase(t, Bp2buildTestCase{ + Dir: "external/rust/crates/foo", + Blueprint: "", + Filesystem: map[string]string{ + "external/rust/crates/foo/src/lib.rs": "", + "external/rust/crates/foo/src/helper.rs": "", + "external/rust/crates/foo/Android.bp": ` +rust_proc_macro { + name: "libfoo", + crate_name: "foo", + srcs: ["src/lib.rs"], + edition: "2021", + features: ["bah-enabled"], + cfgs: ["baz"], + rustlibs: ["libbar"], + bazel_module: { bp2build_available: true }, +} +`, + "external/rust/crates/bar/src/lib.rs": "", + "external/rust/crates/bar/Android.bp": ` +rust_library_host { + name: "libbar", + crate_name: "bar", + srcs: ["src/lib.rs"], + bazel_module: { bp2build_available: true }, +}`, + }, + ExpectedBazelTargets: []string{ + makeBazelTargetHostOrDevice("rust_proc_macro", "libfoo", AttrNameToString{ + "crate_name": `"foo"`, + "srcs": `[ + "src/helper.rs", + "src/lib.rs", + ]`, + "crate_features": `["bah-enabled"]`, + "edition": `"2021"`, + "rustc_flags": `["--cfg=baz"]`, + "deps": `["//external/rust/crates/bar:libbar"]`, + }, android.HostSupported), + }, + }, + ) +} diff --git a/bp2build/rust_protobuf_conversion_test.go b/bp2build/rust_protobuf_conversion_test.go new file mode 100644 index 000000000..cf256aadc --- /dev/null +++ b/bp2build/rust_protobuf_conversion_test.go @@ -0,0 +1,60 @@ +// Copyright 2023 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/rust" + "testing" +) + +func runRustProtobufTestCase(t *testing.T, tc Bp2buildTestCase) { + t.Helper() + RunBp2BuildTestCase(t, registerRustProtobufModuleTypes, tc) +} + +func registerRustProtobufModuleTypes(ctx android.RegistrationContext) { + ctx.RegisterModuleType("rust_protobuf_host", rust.RustProtobufHostFactory) + +} + +func TestRustProtobufHostTestCase(t *testing.T) { + runRustProtobufTestCase(t, Bp2buildTestCase{ + Dir: "external/rust/crates/foo", + Blueprint: "", + Filesystem: map[string]string{ + "external/rust/crates/foo/src/lib.rs": "", + "external/rust/crates/foo/src/helper.rs": "", + "external/rust/crates/foo/Android.bp": ` +rust_protobuf_host { + name: "libfoo", + crate_name: "foo", + protos: ["src/foo.proto"], + bazel_module: { bp2build_available: true }, +} +`, + }, + ExpectedBazelTargets: []string{ + makeBazelTargetHostOrDevice("proto_library", "libfoo_proto", AttrNameToString{ + "srcs": `["src/foo.proto"]`, + }, android.HostSupported), + makeBazelTargetHostOrDevice("rust_proto_library", "libfoo", AttrNameToString{ + "crate_name": `"foo"`, + "deps": `[":libfoo_proto"]`, + }, android.HostSupported), + }, + }, + ) +} diff --git a/bp2build/sh_test_conversion_test.go b/bp2build/sh_test_conversion_test.go new file mode 100644 index 000000000..e99d56689 --- /dev/null +++ b/bp2build/sh_test_conversion_test.go @@ -0,0 +1,186 @@ +// Copyright 2023 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 ( + "testing" + + "android/soong/android" + "android/soong/sh" +) + +func TestShTestSimple(t *testing.T) { + RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{ + Description: "sh_test test", + ModuleTypeUnderTest: "sh_test", + ModuleTypeUnderTestFactory: sh.ShTestFactory, + Blueprint: `sh_test{ + name: "sts-rootcanal-sidebins", + src: "empty.sh", + test_suites: [ + "sts", + "sts-lite", + ], + data_bins: [ + "android.hardware.bluetooth@1.1-service.sim", + "android.hardware.bluetooth@1.1-impl-sim" + ], + data: ["android.hardware.bluetooth@1.1-service.sim.rc"], + data_libs: ["libc++","libcrypto"], + test_config: "art-gtests-target-install-apex.xml", + test_config_template: ":art-run-test-target-template", + auto_gen_config: false, + test_options:{tags: ["no-remote"], + }, +}`, + ExpectedBazelTargets: []string{ + MakeBazelTarget("sh_test", "sts-rootcanal-sidebins", AttrNameToString{ + "srcs": `["empty.sh"]`, + "data": `[ + "android.hardware.bluetooth@1.1-service.sim.rc", + "android.hardware.bluetooth@1.1-service.sim", + "android.hardware.bluetooth@1.1-impl-sim", + "libc++", + "libcrypto", + ]`, + "test_config": `"art-gtests-target-install-apex.xml"`, + "test_config_template": `":art-run-test-target-template"`, + "auto_gen_config": "False", + "tags": `["no-remote"]`, + })}, + }) +} + +func TestShTestHostSimple(t *testing.T) { + RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{ + Description: "sh_test_host test", + ModuleTypeUnderTest: "sh_test_host", + ModuleTypeUnderTestFactory: sh.ShTestHostFactory, + Blueprint: `sh_test_host{ + name: "sts-rootcanal-sidebins", + src: "empty.sh", + test_suites: [ + "sts", + "sts-lite", + ], + data_bins: [ + "android.hardware.bluetooth@1.1-service.sim", + "android.hardware.bluetooth@1.1-impl-sim" + ], + data: ["android.hardware.bluetooth@1.1-service.sim.rc"], + data_libs: ["libc++","libcrypto"], + test_config: "art-gtests-target-install-apex.xml", + test_config_template: ":art-run-test-target-template", + auto_gen_config: false, + test_options:{tags: ["no-remote"], + }, +}`, + ExpectedBazelTargets: []string{ + MakeBazelTarget("sh_test", "sts-rootcanal-sidebins", AttrNameToString{ + "srcs": `["empty.sh"]`, + "data": `[ + "android.hardware.bluetooth@1.1-service.sim.rc", + "android.hardware.bluetooth@1.1-service.sim", + "android.hardware.bluetooth@1.1-impl-sim", + "libc++", + "libcrypto", + ]`, + "tags": `["no-remote"]`, + "test_config": `"art-gtests-target-install-apex.xml"`, + "test_config_template": `":art-run-test-target-template"`, + "auto_gen_config": "False", + "target_compatible_with": `select({ + "//build/bazel/platforms/os:android": ["@platforms//:incompatible"], + "//conditions:default": [], + })`, + })}, + }) +} + +func TestShTestSimpleUnset(t *testing.T) { + RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{ + Description: "sh_test test", + ModuleTypeUnderTest: "sh_test", + ModuleTypeUnderTestFactory: sh.ShTestFactory, + Blueprint: `sh_test{ + name: "sts-rootcanal-sidebins", + src: "empty.sh", + test_suites: [ + "sts", + "sts-lite", + ], + data_bins: [ + "android.hardware.bluetooth@1.1-service.sim", + "android.hardware.bluetooth@1.1-impl-sim" + ], + data: ["android.hardware.bluetooth@1.1-service.sim.rc"], + data_libs: ["libc++","libcrypto"], + test_options:{tags: ["no-remote"], + }, +}`, + ExpectedBazelTargets: []string{ + MakeBazelTarget("sh_test", "sts-rootcanal-sidebins", AttrNameToString{ + "srcs": `["empty.sh"]`, + "data": `[ + "android.hardware.bluetooth@1.1-service.sim.rc", + "android.hardware.bluetooth@1.1-service.sim", + "android.hardware.bluetooth@1.1-impl-sim", + "libc++", + "libcrypto", + ]`, + "tags": `["no-remote"]`, + })}, + }) +} + +func TestShTestHostSimpleUnset(t *testing.T) { + RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{ + Description: "sh_test_host test", + ModuleTypeUnderTest: "sh_test_host", + ModuleTypeUnderTestFactory: sh.ShTestHostFactory, + Blueprint: `sh_test_host{ + name: "sts-rootcanal-sidebins", + src: "empty.sh", + test_suites: [ + "sts", + "sts-lite", + ], + data_bins: [ + "android.hardware.bluetooth@1.1-service.sim", + "android.hardware.bluetooth@1.1-impl-sim" + ], + data: ["android.hardware.bluetooth@1.1-service.sim.rc"], + data_libs: ["libc++","libcrypto"], + test_options:{tags: ["no-remote"], + }, +}`, + ExpectedBazelTargets: []string{ + MakeBazelTarget("sh_test", "sts-rootcanal-sidebins", AttrNameToString{ + "srcs": `["empty.sh"]`, + "data": `[ + "android.hardware.bluetooth@1.1-service.sim.rc", + "android.hardware.bluetooth@1.1-service.sim", + "android.hardware.bluetooth@1.1-impl-sim", + "libc++", + "libcrypto", + ]`, + "tags": `["no-remote"]`, + "target_compatible_with": `select({ + "//build/bazel/platforms/os:android": ["@platforms//:incompatible"], + "//conditions:default": [], + })`, + })}, + }) +} diff --git a/bp2build/soong_config_module_type_conversion_test.go b/bp2build/soong_config_module_type_conversion_test.go index 8302ce87b..5ec6bab29 100644 --- a/bp2build/soong_config_module_type_conversion_test.go +++ b/bp2build/soong_config_module_type_conversion_test.go @@ -15,10 +15,11 @@ package bp2build import ( - "android/soong/android" - "android/soong/cc" "fmt" "testing" + + "android/soong/android" + "android/soong/cc" ) func runSoongConfigModuleTypeTest(t *testing.T, tc Bp2buildTestCase) { @@ -364,9 +365,9 @@ custom_cc_library_static { }` otherDeps := ` -cc_library_static { name: "soc_a_dep", bazel_module: { bp2build_available: false } } -cc_library_static { name: "soc_b_dep", bazel_module: { bp2build_available: false } } -cc_library_static { name: "soc_default_static_dep", bazel_module: { bp2build_available: false } } +cc_library_static { name: "soc_a_dep"} +cc_library_static { name: "soc_b_dep"} +cc_library_static { name: "soc_default_static_dep"} ` runSoongConfigModuleTypeTest(t, Bp2buildTestCase{ @@ -377,6 +378,7 @@ cc_library_static { name: "soc_default_static_dep", bazel_module: { bp2build_ava Filesystem: map[string]string{ "foo/bar/Android.bp": otherDeps, }, + StubbedBuildDefinitions: []string{"//foo/bar:soc_a_dep", "//foo/bar:soc_b_dep", "//foo/bar:soc_default_static_dep"}, ExpectedBazelTargets: []string{`cc_library_static( name = "foo", copts = select({ @@ -763,9 +765,9 @@ cc_binary { }` otherDeps := ` -cc_library { name: "lib_a", bazel_module: { bp2build_available: false } } -cc_library { name: "lib_b", bazel_module: { bp2build_available: false } } -cc_library { name: "lib_default", bazel_module: { bp2build_available: false } } +cc_library { name: "lib_a"} +cc_library { name: "lib_b"} +cc_library { name: "lib_default"} ` runSoongConfigModuleTypeTest(t, Bp2buildTestCase{ @@ -773,6 +775,7 @@ cc_library { name: "lib_default", bazel_module: { bp2build_available: false } } ModuleTypeUnderTest: "cc_binary", ModuleTypeUnderTestFactory: cc.BinaryFactory, Blueprint: bp, + StubbedBuildDefinitions: []string{"//foo/bar:lib_a", "//foo/bar:lib_b", "//foo/bar:lib_default"}, Filesystem: map[string]string{ "foo/bar/Android.bp": otherDeps, }, @@ -852,15 +855,16 @@ cc_binary { }` otherDeps := ` -cc_library { name: "lib_a", bazel_module: { bp2build_available: false } } -cc_library { name: "lib_b", bazel_module: { bp2build_available: false } } -cc_library { name: "lib_c", bazel_module: { bp2build_available: false } } +cc_library { name: "lib_a"} +cc_library { name: "lib_b"} +cc_library { name: "lib_c"} ` runSoongConfigModuleTypeTest(t, Bp2buildTestCase{ Description: "soong config variables - generates selects for library_linking_strategy", ModuleTypeUnderTest: "cc_binary", ModuleTypeUnderTestFactory: cc.BinaryFactory, + StubbedBuildDefinitions: []string{"//foo/bar:lib_a", "//foo/bar:lib_b", "//foo/bar:lib_c"}, Blueprint: bp, Filesystem: map[string]string{ "foo/bar/Android.bp": otherDeps, @@ -949,9 +953,9 @@ cc_binary { }` otherDeps := ` -cc_library { name: "lib_a", bazel_module: { bp2build_available: false } } -cc_library { name: "lib_b", bazel_module: { bp2build_available: false } } -cc_library { name: "lib_default", bazel_module: { bp2build_available: false } } +cc_library { name: "lib_a"} +cc_library { name: "lib_b"} +cc_library { name: "lib_default"} ` runSoongConfigModuleTypeTest(t, Bp2buildTestCase{ @@ -962,6 +966,7 @@ cc_library { name: "lib_default", bazel_module: { bp2build_available: false } } Filesystem: map[string]string{ "foo/bar/Android.bp": otherDeps, }, + StubbedBuildDefinitions: []string{"//foo/bar:lib_a", "//foo/bar:lib_b", "//foo/bar:lib_default"}, ExpectedBazelTargets: []string{`cc_binary( name = "library_linking_strategy_sample_binary", deps = select({ @@ -1031,8 +1036,8 @@ cc_binary { }` otherDeps := ` -cc_library { name: "lib_a", bazel_module: { bp2build_available: false } } -cc_library { name: "lib_b", bazel_module: { bp2build_available: false } } +cc_library { name: "lib_a"} +cc_library { name: "lib_b"} ` runSoongConfigModuleTypeTest(t, Bp2buildTestCase{ @@ -1040,6 +1045,7 @@ cc_library { name: "lib_b", bazel_module: { bp2build_available: false } } ModuleTypeUnderTest: "cc_binary", ModuleTypeUnderTestFactory: cc.BinaryFactory, Blueprint: bp, + StubbedBuildDefinitions: []string{"//foo/bar:lib_a", "//foo/bar:lib_b"}, Filesystem: map[string]string{ "foo/bar/Android.bp": otherDeps, }, @@ -1118,9 +1124,9 @@ cc_binary { }` otherDeps := ` -cc_library { name: "lib_a", bazel_module: { bp2build_available: false } } -cc_library { name: "lib_b", bazel_module: { bp2build_available: false } } -cc_library { name: "lib_default", bazel_module: { bp2build_available: false } } +cc_library { name: "lib_a"} +cc_library { name: "lib_b"} +cc_library { name: "lib_default"} ` runSoongConfigModuleTypeTest(t, Bp2buildTestCase{ @@ -1131,6 +1137,7 @@ cc_library { name: "lib_default", bazel_module: { bp2build_available: false } } Filesystem: map[string]string{ "foo/bar/Android.bp": otherDeps, }, + StubbedBuildDefinitions: []string{"//foo/bar:lib_a", "//foo/bar:lib_b", "//foo/bar:lib_default"}, ExpectedBazelTargets: []string{`cc_binary( name = "alphabet_binary", deps = select({ diff --git a/bp2build/symlink_forest.go b/bp2build/symlink_forest.go index 5c333085d..966b94a80 100644 --- a/bp2build/symlink_forest.go +++ b/bp2build/symlink_forest.go @@ -43,7 +43,7 @@ import ( // clean the whole symlink forest and recreate it. This number can be bumped whenever there's // an incompatible change to the forest layout or a bug in incrementality that needs to be fixed // on machines that may still have the bug present in their forest. -const symlinkForestVersion = 1 +const symlinkForestVersion = 2 type instructionsNode struct { name string diff --git a/bp2build/testing.go b/bp2build/testing.go index 18ae82de9..a81070942 100644 --- a/bp2build/testing.go +++ b/bp2build/testing.go @@ -21,6 +21,8 @@ specific-but-shared functionality among tests in package import ( "fmt" + "path/filepath" + "regexp" "sort" "strings" "testing" @@ -36,6 +38,9 @@ var ( buildDir string ) +var labelRegex = regexp.MustCompile(`^//([^: ]+):([^ ]+)$`) +var simpleModuleNameRegex = regexp.MustCompile(`^[^: /]+$`) + func checkError(t *testing.T, errs []error, expectedErr error) bool { t.Helper() @@ -82,7 +87,19 @@ type Bp2buildTestCase struct { // ExpectedBazelTargets compares the BazelTargets generated in `Dir` (if not empty). // Otherwise, it checks the BazelTargets generated by `Blueprint` in the root directory. ExpectedBazelTargets []string - Filesystem map[string]string + // AlreadyExistingBuildContents, if non-empty, simulates an already-present source BUILD file + // in the directory under test. The BUILD file has the given contents. This BUILD file + // will also be treated as "BUILD file to keep" by the simulated bp2build environment. + AlreadyExistingBuildContents string + + // StubbedBuildDefinitions, if non-empty, adds stub definitions to already-present source + // BUILD files for each bazel label given. The BUILD files with these stub definitions + // are added to the BUILD file given in AlreadyExistingBuildContents. + // Labels may be of the form //pkg/to:target_name (which would be defined in pkg/to/BUILD.bazel) + // or `target_name` (which would be defined in ./BUILD.bazel). + StubbedBuildDefinitions []string + + Filesystem map[string]string // Dir sets the directory which will be compared against the targets in ExpectedBazelTargets. // This should used in conjunction with the Filesystem property to check for targets // generated from a directory that is not the root. @@ -108,23 +125,53 @@ func RunBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.Regi runBp2BuildTestCaseWithSetup(t, bp2buildSetup, tc) } -func RunApiBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) { - t.Helper() - apiBp2BuildSetup := android.GroupFixturePreparers( - android.FixtureRegisterWithContext(registerModuleTypes), - SetApiBp2BuildTestRunner, - ) - runBp2BuildTestCaseWithSetup(t, apiBp2BuildSetup, tc) -} - func runBp2BuildTestCaseWithSetup(t *testing.T, extraPreparer android.FixturePreparer, tc Bp2buildTestCase) { t.Helper() - dir := "." + if tc.Filesystem == nil { + tc.Filesystem = map[string]string{} + } + checkDir := "." + if tc.Dir != "" { + checkDir = tc.Dir + } + keepExistingBuildDirs := tc.KeepBuildFileForDirs + buildFilesToParse := []string{} + + if len(tc.StubbedBuildDefinitions) > 0 { + for _, buildDef := range tc.StubbedBuildDefinitions { + globalLabelMatch := labelRegex.FindStringSubmatch(buildDef) + var dir, targetName string + if len(globalLabelMatch) > 0 { + dir = globalLabelMatch[1] + targetName = globalLabelMatch[2] + } else { + if !simpleModuleNameRegex.MatchString(buildDef) { + t.Errorf("Stubbed build definition '%s' must be either a simple module name or of global target syntax (//foo/bar:baz).", buildDef) + return + } + dir = "." + targetName = buildDef + } + buildFilePath := filepath.Join(dir, "BUILD") + tc.Filesystem[buildFilePath] += + MakeBazelTarget( + "bp2build_test_stub", + targetName, + AttrNameToString{}) + keepExistingBuildDirs = append(keepExistingBuildDirs, dir) + buildFilesToParse = append(buildFilesToParse, buildFilePath) + } + } + if len(tc.AlreadyExistingBuildContents) > 0 { + buildFilePath := filepath.Join(checkDir, "BUILD") + tc.Filesystem[buildFilePath] += tc.AlreadyExistingBuildContents + keepExistingBuildDirs = append(keepExistingBuildDirs, checkDir) + buildFilesToParse = append(buildFilesToParse, buildFilePath) + } filesystem := make(map[string][]byte) for f, content := range tc.Filesystem { filesystem[f] = []byte(content) } - preparers := []android.FixturePreparer{ extraPreparer, android.FixtureMergeMockFs(filesystem), @@ -132,7 +179,7 @@ func runBp2BuildTestCaseWithSetup(t *testing.T, extraPreparer android.FixturePre android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { ctx.RegisterModuleType(tc.ModuleTypeUnderTest, tc.ModuleTypeUnderTestFactory) }), - android.FixtureModifyContext(func(ctx *android.TestContext) { + android.FixtureModifyContextWithMockFs(func(ctx *android.TestContext) { // A default configuration for tests to not have to specify bp2build_available on top level // targets. bp2buildConfig := android.NewBp2BuildAllowlist().SetDefaultConfig( @@ -140,7 +187,7 @@ func runBp2BuildTestCaseWithSetup(t *testing.T, extraPreparer android.FixturePre android.Bp2BuildTopLevel: allowlists.Bp2BuildDefaultTrueRecursively, }, ) - for _, f := range tc.KeepBuildFileForDirs { + for _, f := range keepExistingBuildDirs { bp2buildConfig.SetKeepExistingBuildFile(map[string]bool{ f: /*recursive=*/ false, }) @@ -150,6 +197,10 @@ func runBp2BuildTestCaseWithSetup(t *testing.T, extraPreparer android.FixturePre // from cloning modules to their original state after mutators run. This // would lose some data intentionally set by these mutators. ctx.SkipCloneModulesAfterMutators = true + err := ctx.RegisterExistingBazelTargets(".", buildFilesToParse) + if err != nil { + t.Errorf("error parsing build files in test setup: %s", err) + } }), android.FixtureModifyEnv(func(env map[string]string) { if tc.UnconvertedDepsMode == errorModulesUnconvertedDeps { @@ -168,10 +219,6 @@ func runBp2BuildTestCaseWithSetup(t *testing.T, extraPreparer android.FixturePre return } - checkDir := dir - if tc.Dir != "" { - checkDir = tc.Dir - } expectedTargets := map[string][]string{ checkDir: tc.ExpectedBazelTargets, } @@ -180,27 +227,14 @@ func runBp2BuildTestCaseWithSetup(t *testing.T, extraPreparer android.FixturePre } // SetBp2BuildTestRunner customizes the test fixture mechanism to run tests in Bp2Build mode. -var SetBp2BuildTestRunner = android.FixtureSetTestRunner(&bazelTestRunner{Bp2Build}) +var SetBp2BuildTestRunner = android.FixtureSetTestRunner(&bazelTestRunner{}) -// SetApiBp2BuildTestRunner customizes the test fixture mechanism to run tests in ApiBp2build mode. -var SetApiBp2BuildTestRunner = android.FixtureSetTestRunner(&bazelTestRunner{ApiBp2build}) - -// bazelTestRunner customizes the test fixture mechanism to run tests of the bp2build and -// apiBp2build build modes. -type bazelTestRunner struct { - mode CodegenMode -} +// bazelTestRunner customizes the test fixture mechanism to run tests of the bp2build build mode. +type bazelTestRunner struct{} func (b *bazelTestRunner) FinalPreparer(result *android.TestResult) android.CustomTestResult { ctx := result.TestContext - switch b.mode { - case Bp2Build: - ctx.RegisterForBazelConversion() - case ApiBp2build: - ctx.RegisterForApiBazelConversion() - default: - panic(fmt.Errorf("unknown build mode: %d", b.mode)) - } + ctx.RegisterForBazelConversion() return &BazelTestResult{TestResult: result} } @@ -214,11 +248,7 @@ func (b *bazelTestRunner) PostParseProcessor(result android.CustomTestResult) { return } - codegenMode := Bp2Build - if ctx.Config().BuildMode == android.ApiBp2build { - codegenMode = ApiBp2build - } - codegenCtx := NewCodegenContext(config, ctx.Context, codegenMode, "") + codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build, "") res, errs := GenerateBazelTargets(codegenCtx, false) if bazelResult.CollateErrs(errs) { return @@ -467,7 +497,7 @@ func (m *customModule) dir() *string { return m.props.Dir } -func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (m *customModule) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { if p := m.props.One_to_many_prop; p != nil && *p { customBp2buildOneToMany(ctx, m) return @@ -487,7 +517,10 @@ func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) { } } } - productVariableProps := android.ProductVariableProperties(ctx, ctx.Module()) + productVariableProps, errs := android.ProductVariableProperties(ctx, ctx.Module()) + for _, err := range errs { + ctx.ModuleErrorf("ProductVariableProperties error: %s", err) + } if props, ok := productVariableProps["String_literal_prop"]; ok { for c, p := range props { if val, ok := p.(*string); ok { @@ -522,7 +555,7 @@ func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) { } -func (m *customModule) createConfigSetting(ctx android.TopDownMutatorContext) { +func (m *customModule) createConfigSetting(ctx android.Bp2buildMutatorContext) { csa := bazel.ConfigSettingAttributes{ Flag_values: bazel.StringMapAttribute{ "//build/bazel/rules/my_string_setting": m.Name(), @@ -557,7 +590,7 @@ func (c *customModule) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) // A bp2build mutator that uses load statements and creates a 1:M mapping from // module to target. -func customBp2buildOneToMany(ctx android.TopDownMutatorContext, m *customModule) { +func customBp2buildOneToMany(ctx android.Bp2buildMutatorContext, m *customModule) { baseName := m.Name() attrs := &customBazelModuleAttributes{} @@ -596,11 +629,10 @@ func registerCustomModuleForBp2buildConversion(ctx *android.TestContext) { ctx.RegisterForBazelConversion() } -func simpleModuleDoNotConvertBp2build(typ, name string) string { +func simpleModule(typ, name string) string { return fmt.Sprintf(` %s { name: "%s", - bazel_module: { bp2build_available: false }, }`, typ, name) } @@ -670,6 +702,7 @@ func makeCcStubSuiteTargets(name string, attrs AttrNameToString) string { return "" } STUB_SUITE_ATTRS := map[string]string{ + "api_surface": "api_surface", "stubs_symbol_file": "symbol_file", "stubs_versions": "versions", "soname": "soname", @@ -688,7 +721,9 @@ func makeCcStubSuiteTargets(name string, attrs AttrNameToString) string { } func MakeNeverlinkDuplicateTarget(moduleType string, name string) string { - return MakeNeverlinkDuplicateTargetWithAttrs(moduleType, name, AttrNameToString{}) + return MakeNeverlinkDuplicateTargetWithAttrs(moduleType, name, AttrNameToString{ + "sdk_version": `"current"`, // use as default + }) } func MakeNeverlinkDuplicateTargetWithAttrs(moduleType string, name string, extraAttrs AttrNameToString) string { diff --git a/bpf/bpf.go b/bpf/bpf.go index 45009c1e7..38777ff65 100644 --- a/bpf/bpf.go +++ b/bpf/bpf.go @@ -153,7 +153,9 @@ func (bpf *bpf) GenerateAndroidBuildActions(ctx android.ModuleContext) { // The architecture doesn't matter here, but asm/types.h is included by linux/types.h. "-isystem bionic/libc/kernel/uapi/asm-arm64", "-isystem bionic/libc/kernel/android/uapi", + // TODO(b/296014682): Remove after the bpf_headers is moved to Connectivity "-I frameworks/libs/net/common/native/bpf_headers/include/bpf", + "-I packages/modules/Connectivity/staticlibs/native/bpf_headers/include/bpf", // TODO(b/149785767): only give access to specific file with AID_* constants "-I system/core/libcutils/include", "-I " + ctx.ModuleDir(), @@ -311,7 +313,7 @@ type bazelBpfAttributes struct { } // bpf bp2build converter -func (b *bpf) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (b *bpf) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { if ctx.ModuleType() != "bpf" { return } diff --git a/cc/androidmk.go b/cc/androidmk.go index ce35b5c44..e0e543ff0 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -530,9 +530,9 @@ func (c *snapshotLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entrie entries.SubName = "" - if c.isSanitizerEnabled(cfi) { + if c.IsSanitizerEnabled(cfi) { entries.SubName += ".cfi" - } else if c.isSanitizerEnabled(Hwasan) { + } else if c.IsSanitizerEnabled(Hwasan) { entries.SubName += ".hwasan" } diff --git a/cc/binary.go b/cc/binary.go index 4606b623e..0722f8110 100644 --- a/cc/binary.go +++ b/cc/binary.go @@ -599,7 +599,7 @@ func (handler *ccBinaryBazelHandler) ProcessBazelQueryResponse(ctx android.Modul handler.module.setAndroidMkVariablesFromCquery(info.CcAndroidMkInfo) } -func binaryBp2buildAttrs(ctx android.TopDownMutatorContext, m *Module) binaryAttributes { +func binaryBp2buildAttrs(ctx android.Bp2buildMutatorContext, m *Module) binaryAttributes { baseAttrs := bp2BuildParseBaseProps(ctx, m) binaryLinkerAttrs := bp2buildBinaryLinkerProps(ctx, m) @@ -661,7 +661,7 @@ func binaryBp2buildAttrs(ctx android.TopDownMutatorContext, m *Module) binaryAtt return attrs } -func binaryBp2build(ctx android.TopDownMutatorContext, m *Module) { +func binaryBp2build(ctx android.Bp2buildMutatorContext, m *Module) { // shared with cc_test binaryAttrs := binaryBp2buildAttrs(ctx, m) diff --git a/cc/bp2build.go b/cc/bp2build.go index 7f78e283d..569f721a5 100644 --- a/cc/bp2build.go +++ b/cc/bp2build.go @@ -851,7 +851,7 @@ func bp2BuildYasm(ctx android.Bp2buildMutatorContext, m *Module, ca compilerAttr return ret } -// bp2BuildParseBaseProps returns all compiler, linker, library attributes of a cc module.. +// bp2BuildParseBaseProps returns all compiler, linker, library attributes of a cc module. func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) baseAttributes { archVariantCompilerProps := module.GetArchVariantProperties(ctx, &BaseCompilerProperties{}) archVariantLinkerProps := module.GetArchVariantProperties(ctx, &BaseLinkerProperties{}) @@ -944,7 +944,10 @@ func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) nativeCoverage = BoolPtr(false) } - productVariableProps := android.ProductVariableProperties(ctx, ctx.Module()) + productVariableProps, errs := android.ProductVariableProperties(ctx, ctx.Module()) + for _, err := range errs { + ctx.ModuleErrorf("ProductVariableProperties error: %s", err) + } (&compilerAttrs).convertProductVariables(ctx, productVariableProps) (&linkerAttrs).convertProductVariables(ctx, productVariableProps) @@ -1000,6 +1003,8 @@ func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) if module.afdo != nil && module.afdo.Properties.Afdo { fdoProfileDep := bp2buildFdoProfile(ctx, module) if fdoProfileDep != nil { + // TODO(b/276287371): Only set fdo_profile for android platform + // https://cs.android.com/android/platform/superproject/main/+/main:build/soong/cc/afdo.go;l=105;drc=2dbe160d1af445de32725098570ec594e3944fc5 (&compilerAttrs).fdoProfile.SetValue(*fdoProfileDep) } } @@ -1109,22 +1114,15 @@ func bp2buildFdoProfile( ctx android.Bp2buildMutatorContext, m *Module, ) *bazel.Label { + // TODO(b/267229066): Convert to afdo boolean attribute and let Bazel handles finding + // fdo_profile target from AfdoProfiles product var for _, project := range globalAfdoProfileProjects { - // Ensure handcrafted BUILD file exists in the project - BUILDPath := android.ExistentPathForSource(ctx, project, "BUILD") - if BUILDPath.Valid() { - // We handcraft a BUILD file with fdo_profile targets that use the existing profiles in the project - // This implementation is assuming that every afdo profile in globalAfdoProfileProjects already has - // an associated fdo_profile target declared in the same package. + // Ensure it's a Soong package + bpPath := android.ExistentPathForSource(ctx, project, "Android.bp") + if bpPath.Valid() { // TODO(b/260714900): Handle arch-specific afdo profiles (e.g. `<module-name>-arm<64>.afdo`) path := android.ExistentPathForSource(ctx, project, m.Name()+".afdo") if path.Valid() { - // FIXME: Some profiles only exist internally and are not released to AOSP. - // When generated BUILD files are checked in, we'll run into merge conflict. - // The cc_library_shared target in AOSP won't have reference to an fdo_profile target because - // the profile doesn't exist. Internally, the same cc_library_shared target will - // have reference to the fdo_profile. - // For more context, see b/258682955#comment2 fdoProfileLabel := "//" + strings.TrimSuffix(project, "/") + ":" + m.Name() return &bazel.Label{ Label: fdoProfileLabel, @@ -1380,10 +1378,10 @@ func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversion // having stubs or not, so Bazel select() statement can be used to choose // source/stub variants of them. apexAvailable := module.ApexAvailable() - setStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.export, &la.dynamicDeps, 0, false) - setStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.implementation, &la.implementationDynamicDeps, 1, false) + SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.export, &la.dynamicDeps, 0, false) + SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.implementation, &la.implementationDynamicDeps, 1, false) if len(systemSharedLibs) > 0 { - setStubsForDynamicDeps(ctx, axis, config, apexAvailable, bazelLabelForSharedDeps(ctx, systemSharedLibs), &la.systemDynamicDeps, 2, true) + SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, bazelLabelForSharedDeps(ctx, systemSharedLibs), &la.systemDynamicDeps, 2, true) } } @@ -1583,7 +1581,13 @@ func useStubOrImplInApexWithName(ssi stubSelectionInfo) { } } -func setStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis, +// hasNdkStubs returns true for libfoo if there exists a libfoo.ndk of type ndk_library +func hasNdkStubs(ctx android.BazelConversionPathContext, c *Module) bool { + mod, exists := ctx.ModuleFromName(c.Name() + ndkLibrarySuffix) + return exists && ctx.OtherModuleType(mod) == "ndk_library" +} + +func SetStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis, config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int, buildNonApexWithStubs bool) { // Create a config_setting for each apex_available. @@ -1624,6 +1628,11 @@ func setStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.C if linkable, ok := ctx.Module().(LinkableInterface); ok && linkable.Bootstrap() { sameApiDomain = true } + // If dependency has `apex_available: ["//apex_available:platform]`, then the platform variant of rdep should link against its impl. + // https://cs.android.com/android/_/android/platform/build/soong/+/main:cc/cc.go;l=3617;bpv=1;bpt=0;drc=c6a93d853b37ec90786e745b8d282145e6d3b589 + if depApexAvailable := dep.(*Module).ApexAvailable(); len(depApexAvailable) == 1 && depApexAvailable[0] == android.AvailableToPlatform { + sameApiDomain = true + } } else { sameApiDomain = android.InList(apiDomain, dep.(*Module).ApexAvailable()) } @@ -1638,6 +1647,29 @@ func setStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.C useStubOrImplInApexWithName(ssi) } } + + // If the library has an sdk variant, create additional selects to build this variant against the ndk + // The config setting for this variant will be //build/bazel/rules/apex:unbundled_app + if c, ok := ctx.Module().(*Module); ok && c.Properties.Sdk_version != nil { + for _, l := range dynamicLibs.Includes { + dep, _ := ctx.ModuleFromName(l.OriginalModuleName) + label := l // use the implementation by default + if depC, ok := dep.(*Module); ok && hasNdkStubs(ctx, depC) { + // If the dependency has ndk stubs, build against the ndk stubs + // https://cs.android.com/android/_/android/platform/build/soong/+/main:cc/cc.go;l=2642-2643;drc=e12d252e22dd8afa654325790d3298a0d67bd9d6;bpv=1;bpt=0 + ver := proptools.String(c.Properties.Sdk_version) + // TODO - b/298085502: Add bp2build support for sdk_version: "minimum" + ndkLibModule, _ := ctx.ModuleFromName(dep.Name() + ndkLibrarySuffix) + label = bazel.Label{ + Label: "//" + ctx.OtherModuleDir(ndkLibModule) + ":" + ndkLibModule.Name() + "_stub_libs-" + ver, + } + } + // add the ndk lib label to this axis + existingValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, "unbundled_app") + existingValue.Append(bazel.MakeLabelList([]bazel.Label{label})) + dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, "unbundled_app", bazel.FirstUniqueBazelLabelList(existingValue)) + } + } } func (la *linkerAttributes) convertStripProps(ctx android.BazelConversionPathContext, module *Module) { @@ -1936,6 +1968,8 @@ func bp2buildSanitizerFeatures(ctx android.BazelConversionPathContext, m *Module sanitizerFeatures := bazel.StringListAttribute{} sanitizerCopts := bazel.StringListAttribute{} sanitizerCompilerInputs := bazel.LabelListAttribute{} + memtagFeatures := bazel.StringListAttribute{} + memtagFeature := "" bp2BuildPropParseHelper(ctx, m, &SanitizeProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { var features []string if sanitizerProps, ok := props.(*SanitizeProperties); ok { @@ -1960,9 +1994,18 @@ func bp2buildSanitizerFeatures(ctx android.BazelConversionPathContext, m *Module features = append(features, "android_cfi_assembly_support") } } + + if sanitizerProps.Sanitize.Memtag_heap != nil { + if (axis == bazel.NoConfigAxis && memtagFeature == "") || + (axis == bazel.OsArchConfigurationAxis && config == bazel.OsArchAndroidArm64) { + memtagFeature = setMemtagValue(sanitizerProps, &memtagFeatures) + } + } sanitizerFeatures.SetSelectValue(axis, config, features) } }) + sanitizerFeatures.Append(memtagFeatures) + return sanitizerValues{ features: sanitizerFeatures, copts: sanitizerCopts, @@ -1970,6 +2013,26 @@ func bp2buildSanitizerFeatures(ctx android.BazelConversionPathContext, m *Module } } +func setMemtagValue(sanitizerProps *SanitizeProperties, memtagFeatures *bazel.StringListAttribute) string { + var features []string + if proptools.Bool(sanitizerProps.Sanitize.Memtag_heap) { + features = append(features, "memtag_heap") + } else { + features = append(features, "-memtag_heap") + } + // Logic comes from: https://cs.android.com/android/platform/superproject/main/+/32ea1afbd1148b0b78553f24fa61116c999eb968:build/soong/cc/sanitize.go;l=910 + if sanitizerProps.Sanitize.Diag.Memtag_heap != nil { + if proptools.Bool(sanitizerProps.Sanitize.Diag.Memtag_heap) { + features = append(features, "diag_memtag_heap") + } else { + features = append(features, "-diag_memtag_heap") + } + } + memtagFeatures.SetSelectValue(bazel.OsArchConfigurationAxis, bazel.OsArchAndroidArm64, features) + + return features[0] +} + func bp2buildLtoFeatures(ctx android.BazelConversionPathContext, m *Module) bazel.StringListAttribute { lto_feature_name := "android_thin_lto" ltoBoolFeatures := bazel.BoolAttribute{} @@ -589,6 +589,7 @@ type Generator interface { GeneratorFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags GeneratorSources(ctx ModuleContext) GeneratedSource GeneratorBuildActions(ctx ModuleContext, flags Flags, deps PathDeps) + GeneratorBp2build(ctx android.Bp2buildMutatorContext) bool } // compiler is the interface for a compiler helper object. Different module decorators may implement @@ -879,16 +880,16 @@ type Module struct { installer installer bazelHandler BazelHandler - features []feature - stl *stl - sanitize *sanitize - coverage *coverage - fuzzer *fuzzer - sabi *sabi - vndkdep *vndkdep - lto *lto - afdo *afdo - pgo *pgo + features []feature + stl *stl + sanitize *sanitize + coverage *coverage + fuzzer *fuzzer + sabi *sabi + vndkdep *vndkdep + lto *lto + afdo *afdo + pgo *pgo orderfile *orderfile library libraryInterface @@ -1104,6 +1105,16 @@ func (c *Module) CcLibraryInterface() bool { return false } +func (c *Module) IsNdkPrebuiltStl() bool { + if c.linker == nil { + return false + } + if _, ok := c.linker.(*ndkPrebuiltStlLinker); ok { + return true + } + return false +} + func (c *Module) RlibStd() bool { panic(fmt.Errorf("RlibStd called on non-Rust module: %q", c.BaseModuleName())) } @@ -4158,6 +4169,7 @@ const ( headerLibrary testBin // testBinary already declared ndkLibrary + ndkPrebuiltStl ) func (c *Module) typ() moduleType { @@ -4196,12 +4208,24 @@ func (c *Module) typ() moduleType { return sharedLibrary } else if c.isNDKStubLibrary() { return ndkLibrary + } else if c.IsNdkPrebuiltStl() { + return ndkPrebuiltStl } return unknownType } // ConvertWithBp2build converts Module to Bazel for bp2build. -func (c *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (c *Module) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { + if len(c.generators) > 0 { + allConverted := true + for _, generator := range c.generators { + allConverted = allConverted && generator.GeneratorBp2build(ctx) + } + if allConverted { + return + } + } + prebuilt := c.IsPrebuilt() switch c.typ() { case binary: @@ -4240,6 +4264,10 @@ func (c *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { } else { sharedOrStaticLibraryBp2Build(ctx, c, false) } + case ndkPrebuiltStl: + ndkPrebuiltStlBp2build(ctx, c) + case ndkLibrary: + ndkLibraryBp2build(ctx, c) default: ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "") } diff --git a/cc/config/OWNERS b/cc/config/OWNERS index 580f215c7..c78b6d582 100644 --- a/cc/config/OWNERS +++ b/cc/config/OWNERS @@ -1,3 +1,3 @@ per-file vndk.go = smoreland@google.com, victoryang@google.com -per-file clang.go,global.go,tidy.go = srhines@google.com, chh@google.com, pirama@google.com, yikong@google.com +per-file clang.go,global.go,tidy.go = appujee@google.com, pirama@google.com, srhines@google.com, yabinc@google.com, yikong@google.com, zijunzhao@google.com diff --git a/cc/config/global.go b/cc/config/global.go index 61ea0adda..a586a3f70 100644 --- a/cc/config/global.go +++ b/cc/config/global.go @@ -45,7 +45,6 @@ var ( "-UDEBUG", "-fno-exceptions", - "-Wno-multichar", "-O2", "-fdebug-default-version=5", @@ -68,10 +67,6 @@ var ( // not emit the table by default on Android since NDK still uses GNU binutils. "-faddrsig", - // Turn on -fcommon explicitly, since Clang now defaults to -fno-common. The cleanup bug - // tracking this is http://b/151457797. - "-fcommon", - // Help catch common 32/64-bit errors. "-Werror=int-conversion", @@ -93,9 +88,6 @@ var ( // guide and should not be a warning, at least by default. "-Wno-c99-designator", - // Many old files still have GNU designator syntax. - "-Wno-gnu-designator", - // Warnings from clang-12 "-Wno-gnu-folding-constant", @@ -143,6 +135,9 @@ var ( "-Werror=format-security", "-nostdlibinc", + // Enable MLGO for register allocation. + "-mllvm -regalloc-enable-advisor=release", + // Emit additional debug info for AutoFDO "-fdebug-info-for-profiling", } @@ -170,6 +165,8 @@ var ( "-Wl,--exclude-libs,libgcc_stripped.a", "-Wl,--exclude-libs,libunwind_llvm.a", "-Wl,--exclude-libs,libunwind.a", + // Enable MLGO for register allocation. + "-Wl,-mllvm,-regalloc-enable-advisor=release", } deviceGlobalLldflags = append(deviceGlobalLdflags, commonGlobalLldflags...) @@ -252,11 +249,10 @@ var ( // (anything for which IsThirdPartyPath() in build/soong/android/paths.go // returns true - includes external/, most of vendor/ and most of hardware/) noOverrideExternalGlobalCflags = []string{ + // http://b/151457797 + "-fcommon", // http://b/191699019 "-Wno-format-insufficient-args", - // http://b/296422292 - // Usually signals a mistake and should be a hard error. - "-Wno-sizeof-array-div", // http://b/296321145 // Indicates potential memory or stack corruption, so should be changed // to a hard error. Currently triggered by some vendor code. @@ -323,7 +319,7 @@ var ( // prebuilts/clang default settings. ClangDefaultBase = "prebuilts/clang/host" - ClangDefaultVersion = "clang-r498229" + ClangDefaultVersion = "clang-r498229b" ClangDefaultShortVersion = "17" // Directories with warnings from Android.bp files. diff --git a/cc/config/riscv64_device.go b/cc/config/riscv64_device.go index 40919c0cf..e04862209 100644 --- a/cc/config/riscv64_device.go +++ b/cc/config/riscv64_device.go @@ -26,14 +26,14 @@ var ( // Help catch common 32/64-bit errors. "-Werror=implicit-function-declaration", "-fno-emulated-tls", - "-march=rv64gc_zba_zbb_zbs", + "-march=rv64gcv_zba_zbb_zbs", } riscv64ArchVariantCflags = map[string][]string{} riscv64Ldflags = []string{ "-Wl,--hash-style=gnu", - "-march=rv64gc_zba_zbb_zbs", + "-march=rv64gcv_zba_zbb_zbs", } riscv64Lldflags = append(riscv64Ldflags, diff --git a/cc/fdo_profile.go b/cc/fdo_profile.go index 7fbe71940..05a8f464b 100644 --- a/cc/fdo_profile.go +++ b/cc/fdo_profile.go @@ -16,8 +16,10 @@ package cc import ( "android/soong/android" + "android/soong/bazel" "github.com/google/blueprint" + "github.com/google/blueprint/proptools" ) func init() { @@ -25,11 +27,12 @@ func init() { } func RegisterFdoProfileBuildComponents(ctx android.RegistrationContext) { - ctx.RegisterModuleType("fdo_profile", fdoProfileFactory) + ctx.RegisterModuleType("fdo_profile", FdoProfileFactory) } type fdoProfile struct { android.ModuleBase + android.BazelModuleBase properties fdoProfileProperties } @@ -38,6 +41,49 @@ type fdoProfileProperties struct { Profile *string `android:"arch_variant"` } +type bazelFdoProfileAttributes struct { + Profile bazel.StringAttribute +} + +func (fp *fdoProfile) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { + var profileAttr bazel.StringAttribute + + archVariantProps := fp.GetArchVariantProperties(ctx, &fdoProfileProperties{}) + for axis, configToProps := range archVariantProps { + for config, _props := range configToProps { + if archProps, ok := _props.(*fdoProfileProperties); ok { + if axis.String() == "arch" || axis.String() == "no_config" { + if archProps.Profile != nil { + profileAttr.SetSelectValue(axis, config, archProps.Profile) + } + } + } + } + } + + // Ideally, cc_library_shared's fdo_profile attr can be a select statement so that we + // don't lift the restriction here. However, in cc_library_shared macro, fdo_profile + // is used as a string, we need to temporarily lift the host restriction until we can + // pass use fdo_profile attr with select statement + // https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/cc/cc_library_shared.bzl;l=127;drc=cc01bdfd39857eddbab04ef69ab6db22dcb1858a + // TODO(b/276287371): Drop the restriction override after fdo_profile path is handled properly + var noRestriction bazel.BoolAttribute + noRestriction.SetSelectValue(bazel.NoConfigAxis, "", proptools.BoolPtr(true)) + + ctx.CreateBazelTargetModuleWithRestrictions( + bazel.BazelTargetModuleProperties{ + Rule_class: "fdo_profile", + }, + android.CommonAttributes{ + Name: fp.Name(), + }, + &bazelFdoProfileAttributes{ + Profile: profileAttr, + }, + noRestriction, + ) +} + // FdoProfileInfo is provided by FdoProfileProvider type FdoProfileInfo struct { Path android.Path @@ -77,9 +123,10 @@ func fdoProfileMutator(ctx android.BottomUpMutatorContext) { } } -func fdoProfileFactory() android.Module { +func FdoProfileFactory() android.Module { m := &fdoProfile{} m.AddProperties(&m.properties) android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibBoth) + android.InitBazelModule(m) return m } diff --git a/cc/generated_cc_library.go b/cc/generated_cc_library.go index 55e19f9a9..8428e9420 100644 --- a/cc/generated_cc_library.go +++ b/cc/generated_cc_library.go @@ -28,9 +28,8 @@ func GeneratedCcLibraryModuleFactory(moduleName string, callbacks Generator) and staticAndSharedLibrarySdkMemberType, } - // TODO: Need to be bazelable - // module.bazelable = true - // module.bazelHandler = &ccLibraryBazelHandler{module: module} + module.bazelable = true + module.bazelHandler = &ccLibraryBazelHandler{module: module} module.generators = append(module.generators, callbacks) diff --git a/cc/library.go b/cc/library.go index 2d4d60440..b9dc71b32 100644 --- a/cc/library.go +++ b/cc/library.go @@ -308,7 +308,7 @@ func stripAttrsFromLinkerAttrs(la *linkerAttributes) stripAttributes { } } -func libraryBp2Build(ctx android.TopDownMutatorContext, m *Module) { +func libraryBp2Build(ctx android.Bp2buildMutatorContext, m *Module) { sharedAttrs := bp2BuildParseSharedProps(ctx, m) staticAttrs := bp2BuildParseStaticProps(ctx, m) baseAttributes := bp2BuildParseBaseProps(ctx, m) @@ -480,7 +480,7 @@ func libraryBp2Build(ctx android.TopDownMutatorContext, m *Module) { createStubsBazelTargetIfNeeded(ctx, m, compilerAttrs, exportedIncludes, baseAttributes) } -func createStubsBazelTargetIfNeeded(ctx android.TopDownMutatorContext, m *Module, compilerAttrs compilerAttributes, exportedIncludes BazelIncludes, baseAttributes baseAttributes) { +func createStubsBazelTargetIfNeeded(ctx android.Bp2buildMutatorContext, m *Module, compilerAttrs compilerAttributes, exportedIncludes BazelIncludes, baseAttributes baseAttributes) { if compilerAttrs.stubsSymbolFile != nil && len(compilerAttrs.stubsVersions.Value) > 0 { stubSuitesProps := bazel.BazelTargetModuleProperties{ Rule_class: "cc_stub_suite", @@ -494,6 +494,7 @@ func createStubsBazelTargetIfNeeded(ctx android.TopDownMutatorContext, m *Module Soname: &soname, Source_library_label: proptools.StringPtr(m.GetBazelLabel(ctx, m)), Deps: baseAttributes.deps, + Api_surface: proptools.StringPtr("module-libapi"), } ctx.CreateBazelTargetModule(stubSuitesProps, android.CommonAttributes{Name: m.Name() + "_stub_libs"}, @@ -2885,7 +2886,7 @@ func maybeInjectBoringSSLHash(ctx android.ModuleContext, outputFile android.Modu return outputFile } -func bp2buildParseAbiCheckerProps(ctx android.TopDownMutatorContext, module *Module) bazelCcHeaderAbiCheckerAttributes { +func bp2buildParseAbiCheckerProps(ctx android.Bp2buildMutatorContext, module *Module) bazelCcHeaderAbiCheckerAttributes { lib, ok := module.linker.(*libraryDecorator) if !ok { return bazelCcHeaderAbiCheckerAttributes{} @@ -2908,7 +2909,7 @@ func bp2buildParseAbiCheckerProps(ctx android.TopDownMutatorContext, module *Mod return abiCheckerAttrs } -func sharedOrStaticLibraryBp2Build(ctx android.TopDownMutatorContext, module *Module, isStatic bool) { +func sharedOrStaticLibraryBp2Build(ctx android.Bp2buildMutatorContext, module *Module, isStatic bool) { baseAttributes := bp2BuildParseBaseProps(ctx, module) compilerAttrs := baseAttributes.compilerAttributes linkerAttrs := baseAttributes.linkerAttributes @@ -3121,6 +3122,7 @@ type bazelCcStubSuiteAttributes struct { Source_library_label *string Soname *string Deps bazel.LabelListAttribute + Api_surface *string } type bazelCcHeaderAbiCheckerAttributes struct { diff --git a/cc/library_headers.go b/cc/library_headers.go index ce9c4aacf..5eba6ab96 100644 --- a/cc/library_headers.go +++ b/cc/library_headers.go @@ -129,7 +129,7 @@ type bazelCcLibraryHeadersAttributes struct { sdkAttributes } -func libraryHeadersBp2Build(ctx android.TopDownMutatorContext, module *Module) { +func libraryHeadersBp2Build(ctx android.Bp2buildMutatorContext, module *Module) { baseAttributes := bp2BuildParseBaseProps(ctx, module) exportedIncludes := bp2BuildParseExportedIncludes(ctx, module, &baseAttributes.includes) linkerAttrs := baseAttributes.linkerAttributes @@ -153,8 +153,13 @@ func libraryHeadersBp2Build(ctx android.TopDownMutatorContext, module *Module) { tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module) + name := module.Name() + if module.IsPrebuilt() { + name = android.RemoveOptionalPrebuiltPrefix(name) + } + ctx.CreateBazelTargetModule(props, android.CommonAttributes{ - Name: module.Name(), + Name: name, Tags: tags, }, attrs) } diff --git a/cc/linkable.go b/cc/linkable.go index 209939916..5b5b856ab 100644 --- a/cc/linkable.go +++ b/cc/linkable.go @@ -95,6 +95,18 @@ type Snapshottable interface { // IsSnapshotPrebuilt returns true if this module is a snapshot prebuilt. IsSnapshotPrebuilt() bool + + // IsSnapshotSanitizer returns true if this snapshot module implements SnapshotSanitizer. + IsSnapshotSanitizer() bool + + // IsSnapshotSanitizerAvailable returns true if this snapshot module has a sanitizer source available (cfi, hwasan). + IsSnapshotSanitizerAvailable(t SanitizerType) bool + + // SetSnapshotSanitizerVariation sets the sanitizer variation type for this snapshot module. + SetSnapshotSanitizerVariation(t SanitizerType, enabled bool) + + // IsSnapshotUnsanitizedVariant returns true if this is the unsanitized snapshot module variant. + IsSnapshotUnsanitizedVariant() bool } // LinkableInterface is an interface for a type of module that is linkable in a C++ library. @@ -162,7 +162,7 @@ func (lto *lto) Never() bool { } func GlobalThinLTO(ctx android.BaseModuleContext) bool { - return ctx.Config().IsEnvTrue("GLOBAL_THINLTO") + return !ctx.Config().IsEnvFalse("GLOBAL_THINLTO") } // Propagate lto requirements down from binaries diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go index d0ae4a56d..1a8e90fd9 100644 --- a/cc/ndk_headers.go +++ b/cc/ndk_headers.go @@ -82,6 +82,7 @@ type headerModule struct { properties headerProperties + srcPaths android.Paths installPaths android.Paths licensePath android.Path } @@ -125,8 +126,8 @@ func (m *headerModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License)) - srcFiles := android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs) - for _, header := range srcFiles { + m.srcPaths = android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs) + for _, header := range m.srcPaths { installDir := getHeaderInstallDir(ctx, header, String(m.properties.From), String(m.properties.To)) installedPath := ctx.InstallFile(installDir, header.Base(), header) @@ -193,6 +194,7 @@ type versionedHeaderModule struct { properties versionedHeaderProperties + srcPaths android.Paths installPaths android.Paths licensePath android.Path } @@ -211,9 +213,9 @@ func (m *versionedHeaderModule) GenerateAndroidBuildActions(ctx android.ModuleCo fromSrcPath := android.PathForModuleSrc(ctx, String(m.properties.From)) toOutputPath := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To)) - srcFiles := ctx.GlobFiles(headerGlobPattern(fromSrcPath.String()), nil) + m.srcPaths = ctx.GlobFiles(headerGlobPattern(fromSrcPath.String()), nil) var installPaths []android.WritablePath - for _, header := range srcFiles { + for _, header := range m.srcPaths { installDir := getHeaderInstallDir(ctx, header, String(m.properties.From), String(m.properties.To)) installPath := installDir.Join(ctx, header.Base()) installPaths = append(installPaths, installPath) @@ -224,11 +226,11 @@ func (m *versionedHeaderModule) GenerateAndroidBuildActions(ctx android.ModuleCo ctx.ModuleErrorf("glob %q matched zero files", String(m.properties.From)) } - processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, srcFiles, installPaths) + processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, m.srcPaths, installPaths) } func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir android.Path, - srcFiles android.Paths, installPaths []android.WritablePath) android.Path { + srcPaths android.Paths, installPaths []android.WritablePath) android.Path { // The versioner depends on a dependencies directory to simplify determining include paths // when parsing headers. This directory contains architecture specific directories as well // as a common directory, each of which contains symlinks to the actually directories to @@ -253,7 +255,7 @@ func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir andro Rule: versionBionicHeaders, Description: "versioner preprocess " + srcDir.Rel(), Output: timestampFile, - Implicits: append(srcFiles, depsGlob...), + Implicits: append(srcPaths, depsGlob...), ImplicitOutputs: installPaths, Args: map[string]string{ "depsPath": depsPath.String(), @@ -317,6 +319,7 @@ type preprocessedHeadersModule struct { properties preprocessedHeadersProperties + srcPaths android.Paths installPaths android.Paths licensePath android.Path } @@ -329,9 +332,9 @@ func (m *preprocessedHeadersModule) GenerateAndroidBuildActions(ctx android.Modu preprocessor := android.PathForModuleSrc(ctx, String(m.properties.Preprocessor)) m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License)) - srcFiles := android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs) + m.srcPaths = android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs) installDir := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To)) - for _, src := range srcFiles { + for _, src := range m.srcPaths { installPath := installDir.Join(ctx, src.Base()) m.installPaths = append(m.installPaths, installPath) diff --git a/cc/ndk_library.go b/cc/ndk_library.go index 9281aebb5..b3bb2da15 100644 --- a/cc/ndk_library.go +++ b/cc/ndk_library.go @@ -43,11 +43,17 @@ var ( CommandDeps: []string{"$ndkStubGenerator"}, }, "arch", "apiLevel", "apiMap", "flags") + // $headersList should include paths to public headers. All types + // that are defined outside of public headers will be excluded from + // ABI monitoring. + // + // STG tool doesn't access content of files listed in $headersList, + // so there is no need to add them to dependencies. stg = pctx.AndroidStaticRule("stg", blueprint.RuleParams{ - Command: "$stg -S :$symbolList --elf $in -o $out", + Command: "$stg -S :$symbolList --file-filter :$headersList --elf $in -o $out", CommandDeps: []string{"$stg"}, - }, "symbolList") + }, "symbolList", "headersList") stgdiff = pctx.AndroidStaticRule("stgdiff", blueprint.RuleParams{ @@ -347,14 +353,19 @@ func (this *stubDecorator) dumpAbi(ctx ModuleContext, symbolList android.Path) { this.abiDumpPath = getNdkAbiDumpInstallBase(ctx).Join(ctx, this.apiLevel.String(), ctx.Arch().ArchType.String(), this.libraryName(ctx), "abi.stg") + headersList := getNdkABIHeadersFile(ctx) ctx.Build(pctx, android.BuildParams{ Rule: stg, Description: fmt.Sprintf("stg %s", implementationLibrary), Input: implementationLibrary, - Implicit: symbolList, - Output: this.abiDumpPath, + Implicits: []android.Path{ + symbolList, + headersList, + }, + Output: this.abiDumpPath, Args: map[string]string{ - "symbolList": symbolList.String(), + "symbolList": symbolList.String(), + "headersList": headersList.String(), }, }) } @@ -404,7 +415,7 @@ func (this *stubDecorator) diffAbi(ctx ModuleContext) { // Also ensure that the ABI of the next API level (if there is one) matches // this API level. *New* ABI is allowed, but any changes to APIs that exist // in this API level are disallowed. - if !this.apiLevel.IsCurrent() { + if !this.apiLevel.IsCurrent() && prebuiltAbiDump.Valid() { nextApiLevel := findNextApiLevel(ctx, this.apiLevel) if nextApiLevel == nil { panic(fmt.Errorf("could not determine which API level follows "+ @@ -424,10 +435,12 @@ func (this *stubDecorator) diffAbi(ctx ModuleContext) { } else { ctx.Build(pctx, android.BuildParams{ Rule: stgdiff, - Description: fmt.Sprintf("abidiff %s %s", this.abiDumpPath, - nextAbiDump), + Description: fmt.Sprintf( + "Comparing ABI to the next API level %s %s", + prebuiltAbiDump, nextAbiDump), Output: nextAbiDiffPath, - Inputs: android.Paths{this.abiDumpPath, nextAbiDump.Path()}, + Inputs: android.Paths{ + prebuiltAbiDump.Path(), nextAbiDump.Path()}, Args: map[string]string{ "args": "--format=small --ignore=interface_addition", }, @@ -570,3 +583,40 @@ func apiHeaderLabels(ctx android.TopDownMutatorContext, hdrLibs []string) bazel. } return android.BazelLabelForModuleDepsWithFn(ctx, hdrLibs, addSuffix) } + +func ndkLibraryBp2build(ctx android.Bp2buildMutatorContext, c *Module) { + ndk, _ := c.linker.(*stubDecorator) + props := bazel.BazelTargetModuleProperties{ + Rule_class: "cc_stub_suite", + Bzl_load_location: "//build/bazel/rules/cc:cc_stub_library.bzl", + } + sourceLibraryName := strings.TrimSuffix(c.Name(), ".ndk") + fromApiLevel, err := android.ApiLevelFromUser(ctx, proptools.String(ndk.properties.First_version)) + if err != nil { + ctx.PropertyErrorf("first_version", "error converting first_version %v", proptools.String(ndk.properties.First_version)) + } + symbolFileLabel := android.BazelLabelForModuleSrcSingle(ctx, proptools.String(ndk.properties.Symbol_file)) + attrs := &bazelCcStubSuiteAttributes{ + // TODO - b/300504837 Add ndk headers + Symbol_file: proptools.StringPtr(symbolFileLabel.Label), + Soname: proptools.StringPtr(sourceLibraryName + ".so"), + Api_surface: proptools.StringPtr(android.PublicApi.String()), + } + if sourceLibrary, exists := ctx.ModuleFromName(sourceLibraryName); exists { + // the source library might not exist in minimal/unbuildable branches like kernel-build-tools. + // check for its existence + attrs.Source_library_label = proptools.StringPtr(c.GetBazelLabel(ctx, sourceLibrary)) + } + if ctx.Config().RawPlatformSdkVersion() != nil { + // This is a hack to populate `versions` only on branches that set a platform_sdk_version + // This prevents errors on branches such as kernel-build-tools + // This hack is acceptable since we are not required to support NDK Bazel builds on those branches + attrs.Versions = bazel.MakeStringListAttribute(ndkLibraryVersions(ctx, fromApiLevel)) + } + + ctx.CreateBazelTargetModule( + props, + android.CommonAttributes{Name: c.Name() + "_stub_libs"}, + attrs, + ) +} diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go index d3a0a002e..c3e65106a 100644 --- a/cc/ndk_prebuilt.go +++ b/cc/ndk_prebuilt.go @@ -15,9 +15,11 @@ package cc import ( + "path/filepath" "strings" "android/soong/android" + "android/soong/bazel" ) func init() { @@ -64,6 +66,7 @@ func NdkPrebuiltSharedStlFactory() android.Module { module.Properties.Sdk_version = StringPtr("minimum") module.Properties.AlwaysSdk = true module.stl.Properties.Stl = StringPtr("none") + module.bazelable = true return module.Init() } @@ -84,12 +87,16 @@ func NdkPrebuiltStaticStlFactory() android.Module { module.Properties.AlwaysSdk = true module.Properties.Sdk_version = StringPtr("current") module.stl.Properties.Stl = StringPtr("none") + module.bazelable = true return module.Init() } +const ( + libDir = "current/sources/cxx-stl/llvm-libc++/libs" +) + func getNdkStlLibDir(ctx android.ModuleContext) android.SourcePath { - libDir := "prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs" - return android.PathForSource(ctx, libDir).Join(ctx, ctx.Arch().Abi[0]) + return android.PathForSource(ctx, ctx.ModuleDir(), libDir).Join(ctx, ctx.Arch().Abi[0]) } func (ndk *ndkPrebuiltStlLinker) link(ctx ModuleContext, flags Flags, @@ -128,3 +135,81 @@ func (ndk *ndkPrebuiltStlLinker) link(ctx ModuleContext, flags Flags, return lib } + +var ( + archToAbiDirMap = map[string]string{ + "android_arm": "armeabi-v7a", + "android_arm64": "arm64-v8a", + "android_riscv64": "riscv64", + "android_x86": "x86", + "android_x86_64": "x86_64", + } +) + +// stlSrcBp2build returns a bazel label for the checked-in .so/.a file +// It contains a select statement for each ABI +func stlSrcBp2build(ctx android.Bp2buildMutatorContext, c *Module) bazel.LabelAttribute { + libName := strings.TrimPrefix(c.Name(), "ndk_") + libExt := ".so" // TODO - b/201079053: Support windows + if ctx.ModuleType() == "ndk_prebuilt_static_stl" { + libExt = ".a" + } + src := bazel.LabelAttribute{} + for arch, abiDir := range archToAbiDirMap { + srcPath := filepath.Join(libDir, abiDir, libName+libExt) + src.SetSelectValue( + bazel.OsArchConfigurationAxis, + arch, + android.BazelLabelForModuleSrcSingle(ctx, srcPath), + ) + } + return src +} + +// stlIncludesBp2build returns the includes exported by the STL +func stlIncludesBp2build(c *Module) bazel.StringListAttribute { + linker, _ := c.linker.(*ndkPrebuiltStlLinker) + includeDirs := append( + []string{}, + linker.libraryDecorator.flagExporter.Properties.Export_include_dirs..., + ) + includeDirs = append( + includeDirs, + linker.libraryDecorator.flagExporter.Properties.Export_system_include_dirs..., + ) + return bazel.MakeStringListAttribute(android.FirstUniqueStrings(includeDirs)) +} + +func ndkPrebuiltStlBp2build(ctx android.Bp2buildMutatorContext, c *Module) { + if ctx.ModuleType() == "ndk_prebuilt_static_stl" { + ndkPrebuiltStaticStlBp2build(ctx, c) + } else { + ndkPrebuiltSharedStlBp2build(ctx, c) + } +} + +func ndkPrebuiltStaticStlBp2build(ctx android.Bp2buildMutatorContext, c *Module) { + props := bazel.BazelTargetModuleProperties{ + Rule_class: "cc_prebuilt_library_static", + Bzl_load_location: "//build/bazel/rules/cc:cc_prebuilt_library_static.bzl", + } + attrs := &bazelPrebuiltLibraryStaticAttributes{ + Static_library: stlSrcBp2build(ctx, c), + Export_system_includes: stlIncludesBp2build(c), // The exports are always as system + } + // TODO: min_sdk_version + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: c.Name()}, attrs) +} + +func ndkPrebuiltSharedStlBp2build(ctx android.Bp2buildMutatorContext, c *Module) { + props := bazel.BazelTargetModuleProperties{ + Rule_class: "cc_prebuilt_library_shared", + Bzl_load_location: "//build/bazel/rules/cc:cc_prebuilt_library_shared.bzl", + } + attrs := &bazelPrebuiltLibrarySharedAttributes{ + Shared_library: stlSrcBp2build(ctx, c), + Export_system_includes: stlIncludesBp2build(c), // The exports are always as system + } + // TODO: min_sdk_version + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: c.Name()}, attrs) +} diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go index feb388037..9ec2ae4ea 100644 --- a/cc/ndk_sysroot.go +++ b/cc/ndk_sysroot.go @@ -54,6 +54,7 @@ package cc import ( "android/soong/android" + "strings" ) func init() { @@ -96,15 +97,56 @@ func getNdkFullTimestampFile(ctx android.PathContext) android.WritablePath { return android.PathForOutput(ctx, "ndk.timestamp") } +// The list of all NDK headers as they are located in the repo. +// Used for ABI monitoring to track only structures defined in NDK headers. +func getNdkABIHeadersFile(ctx android.PathContext) android.WritablePath { + return android.PathForOutput(ctx, "ndk_abi_headers.txt") +} + func NdkSingleton() android.Singleton { return &ndkSingleton{} } +// Collect all NDK exported headers paths into a file that is used to +// detect public types that should be ABI monitored. +// +// Assume that we have the following code in exported header: +// +// typedef struct Context Context; +// typedef struct Output { +// ... +// } Output; +// void DoSomething(Context* ctx, Output* output); +// +// If none of public headers exported to end-users contain definition of +// "struct Context", then "struct Context" layout and members shouldn't be +// monitored. However we use DWARF information from a real library, which +// may have access to the definition of "string Context" from +// implementation headers, and it will leak to ABI. +// +// STG tool doesn't access source and header files, only DWARF information +// from compiled library. And the DWARF contains file name where a type is +// defined. So we need a rule to build a list of paths to public headers, +// so STG can distinguish private types from public and do not monitor +// private types that are not accessible to library users. +func writeNdkAbiSrcFilter(ctx android.BuilderContext, + headerSrcPaths android.Paths, outputFile android.WritablePath) { + var filterBuilder strings.Builder + filterBuilder.WriteString("[decl_file_allowlist]\n") + for _, headerSrcPath := range headerSrcPaths { + filterBuilder.WriteString(headerSrcPath.String()) + filterBuilder.WriteString("\n") + } + + android.WriteFileRule(ctx, outputFile, filterBuilder.String()) +} + type ndkSingleton struct{} func (n *ndkSingleton) GenerateBuildActions(ctx android.SingletonContext) { var staticLibInstallPaths android.Paths - var headerPaths android.Paths + var headerSrcPaths android.Paths + var headerInstallPaths android.Paths var installPaths android.Paths var licensePaths android.Paths ctx.VisitAllModules(func(module android.Module) { @@ -113,19 +155,22 @@ func (n *ndkSingleton) GenerateBuildActions(ctx android.SingletonContext) { } if m, ok := module.(*headerModule); ok { - headerPaths = append(headerPaths, m.installPaths...) + headerSrcPaths = append(headerSrcPaths, m.srcPaths...) + headerInstallPaths = append(headerInstallPaths, m.installPaths...) installPaths = append(installPaths, m.installPaths...) licensePaths = append(licensePaths, m.licensePath) } if m, ok := module.(*versionedHeaderModule); ok { - headerPaths = append(headerPaths, m.installPaths...) + headerSrcPaths = append(headerSrcPaths, m.srcPaths...) + headerInstallPaths = append(headerInstallPaths, m.installPaths...) installPaths = append(installPaths, m.installPaths...) licensePaths = append(licensePaths, m.licensePath) } if m, ok := module.(*preprocessedHeadersModule); ok { - headerPaths = append(headerPaths, m.installPaths...) + headerSrcPaths = append(headerSrcPaths, m.srcPaths...) + headerInstallPaths = append(headerInstallPaths, m.installPaths...) installPaths = append(installPaths, m.installPaths...) licensePaths = append(licensePaths, m.licensePath) } @@ -175,9 +220,11 @@ func (n *ndkSingleton) GenerateBuildActions(ctx android.SingletonContext) { ctx.Build(pctx, android.BuildParams{ Rule: android.Touch, Output: getNdkHeadersTimestampFile(ctx), - Implicits: headerPaths, + Implicits: headerInstallPaths, }) + writeNdkAbiSrcFilter(ctx, headerSrcPaths, getNdkABIHeadersFile(ctx)) + fullDepPaths := append(staticLibInstallPaths, getNdkBaseTimestampFile(ctx)) // There's a phony "ndk" rule defined in core/main.mk that depends on this. diff --git a/cc/object.go b/cc/object.go index ca1484538..a3000e06e 100644 --- a/cc/object.go +++ b/cc/object.go @@ -156,7 +156,7 @@ type bazelObjectAttributes struct { // 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 *Module) { +func objectBp2Build(ctx android.Bp2buildMutatorContext, m *Module) { 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") diff --git a/cc/prebuilt.go b/cc/prebuilt.go index a4ca59050..b4819b013 100644 --- a/cc/prebuilt.go +++ b/cc/prebuilt.go @@ -363,12 +363,12 @@ type bazelPrebuiltLibraryStaticAttributes struct { // all variants // // In all cases, cc_prebuilt_library_static target names will be appended with "_bp2build_cc_library_static". -func prebuiltLibraryBp2Build(ctx android.TopDownMutatorContext, module *Module) { +func prebuiltLibraryBp2Build(ctx android.Bp2buildMutatorContext, module *Module) { prebuiltLibraryStaticBp2Build(ctx, module, true) prebuiltLibrarySharedBp2Build(ctx, module) } -func prebuiltLibraryStaticBp2Build(ctx android.TopDownMutatorContext, module *Module, fullBuild bool) { +func prebuiltLibraryStaticBp2Build(ctx android.Bp2buildMutatorContext, module *Module, fullBuild bool) { prebuiltAttrs := Bp2BuildParsePrebuiltLibraryProps(ctx, module, true) exportedIncludes := bp2BuildParseExportedIncludes(ctx, module, nil) @@ -404,7 +404,7 @@ type bazelPrebuiltLibrarySharedAttributes struct { Export_system_includes bazel.StringListAttribute } -func prebuiltLibrarySharedBp2Build(ctx android.TopDownMutatorContext, module *Module) { +func prebuiltLibrarySharedBp2Build(ctx android.Bp2buildMutatorContext, module *Module) { prebuiltAttrs := Bp2BuildParsePrebuiltLibraryProps(ctx, module, false) exportedIncludes := bp2BuildParseExportedIncludes(ctx, module, nil) @@ -637,7 +637,7 @@ type bazelPrebuiltObjectAttributes struct { Src bazel.LabelAttribute } -func prebuiltObjectBp2Build(ctx android.TopDownMutatorContext, module *Module) { +func prebuiltObjectBp2Build(ctx android.Bp2buildMutatorContext, module *Module) { prebuiltAttrs := bp2BuildParsePrebuiltObjectProps(ctx, module) attrs := &bazelPrebuiltObjectAttributes{ @@ -797,7 +797,7 @@ type bazelPrebuiltBinaryAttributes struct { Strip stripAttributes } -func prebuiltBinaryBp2Build(ctx android.TopDownMutatorContext, module *Module) { +func prebuiltBinaryBp2Build(ctx android.Bp2buildMutatorContext, module *Module) { prebuiltAttrs := bp2BuildParsePrebuiltBinaryProps(ctx, module) var la linkerAttributes diff --git a/cc/sanitize.go b/cc/sanitize.go index 30bce9bff..9ceb1c8a0 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -553,7 +553,9 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { } if found, globalSanitizers = removeFromList("hwaddress", globalSanitizers); found && s.Hwaddress == nil { - s.Hwaddress = proptools.BoolPtr(true) + if !ctx.Config().HWASanDisabledForPath(ctx.ModuleDir()) { + s.Hwaddress = proptools.BoolPtr(true) + } } if found, globalSanitizers = removeFromList("writeonly", globalSanitizers); found && s.Writeonly == nil { @@ -677,12 +679,6 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { s.Integer_overflow = nil } - // TODO(b/254713216): CFI doesn't work for riscv64 yet because LTO doesn't work. - if ctx.Arch().ArchType == android.Riscv64 { - s.Cfi = nil - s.Diag.Cfi = nil - } - // Disable CFI for musl if ctx.toolchain().Musl() { s.Cfi = nil @@ -1189,7 +1185,7 @@ func (s *sanitizerSplitMutator) markSanitizableApexesMutator(ctx android.TopDown if sanitizeable, ok := ctx.Module().(Sanitizeable); ok { enabled := sanitizeable.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name()) ctx.VisitDirectDeps(func(dep android.Module) { - if c, ok := dep.(*Module); ok && c.sanitize.isSanitizerEnabled(s.sanitizer) { + if c, ok := dep.(PlatformSanitizeable); ok && c.IsSanitizerEnabled(s.sanitizer) { enabled = true } }) @@ -1243,12 +1239,10 @@ func (s *sanitizerSplitMutator) Split(ctx android.BaseModuleContext) []string { } } - if c, ok := ctx.Module().(*Module); ok { - //TODO: When Rust modules have vendor support, enable this path for PlatformSanitizeable - + if c, ok := ctx.Module().(LinkableInterface); ok { // Check if it's a snapshot module supporting sanitizer - if ss, ok := c.linker.(snapshotSanitizer); ok { - if ss.isSanitizerAvailable(s.sanitizer) { + if c.IsSnapshotSanitizer() { + if c.IsSnapshotSanitizerAvailable(s.sanitizer) { return []string{"", s.sanitizer.variationName()} } else { return []string{""} @@ -1280,8 +1274,8 @@ func (s *sanitizerSplitMutator) OutgoingTransition(ctx android.OutgoingTransitio func (s *sanitizerSplitMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { if d, ok := ctx.Module().(PlatformSanitizeable); ok { - if dm, ok := ctx.Module().(*Module); ok { - if ss, ok := dm.linker.(snapshotSanitizer); ok && ss.isSanitizerAvailable(s.sanitizer) { + if dm, ok := ctx.Module().(LinkableInterface); ok { + if dm.IsSnapshotSanitizerAvailable(s.sanitizer) { return incomingVariation } } @@ -1396,19 +1390,19 @@ func (s *sanitizerSplitMutator) Mutate(mctx android.BottomUpMutatorContext, vari if sanitizerVariation { sanitizeable.AddSanitizerDependencies(mctx, s.sanitizer.name()) } - } else if c, ok := mctx.Module().(*Module); ok { - if ss, ok := c.linker.(snapshotSanitizer); ok && ss.isSanitizerAvailable(s.sanitizer) { - if !ss.isUnsanitizedVariant() { + } else if c, ok := mctx.Module().(LinkableInterface); ok { + if c.IsSnapshotSanitizerAvailable(s.sanitizer) { + if !c.IsSnapshotUnsanitizedVariant() { // Snapshot sanitizer may have only one variantion. // Skip exporting the module if it already has a sanitizer variation. c.SetPreventInstall() c.SetHideFromMake() return } - c.linker.(snapshotSanitizer).setSanitizerVariation(s.sanitizer, sanitizerVariation) + c.SetSnapshotSanitizerVariation(s.sanitizer, sanitizerVariation) // Export the static lib name to make - if c.static() && c.ExportedToMake() { + if c.Static() && c.ExportedToMake() { // use BaseModuleName which is the name for Make. if s.sanitizer == cfi { cfiStaticLibs(mctx.Config()).add(c, c.BaseModuleName()) @@ -1420,6 +1414,35 @@ func (s *sanitizerSplitMutator) Mutate(mctx android.BottomUpMutatorContext, vari } } +func (c *Module) IsSnapshotSanitizer() bool { + if _, ok := c.linker.(SnapshotSanitizer); ok { + return true + } + return false +} + +func (c *Module) IsSnapshotSanitizerAvailable(t SanitizerType) bool { + if ss, ok := c.linker.(SnapshotSanitizer); ok { + return ss.IsSanitizerAvailable(t) + } + return false +} + +func (c *Module) SetSnapshotSanitizerVariation(t SanitizerType, enabled bool) { + if ss, ok := c.linker.(SnapshotSanitizer); ok { + ss.SetSanitizerVariation(t, enabled) + } else { + panic(fmt.Errorf("Calling SetSnapshotSanitizerVariation on a non-snapshotLibraryDecorator: %s", c.Name())) + } +} + +func (c *Module) IsSnapshotUnsanitizedVariant() bool { + if ss, ok := c.linker.(SnapshotSanitizer); ok { + return ss.IsUnsanitizedVariant() + } + return false +} + func (c *Module) SanitizeNever() bool { return Bool(c.sanitize.Properties.SanitizeMutated.Never) } @@ -1650,12 +1673,12 @@ func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { Bool(sanProps.Fuzzer) || Bool(sanProps.Undefined) || Bool(sanProps.All_undefined) { - if toolchain.Musl() || (c.staticBinary() && toolchain.Bionic()) { - // Use a static runtime for static binaries. - // Also use a static runtime for musl to match - // what clang does for glibc. Otherwise dlopening - // libraries that depend on libclang_rt.ubsan_standalone.so - // fails with: + if toolchain.Musl() || c.staticBinary() { + // Use a static runtime for static binaries. For sanitized glibc binaries the runtime is + // added automatically by clang, but for static glibc binaries that are not sanitized but + // have a sanitized dependency the runtime needs to be added manually. + // Also manually add a static runtime for musl to match what clang does for glibc. + // Otherwise dlopening libraries that depend on libclang_rt.ubsan_standalone.so fails with: // Error relocating ...: initial-exec TLS resolves to dynamic definition addStaticDeps(config.UndefinedBehaviorSanitizerRuntimeLibrary(toolchain)+".static", true) } else { diff --git a/cc/sanitize_test.go b/cc/sanitize_test.go index 29b17d415..49117a082 100644 --- a/cc/sanitize_test.go +++ b/cc/sanitize_test.go @@ -714,6 +714,15 @@ func TestUbsan(t *testing.T) { ], } + cc_binary { + name: "static_bin_with_ubsan_dep", + static_executable: true, + host_supported: true, + static_libs: [ + "libubsan_diag", + ], + } + cc_library_shared { name: "libshared", host_supported: true, @@ -742,6 +751,17 @@ func TestUbsan(t *testing.T) { } cc_library_static { + name: "libubsan_diag", + host_supported: true, + sanitize: { + undefined: true, + diag: { + undefined: true, + }, + }, + } + + cc_library_static { name: "libstatic", host_supported: true, } @@ -763,6 +783,7 @@ func TestUbsan(t *testing.T) { sharedVariant := variant + "_shared" minimalRuntime := result.ModuleForTests("libclang_rt.ubsan_minimal", staticVariant) + standaloneRuntime := result.ModuleForTests("libclang_rt.ubsan_standalone.static", staticVariant) // The binaries, one with ubsan and one without binWithUbsan := result.ModuleForTests("bin_with_ubsan", variant) @@ -770,6 +791,7 @@ func TestUbsan(t *testing.T) { libSharedUbsan := result.ModuleForTests("libsharedubsan", sharedVariant) binDependsUbsanShared := result.ModuleForTests("bin_depends_ubsan_shared", variant) binNoUbsan := result.ModuleForTests("bin_no_ubsan", variant) + staticBin := result.ModuleForTests("static_bin_with_ubsan_dep", variant) android.AssertStringListContains(t, "missing libclang_rt.ubsan_minimal in bin_with_ubsan static libs", strings.Split(binWithUbsan.Rule("ld").Args["libFlags"], " "), @@ -810,6 +832,11 @@ func TestUbsan(t *testing.T) { android.AssertStringListDoesNotContain(t, "unexpected -Wl,--exclude-libs for minimal runtime in bin_no_ubsan static libs", strings.Split(binNoUbsan.Rule("ld").Args["ldFlags"], " "), "-Wl,--exclude-libs="+minimalRuntime.OutputFiles(t, "")[0].Base()) + + android.AssertStringListContains(t, "missing libclang_rt.ubsan_standalone.static in static_bin_with_ubsan_dep static libs", + strings.Split(staticBin.Rule("ld").Args["libFlags"], " "), + standaloneRuntime.OutputFiles(t, "")[0].String()) + } t.Run("host", func(t *testing.T) { check(t, buildOS, preparer) }) diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go index bb1331051..e29c446e7 100644 --- a/cc/snapshot_prebuilt.go +++ b/cc/snapshot_prebuilt.go @@ -403,11 +403,11 @@ type SnapshotLibraryProperties struct { Sanitize_minimal_dep *bool `android:"arch_variant"` } -type snapshotSanitizer interface { - isSanitizerAvailable(t SanitizerType) bool - setSanitizerVariation(t SanitizerType, enabled bool) - isSanitizerEnabled(t SanitizerType) bool - isUnsanitizedVariant() bool +type SnapshotSanitizer interface { + IsSanitizerAvailable(t SanitizerType) bool + SetSanitizerVariation(t SanitizerType, enabled bool) + IsSanitizerEnabled(t SanitizerType) bool + IsUnsanitizedVariant() bool } type snapshotLibraryDecorator struct { @@ -460,9 +460,9 @@ func (p *snapshotLibraryDecorator) link(ctx ModuleContext, flags Flags, deps Pat return p.libraryDecorator.link(ctx, flags, deps, objs) } - if p.isSanitizerEnabled(cfi) { + if p.IsSanitizerEnabled(cfi) { p.properties = p.sanitizerProperties.Cfi - } else if p.isSanitizerEnabled(Hwasan) { + } else if p.IsSanitizerEnabled(Hwasan) { p.properties = p.sanitizerProperties.Hwasan } @@ -526,9 +526,9 @@ func (p *snapshotLibraryDecorator) nativeCoverage() bool { return false } -var _ snapshotSanitizer = (*snapshotLibraryDecorator)(nil) +var _ SnapshotSanitizer = (*snapshotLibraryDecorator)(nil) -func (p *snapshotLibraryDecorator) isSanitizerAvailable(t SanitizerType) bool { +func (p *snapshotLibraryDecorator) IsSanitizerAvailable(t SanitizerType) bool { switch t { case cfi: return p.sanitizerProperties.Cfi.Src != nil @@ -539,23 +539,23 @@ func (p *snapshotLibraryDecorator) isSanitizerAvailable(t SanitizerType) bool { } } -func (p *snapshotLibraryDecorator) setSanitizerVariation(t SanitizerType, enabled bool) { - if !enabled || p.isSanitizerEnabled(t) { +func (p *snapshotLibraryDecorator) SetSanitizerVariation(t SanitizerType, enabled bool) { + if !enabled || p.IsSanitizerEnabled(t) { return } - if !p.isUnsanitizedVariant() { + if !p.IsUnsanitizedVariant() { panic(fmt.Errorf("snapshot Sanitizer must be one of Cfi or Hwasan but not both")) } p.sanitizerProperties.SanitizerVariation = t } -func (p *snapshotLibraryDecorator) isSanitizerEnabled(t SanitizerType) bool { +func (p *snapshotLibraryDecorator) IsSanitizerEnabled(t SanitizerType) bool { return p.sanitizerProperties.SanitizerVariation == t } -func (p *snapshotLibraryDecorator) isUnsanitizedVariant() bool { - return !p.isSanitizerEnabled(Asan) && - !p.isSanitizerEnabled(Hwasan) +func (p *snapshotLibraryDecorator) IsUnsanitizedVariant() bool { + return !p.IsSanitizerEnabled(Asan) && + !p.IsSanitizerEnabled(Hwasan) } func snapshotLibraryFactory(image SnapshotImage, moduleSuffix string) (*Module, *snapshotLibraryDecorator) { @@ -172,6 +172,7 @@ func (stl *stl) deps(ctx BaseModuleContext, deps Deps) Deps { // The system STL doesn't have a prebuilt (it uses the system's libstdc++), but it does have // its own includes. The includes are handled in CCBase.Flags(). deps.SharedLibs = append([]string{"libstdc++"}, deps.SharedLibs...) + deps.HeaderLibs = append([]string{"ndk_system"}, deps.HeaderLibs...) case "ndk_libc++_shared", "ndk_libc++_static": if stl.Properties.SelectedStl == "ndk_libc++_shared" { deps.SharedLibs = append(deps.SharedLibs, stl.Properties.SelectedStl) @@ -219,8 +220,7 @@ func (stl *stl) flags(ctx ModuleContext, flags Flags) Flags { case "libstdc++": // Nothing case "ndk_system": - ndkSrcRoot := android.PathForSource(ctx, "prebuilts/ndk/current/sources/cxx-stl/system/include") - flags.Local.CFlags = append(flags.Local.CFlags, "-isystem "+ndkSrcRoot.String()) + // Nothing: The exports of ndk_system will be added automatically to the local cflags case "ndk_libc++_shared", "ndk_libc++_static": if ctx.Arch().ArchType == android.Arm { // Make sure the _Unwind_XXX symbols are not re-exported. diff --git a/cc/test.go b/cc/test.go index adc80c2f0..7a6cf1b4e 100644 --- a/cc/test.go +++ b/cc/test.go @@ -395,7 +395,7 @@ func (test *testBinary) install(ctx ModuleContext, file android.Path) { useVendor := ctx.inVendor() || ctx.useVndk() testInstallBase := getTestInstallBase(useVendor) - configs := getTradefedConfigOptions(ctx, &test.Properties, test.isolated(ctx)) + configs := getTradefedConfigOptions(ctx, &test.Properties, test.isolated(ctx), ctx.Device()) test.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{ TestConfigProp: test.Properties.Test_config, @@ -435,22 +435,24 @@ func getTestInstallBase(useVendor bool) string { return testInstallBase } -func getTradefedConfigOptions(ctx android.EarlyModuleContext, properties *TestBinaryProperties, isolated bool) []tradefed.Config { +func getTradefedConfigOptions(ctx android.EarlyModuleContext, properties *TestBinaryProperties, isolated bool, device bool) []tradefed.Config { var configs []tradefed.Config for _, module := range properties.Test_mainline_modules { configs = append(configs, tradefed.Option{Name: "config-descriptor:metadata", Key: "mainline-param", Value: module}) } - if Bool(properties.Require_root) { - configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil}) - } else { - var options []tradefed.Option - options = append(options, tradefed.Option{Name: "force-root", Value: "false"}) - configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", options}) - } - if Bool(properties.Disable_framework) { - var options []tradefed.Option - configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.StopServicesSetup", options}) + if device { + if Bool(properties.Require_root) { + configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil}) + } else { + var options []tradefed.Option + options = append(options, tradefed.Option{Name: "force-root", Value: "false"}) + configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", options}) + } + if Bool(properties.Disable_framework) { + var options []tradefed.Option + configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.StopServicesSetup", options}) + } } if isolated { configs = append(configs, tradefed.Option{Name: "not-shardable", Value: "true"}) @@ -698,7 +700,7 @@ type testBinaryAttributes struct { // TODO(b/244432609): handle `isolated` property. // TODO(b/244432134): handle custom runpaths for tests that assume runfile layouts not // default to bazel. (see linkerInit function) -func testBinaryBp2build(ctx android.TopDownMutatorContext, m *Module) { +func testBinaryBp2build(ctx android.Bp2buildMutatorContext, m *Module) { var testBinaryAttrs testBinaryAttributes testBinaryAttrs.binaryAttributes = binaryBp2buildAttrs(ctx, m) @@ -720,6 +722,21 @@ func testBinaryBp2build(ctx android.TopDownMutatorContext, m *Module) { } } + // The logic comes from https://cs.android.com/android/platform/superproject/main/+/0df8153267f96da877febc5332240fa06ceb8533:build/soong/cc/sanitize.go;l=488 + var features bazel.StringListAttribute + curFeatures := testBinaryAttrs.binaryAttributes.Features.SelectValue(bazel.OsArchConfigurationAxis, bazel.OsArchAndroidArm64) + var newFeatures []string + if !android.InList("memtag_heap", curFeatures) && !android.InList("-memtag_heap", curFeatures) { + newFeatures = append(newFeatures, "memtag_heap") + if !android.InList("diag_memtag_heap", curFeatures) && !android.InList("-diag_memtag_heap", curFeatures) { + newFeatures = append(newFeatures, "diag_memtag_heap") + } + } + + features.SetSelectValue(bazel.OsArchConfigurationAxis, bazel.OsArchAndroidArm64, newFeatures) + testBinaryAttrs.binaryAttributes.Features.Append(features) + testBinaryAttrs.binaryAttributes.Features.DeduplicateAxesFromBase() + m.convertTidyAttributes(ctx, &testBinaryAttrs.tidyAttributes) testBinary := m.linker.(*testBinary) @@ -745,7 +762,7 @@ func testBinaryBp2build(ctx android.TopDownMutatorContext, m *Module) { p.Auto_gen_config, p.Test_options.Test_suite_tag, p.Test_config_template, - getTradefedConfigOptions(ctx, p, gtestIsolated), + getTradefedConfigOptions(ctx, p, gtestIsolated, true), &testInstallBase, ) testBinaryAttrs.TestConfigAttributes = testConfigAttributes diff --git a/cc/testing.go b/cc/testing.go index d1632aaa6..21745c3d1 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -35,6 +35,7 @@ func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) { multitree.RegisterApiImportsModule(ctx) + ctx.RegisterModuleType("prebuilt_build_tool", android.NewPrebuiltBuildTool) ctx.RegisterModuleType("cc_benchmark", BenchmarkFactory) ctx.RegisterModuleType("cc_object", ObjectFactory) ctx.RegisterModuleType("cc_genrule", GenRuleFactory) @@ -67,6 +68,26 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { func commonDefaultModules() string { return ` + prebuilt_build_tool { + name: "clang++", + src: "bin/clang++", + } + prebuilt_build_tool { + name: "clang++.real", + src: "bin/clang++.real", + } + prebuilt_build_tool { + name: "lld", + src: "bin/lld", + } + prebuilt_build_tool { + name: "ld.lld", + src: "bin/ld.lld", + } + prebuilt_build_tool { + name: "llvm-ar", + src: "bin/llvm-ar", + } cc_defaults { name: "toolchain_libs_defaults", host_supported: true, @@ -558,7 +579,7 @@ var PrepareForTestWithCcBuildComponents = android.GroupFixturePreparers( // This includes files that are needed by all, or at least most, instances of a cc module type. android.MockFS{ // Needed for ndk_prebuilt_(shared|static)_stl. - "prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs": nil, + "defaults/cc/common/current/sources/cxx-stl/llvm-libc++/libs": nil, }.AddToFixture(), ) @@ -568,6 +589,12 @@ var PrepareForTestWithCcDefaultModules = android.GroupFixturePreparers( // Additional files needed in tests that disallow non-existent source. android.MockFS{ + "defaults/cc/common/bin/clang++": nil, + "defaults/cc/common/bin/clang++.real": nil, + "defaults/cc/common/bin/lld": nil, + "defaults/cc/common/bin/ld.lld": nil, + "defaults/cc/common/bin/llvm-ar": nil, + "defaults/cc/common/libc.map.txt": nil, "defaults/cc/common/libdl.map.txt": nil, "defaults/cc/common/libm.map.txt": nil, @@ -671,7 +698,7 @@ var PrepareForTestWithHostMusl = android.GroupFixturePreparers( // PrepareForTestWithFdoProfile registers module types to test with fdo_profile var PrepareForTestWithFdoProfile = android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { ctx.RegisterModuleType("soong_namespace", android.NamespaceFactory) - ctx.RegisterModuleType("fdo_profile", fdoProfileFactory) + ctx.RegisterModuleType("fdo_profile", FdoProfileFactory) }) // TestConfig is the legacy way of creating a test Config for testing cc modules. diff --git a/cc/vndk.go b/cc/vndk.go index 82a2a4b27..5ac5032c5 100644 --- a/cc/vndk.go +++ b/cc/vndk.go @@ -41,21 +41,33 @@ const ( func VndkLibrariesTxtModules(vndkVersion string, ctx android.BaseModuleContext) []string { if vndkVersion == "current" { - result := []string{ - vndkCoreLibrariesTxt, - vndkSpLibrariesTxt, - vndkPrivateLibrariesTxt, - vndkProductLibrariesTxt, - } + // We can assume all txt files are snapshotted if we find one of them. + currentVndkSnapshotted := ctx.OtherModuleExists(insertVndkVersion(llndkLibrariesTxt, ctx.DeviceConfig().PlatformVndkVersion())) + if currentVndkSnapshotted { + // If the current VNDK is already snapshotted (which can happen with + // the `next` config), use the prebuilt txt files in the snapshot. + // This is because the txt files built from source are probably be + // for the in-development version. + vndkVersion = ctx.DeviceConfig().PlatformVndkVersion() + } else { + // Use the txt files generated from the source + result := []string{ + vndkCoreLibrariesTxt, + vndkSpLibrariesTxt, + vndkPrivateLibrariesTxt, + vndkProductLibrariesTxt, + } - // TODO(b/290159430) This part will not be required once deprecation of VNDK - // is handled with 'ro.vndk.version' property - if !ctx.Config().IsVndkDeprecated() { - result = append(result, llndkLibrariesTxt) - } + // TODO(b/290159430) This part will not be required once deprecation + // of VNDK is handled with 'ro.vndk.version' property + if !ctx.Config().IsVndkDeprecated() { + result = append(result, llndkLibrariesTxt) + } - return result + return result + } } + // Snapshot vndks have their own *.libraries.VER.txt files. // Note that snapshots don't have "vndkcorevariant.libraries.VER.txt" result := []string{ @@ -535,6 +547,15 @@ func insertVndkVersion(filename string, vndkVersion string) string { return filename } +func (txt *vndkLibrariesTxt) DepsMutator(mctx android.BottomUpMutatorContext) { + versionedName := insertVndkVersion(txt.Name(), mctx.DeviceConfig().PlatformVndkVersion()) + if mctx.OtherModuleExists(versionedName) { + // If the prebuilt vndk libraries txt files exist, install them instead. + txt.HideFromMake() + mctx.AddDependency(txt, nil, versionedName) + } +} + func (txt *vndkLibrariesTxt) GenerateAndroidBuildActions(ctx android.ModuleContext) { filename := txt.Name() diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go index fc56dd526..3364f503f 100644 --- a/cmd/sbox/sbox.go +++ b/cmd/sbox/sbox.go @@ -119,6 +119,9 @@ func run() error { } manifest, err := readManifest(manifestFile) + if err != nil { + return err + } if len(manifest.Commands) == 0 { return fmt.Errorf("at least one commands entry is required in %q", manifestFile) diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go index 20e366e8a..d20847bb2 100644 --- a/cmd/soong_build/main.go +++ b/cmd/soong_build/main.go @@ -21,13 +21,11 @@ import ( "fmt" "os" "path/filepath" - "regexp" "strings" "time" "android/soong/android" "android/soong/android/allowlists" - "android/soong/bazel" "android/soong/bp2build" "android/soong/shared" "android/soong/ui/metrics/bp2build_metrics_proto" @@ -76,7 +74,6 @@ func init() { flag.StringVar(&cmdlineArgs.ModuleActionsFile, "module_actions_file", "", "JSON file to output inputs/outputs of actions of modules") flag.StringVar(&cmdlineArgs.DocFile, "soong_docs", "", "build documentation file to output") flag.StringVar(&cmdlineArgs.BazelQueryViewDir, "bazel_queryview_dir", "", "path to the bazel queryview directory relative to --top") - flag.StringVar(&cmdlineArgs.BazelApiBp2buildDir, "bazel_api_bp2build_dir", "", "path to the bazel api_bp2build directory relative to --top") flag.StringVar(&cmdlineArgs.Bp2buildMarker, "bp2build_marker", "", "If set, run bp2build, touch the specified marker file then exit") flag.StringVar(&cmdlineArgs.SymlinkForestMarker, "symlink_forest_marker", "", "If set, create the bp2build symlink forest, touch the specified marker file, then exit") flag.StringVar(&cmdlineArgs.OutFile, "o", "build.ninja", "the Ninja file to output") @@ -169,120 +166,6 @@ func runQueryView(queryviewDir, queryviewMarker string, ctx *android.Context) { touch(shared.JoinPath(topDir, queryviewMarker)) } -// Run the code-generation phase to convert API contributions to BUILD files. -// Return marker file for the new synthetic workspace -func runApiBp2build(ctx *android.Context, extraNinjaDeps []string) string { - ctx.EventHandler.Begin("api_bp2build") - defer ctx.EventHandler.End("api_bp2build") - // api_bp2build does not run the typical pipeline of soong mutators. - // Hoevever, it still runs the defaults mutator which can create dependencies. - // These dependencies might not always exist (e.g. in tests) - ctx.SetAllowMissingDependencies(ctx.Config().AllowMissingDependencies()) - ctx.RegisterForApiBazelConversion() - - // Register the Android.bp files in the tree - // Add them to the workspace's .d file - ctx.SetModuleListFile(cmdlineArgs.ModuleListFile) - if paths, err := ctx.ListModulePaths("."); err == nil { - extraNinjaDeps = append(extraNinjaDeps, paths...) - } else { - panic(err) - } - - // Run the loading and analysis phase - ninjaDeps, err := bootstrap.RunBlueprint(cmdlineArgs.Args, - bootstrap.StopBeforePrepareBuildActions, - ctx.Context, - ctx.Config()) - maybeQuit(err, "") - ninjaDeps = append(ninjaDeps, extraNinjaDeps...) - - // Add the globbed dependencies - ninjaDeps = append(ninjaDeps, writeBuildGlobsNinjaFile(ctx)...) - - // Run codegen to generate BUILD files - codegenContext := bp2build.NewCodegenContext(ctx.Config(), ctx, bp2build.ApiBp2build, topDir) - absoluteApiBp2buildDir := shared.JoinPath(topDir, cmdlineArgs.BazelApiBp2buildDir) - // Always generate bp2build_all_srcs filegroups in api_bp2build. - // This is necessary to force each Android.bp file to create an equivalent BUILD file - // and prevent package boundray issues. - // e.g. - // Source - // f/b/Android.bp - // java_library{ - // name: "foo", - // api: "api/current.txt", - // } - // - // f/b/api/Android.bp <- will cause package boundary issues - // - // Gen - // f/b/BUILD - // java_contribution{ - // name: "foo.contribution", - // api: "//f/b/api:current.txt", - // } - // - // If we don't generate f/b/api/BUILD, foo.contribution will be unbuildable. - err = createBazelWorkspace(codegenContext, absoluteApiBp2buildDir, true) - maybeQuit(err, "") - ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...) - - // Create soong_injection repository - soongInjectionFiles, workspaceFiles, err := bp2build.CreateSoongInjectionDirFiles(codegenContext, bp2build.CreateCodegenMetrics()) - maybeQuit(err, "") - absoluteSoongInjectionDir := shared.JoinPath(topDir, ctx.Config().SoongOutDir(), bazel.SoongInjectionDirName) - for _, file := range soongInjectionFiles { - // The API targets in api_bp2build workspace do not have any dependency on api_bp2build. - // But we need to create these files to prevent errors during Bazel analysis. - // These need to be created in Read-Write mode. - // This is because the subsequent step (bp2build in api domain analysis) creates them in Read-Write mode - // to allow users to edit/experiment in the synthetic workspace. - writeReadWriteFile(absoluteSoongInjectionDir, file) - } - for _, file := range workspaceFiles { - writeReadWriteFile(absoluteApiBp2buildDir, file) - } - - workspace := shared.JoinPath(ctx.Config().SoongOutDir(), "api_bp2build") - // Create the symlink forest - symlinkDeps, _, _ := bp2build.PlantSymlinkForest( - ctx.Config().IsEnvTrue("BP2BUILD_VERBOSE"), - topDir, - workspace, - cmdlineArgs.BazelApiBp2buildDir, - apiBuildFileExcludes(ctx)) - ninjaDeps = append(ninjaDeps, symlinkDeps...) - - workspaceMarkerFile := workspace + ".marker" - writeDepFile(workspaceMarkerFile, ctx.EventHandler, ninjaDeps) - touch(shared.JoinPath(topDir, workspaceMarkerFile)) - return workspaceMarkerFile -} - -// With some exceptions, api_bp2build does not have any dependencies on the checked-in BUILD files -// Exclude them from the generated workspace to prevent unrelated errors during the loading phase -func apiBuildFileExcludes(ctx *android.Context) []string { - ret := bazelArtifacts() - srcs, err := getExistingBazelRelatedFiles(topDir) - maybeQuit(err, "Error determining existing Bazel-related files") - for _, src := range srcs { - // Exclude all src BUILD files - if src != "WORKSPACE" && - src != "BUILD" && - src != "BUILD.bazel" && - !strings.HasPrefix(src, "build/bazel") && - !strings.HasPrefix(src, "external/bazel-skylib") && - !strings.HasPrefix(src, "prebuilts/clang") { - ret = append(ret, src) - } - } - // Android.bp files for api surfaces are mounted to out/, but out/ should not be a - // dep for api_bp2build. Otherwise, api_bp2build will be run every single time - ret = append(ret, ctx.Config().OutDir()) - return ret -} - func writeNinjaHint(ctx *android.Context) error { ctx.BeginEvent("ninja_hint") defer ctx.EndEvent("ninja_hint") @@ -551,9 +434,6 @@ func main() { // Run the alternate pipeline of bp2build mutators and singleton to convert // Blueprint to BUILD files before everything else. finalOutputFile = runBp2Build(ctx, extraNinjaDeps, metricsDir) - case android.ApiBp2build: - finalOutputFile = runApiBp2build(ctx, extraNinjaDeps) - writeMetrics(configuration, ctx.EventHandler, metricsDir) default: ctx.Register() isMixedBuildsEnabled := configuration.IsMixedBuildsEnabled() @@ -736,43 +616,6 @@ func excludedFromSymlinkForest(ctx *android.Context, verbose bool) []string { return excluded } -// buildTargetsByPackage parses Bazel BUILD.bazel and BUILD files under -// the workspace, and returns a map containing names of Bazel targets defined in -// these BUILD files. -// For example, maps "//foo/bar" to ["baz", "qux"] if `//foo/bar:{baz,qux}` exist. -func buildTargetsByPackage(ctx *android.Context) map[string][]string { - existingBazelFiles, err := getExistingBazelRelatedFiles(topDir) - maybeQuit(err, "Error determining existing Bazel-related files") - - result := map[string][]string{} - - // Search for instances of `name = "$NAME"` (with arbitrary spacing). - targetNameRegex := regexp.MustCompile(`(?m)^\s*name\s*=\s*\"([^\"]+)\"`) - - for _, path := range existingBazelFiles { - if !ctx.Config().Bp2buildPackageConfig.ShouldKeepExistingBuildFileForDir(filepath.Dir(path)) { - continue - } - fullPath := shared.JoinPath(topDir, path) - sourceDir := filepath.Dir(path) - fileInfo, err := os.Stat(fullPath) - maybeQuit(err, "Error accessing Bazel file '%s'", fullPath) - - if !fileInfo.IsDir() && - (fileInfo.Name() == "BUILD" || fileInfo.Name() == "BUILD.bazel") { - // Process this BUILD file. - buildFileContent, err := os.ReadFile(fullPath) - maybeQuit(err, "Error reading Bazel file '%s'", fullPath) - - matches := targetNameRegex.FindAllStringSubmatch(string(buildFileContent), -1) - for _, match := range matches { - result[sourceDir] = append(result[sourceDir], match[1]) - } - } - } - return result -} - // Run Soong in the bp2build mode. This creates a standalone context that registers // an alternate pipeline of mutators and singletons specifically for generating // Bazel BUILD files instead of Ninja files. @@ -781,7 +624,11 @@ func runBp2Build(ctx *android.Context, extraNinjaDeps []string, metricsDir strin ctx.EventHandler.Do("bp2build", func() { ctx.EventHandler.Do("read_build", func() { - ctx.Config().SetBazelBuildFileTargets(buildTargetsByPackage(ctx)) + existingBazelFiles, err := getExistingBazelRelatedFiles(topDir) + maybeQuit(err, "Error determining existing Bazel-related files") + + err = ctx.RegisterExistingBazelTargets(topDir, existingBazelFiles) + maybeQuit(err, "Error parsing existing Bazel-related files") }) // Propagate "allow misssing dependencies" bit. This is normally set in diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go index 4097e8a3f..3b8f4f5a4 100644 --- a/cmd/soong_ui/main.go +++ b/cmd/soong_ui/main.go @@ -289,10 +289,7 @@ func logAndSymlinkSetup(buildCtx build.Context, config build.Config) { } } - // Fix up the source tree due to a repo bug where it doesn't remove - // linkfiles that have been removed - fixBadDanglingLink(buildCtx, "hardware/qcom/sdm710/Android.bp") - fixBadDanglingLink(buildCtx, "hardware/qcom/sdm710/Android.mk") + removeBadTargetRename(buildCtx, config) // Create a source finder. f := build.NewSourceFinder(buildCtx, config) @@ -300,16 +297,26 @@ func logAndSymlinkSetup(buildCtx build.Context, config build.Config) { build.FindSources(buildCtx, config, f) } -func fixBadDanglingLink(ctx build.Context, name string) { - _, err := os.Lstat(name) +func removeBadTargetRename(ctx build.Context, config build.Config) { + log := ctx.ContextImpl.Logger + // find bad paths + m, err := filepath.Glob(filepath.Join(config.OutDir(), "bazel", "output", "execroot", "__main__", "bazel-out", "mixed_builds_product-*", "bin", "tools", "metalava", "metalava")) if err != nil { - return + log.Fatalf("Glob for invalid file failed %s", err) } - _, err = os.Stat(name) - if os.IsNotExist(err) { - err = os.Remove(name) + for _, f := range m { + info, err := os.Stat(f) if err != nil { - ctx.Fatalf("Failed to remove dangling link %q: %v", name, err) + log.Fatalf("Stat of invalid file %q failed %s", f, err) + } + // if it's a directory, leave it, but remove the files + if !info.IsDir() { + err = os.Remove(f) + if err != nil { + log.Fatalf("Remove of invalid file %q failed %s", f, err) + } else { + log.Verbosef("Removed %q", f) + } } } } diff --git a/cmd/zip2zip/zip2zip_test.go b/cmd/zip2zip/zip2zip_test.go index c238098ec..85a69efeb 100644 --- a/cmd/zip2zip/zip2zip_test.go +++ b/cmd/zip2zip/zip2zip_test.go @@ -471,6 +471,56 @@ func TestZip2Zip(t *testing.T) { } } +// TestZip2Zip64 tests that zip2zip on zip file larger than 4GB produces a valid zip file. +func TestZip2Zip64(t *testing.T) { + if testing.Short() { + t.Skip("skipping slow test in short mode") + } + inputBuf := &bytes.Buffer{} + outputBuf := &bytes.Buffer{} + + inputWriter := zip.NewWriter(inputBuf) + w, err := inputWriter.CreateHeaderAndroid(&zip.FileHeader{ + Name: "a", + Method: zip.Store, + }) + if err != nil { + t.Fatal(err) + } + buf := make([]byte, 4*1024*1024) + for i := 0; i < 1025; i++ { + w.Write(buf) + } + w, err = inputWriter.CreateHeaderAndroid(&zip.FileHeader{ + Name: "b", + Method: zip.Store, + }) + for i := 0; i < 1025; i++ { + w.Write(buf) + } + inputWriter.Close() + inputBytes := inputBuf.Bytes() + + inputReader, err := zip.NewReader(bytes.NewReader(inputBytes), int64(len(inputBytes))) + if err != nil { + t.Fatal(err) + } + + outputWriter := zip.NewWriter(outputBuf) + err = zip2zip(inputReader, outputWriter, false, false, false, + nil, nil, nil, nil) + if err != nil { + t.Fatal(err) + } + + outputWriter.Close() + outputBytes := outputBuf.Bytes() + _, err = zip.NewReader(bytes.NewReader(outputBytes), int64(len(outputBytes))) + if err != nil { + t.Fatal(err) + } +} + func TestConstantPartOfPattern(t *testing.T) { testCases := []struct{ in, out string }{ { diff --git a/compliance/OWNERS b/compliance/OWNERS deleted file mode 100644 index f52e201c1..000000000 --- a/compliance/OWNERS +++ /dev/null @@ -1,8 +0,0 @@ -# OSEP Build -bbadour@google.com -kanouche@google.com -napier@google.com - -# Open Source Compliance Tools -rtp@google.com -austinyuan@google.com diff --git a/etc/Android.bp b/etc/Android.bp index c67023679..cefd717aa 100644 --- a/etc/Android.bp +++ b/etc/Android.bp @@ -14,10 +14,12 @@ bootstrap_go_package { srcs: [ "prebuilt_etc.go", "snapshot_etc.go", + "install_symlink.go", ], testSrcs: [ "prebuilt_etc_test.go", "snapshot_etc_test.go", + "install_symlink_test.go", ], pluginFor: ["soong_build"], } diff --git a/etc/install_symlink.go b/etc/install_symlink.go new file mode 100644 index 000000000..2182b8669 --- /dev/null +++ b/etc/install_symlink.go @@ -0,0 +1,92 @@ +// Copyright 2023 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 etc + +import ( + "android/soong/android" + "path/filepath" + "strings" +) + +func init() { + RegisterInstallSymlinkBuildComponents(android.InitRegistrationContext) +} + +func RegisterInstallSymlinkBuildComponents(ctx android.RegistrationContext) { + ctx.RegisterModuleType("install_symlink", InstallSymlinkFactory) +} + +// install_symlink can be used to install an symlink with an arbitrary target to an arbitrary path +// on the device. +func InstallSymlinkFactory() android.Module { + module := &InstallSymlink{} + module.AddProperties(&module.properties) + android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) + return module +} + +type InstallSymlinkProperties struct { + // Where to install this symlink, relative to the partition it's installed on. + // Which partition it's installed on can be controlled by the vendor, system_ext, ramdisk, etc. + // properties. + Installed_location string + // The target of the symlink, aka where the symlink points. + Symlink_target string +} + +type InstallSymlink struct { + android.ModuleBase + properties InstallSymlinkProperties + + output android.Path + installedPath android.InstallPath +} + +func (m *InstallSymlink) GenerateAndroidBuildActions(ctx android.ModuleContext) { + if filepath.Clean(m.properties.Symlink_target) != m.properties.Symlink_target { + ctx.PropertyErrorf("symlink_target", "Should be a clean filepath") + return + } + if filepath.Clean(m.properties.Installed_location) != m.properties.Installed_location { + ctx.PropertyErrorf("installed_location", "Should be a clean filepath") + return + } + if strings.HasPrefix(m.properties.Installed_location, "../") || strings.HasPrefix(m.properties.Installed_location, "/") { + ctx.PropertyErrorf("installed_location", "Should not start with / or ../") + return + } + + out := android.PathForModuleOut(ctx, "out.txt") + android.WriteFileRuleVerbatim(ctx, out, "") + m.output = out + + name := filepath.Base(m.properties.Installed_location) + installDir := android.PathForModuleInstall(ctx, filepath.Dir(m.properties.Installed_location)) + m.installedPath = ctx.InstallAbsoluteSymlink(installDir, name, m.properties.Symlink_target) +} + +func (m *InstallSymlink) AndroidMkEntries() []android.AndroidMkEntries { + return []android.AndroidMkEntries{{ + Class: "FAKE", + // Need at least one output file in order for this to take effect. + OutputFile: android.OptionalPathForPath(m.output), + Include: "$(BUILD_PHONY_PACKAGE)", + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { + entries.AddStrings("LOCAL_SOONG_INSTALL_SYMLINKS", m.installedPath.String()) + }, + }, + }} +} diff --git a/etc/install_symlink_test.go b/etc/install_symlink_test.go new file mode 100644 index 000000000..d7165e5de --- /dev/null +++ b/etc/install_symlink_test.go @@ -0,0 +1,135 @@ +// Copyright 2023 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 etc + +import ( + "android/soong/android" + "strings" + "testing" +) + +var prepareForInstallSymlinkTest = android.GroupFixturePreparers( + android.PrepareForTestWithArchMutator, + android.FixtureRegisterWithContext(RegisterInstallSymlinkBuildComponents), +) + +func TestInstallSymlinkBasic(t *testing.T) { + result := prepareForInstallSymlinkTest.RunTestWithBp(t, ` + install_symlink { + name: "foo", + installed_location: "bin/foo", + symlink_target: "/system/system_ext/bin/foo", + } + `) + + foo_variants := result.ModuleVariantsForTests("foo") + if len(foo_variants) != 1 { + t.Fatalf("expected 1 variant, got %#v", foo_variants) + } + + foo := result.ModuleForTests("foo", "android_common").Module() + androidMkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, foo) + if len(androidMkEntries) != 1 { + t.Fatalf("expected 1 androidmkentry, got %d", len(androidMkEntries)) + } + + symlinks := androidMkEntries[0].EntryMap["LOCAL_SOONG_INSTALL_SYMLINKS"] + if len(symlinks) != 1 { + t.Fatalf("Expected 1 symlink, got %d", len(symlinks)) + } + + if !strings.HasSuffix(symlinks[0], "system/bin/foo") { + t.Fatalf("Expected symlink install path to end in system/bin/foo, got: %s", symlinks[0]) + } +} + +func TestInstallSymlinkToRecovery(t *testing.T) { + result := prepareForInstallSymlinkTest.RunTestWithBp(t, ` + install_symlink { + name: "foo", + installed_location: "bin/foo", + symlink_target: "/system/system_ext/bin/foo", + recovery: true, + } + `) + + foo_variants := result.ModuleVariantsForTests("foo") + if len(foo_variants) != 1 { + t.Fatalf("expected 1 variant, got %#v", foo_variants) + } + + foo := result.ModuleForTests("foo", "android_common").Module() + androidMkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, foo) + if len(androidMkEntries) != 1 { + t.Fatalf("expected 1 androidmkentry, got %d", len(androidMkEntries)) + } + + symlinks := androidMkEntries[0].EntryMap["LOCAL_SOONG_INSTALL_SYMLINKS"] + if len(symlinks) != 1 { + t.Fatalf("Expected 1 symlink, got %d", len(symlinks)) + } + + if !strings.HasSuffix(symlinks[0], "recovery/root/system/bin/foo") { + t.Fatalf("Expected symlink install path to end in recovery/root/system/bin/foo, got: %s", symlinks[0]) + } +} + +func TestErrorOnNonCleanTarget(t *testing.T) { + prepareForInstallSymlinkTest. + ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern("Should be a clean filepath")). + RunTestWithBp(t, ` + install_symlink { + name: "foo", + installed_location: "bin/foo", + symlink_target: "/system/system_ext/../bin/foo", + } + `) +} + +func TestErrorOnNonCleanInstalledLocation(t *testing.T) { + prepareForInstallSymlinkTest. + ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern("Should be a clean filepath")). + RunTestWithBp(t, ` + install_symlink { + name: "foo", + installed_location: "bin/../foo", + symlink_target: "/system/system_ext/bin/foo", + } + `) +} + +func TestErrorOnInstalledPathStartingWithDotDot(t *testing.T) { + prepareForInstallSymlinkTest. + ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern("Should not start with / or \\.\\./")). + RunTestWithBp(t, ` + install_symlink { + name: "foo", + installed_location: "../bin/foo", + symlink_target: "/system/system_ext/bin/foo", + } + `) +} + +func TestErrorOnInstalledPathStartingWithSlash(t *testing.T) { + prepareForInstallSymlinkTest. + ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern("Should not start with / or \\.\\./")). + RunTestWithBp(t, ` + install_symlink { + name: "foo", + installed_location: "/bin/foo", + symlink_target: "/system/system_ext/bin/foo", + } + `) +} diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go index 370a4235b..94235319a 100644 --- a/etc/prebuilt_etc.go +++ b/etc/prebuilt_etc.go @@ -40,6 +40,7 @@ import ( "android/soong/bazel" "android/soong/bazel/cquery" "android/soong/snapshot" + "android/soong/ui/metrics/bp2build_metrics_proto" ) var pctx = android.NewPackageContext("android/soong/etc") @@ -711,7 +712,7 @@ type bazelPrebuiltFileAttributes struct { // Bp2buildHelper returns a bazelPrebuiltFileAttributes used for the conversion // of prebuilt_* modules. bazelPrebuiltFileAttributes has the common attributes // used by both prebuilt_etc_xml and other prebuilt_* moodules -func (module *PrebuiltEtc) Bp2buildHelper(ctx android.TopDownMutatorContext) *bazelPrebuiltFileAttributes { +func (module *PrebuiltEtc) Bp2buildHelper(ctx android.Bp2buildMutatorContext) (*bazelPrebuiltFileAttributes, bool) { var src bazel.LabelAttribute for axis, configToProps := range module.GetArchVariantProperties(ctx, &prebuiltEtcProperties{}) { for config, p := range configToProps { @@ -720,12 +721,20 @@ func (module *PrebuiltEtc) Bp2buildHelper(ctx android.TopDownMutatorContext) *ba continue } if props.Src != nil { - label := android.BazelLabelForModuleSrcSingle(ctx, *props.Src) + srcStr := proptools.String(props.Src) + if srcStr == ctx.ModuleName() { + ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "src == name") + return &bazelPrebuiltFileAttributes{}, false + } + label := android.BazelLabelForModuleSrcSingle(ctx, srcStr) src.SetSelectValue(axis, config, label) } } - - for propName, productConfigProps := range android.ProductVariableProperties(ctx, ctx.Module()) { + productVarProperties, errs := android.ProductVariableProperties(ctx, ctx.Module()) + for _, err := range errs { + ctx.ModuleErrorf("ProductVariableProperties error: %s", err) + } + for propName, productConfigProps := range productVarProperties { for configProp, propVal := range productConfigProps { if propName == "Src" { props, ok := propVal.(*string) @@ -779,21 +788,23 @@ func (module *PrebuiltEtc) Bp2buildHelper(ctx android.TopDownMutatorContext) *ba attrs.Filename_from_src = bazel.BoolAttribute{Value: moduleProps.Filename_from_src} } - return attrs - + return attrs, true } // ConvertWithBp2build performs bp2build conversion of PrebuiltEtc // prebuilt_* modules (except prebuilt_etc_xml) are PrebuiltEtc, // which we treat as *PrebuiltFile* -func (module *PrebuiltEtc) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (module *PrebuiltEtc) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { var dir = module.installDirBase // prebuilt_file supports only `etc` or `usr/share` if !(dir == "etc" || dir == "usr/share") { return } - attrs := module.Bp2buildHelper(ctx) + attrs, convertible := module.Bp2buildHelper(ctx) + if !convertible { + return + } props := bazel.BazelTargetModuleProperties{ Rule_class: "prebuilt_file", diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go index df7664d7d..5c4e222dd 100644 --- a/etc/prebuilt_etc_test.go +++ b/etc/prebuilt_etc_test.go @@ -83,7 +83,7 @@ func TestPrebuiltEtcVariants(t *testing.T) { baz_variants := result.ModuleVariantsForTests("baz.conf") if len(baz_variants) != 1 { - t.Errorf("expected 1, got %#v", bar_variants) + t.Errorf("expected 1, got %#v", baz_variants) } } diff --git a/filesystem/avb_add_hash_footer.go b/filesystem/avb_add_hash_footer.go index f3fecd042..dabbc461b 100644 --- a/filesystem/avb_add_hash_footer.go +++ b/filesystem/avb_add_hash_footer.go @@ -68,6 +68,9 @@ type avbAddHashFooterProperties struct { // List of properties to add to the footer Props []avbProp + // The index used to prevent rollback of the image on device. + Rollback_index *int64 + // Include descriptors from images Include_descriptors_from_images []string `android:"path,arch_variant"` } @@ -128,6 +131,14 @@ func (a *avbAddHashFooter) GenerateAndroidBuildActions(ctx android.ModuleContext addAvbProp(ctx, cmd, prop) } + if a.properties.Rollback_index != nil { + rollbackIndex := proptools.Int(a.properties.Rollback_index) + if rollbackIndex < 0 { + ctx.PropertyErrorf("rollback_index", "Rollback index must be non-negative") + } + cmd.Flag(fmt.Sprintf(" --rollback_index %x", rollbackIndex)) + } + cmd.FlagWithOutput("--image ", a.output) builder.Build("avbAddHashFooter", fmt.Sprintf("avbAddHashFooter %s", ctx.ModuleName())) diff --git a/genrule/genrule.go b/genrule/genrule.go index 8e3f2780d..01cac5b1f 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -912,7 +912,7 @@ type genRuleProperties struct { Out []string } -type bazelGenruleAttributes struct { +type BazelGenruleAttributes struct { Srcs bazel.LabelListAttribute Outs []string Tools bazel.LabelListAttribute @@ -920,7 +920,7 @@ type bazelGenruleAttributes struct { } // ConvertWithBp2build converts a Soong module -> Bazel target. -func (m *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (m *Module) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { // Bazel only has the "tools" attribute. tools_prop := android.BazelLabelForModuleDeps(ctx, m.properties.Tools) tool_files_prop := android.BazelLabelForModuleSrc(ctx, m.properties.Tool_files) @@ -993,7 +993,10 @@ func (m *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { var cmdProp bazel.StringAttribute cmdProp.SetValue(replaceVariables(proptools.String(m.properties.Cmd))) - allProductVariableProps := android.ProductVariableProperties(ctx, m) + allProductVariableProps, errs := android.ProductVariableProperties(ctx, m) + for _, err := range errs { + ctx.ModuleErrorf("ProductVariableProperties error: %s", err) + } if productVariableProps, ok := allProductVariableProps["Cmd"]; ok { for productVariable, value := range productVariableProps { var cmd string @@ -1036,7 +1039,7 @@ func (m *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { break } } - attrs := &bazelGenruleAttributes{ + attrs := &BazelGenruleAttributes{ Srcs: srcs, Outs: outs, Cmd: cmdProp, diff --git a/java/aar.go b/java/aar.go index 021619603..f28d97149 100644 --- a/java/aar.go +++ b/java/aar.go @@ -993,7 +993,7 @@ var extractJNI = pctx.AndroidStaticRule("extractJNI", `jni_files=$$(find $outDir/jni -type f) && ` + // print error message if there are no JNI libs for this arch `[ -n "$$jni_files" ] || (echo "ERROR: no JNI libs found for arch ${archString}" && exit 1) && ` + - `${config.SoongZipCmd} -o $out -P 'lib/${archString}' ` + + `${config.SoongZipCmd} -o $out -L 0 -P 'lib/${archString}' ` + `-C $outDir/jni/${archString} $$(echo $$jni_files | xargs -n1 printf " -f %s")`, CommandDeps: []string{"${config.SoongZipCmd}"}, }, @@ -1239,7 +1239,7 @@ type bazelAndroidLibraryImport struct { Sdk_version bazel.StringAttribute } -func (a *aapt) convertAaptAttrsWithBp2Build(ctx android.TopDownMutatorContext) (*bazelAapt, bool) { +func (a *aapt) convertAaptAttrsWithBp2Build(ctx android.Bp2buildMutatorContext) (*bazelAapt, bool) { manifest := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml") resourceFiles := bazel.LabelList{ @@ -1275,7 +1275,7 @@ func (a *aapt) convertAaptAttrsWithBp2Build(ctx android.TopDownMutatorContext) ( }, true } -func (a *AARImport) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (a *AARImport) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { aars := android.BazelLabelForModuleSrcExcludes(ctx, a.properties.Aars, []string{}) exportableStaticLibs := []string{} // TODO(b/240716882): investigate and handle static_libs deps that are not imports. They are not supported for export by Bazel. @@ -1328,7 +1328,7 @@ func AndroidLibraryBazelTargetModuleProperties() bazel.BazelTargetModuleProperti } } -func (a *AndroidLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (a *AndroidLibrary) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { commonAttrs, bp2buildInfo, supported := a.convertLibraryAttrsBp2Build(ctx) if !supported { return @@ -1340,7 +1340,10 @@ func (a *AndroidLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) if !commonAttrs.Srcs.IsEmpty() { deps.Append(depLabels.StaticDeps) // we should only append these if there are sources to use them } else if !depLabels.Deps.IsEmpty() { - ctx.ModuleErrorf("Module has direct dependencies but no sources. Bazel will not allow this.") + ctx.MarkBp2buildUnconvertible( + bp2build_metrics_proto.UnconvertedReasonType_UNSUPPORTED, + "Module has direct dependencies but no sources. Bazel will not allow this.") + return } name := a.Name() props := AndroidLibraryBazelTargetModuleProperties() diff --git a/java/androidmk.go b/java/androidmk.go index 82505e9e3..b7e2d2ff3 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -79,6 +79,9 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { } else if !library.ApexModuleBase.AvailableFor(android.AvailableToPlatform) { // Platform variant. If not available for the platform, we don't need Make module. entriesList = append(entriesList, android.AndroidMkEntries{Disabled: true}) + } else if library.properties.Headers_only { + // If generating headers only then don't expose to Make. + entriesList = append(entriesList, android.AndroidMkEntries{Disabled: true}) } else { entriesList = append(entriesList, android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", diff --git a/java/app.go b/java/app.go index 7cf86c02f..3ab814ab2 100755 --- a/java/app.go +++ b/java/app.go @@ -29,7 +29,9 @@ import ( "android/soong/bazel" "android/soong/cc" "android/soong/dexpreopt" + "android/soong/genrule" "android/soong/tradefed" + "android/soong/ui/metrics/bp2build_metrics_proto" ) func init() { @@ -315,6 +317,17 @@ func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.generateJavaUsedByApex(ctx) } +func (a *AndroidApp) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { + defaultMinSdkVersion := a.Module.MinSdkVersion(ctx) + if proptools.Bool(a.appProperties.Updatable) { + overrideApiLevel := android.MinSdkVersionFromValue(ctx, ctx.DeviceConfig().ApexGlobalMinSdkVersionOverride()) + if !overrideApiLevel.IsNone() && overrideApiLevel.CompareTo(defaultMinSdkVersion) > 0 { + return overrideApiLevel + } + } + return defaultMinSdkVersion +} + func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { if a.Updatable() { if !a.SdkVersion(ctx).Stable() { @@ -1059,6 +1072,7 @@ func AndroidAppFactory() android.Module { module.Module.dexProperties.Optimize.EnabledByDefault = true module.Module.dexProperties.Optimize.Shrink = proptools.BoolPtr(true) + module.Module.dexProperties.Optimize.Proguard_compatibility = proptools.BoolPtr(false) module.Module.properties.Instrument = true module.Module.properties.Supports_static_instrumentation = true @@ -1102,6 +1116,8 @@ type AndroidTest struct { testConfig android.Path extraTestConfigs android.Paths data android.Paths + + android.BazelModuleBase } func (a *AndroidTest) InstallInTestcases() bool { @@ -1219,6 +1235,8 @@ func AndroidTestFactory() android.Module { android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) android.InitOverridableModule(module, &module.overridableAppProperties.Overrides) + + android.InitBazelModule(module) return module } @@ -1240,6 +1258,8 @@ type AndroidTestHelperApp struct { AndroidApp appTestHelperAppProperties appTestHelperAppProperties + + android.BazelModuleBase } func (a *AndroidTestHelperApp) InstallInTestcases() bool { @@ -1271,6 +1291,7 @@ func AndroidTestHelperAppFactory() android.Module { android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) android.InitApexModule(module) + android.InitBazelModule(module) return module } @@ -1577,11 +1598,11 @@ type bazelAndroidAppCertificateAttributes struct { Certificate string } -func (m *AndroidAppCertificate) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (m *AndroidAppCertificate) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { androidAppCertificateBp2Build(ctx, m) } -func androidAppCertificateBp2Build(ctx android.TopDownMutatorContext, module *AndroidAppCertificate) { +func androidAppCertificateBp2Build(ctx android.Bp2buildMutatorContext, module *AndroidAppCertificate) { var certificate string if module.properties.Certificate != nil { certificate = *module.properties.Certificate @@ -1613,23 +1634,30 @@ type bazelAndroidAppAttributes struct { Certificate bazel.LabelAttribute Certificate_name bazel.StringAttribute Manifest_values *manifestValueAttribute + Optimize *bool + Proguard_specs bazel.LabelListAttribute } -// ConvertWithBp2build is used to convert android_app to Bazel. -func (a *AndroidApp) ConvertWithBp2build(ctx android.TopDownMutatorContext) { - commonAttrs, bp2BuildInfo, supported := a.convertLibraryAttrsBp2Build(ctx) - if !supported { - return - } - depLabels := bp2BuildInfo.DepLabels - - deps := depLabels.Deps - deps.Append(depLabels.StaticDeps) - +func convertWithBp2build(ctx android.Bp2buildMutatorContext, a *AndroidApp) (bool, android.CommonAttributes, *bazelAndroidAppAttributes) { aapt, supported := a.convertAaptAttrsWithBp2Build(ctx) if !supported { - return + return false, android.CommonAttributes{}, &bazelAndroidAppAttributes{} + } + if a.appProperties.Jni_uses_platform_apis != nil { + ctx.MarkBp2buildUnconvertible( + bp2build_metrics_proto.UnconvertedReasonType_UNSUPPORTED, + "TODO - b/299360988: Add bp2build support for jni_uses_platform_apis", + ) + return false, android.CommonAttributes{}, &bazelAndroidAppAttributes{} + } + if a.appProperties.Jni_uses_sdk_apis != nil { + ctx.MarkBp2buildUnconvertible( + bp2build_metrics_proto.UnconvertedReasonType_UNSUPPORTED, + "TODO - b/299360988: Add bp2build support for jni_uses_sdk_apis", + ) + return false, android.CommonAttributes{}, &bazelAndroidAppAttributes{} } + certificate, certificateName := android.BazelStringOrLabelFromProp(ctx, a.overridableAppProperties.Certificate) manifestValues := &manifestValueAttribute{} @@ -1664,11 +1692,63 @@ func (a *AndroidApp) ConvertWithBp2build(ctx android.TopDownMutatorContext) { Manifest_values: manifestValues, } - props := bazel.BazelTargetModuleProperties{ - Rule_class: "android_binary", - Bzl_load_location: "//build/bazel/rules/android:android_binary.bzl", + if !BoolDefault(a.dexProperties.Optimize.Enabled, true) { + appAttrs.Optimize = proptools.BoolPtr(false) + } else { + handCraftedFlags := "" + if Bool(a.dexProperties.Optimize.Ignore_warnings) { + handCraftedFlags += "-ignorewarning " + } + if !Bool(a.dexProperties.Optimize.Shrink) { + handCraftedFlags += "-dontshrink " + } + if !Bool(a.dexProperties.Optimize.Optimize) { + handCraftedFlags += "-dontoptimize " + } + if !Bool(a.dexProperties.Optimize.Obfuscate) { + handCraftedFlags += "-dontobfuscate " + } + appAttrs.Proguard_specs = bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, a.dexProperties.Optimize.Proguard_flags_files)) + if handCraftedFlags != "" { + generatedFlagFileRuleName := a.Name() + "_proguard_flags" + ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{ + Rule_class: "genrule", + }, android.CommonAttributes{ + Name: generatedFlagFileRuleName, + SkipData: proptools.BoolPtr(true), + }, &genrule.BazelGenruleAttributes{ + Outs: []string{a.Name() + "_proguard.flags"}, + Cmd: bazel.StringAttribute{ + Value: proptools.StringPtr("echo " + handCraftedFlags + "> $(OUTS)"), + }, + }) + appAttrs.Proguard_specs.Add(bazel.MakeLabelAttribute(":" + generatedFlagFileRuleName)) + } } + commonAttrs, bp2BuildInfo, supported := a.convertLibraryAttrsBp2Build(ctx) + if !supported { + return false, android.CommonAttributes{}, &bazelAndroidAppAttributes{} + } + depLabels := bp2BuildInfo.DepLabels + + deps := depLabels.Deps + deps.Append(depLabels.StaticDeps) + + var jniDeps bazel.LabelListAttribute + archVariantProps := a.GetArchVariantProperties(ctx, &appProperties{}) + for axis, configToProps := range archVariantProps { + for config, _props := range configToProps { + if archProps, ok := _props.(*appProperties); ok { + archJniLibs := android.BazelLabelForModuleDeps( + ctx, + android.LastUniqueStrings(android.CopyOf(archProps.Jni_libs))) + jniDeps.SetSelectValue(axis, config, archJniLibs) + } + } + } + deps.Append(jniDeps) + if !bp2BuildInfo.hasKotlin { appAttrs.javaCommonAttributes = commonAttrs appAttrs.bazelAapt = aapt @@ -1694,10 +1774,55 @@ func (a *AndroidApp) ConvertWithBp2build(ctx android.TopDownMutatorContext) { } } - ctx.CreateBazelTargetModule( - props, - android.CommonAttributes{Name: a.Name(), SkipData: proptools.BoolPtr(true)}, - appAttrs, - ) + return true, android.CommonAttributes{Name: a.Name(), SkipData: proptools.BoolPtr(true)}, appAttrs +} + +// ConvertWithBp2build is used to convert android_app to Bazel. +func (a *AndroidApp) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { + if ok, commonAttrs, appAttrs := convertWithBp2build(ctx, a); ok { + props := bazel.BazelTargetModuleProperties{ + Rule_class: "android_binary", + Bzl_load_location: "//build/bazel/rules/android:android_binary.bzl", + } + ctx.CreateBazelTargetModule(props, commonAttrs, appAttrs) + } + +} + +// ConvertWithBp2build is used to convert android_test to Bazel. +func (at *AndroidTest) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { + if ok, commonAttrs, appAttrs := convertWithBp2build(ctx, &at.AndroidApp); ok { + props := bazel.BazelTargetModuleProperties{ + Rule_class: "android_test", + Bzl_load_location: "//build/bazel/rules/android:android_test.bzl", + } + + ctx.CreateBazelTargetModule(props, commonAttrs, appAttrs) + } + +} + +func (atha *AndroidTestHelperApp) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { + if ok, commonAttrs, appAttrs := convertWithBp2build(ctx, &atha.AndroidApp); ok { + // an android_test_helper_app is an android_binary with testonly = True + commonAttrs.Testonly = proptools.BoolPtr(true) + + // additionally, it sets default values differently to android_app, + // https://cs.android.com/android/platform/superproject/main/+/main:build/soong/java/app.go;l=1273-1279;drc=e12c083198403ec694af6c625aed11327eb2bf7f + // + // installable: true (settable prop) + // use_embedded_native_libs: true (settable prop) + // lint.test: true (settable prop) + // optimize EnabledByDefault: true (blueprint mutated prop) + // AlwaysPackageNativeLibs: true (blueprint mutated prop) + // dexpreopt isTest: true (not prop) + + props := bazel.BazelTargetModuleProperties{ + Rule_class: "android_binary", + Bzl_load_location: "//build/bazel/rules/android:android_binary.bzl", + } + + ctx.CreateBazelTargetModule(props, commonAttrs, appAttrs) + } } diff --git a/java/app_import.go b/java/app_import.go index ad1765e9d..c5d09fdf1 100644 --- a/java/app_import.go +++ b/java/app_import.go @@ -19,6 +19,7 @@ package java import ( "fmt" "reflect" + "strings" "github.com/google/blueprint" @@ -51,27 +52,11 @@ var ( Description: "Uncompress dex files", }) - checkDexLibsAreUncompressedRule = pctx.AndroidStaticRule("check-dex-libs-are-uncompressed", blueprint.RuleParams{ - // grep -v ' stor ' will search for lines that don't have ' stor '. stor means the file is stored uncompressed - Command: "if (zipinfo $in '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then " + - "echo $in: Contains compressed JNI libraries and/or dex files >&2;" + - "exit 1; " + - "else " + - "touch $out; " + - "fi", - Description: "Check for compressed JNI libs or dex files", - }) - - checkJniLibsAreUncompressedRule = pctx.AndroidStaticRule("check-jni-libs-are-uncompressed", blueprint.RuleParams{ - // grep -v ' stor ' will search for lines that don't have ' stor '. stor means the file is stored uncompressed - Command: "if (zipinfo $in 'lib/*.so' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then " + - "echo $in: Contains compressed JNI libraries >&2;" + - "exit 1; " + - "else " + - "touch $out; " + - "fi", - Description: "Check for compressed JNI libs or dex files", - }) + checkPresignedApkRule = pctx.AndroidStaticRule("check-presigned-apk", blueprint.RuleParams{ + Command: "build/soong/scripts/check_prebuilt_presigned_apk.py --aapt2 ${config.Aapt2Cmd} --zipalign ${config.ZipAlign} $extraArgs $in $out", + CommandDeps: []string{"build/soong/scripts/check_prebuilt_presigned_apk.py", "${config.Aapt2Cmd}", "${config.ZipAlign}"}, + Description: "Check presigned apk", + }, "extraArgs") ) func RegisterAppImportBuildComponents(ctx android.RegistrationContext) { @@ -277,6 +262,14 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext a.hideApexVariantFromMake = true } + if Bool(a.properties.Preprocessed) { + if a.properties.Presigned != nil && !*a.properties.Presigned { + ctx.ModuleErrorf("Setting preprocessed: true implies presigned: true, so you cannot set presigned to false") + } + t := true + a.properties.Presigned = &t + } + numCertPropsSet := 0 if String(a.properties.Certificate) != "" { numCertPropsSet++ @@ -288,11 +281,9 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext numCertPropsSet++ } if numCertPropsSet != 1 { - ctx.ModuleErrorf("One and only one of certficate, presigned, and default_dev_cert properties must be set") + ctx.ModuleErrorf("One and only one of certficate, presigned (implied by preprocessed), and default_dev_cert properties must be set") } - _, _, certificates := collectAppDeps(ctx, a, false, false) - // TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK // TODO: LOCAL_PACKAGE_SPLITS @@ -346,25 +337,20 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext // Sign or align the package if package has not been preprocessed if proptools.Bool(a.properties.Preprocessed) { - var output android.WritablePath - if !proptools.Bool(a.properties.Skip_preprocessed_apk_checks) { - output = android.PathForModuleOut(ctx, "validated-prebuilt", apkFilename) - a.validatePreprocessedApk(ctx, srcApk, output) - } else { - // If using the input APK unmodified, still make a copy of it so that the output filename has the - // right basename. - output = android.PathForModuleOut(ctx, apkFilename) - ctx.Build(pctx, android.BuildParams{ - Rule: android.Cp, - Input: srcApk, - Output: output, - }) - } + validationStamp := a.validatePresignedApk(ctx, srcApk) + output := android.PathForModuleOut(ctx, apkFilename) + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Input: srcApk, + Output: output, + Validation: validationStamp, + }) a.outputFile = output a.certificate = PresignedCertificate } else if !Bool(a.properties.Presigned) { // If the certificate property is empty at this point, default_dev_cert must be set to true. // Which makes processMainCert's behavior for the empty cert string WAI. + _, _, certificates := collectAppDeps(ctx, a, false, false) a.certificate, certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx) signed := android.PathForModuleOut(ctx, "signed", apkFilename) var lineageFile android.Path @@ -377,8 +363,9 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext SignAppPackage(ctx, signed, jnisUncompressed, certificates, nil, lineageFile, rotationMinSdkVersion) a.outputFile = signed } else { + validationStamp := a.validatePresignedApk(ctx, srcApk) alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename) - TransformZipAlign(ctx, alignedApk, jnisUncompressed) + TransformZipAlign(ctx, alignedApk, jnisUncompressed, []android.Path{validationStamp}) a.outputFile = alignedApk a.certificate = PresignedCertificate } @@ -394,42 +381,28 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext // TODO: androidmk converter jni libs } -func (a *AndroidAppImport) validatePreprocessedApk(ctx android.ModuleContext, srcApk android.Path, dstApk android.WritablePath) { - var validations android.Paths - - alignmentStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "alignment.stamp") - ctx.Build(pctx, android.BuildParams{ - Rule: checkZipAlignment, - Input: srcApk, - Output: alignmentStamp, - }) - - validations = append(validations, alignmentStamp) - jniCompressionStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "jni_compression.stamp") - ctx.Build(pctx, android.BuildParams{ - Rule: checkJniLibsAreUncompressedRule, - Input: srcApk, - Output: jniCompressionStamp, - }) - validations = append(validations, jniCompressionStamp) - +func (a *AndroidAppImport) validatePresignedApk(ctx android.ModuleContext, srcApk android.Path) android.Path { + stamp := android.PathForModuleOut(ctx, "validated-prebuilt", "check.stamp") + var extraArgs []string if a.Privileged() { - // It's ok for non-privileged apps to have compressed dex files, see go/gms-uncompressed-jni-slides - dexCompressionStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "dex_compression.stamp") - ctx.Build(pctx, android.BuildParams{ - Rule: checkDexLibsAreUncompressedRule, - Input: srcApk, - Output: dexCompressionStamp, - }) - validations = append(validations, dexCompressionStamp) + extraArgs = append(extraArgs, "--privileged") + } + if proptools.Bool(a.properties.Skip_preprocessed_apk_checks) { + extraArgs = append(extraArgs, "--skip-preprocessed-apk-checks") + } + if proptools.Bool(a.properties.Preprocessed) { + extraArgs = append(extraArgs, "--preprocessed") } ctx.Build(pctx, android.BuildParams{ - Rule: android.Cp, - Input: srcApk, - Output: dstApk, - Validations: validations, + Rule: checkPresignedApkRule, + Input: srcApk, + Output: stamp, + Args: map[string]string{ + "extraArgs": strings.Join(extraArgs, " "), + }, }) + return stamp } func (a *AndroidAppImport) Prebuilt() *android.Prebuilt { diff --git a/java/app_import_test.go b/java/app_import_test.go index bb8fab93b..8f29bb373 100644 --- a/java/app_import_test.go +++ b/java/app_import_test.go @@ -629,31 +629,21 @@ func TestAndroidTestImport_Preprocessed(t *testing.T) { presigned: true, preprocessed: true, } - - android_test_import { - name: "foo_cert", - apk: "prebuilts/apk/app.apk", - certificate: "cert/new_cert", - preprocessed: true, - } `) - testModules := []string{"foo", "foo_cert"} - for _, m := range testModules { - apkName := m + ".apk" - variant := ctx.ModuleForTests(m, "android_common") - jniRule := variant.Output("jnis-uncompressed/" + apkName).BuildParams.Rule.String() - if jniRule != android.Cp.String() { - t.Errorf("Unexpected JNI uncompress rule: " + jniRule) - } + apkName := "foo.apk" + variant := ctx.ModuleForTests("foo", "android_common") + jniRule := variant.Output("jnis-uncompressed/" + apkName).BuildParams.Rule.String() + if jniRule != android.Cp.String() { + t.Errorf("Unexpected JNI uncompress rule: " + jniRule) + } - // Make sure signing and aligning were skipped. - if variant.MaybeOutput("signed/"+apkName).Rule != nil { - t.Errorf("signing rule shouldn't be included for preprocessed.") - } - if variant.MaybeOutput("zip-aligned/"+apkName).Rule != nil { - t.Errorf("aligning rule shouldn't be for preprocessed") - } + // Make sure signing and aligning were skipped. + if variant.MaybeOutput("signed/"+apkName).Rule != nil { + t.Errorf("signing rule shouldn't be included for preprocessed.") + } + if variant.MaybeOutput("zip-aligned/"+apkName).Rule != nil { + t.Errorf("aligning rule shouldn't be for preprocessed") } } @@ -669,14 +659,19 @@ func TestAndroidAppImport_Preprocessed(t *testing.T) { apkName := "foo.apk" variant := ctx.ModuleForTests("foo", "android_common") - outputBuildParams := variant.Output("validated-prebuilt/" + apkName).BuildParams + outputBuildParams := variant.Output(apkName).BuildParams if outputBuildParams.Rule.String() != android.Cp.String() { t.Errorf("Unexpected prebuilt android_app_import rule: " + outputBuildParams.Rule.String()) } // Make sure compression and aligning were validated. - if len(outputBuildParams.Validations) != 2 { - t.Errorf("Expected compression/alignment validation rules, found %d validations", len(outputBuildParams.Validations)) + if outputBuildParams.Validation == nil { + t.Errorf("Expected validation rule, but was not found") + } + + validationBuildParams := variant.Output("validated-prebuilt/check.stamp").BuildParams + if validationBuildParams.Rule.String() != checkPresignedApkRule.String() { + t.Errorf("Unexpected validation rule: " + validationBuildParams.Rule.String()) } } diff --git a/java/app_test.go b/java/app_test.go index 8474ea7d6..fc57f444a 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -4137,3 +4137,49 @@ func TestPrivappAllowlistAndroidMk(t *testing.T) { "\\S+soong/.intermediates/foo/android_common_bar/privapp_allowlist_com.google.android.foo.xml:\\S+/target/product/test_device/system/etc/permissions/bar.xml", ) } + +func TestApexGlobalMinSdkVersionOverride(t *testing.T) { + result := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.ApexGlobalMinSdkVersionOverride = proptools.StringPtr("Tiramisu") + }), + ).RunTestWithBp(t, ` + android_app { + name: "com.android.bar", + srcs: ["a.java"], + sdk_version: "current", + } + android_app { + name: "com.android.foo", + srcs: ["a.java"], + sdk_version: "current", + min_sdk_version: "S", + updatable: true, + } + override_android_app { + name: "com.android.go.foo", + base: "com.android.foo", + } + `) + foo := result.ModuleForTests("com.android.foo", "android_common").Rule("manifestFixer") + fooOverride := result.ModuleForTests("com.android.foo", "android_common_com.android.go.foo").Rule("manifestFixer") + bar := result.ModuleForTests("com.android.bar", "android_common").Rule("manifestFixer") + + android.AssertStringDoesContain(t, + "expected manifest fixer to set com.android.bar minSdkVersion to S", + bar.BuildParams.Args["args"], + "--minSdkVersion S", + ) + android.AssertStringDoesContain(t, + "com.android.foo: expected manifest fixer to set minSdkVersion to T", + foo.BuildParams.Args["args"], + "--minSdkVersion T", + ) + android.AssertStringDoesContain(t, + "com.android.go.foo: expected manifest fixer to set minSdkVersion to T", + fooOverride.BuildParams.Args["args"], + "--minSdkVersion T", + ) + +} diff --git a/java/base.go b/java/base.go index 4fe093af9..a110aff56 100644 --- a/java/base.go +++ b/java/base.go @@ -192,6 +192,9 @@ type CommonProperties struct { // Additional srcJars tacked in by GeneratedJavaLibraryModule Generated_srcjars []android.Path `android:"mutated"` + + // If true, then only the headers are built and not the implementation jar. + Headers_only bool } // Properties that are specific to device modules. Host module factories should not add these when @@ -574,6 +577,17 @@ func (j *Module) checkPlatformAPI(ctx android.ModuleContext) { } } +func (j *Module) checkHeadersOnly(ctx android.ModuleContext) { + if _, ok := ctx.Module().(android.SdkContext); ok { + headersOnly := proptools.Bool(&j.properties.Headers_only) + installable := proptools.Bool(j.properties.Installable) + + if headersOnly && installable { + ctx.PropertyErrorf("headers_only", "This module has conflicting settings. headers_only is true which, which means this module doesn't generate an implementation jar. However installable is set to true.") + } + } +} + func (j *Module) addHostProperties() { j.AddProperties( &j.properties, @@ -1063,8 +1077,8 @@ func (j *Module) AddJSONData(d *map[string]interface{}) { } -func (module *Module) addGeneratedSrcJars(path android.Path) { - module.properties.Generated_srcjars = append(module.properties.Generated_srcjars, path) +func (j *Module) addGeneratedSrcJars(path android.Path) { + j.properties.Generated_srcjars = append(j.properties.Generated_srcjars, path) } func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspathJars, extraCombinedJars android.Paths) { @@ -1153,6 +1167,36 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath // final R classes from the app. flags.classpath = append(android.CopyOf(extraClasspathJars), flags.classpath...) + // If compiling headers then compile them and skip the rest + if j.properties.Headers_only { + if srcFiles.HasExt(".kt") { + ctx.ModuleErrorf("Compiling headers_only with .kt not supported") + } + if ctx.Config().IsEnvFalse("TURBINE_ENABLED") || disableTurbine { + ctx.ModuleErrorf("headers_only is enabled but Turbine is disabled.") + } + + _, j.headerJarFile = + j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, + extraCombinedJars) + if ctx.Failed() { + return + } + + ctx.SetProvider(JavaInfoProvider, JavaInfo{ + HeaderJars: android.PathsIfNonNil(j.headerJarFile), + TransitiveLibsHeaderJars: j.transitiveLibsHeaderJars, + TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars, + AidlIncludeDirs: j.exportAidlIncludeDirs, + ExportedPlugins: j.exportedPluginJars, + ExportedPluginClasses: j.exportedPluginClasses, + ExportedPluginDisableTurbine: j.exportedDisableTurbine, + }) + + j.outputFile = j.headerJarFile + return + } + if srcFiles.HasExt(".kt") { // When using kotlin sources turbine is used to generate annotation processor sources, // including for annotation processors that generate API, so we can use turbine for @@ -1564,7 +1608,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath false, nil, nil) if *j.dexProperties.Uncompress_dex { combinedAlignedJar := android.PathForModuleOut(ctx, "dex-withres-aligned", jarName).OutputPath - TransformZipAlign(ctx, combinedAlignedJar, combinedJar) + TransformZipAlign(ctx, combinedAlignedJar, combinedJar, nil) dexOutputFile = combinedAlignedJar } else { dexOutputFile = combinedJar @@ -2315,7 +2359,7 @@ type ModuleWithStem interface { var _ ModuleWithStem = (*Module)(nil) -func (j *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (j *Module) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { switch ctx.ModuleType() { case "java_library", "java_library_host", "java_library_static", "tradefed_java_library_host": if lib, ok := ctx.Module().(*Library); ok { diff --git a/java/builder.go b/java/builder.go index debf49a00..ee7e225a8 100644 --- a/java/builder.go +++ b/java/builder.go @@ -259,19 +259,6 @@ var ( }, ) - checkZipAlignment = pctx.AndroidStaticRule("checkzipalign", - blueprint.RuleParams{ - Command: "if ! ${config.ZipAlign} -c -p 4 $in > /dev/null; then " + - "echo $in: Improper package alignment >&2; " + - "exit 1; " + - "else " + - "touch $out; " + - "fi", - CommandDeps: []string{"${config.ZipAlign}"}, - Description: "Check zip alignment", - }, - ) - convertImplementationJarToHeaderJarRule = pctx.AndroidStaticRule("convertImplementationJarToHeaderJar", blueprint.RuleParams{ Command: `${config.Zip2ZipCmd} -i ${in} -o ${out} -x 'META-INF/services/**/*'`, @@ -689,12 +676,13 @@ func GenerateMainClassManifest(ctx android.ModuleContext, outputFile android.Wri android.WriteFileRule(ctx, outputFile, "Main-Class: "+mainClass+"\n") } -func TransformZipAlign(ctx android.ModuleContext, outputFile android.WritablePath, inputFile android.Path) { +func TransformZipAlign(ctx android.ModuleContext, outputFile android.WritablePath, inputFile android.Path, validations android.Paths) { ctx.Build(pctx, android.BuildParams{ Rule: zipalign, Description: "align", Input: inputFile, Output: outputFile, + Validations: validations, }) } diff --git a/java/device_host_converter.go b/java/device_host_converter.go index 5460dc993..c5ba245ea 100644 --- a/java/device_host_converter.go +++ b/java/device_host_converter.go @@ -198,7 +198,7 @@ type bazelDeviceHostConverterAttributes struct { Exports bazel.LabelListAttribute } -func (d *DeviceHostConverter) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (d *DeviceHostConverter) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { ctx.CreateBazelTargetModule( bazel.BazelTargetModuleProperties{ Rule_class: "java_host_for_device", diff --git a/java/dex.go b/java/dex.go index df501bffa..c1d51c7bf 100644 --- a/java/dex.go +++ b/java/dex.go @@ -45,8 +45,8 @@ type DexProperties struct { // Whether to continue building even if warnings are emitted. Defaults to true. Ignore_warnings *bool - // If true, runs R8 in Proguard compatibility mode (default). - // Otherwise, runs R8 in full mode. + // If true, runs R8 in Proguard compatibility mode, otherwise runs R8 in full mode. + // Defaults to false for apps, true for libraries and tests. Proguard_compatibility *bool // If true, optimize for size by removing unused code. Defaults to true for apps, @@ -217,8 +217,9 @@ func (d *dexer) dexCommonFlags(ctx android.ModuleContext, // Note: Targets with a min SDK kind of core_platform (e.g., framework.jar) or unspecified (e.g., // services.jar), are not classified as stable, which is WAI. // TODO(b/232073181): Expand to additional min SDK cases after validation. + var addAndroidPlatformBuildFlag = false if !dexParams.sdkVersion.Stable() { - flags = append(flags, "--android-platform-build") + addAndroidPlatformBuildFlag = true } effectiveVersion, err := dexParams.minSdkVersion.EffectiveVersion(ctx) @@ -226,7 +227,18 @@ func (d *dexer) dexCommonFlags(ctx android.ModuleContext, ctx.PropertyErrorf("min_sdk_version", "%s", err) } - flags = append(flags, "--min-api "+strconv.Itoa(effectiveVersion.FinalOrFutureInt())) + // If the specified SDK level is 10000, then configure the compiler to use the + // current platform SDK level and to compile the build as a platform build. + var minApiFlagValue = effectiveVersion.FinalOrFutureInt() + if minApiFlagValue == 10000 { + minApiFlagValue = ctx.Config().PlatformSdkVersion().FinalInt() + addAndroidPlatformBuildFlag = true + } + flags = append(flags, "--min-api "+strconv.Itoa(minApiFlagValue)) + + if addAndroidPlatformBuildFlag { + flags = append(flags, "--android-platform-build") + } return flags, deps } @@ -303,15 +315,14 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Fl if BoolDefault(opt.Proguard_compatibility, true) { r8Flags = append(r8Flags, "--force-proguard-compatibility") - } else { + } + + if Bool(opt.Optimize) || Bool(opt.Obfuscate) { // TODO(b/213833843): Allow configuration of the prefix via a build variable. var sourceFilePrefix = "go/retraceme " var sourceFileTemplate = "\"" + sourceFilePrefix + "%MAP_ID\"" - // TODO(b/200967150): Also tag the source file in compat builds. - if Bool(opt.Optimize) || Bool(opt.Obfuscate) { - r8Flags = append(r8Flags, "--map-id-template", "%MAP_HASH") - r8Flags = append(r8Flags, "--source-file-template", sourceFileTemplate) - } + r8Flags = append(r8Flags, "--map-id-template", "%MAP_HASH") + r8Flags = append(r8Flags, "--source-file-template", sourceFileTemplate) } // TODO(ccross): Don't shrink app instrumentation tests by default. @@ -438,7 +449,7 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam } if proptools.Bool(d.dexProperties.Uncompress_dex) { alignedJavalibJar := android.PathForModuleOut(ctx, "aligned", dexParams.jarName).OutputPath - TransformZipAlign(ctx, alignedJavalibJar, javalibJar) + TransformZipAlign(ctx, alignedJavalibJar, javalibJar, nil) javalibJar = alignedJavalibJar } diff --git a/java/droiddoc.go b/java/droiddoc.go index 3ba306554..d5547d05c 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -22,6 +22,7 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/bazel" "android/soong/java/config" ) @@ -844,6 +845,7 @@ type ExportedDroiddocDirProperties struct { type ExportedDroiddocDir struct { android.ModuleBase + android.BazelModuleBase properties ExportedDroiddocDirProperties @@ -856,6 +858,7 @@ func ExportedDroiddocDirFactory() android.Module { module := &ExportedDroiddocDir{} module.AddProperties(&module.properties) android.InitAndroidModule(module) + android.InitBazelModule(module) return module } @@ -867,6 +870,28 @@ func (d *ExportedDroiddocDir) GenerateAndroidBuildActions(ctx android.ModuleCont d.deps = android.PathsForModuleSrc(ctx, []string{filepath.Join(path, "**/*")}) } +// ConvertWithBp2build implements android.BazelModule. +func (d *ExportedDroiddocDir) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { + props := bazel.BazelTargetModuleProperties{ + // Use the native py_library rule. + Rule_class: "droiddoc_exported_dir", + Bzl_load_location: "//build/bazel/rules/droiddoc:droiddoc_exported_dir.bzl", + } + + type BazelAttrs struct { + Dir *string + Srcs bazel.LabelListAttribute + } + + attrs := &BazelAttrs{ + Dir: proptools.StringPtr(*d.properties.Path), + Srcs: bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, []string{filepath.Join(*d.properties.Path, "**/*")})), + } + + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: d.Name()}, attrs) + +} + // Defaults type DocDefaults struct { android.ModuleBase diff --git a/java/droidstubs.go b/java/droidstubs.go index f05ef1fdd..1d5dd7624 100644 --- a/java/droidstubs.go +++ b/java/droidstubs.go @@ -539,7 +539,7 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi // Force metalava to sort overloaded methods by their order in the source code. // See b/285312164 for more information. - cmd.FlagWithArg("--api-overloaded-method-order ", "source") + cmd.FlagWithArg("--format-defaults ", "overloaded-method-order=source") return cmd } diff --git a/java/generated_java_library.go b/java/generated_java_library.go index 1cab6acc4..578237e3b 100644 --- a/java/generated_java_library.go +++ b/java/generated_java_library.go @@ -22,6 +22,10 @@ type GeneratedJavaLibraryModule struct { Library callbacks GeneratedJavaLibraryCallbacks moduleName string + + // true if we've already called DepsMutator. Can't call AddLibrary or AddSharedLibrary + // after DepsMutator. + depsMutatorDone bool } type GeneratedJavaLibraryCallbacks interface { @@ -59,8 +63,25 @@ func GeneratedJavaLibraryModuleFactory(moduleName string, callbacks GeneratedJav return module } +// Add a java shared library as a dependency, as if they had said `libs: [ "name" ]` +func (module *GeneratedJavaLibraryModule) AddSharedLibrary(name string) { + if module.depsMutatorDone { + panic("GeneratedJavaLibraryModule.AddLibrary called after DepsMutator") + } + module.Library.properties.Libs = append(module.Library.properties.Libs, name) +} + +// Add a java shared library as a dependency, as if they had said `libs: [ "name" ]` +func (module *GeneratedJavaLibraryModule) AddStaticLibrary(name string) { + if module.depsMutatorDone { + panic("GeneratedJavaLibraryModule.AddStaticLibrary called after DepsMutator") + } + module.Library.properties.Static_libs = append(module.Library.properties.Static_libs, name) +} + func (module *GeneratedJavaLibraryModule) DepsMutator(ctx android.BottomUpMutatorContext) { module.callbacks.DepsMutator(module, ctx) + module.depsMutatorDone = true module.Library.DepsMutator(ctx) } diff --git a/java/hiddenapi.go b/java/hiddenapi.go index 4d08b8307..fe3fe7b61 100644 --- a/java/hiddenapi.go +++ b/java/hiddenapi.go @@ -305,7 +305,7 @@ func hiddenAPIEncodeDex(ctx android.ModuleContext, dexInput, flagsCSV android.Pa }) if uncompressDex { - TransformZipAlign(ctx, output, encodeRuleOutput) + TransformZipAlign(ctx, output, encodeRuleOutput, nil) } return output diff --git a/java/java.go b/java/java.go index 5f59fe401..d5aeb7cb2 100644 --- a/java/java.go +++ b/java/java.go @@ -21,6 +21,7 @@ package java import ( "fmt" "path/filepath" + "sort" "strings" "android/soong/bazel" @@ -63,6 +64,7 @@ func registerJavaBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("dex_import", DexImportFactory) ctx.RegisterModuleType("java_api_library", ApiLibraryFactory) ctx.RegisterModuleType("java_api_contribution", ApiContributionFactory) + ctx.RegisterModuleType("java_api_contribution_import", ApiContributionImportFactory) // This mutator registers dependencies on dex2oat for modules that should be // dexpreopted. This is done late when the final variants have been @@ -698,6 +700,7 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { } j.checkSdkVersions(ctx) + j.checkHeadersOnly(ctx) if ctx.Device() { j.dexpreopter.installPath = j.dexpreopter.getInstallPath( ctx, android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")) @@ -1621,7 +1624,8 @@ func ApiContributionFactory() android.Module { } type JavaApiImportInfo struct { - ApiFile android.Path + ApiFile android.Path + ApiSurface string } var JavaApiImportProvider = blueprint.NewProvider(JavaApiImportInfo{}) @@ -1633,7 +1637,8 @@ func (ap *JavaApiContribution) GenerateAndroidBuildActions(ctx android.ModuleCon } ctx.SetProvider(JavaApiImportProvider, JavaApiImportInfo{ - ApiFile: apiFile, + ApiFile: apiFile, + ApiSurface: proptools.String(ap.properties.Api_surface), }) } @@ -1733,7 +1738,6 @@ func metalavaStubCmd(ctx android.ModuleContext, rule *android.RuleBuilder, cmd.Flag("--color"). Flag("--quiet"). - Flag("--format=v2"). Flag("--include-annotations"). // The flag makes nullability issues as warnings rather than errors by replacing // @Nullable/@NonNull in the listed packages APIs with @RecentlyNullable/@RecentlyNonNull, @@ -1745,14 +1749,13 @@ func metalavaStubCmd(ctx android.ModuleContext, rule *android.RuleBuilder, FlagWithArg("--hide ", "InvalidNullabilityOverride"). FlagWithArg("--hide ", "ChangedDefault") - // Force metalava to ignore classes on the classpath when an API file contains missing classes. - // See b/285140653 for more information. + // The main purpose of the `--api-class-resolution api` option is to force metalava to ignore + // classes on the classpath when an API file contains missing classes. However, as this command + // does not specify `--classpath` this is not needed for that. However, this is also used as a + // signal to the special metalava code for generating stubs from text files that it needs to add + // some additional items into the API (e.g. default constructors). cmd.FlagWithArg("--api-class-resolution ", "api") - // Force metalava to sort overloaded methods by their order in the source code. - // See b/285312164 for more information. - cmd.FlagWithArg("--api-overloaded-method-order ", "source") - return cmd } @@ -1798,6 +1801,7 @@ func (al *ApiLibrary) extractApiSrcs(ctx android.ModuleContext, rule *android.Ru Flag("-jar"). Flag("-write_if_changed"). Flag("-ignore_missing_files"). + Flag("-quiet"). FlagWithArg("-C ", unzippedSrcJarDir.String()). FlagWithInput("-l ", classFilesList). FlagWithOutput("-o ", al.stubsJarWithoutStaticLibs) @@ -1820,18 +1824,29 @@ func (al *ApiLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { var scopeOrderedSourceFileNames = allApiScopes.Strings( func(s *apiScope) string { return s.apiFilePrefix + "current.txt" }) -func (al *ApiLibrary) sortApiFilesByApiScope(ctx android.ModuleContext, srcFiles android.Paths) android.Paths { - sortedSrcFiles := android.Paths{} +func (al *ApiLibrary) sortApiFilesByApiScope(ctx android.ModuleContext, srcFilesInfo []JavaApiImportInfo, apiFiles android.Paths) android.Paths { + var sortedSrcFiles android.Paths - for _, scopeSourceFileName := range scopeOrderedSourceFileNames { - for _, sourceFileName := range srcFiles { - if sourceFileName.Base() == scopeSourceFileName { - sortedSrcFiles = append(sortedSrcFiles, sourceFileName) + for i, apiScope := range allApiScopes { + for _, srcFileInfo := range srcFilesInfo { + if srcFileInfo.ApiFile.Base() == scopeOrderedSourceFileNames[i] || srcFileInfo.ApiSurface == apiScope.name { + sortedSrcFiles = append(sortedSrcFiles, android.PathForSource(ctx, srcFileInfo.ApiFile.String())) + } + } + // TODO: b/300964421 - Remove when api_files property is removed + for _, apiFileName := range apiFiles { + if apiFileName.Base() == scopeOrderedSourceFileNames[i] { + sortedSrcFiles = append(sortedSrcFiles, apiFileName) } } } - if len(srcFiles) != len(sortedSrcFiles) { - ctx.ModuleErrorf("Unrecognizable source file found within %s", srcFiles) + + if len(srcFilesInfo)+len(apiFiles) != len(sortedSrcFiles) { + var srcFiles android.Paths + for _, srcFileInfo := range srcFilesInfo { + srcFiles = append(srcFiles, srcFileInfo.ApiFile) + } + ctx.ModuleErrorf("Unrecognizable source file found within %s", append(srcFiles, apiFiles...)) } return sortedSrcFiles @@ -1852,7 +1867,7 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { homeDir := android.PathForModuleOut(ctx, "metalava", "home") - var srcFiles android.Paths + var srcFilesInfo []JavaApiImportInfo var classPaths android.Paths var staticLibs android.Paths var depApiSrcsStubsJar android.Path @@ -1861,11 +1876,10 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { switch tag { case javaApiContributionTag: provider := ctx.OtherModuleProvider(dep, JavaApiImportProvider).(JavaApiImportInfo) - providerApiFile := provider.ApiFile - if providerApiFile == nil && !ctx.Config().AllowMissingDependencies() { + if provider.ApiFile == nil && !ctx.Config().AllowMissingDependencies() { ctx.ModuleErrorf("Error: %s has an empty api file.", dep.Name()) } - srcFiles = append(srcFiles, android.PathForSource(ctx, providerApiFile.String())) + srcFilesInfo = append(srcFilesInfo, provider) case libTag: provider := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo) classPaths = append(classPaths, provider.HeaderJars...) @@ -1879,16 +1893,19 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { }) // Add the api_files inputs + // These are api files in the module subdirectory, which are not provided by + // java_api_contribution but provided directly as module property. + var apiFiles android.Paths for _, api := range al.properties.Api_files { - srcFiles = append(srcFiles, android.PathForModuleSrc(ctx, api)) + apiFiles = append(apiFiles, android.PathForModuleSrc(ctx, api)) } + srcFiles := al.sortApiFilesByApiScope(ctx, srcFilesInfo, apiFiles) + if srcFiles == nil && !ctx.Config().AllowMissingDependencies() { ctx.ModuleErrorf("Error: %s has an empty api file.", ctx.ModuleName()) } - srcFiles = al.sortApiFilesByApiScope(ctx, srcFiles) - cmd := metalavaStubCmd(ctx, rule, srcFiles, homeDir) al.stubsFlags(ctx, cmd, stubsDir) @@ -1914,7 +1931,7 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { FlagWithArg("-C ", stubsDir.String()). FlagWithArg("-D ", stubsDir.String()) - rule.Build("metalava", "metalava merged") + rule.Build("metalava", "metalava merged text") if depApiSrcsStubsJar == nil { var flags javaBuilderFlags @@ -2755,32 +2772,41 @@ func addCLCFromDep(ctx android.ModuleContext, depModule android.Module, type javaResourcesAttributes struct { Resources bazel.LabelListAttribute Resource_strip_prefix *string + Additional_resources bazel.LabelListAttribute } -func (m *Library) javaResourcesGetSingleFilegroupStripPrefix(ctx android.TopDownMutatorContext) (string, bool) { - if otherM, ok := ctx.ModuleFromName(m.properties.Java_resources[0]); ok && len(m.properties.Java_resources) == 1 { +func (m *Library) getResourceFilegroupStripPrefix(ctx android.Bp2buildMutatorContext, resourceFilegroup string) (*string, bool) { + if otherM, ok := ctx.ModuleFromName(resourceFilegroup); ok { if fg, isFilegroup := otherM.(android.FileGroupPath); isFilegroup { - return filepath.Join(ctx.OtherModuleDir(otherM), fg.GetPath(ctx)), true + return proptools.StringPtr(filepath.Join(ctx.OtherModuleDir(otherM), fg.GetPath(ctx))), true } } - return "", false + return proptools.StringPtr(""), false } -func (m *Library) convertJavaResourcesAttributes(ctx android.TopDownMutatorContext) *javaResourcesAttributes { +func (m *Library) convertJavaResourcesAttributes(ctx android.Bp2buildMutatorContext) *javaResourcesAttributes { var resources bazel.LabelList var resourceStripPrefix *string - if m.properties.Java_resources != nil && len(m.properties.Java_resource_dirs) > 0 { - ctx.ModuleErrorf("bp2build doesn't support both java_resources and java_resource_dirs being set on the same module.") - } + additionalJavaResourcesMap := make(map[string]*javaResourcesAttributes) if m.properties.Java_resources != nil { - if prefix, ok := m.javaResourcesGetSingleFilegroupStripPrefix(ctx); ok { - resourceStripPrefix = proptools.StringPtr(prefix) - } else { + for _, res := range m.properties.Java_resources { + if prefix, isFilegroup := m.getResourceFilegroupStripPrefix(ctx, res); isFilegroup { + otherM, _ := ctx.ModuleFromName(res) + resourcesTargetName := ctx.ModuleName() + "_filegroup_resources_" + otherM.Name() + additionalJavaResourcesMap[resourcesTargetName] = &javaResourcesAttributes{ + Resources: bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, []string{res})), + Resource_strip_prefix: prefix, + } + } else { + resources.Append(android.BazelLabelForModuleSrc(ctx, []string{res})) + } + } + + if !resources.IsEmpty() { resourceStripPrefix = proptools.StringPtr(ctx.ModuleDir()) } - resources.Append(android.BazelLabelForModuleSrc(ctx, m.properties.Java_resources)) } //TODO(b/179889880) handle case where glob includes files outside package @@ -2791,23 +2817,51 @@ func (m *Library) convertJavaResourcesAttributes(ctx android.TopDownMutatorConte m.properties.Exclude_java_resources, ) - for i, resDep := range resDeps { + for _, resDep := range resDeps { dir, files := resDep.dir, resDep.files - resources.Append(bazel.MakeLabelList(android.RootToModuleRelativePaths(ctx, files))) - // Bazel includes the relative path from the WORKSPACE root when placing the resource // inside the JAR file, so we need to remove that prefix - resourceStripPrefix = proptools.StringPtr(dir.String()) - if i > 0 { - // TODO(b/226423379) allow multiple resource prefixes - ctx.ModuleErrorf("bp2build does not support more than one directory in java_resource_dirs (b/226423379)") + prefix := proptools.StringPtr(dir.String()) + resourcesTargetName := ctx.ModuleName() + "_resource_dir_" + dir.String() + additionalJavaResourcesMap[resourcesTargetName] = &javaResourcesAttributes{ + Resources: bazel.MakeLabelListAttribute(bazel.MakeLabelList(android.RootToModuleRelativePaths(ctx, files))), + Resource_strip_prefix: prefix, + } + } + + var additionalResourceLabels bazel.LabelList + if len(additionalJavaResourcesMap) > 0 { + var additionalResources []string + for resName, _ := range additionalJavaResourcesMap { + additionalResources = append(additionalResources, resName) } + sort.Strings(additionalResources) + + for i, resName := range additionalResources { + resAttr := additionalJavaResourcesMap[resName] + if resourceStripPrefix == nil && i == 0 { + resourceStripPrefix = resAttr.Resource_strip_prefix + resources = resAttr.Resources.Value + } else if !resAttr.Resources.IsEmpty() { + ctx.CreateBazelTargetModule( + bazel.BazelTargetModuleProperties{ + Rule_class: "java_resources", + Bzl_load_location: "//build/bazel/rules/java:java_resources.bzl", + }, + android.CommonAttributes{Name: resName}, + resAttr, + ) + additionalResourceLabels.Append(android.BazelLabelForModuleSrc(ctx, []string{resName})) + } + } + } return &javaResourcesAttributes{ Resources: bazel.MakeLabelListAttribute(resources), Resource_strip_prefix: resourceStripPrefix, + Additional_resources: bazel.MakeLabelListAttribute(additionalResourceLabels), } } @@ -2861,11 +2915,21 @@ func javaXsdTargetName(xsd android.XsdConfigBp2buildTargets) string { // which has other non-attribute information needed for bp2build conversion // that needs different handling depending on the module types, and thus needs // to be returned to the calling function. -func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) (*javaCommonAttributes, *bp2BuildJavaInfo, bool) { +func (m *Library) convertLibraryAttrsBp2Build(ctx android.Bp2buildMutatorContext) (*javaCommonAttributes, *bp2BuildJavaInfo, bool) { var srcs bazel.LabelListAttribute var deps bazel.LabelListAttribute var staticDeps bazel.LabelListAttribute + if proptools.String(m.deviceProperties.Sdk_version) == "" && m.DeviceSupported() { + // TODO(b/297356704): handle platform apis in bp2build + ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "sdk_version unset") + return &javaCommonAttributes{}, &bp2BuildJavaInfo{}, false + } else if proptools.String(m.deviceProperties.Sdk_version) == "core_platform" { + // TODO(b/297356582): handle core_platform in bp2build + ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "sdk_version core_platform") + return &javaCommonAttributes{}, &bp2BuildJavaInfo{}, false + } + archVariantProps := m.GetArchVariantProperties(ctx, &CommonProperties{}) for axis, configToProps := range archVariantProps { for config, _props := range configToProps { @@ -3072,7 +3136,7 @@ func javaLibraryBazelTargetModuleProperties() bazel.BazelTargetModuleProperties } } -func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) { +func javaLibraryBp2Build(ctx android.Bp2buildMutatorContext, m *Library) { commonAttrs, bp2BuildInfo, supported := m.convertLibraryAttrsBp2Build(ctx) if !supported { return @@ -3080,16 +3144,22 @@ func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) { depLabels := bp2BuildInfo.DepLabels deps := depLabels.Deps + exports := depLabels.StaticDeps if !commonAttrs.Srcs.IsEmpty() { - deps.Append(depLabels.StaticDeps) // we should only append these if there are sources to use them + deps.Append(exports) // we should only append these if there are sources to use them } else if !deps.IsEmpty() { - ctx.ModuleErrorf("Module has direct dependencies but no sources. Bazel will not allow this.") + // java_library does not accept deps when there are no srcs because + // there is no compilation happening, but it accepts exports. + // The non-empty deps here are unnecessary as deps on the java_library + // since they aren't being propagated to any dependencies. + // So we can drop deps here. + deps = bazel.LabelListAttribute{} } var props bazel.BazelTargetModuleProperties attrs := &javaLibraryAttributes{ javaCommonAttributes: commonAttrs, Deps: deps, - Exports: depLabels.StaticDeps, + Exports: exports, } name := m.Name() @@ -3122,7 +3192,7 @@ type javaBinaryHostAttributes struct { } // JavaBinaryHostBp2Build is for java_binary_host bp2build. -func javaBinaryHostBp2Build(ctx android.TopDownMutatorContext, m *Binary) { +func javaBinaryHostBp2Build(ctx android.Bp2buildMutatorContext, m *Binary) { commonAttrs, bp2BuildInfo, supported := m.convertLibraryAttrsBp2Build(ctx) if !supported { return @@ -3209,7 +3279,7 @@ type javaTestHostAttributes struct { } // javaTestHostBp2Build is for java_test_host bp2build. -func javaTestHostBp2Build(ctx android.TopDownMutatorContext, m *TestHost) { +func javaTestHostBp2Build(ctx android.Bp2buildMutatorContext, m *TestHost) { commonAttrs, bp2BuildInfo, supported := m.convertLibraryAttrsBp2Build(ctx) if !supported { return @@ -3262,7 +3332,7 @@ type libraryCreationInfo struct { // helper function that creates java_library target from java_binary_host or java_test_host, // and returns the library target name, -func createLibraryTarget(ctx android.TopDownMutatorContext, libInfo libraryCreationInfo) string { +func createLibraryTarget(ctx android.Bp2buildMutatorContext, libInfo libraryCreationInfo) string { libName := libInfo.baseName + "_lib" var libProps bazel.BazelTargetModuleProperties if libInfo.hasKotlin { @@ -3285,7 +3355,7 @@ type bazelJavaImportAttributes struct { } // java_import bp2Build converter. -func (i *Import) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (i *Import) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { var jars bazel.LabelListAttribute archVariantProps := i.GetArchVariantProperties(ctx, &ImportProperties{}) for axis, configToProps := range archVariantProps { @@ -3321,7 +3391,6 @@ func (i *Import) ConvertWithBp2build(ctx android.TopDownMutatorContext) { javaLibraryBazelTargetModuleProperties(), android.CommonAttributes{Name: name + "-neverlink"}, neverlinkAttrs) - } var _ android.MixedBuildBuildable = (*Import)(nil) @@ -3374,3 +3443,30 @@ func (i *Import) QueueBazelCall(ctx android.BaseModuleContext) { func (i *Import) IsMixedBuildSupported(ctx android.BaseModuleContext) bool { return true } + +type JavaApiContributionImport struct { + JavaApiContribution + + prebuilt android.Prebuilt +} + +func ApiContributionImportFactory() android.Module { + module := &JavaApiContributionImport{} + android.InitAndroidModule(module) + android.InitDefaultableModule(module) + android.InitPrebuiltModule(module, &[]string{""}) + module.AddProperties(&module.properties) + return module +} + +func (module *JavaApiContributionImport) Prebuilt() *android.Prebuilt { + return &module.prebuilt +} + +func (module *JavaApiContributionImport) Name() string { + return module.prebuilt.Name(module.ModuleBase.Name()) +} + +func (ap *JavaApiContributionImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { + ap.JavaApiContribution.GenerateAndroidBuildActions(ctx) +} diff --git a/java/java_test.go b/java/java_test.go index 6110e21cb..2ee05ec73 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -1865,11 +1865,13 @@ func TestJavaApiLibraryAndProviderLink(t *testing.T) { java_api_contribution { name: "foo1", api_file: "current.txt", + api_surface: "public", } ` provider_bp_b := `java_api_contribution { name: "foo2", api_file: "current.txt", + api_surface: "public", } ` ctx, _ := testJavaWithFS(t, ` @@ -1919,24 +1921,28 @@ func TestJavaApiLibraryAndDefaultsLink(t *testing.T) { java_api_contribution { name: "foo1", api_file: "current.txt", + api_surface: "public", } ` provider_bp_b := ` java_api_contribution { name: "foo2", api_file: "current.txt", + api_surface: "public", } ` provider_bp_c := ` java_api_contribution { name: "foo3", - api_file: "current.txt", + api_file: "system-current.txt", + api_surface: "system", } ` provider_bp_d := ` java_api_contribution { name: "foo4", - api_file: "current.txt", + api_file: "system-current.txt", + api_surface: "system", } ` ctx, _ := testJavaWithFS(t, ` @@ -1992,8 +1998,9 @@ func TestJavaApiLibraryAndDefaultsLink(t *testing.T) { sourceTextFileDirs: []string{"a/current.txt", "b/current.txt"}, }, { - moduleName: "bar3", - sourceTextFileDirs: []string{"c/current.txt", "a/current.txt", "b/current.txt", "d/current.txt", "api1/current.txt", "api2/current.txt"}, + moduleName: "bar3", + // API text files need to be sorted from the narrower api scope to the wider api scope + sourceTextFileDirs: []string{"a/current.txt", "b/current.txt", "api1/current.txt", "api2/current.txt", "c/system-current.txt", "d/system-current.txt"}, }, } for _, c := range testcases { @@ -2011,12 +2018,14 @@ func TestJavaApiLibraryJarGeneration(t *testing.T) { java_api_contribution { name: "foo1", api_file: "current.txt", + api_surface: "public", } ` provider_bp_b := ` java_api_contribution { name: "foo2", api_file: "current.txt", + api_surface: "public", } ` ctx, _ := testJavaWithFS(t, ` @@ -2064,12 +2073,14 @@ func TestJavaApiLibraryLibsLink(t *testing.T) { java_api_contribution { name: "foo1", api_file: "current.txt", + api_surface: "public", } ` provider_bp_b := ` java_api_contribution { name: "foo2", api_file: "current.txt", + api_surface: "public", } ` lib_bp_a := ` @@ -2139,12 +2150,14 @@ func TestJavaApiLibraryStaticLibsLink(t *testing.T) { java_api_contribution { name: "foo1", api_file: "current.txt", + api_surface: "public", } ` provider_bp_b := ` java_api_contribution { name: "foo2", api_file: "current.txt", + api_surface: "public", } ` lib_bp_a := ` @@ -2213,12 +2226,14 @@ func TestJavaApiLibraryFullApiSurfaceStub(t *testing.T) { java_api_contribution { name: "foo1", api_file: "current.txt", + api_surface: "public", } ` provider_bp_b := ` java_api_contribution { name: "foo2", api_file: "current.txt", + api_surface: "public", } ` lib_bp_a := ` @@ -2370,3 +2385,41 @@ func TestJavaLibraryWithResourcesStem(t *testing.T) { t.Errorf("Module output does not contain expected jar %s", "test.jar") } } + +func TestHeadersOnly(t *testing.T) { + ctx, _ := testJava(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + headers_only: true, + } + `) + + turbine := ctx.ModuleForTests("foo", "android_common").Rule("turbine") + if len(turbine.Inputs) != 1 || turbine.Inputs[0].String() != "a.java" { + t.Errorf(`foo inputs %v != ["a.java"]`, turbine.Inputs) + } + + javac := ctx.ModuleForTests("foo", "android_common").MaybeRule("javac") + android.AssertDeepEquals(t, "javac rule", nil, javac.Rule) +} + +func TestJavaApiContributionImport(t *testing.T) { + ctx, _ := testJava(t, ` + java_api_library { + name: "foo", + api_contributions: ["bar"], + } + java_api_contribution_import { + name: "bar", + api_file: "current.txt", + api_surface: "public", + } + `) + m := ctx.ModuleForTests("foo", "android_common") + manifest := m.Output("metalava.sbox.textproto") + sboxProto := android.RuleBuilderSboxProtoForTests(t, manifest) + manifestCommand := sboxProto.Commands[0].GetCommand() + sourceFilesFlag := "--source-files current.txt" + android.AssertStringDoesContain(t, "source text files not present", manifestCommand, sourceFilesFlag) +} diff --git a/java/kotlin.go b/java/kotlin.go index 3637e2e71..aa2db0ecd 100644 --- a/java/kotlin.go +++ b/java/kotlin.go @@ -145,7 +145,7 @@ var kaptStubs = pctx.AndroidRemoteStaticRule("kaptStubs", android.RemoteRuleSupp `$kaptProcessorPath ` + `$kaptProcessor ` + `-Xbuild-file=$kotlinBuildFile && ` + - `${config.SoongZipCmd} -jar -o $out -C $kaptDir/stubs -D $kaptDir/stubs && ` + + `${config.SoongZipCmd} -jar -write_if_changed -o $out -C $kaptDir/stubs -D $kaptDir/stubs && ` + `rm -rf "$srcJarDir"`, CommandDeps: []string{ "${config.KotlincCmd}", @@ -157,6 +157,7 @@ var kaptStubs = pctx.AndroidRemoteStaticRule("kaptStubs", android.RemoteRuleSupp }, Rspfile: "$out.rsp", RspfileContent: `$in`, + Restat: true, }, "kotlincFlags", "encodedJavacFlags", "kaptProcessorPath", "kaptProcessor", "classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", "kaptDir", "kotlinJvmTarget", diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go index 124827523..662a2d768 100644 --- a/java/platform_compat_config.go +++ b/java/platform_compat_config.go @@ -130,7 +130,7 @@ type bazelPlatformCompatConfigAttributes struct { Src bazel.LabelAttribute } -func (p *platformCompatConfig) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (p *platformCompatConfig) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { props := bazel.BazelTargetModuleProperties{ Rule_class: "platform_compat_config", Bzl_load_location: "//build/bazel/rules/java:platform_compat_config.bzl", diff --git a/java/plugin.go b/java/plugin.go index 51272981b..4d4c199f7 100644 --- a/java/plugin.go +++ b/java/plugin.go @@ -64,7 +64,7 @@ type pluginAttributes struct { } // ConvertWithBp2build is used to convert android_app to Bazel. -func (p *Plugin) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (p *Plugin) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { pluginName := p.Name() commonAttrs, bp2BuildInfo, supported := p.convertLibraryAttrsBp2Build(ctx) if !supported { diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go index 044802e4d..99cb99ba2 100644 --- a/java/prebuilt_apis.go +++ b/java/prebuilt_apis.go @@ -55,6 +55,11 @@ type prebuiltApisProperties struct { // If set to true, compile dex for java_import modules. Defaults to false. Imports_compile_dex *bool + + // If set to true, allow incremental platform API of the form MM.m where MM is the major release + // version corresponding to the API level/SDK_INT and m is an incremental release version + // (e.g. API changes associated with QPR). Defaults to false. + Allow_incremental_platform_api *bool } type prebuiltApis struct { @@ -69,6 +74,8 @@ func (module *prebuiltApis) GenerateAndroidBuildActions(ctx android.ModuleContex // parsePrebuiltPath parses the relevant variables out of a variety of paths, e.g. // <version>/<scope>/<module>.jar // <version>/<scope>/api/<module>.txt +// *Note when using incremental platform API, <version> may be of the form MM.m where MM is the +// API level and m is an incremental release, otherwise <version> is a single integer corresponding to the API level only. // extensions/<version>/<scope>/<module>.jar // extensions/<version>/<scope>/api/<module>.txt func parsePrebuiltPath(ctx android.LoadHookContext, p string) (module string, version string, scope string) { @@ -90,8 +97,25 @@ func parsePrebuiltPath(ctx android.LoadHookContext, p string) (module string, ve } // parseFinalizedPrebuiltPath is like parsePrebuiltPath, but verifies the version is numeric (a finalized version). -func parseFinalizedPrebuiltPath(ctx android.LoadHookContext, p string) (module string, version int, scope string) { +func parseFinalizedPrebuiltPath(ctx android.LoadHookContext, p string, allowIncremental bool) (module string, version int, release int, scope string) { module, v, scope := parsePrebuiltPath(ctx, p) + if allowIncremental { + parts := strings.Split(v, ".") + if len(parts) != 2 { + ctx.ModuleErrorf("Found unexpected version '%v' for incremental prebuilts - expect MM.m format for incremental API with both major (MM) an minor (m) revision.", v) + return + } + sdk, sdk_err := strconv.Atoi(parts[0]) + qpr, qpr_err := strconv.Atoi(parts[1]) + if sdk_err != nil || qpr_err != nil { + ctx.ModuleErrorf("Unable to read version number for incremental prebuilt api '%v'", v) + return + } + version = sdk + release = qpr + return + } + release = 0 version, err := strconv.Atoi(v) if err != nil { ctx.ModuleErrorf("Found finalized API files in non-numeric dir '%v'", v) @@ -268,29 +292,35 @@ func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) { } // Create modules for all (<module>, <scope, <version>) triplets, + allowIncremental := proptools.BoolDefault(p.properties.Allow_incremental_platform_api, false) for _, f := range apiLevelFiles { - module, version, scope := parseFinalizedPrebuiltPath(mctx, f) - createApiModule(mctx, PrebuiltApiModuleName(module, scope, strconv.Itoa(version)), f) + module, version, release, scope := parseFinalizedPrebuiltPath(mctx, f, allowIncremental) + if allowIncremental { + incrementalVersion := strconv.Itoa(version) + "." + strconv.Itoa(release) + createApiModule(mctx, PrebuiltApiModuleName(module, scope, incrementalVersion), f) + } else { + createApiModule(mctx, PrebuiltApiModuleName(module, scope, strconv.Itoa(version)), f) + } } // Figure out the latest version of each module/scope type latestApiInfo struct { module, scope, path string - version int + version, release int isExtensionApiFile bool } getLatest := func(files []string, isExtensionApiFile bool) map[string]latestApiInfo { m := make(map[string]latestApiInfo) for _, f := range files { - module, version, scope := parseFinalizedPrebuiltPath(mctx, f) + module, version, release, scope := parseFinalizedPrebuiltPath(mctx, f, allowIncremental) if strings.HasSuffix(module, "incompatibilities") { continue } key := module + "." + scope info, exists := m[key] - if !exists || version > info.version { - m[key] = latestApiInfo{module, scope, f, version, isExtensionApiFile} + if !exists || version > info.version || (version == info.version && release > info.release) { + m[key] = latestApiInfo{module, scope, f, version, release, isExtensionApiFile} } } return m diff --git a/java/prebuilt_apis_test.go b/java/prebuilt_apis_test.go index 2b8435325..b6fb2c6bf 100644 --- a/java/prebuilt_apis_test.go +++ b/java/prebuilt_apis_test.go @@ -99,3 +99,26 @@ func TestPrebuiltApis_WithExtensions(t *testing.T) { android.AssertStringEquals(t, "Expected latest bar = extension level 2", "prebuilts/sdk/extensions/2/public/api/bar.txt", bar_input) android.AssertStringEquals(t, "Expected latest baz = api level 32", "prebuilts/sdk/32/public/api/baz.txt", baz_input) } + +func TestPrebuiltApis_WithIncrementalApi(t *testing.T) { + runTestWithIncrementalApi := func() (foo_input, bar_input, baz_input string) { + result := android.GroupFixturePreparers( + prepareForJavaTest, + FixtureWithPrebuiltIncrementalApis(map[string][]string{ + "33.0": {"foo"}, + "33.1": {"foo", "bar", "baz"}, + "33.2": {"foo", "bar"}, + "current": {"foo", "bar"}, + }), + ).RunTest(t) + foo_input = result.ModuleForTests("foo.api.public.latest", "").Rule("generator").Implicits[0].String() + bar_input = result.ModuleForTests("bar.api.public.latest", "").Rule("generator").Implicits[0].String() + baz_input = result.ModuleForTests("baz.api.public.latest", "").Rule("generator").Implicits[0].String() + return + } + // 33.1 is the latest for baz, 33.2 is the latest for both foo & bar + foo_input, bar_input, baz_input := runTestWithIncrementalApi() + android.AssertStringEquals(t, "Expected latest foo = api level 33.2", "prebuilts/sdk/33.2/public/api/foo.txt", foo_input) + android.AssertStringEquals(t, "Expected latest bar = api level 33.2", "prebuilts/sdk/33.2/public/api/bar.txt", bar_input) + android.AssertStringEquals(t, "Expected latest baz = api level 33.1", "prebuilts/sdk/33.1/public/api/baz.txt", baz_input) +} diff --git a/java/proto.go b/java/proto.go index c732d9842..2ed7b27e9 100644 --- a/java/proto.go +++ b/java/proto.go @@ -143,7 +143,14 @@ func protoFlags(ctx android.ModuleContext, j *CommonProperties, p *android.Proto } type protoAttributes struct { - Deps bazel.LabelListAttribute + Deps bazel.LabelListAttribute + + // A list of proto_library targets that the proto_library in `deps` depends on + // This list is overestimation. + // Overestimation is necessary since Soong includes other protos via proto.include_dirs and not + // a specific .proto file module explicitly. + Transitive_deps bazel.LabelListAttribute + Sdk_version bazel.StringAttribute Java_version bazel.StringAttribute } @@ -176,11 +183,11 @@ func bp2buildProto(ctx android.Bp2buildMutatorContext, m *Module, protoSrcs baze ctx.PropertyErrorf("proto.type", "cannot handle conversion at this time: %q", typ) } - protoLabel := bazel.Label{Label: ":" + m.Name() + "_proto"} protoAttrs := &protoAttributes{ - Deps: bazel.MakeSingleLabelListAttribute(protoLabel), - Java_version: bazel.StringAttribute{Value: m.properties.Java_version}, - Sdk_version: bazel.StringAttribute{Value: m.deviceProperties.Sdk_version}, + Deps: bazel.MakeLabelListAttribute(protoInfo.Proto_libs), + Transitive_deps: bazel.MakeLabelListAttribute(protoInfo.Transitive_proto_libs), + Java_version: bazel.StringAttribute{Value: m.properties.Java_version}, + Sdk_version: bazel.StringAttribute{Value: m.deviceProperties.Sdk_version}, } name := m.Name() + suffix diff --git a/java/sdk_library.go b/java/sdk_library.go index b1ddde093..27f862662 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -1633,7 +1633,7 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext }{} props.Name = proptools.StringPtr(module.sourceStubLibraryModuleName(apiScope)) - props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility) + props.Visibility = []string{"//visibility:override", "//visibility:private"} // sources are generated from the droiddoc props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope)} sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope) @@ -1829,7 +1829,7 @@ func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, }{} props.Name = proptools.StringPtr(module.apiLibraryModuleName(apiScope)) - props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility) + props.Visibility = []string{"//visibility:override", "//visibility:private"} apiContributions := []string{} @@ -2276,27 +2276,25 @@ func SdkLibraryFactory() android.Module { } type bazelSdkLibraryAttributes struct { - Public bazel.StringAttribute - System bazel.StringAttribute - Test bazel.StringAttribute - Module_lib bazel.StringAttribute - System_server bazel.StringAttribute + Public *bazel.Label + System *bazel.Label + Test *bazel.Label + Module_lib *bazel.Label + System_server *bazel.Label } // java_sdk_library bp2build converter -func (module *SdkLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (module *SdkLibrary) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { if ctx.ModuleType() != "java_sdk_library" { ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "") return } - nameToAttr := make(map[string]bazel.StringAttribute) + nameToAttr := make(map[string]*bazel.Label) for _, scope := range module.getGeneratedApiScopes(ctx) { - apiSurfaceFile := path.Join(module.getApiDir(), scope.apiFilePrefix+"current.txt") - var scopeStringAttribute bazel.StringAttribute - scopeStringAttribute.SetValue(apiSurfaceFile) - nameToAttr[scope.name] = scopeStringAttribute + apiSurfaceFile := android.BazelLabelForModuleSrcSingle(ctx, path.Join(module.getApiDir(), scope.apiFilePrefix+"current.txt")) + nameToAttr[scope.name] = &apiSurfaceFile } attrs := bazelSdkLibraryAttributes{ @@ -2355,6 +2353,7 @@ type sdkLibraryImportProperties struct { type SdkLibraryImport struct { android.ModuleBase android.DefaultableModuleBase + android.BazelModuleBase prebuilt android.Prebuilt android.ApexModuleBase @@ -2438,6 +2437,7 @@ func sdkLibraryImportFactory() android.Module { android.InitPrebuiltModule(module, &[]string{""}) android.InitApexModule(module) + android.InitBazelModule(module) InitJavaModule(module, android.HostAndDeviceSupported) module.SetDefaultableHook(func(mctx android.DefaultableHookContext) { @@ -2448,6 +2448,33 @@ func sdkLibraryImportFactory() android.Module { return module } +// java_sdk_library bp2build converter +func (i *SdkLibraryImport) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { + nameToAttr := make(map[string]*bazel.Label) + + for scope, props := range i.scopeProperties { + if api := proptools.String(props.Current_api); api != "" { + apiSurfaceFile := android.BazelLabelForModuleSrcSingle(ctx, api) + nameToAttr[scope.name] = &apiSurfaceFile + } + } + + attrs := bazelSdkLibraryAttributes{ + Public: nameToAttr["public"], + System: nameToAttr["system"], + Test: nameToAttr["test"], + Module_lib: nameToAttr["module-lib"], + System_server: nameToAttr["system-server"], + } + props := bazel.BazelTargetModuleProperties{ + Rule_class: "java_sdk_library", + Bzl_load_location: "//build/bazel/rules/java:sdk_library.bzl", + } + + name := android.RemoveOptionalPrebuiltPrefix(i.Name()) + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name}, &attrs) +} + var _ PermittedPackagesForUpdatableBootJars = (*SdkLibraryImport)(nil) func (module *SdkLibraryImport) PermittedPackagesForUpdatableBootJars() []string { @@ -2479,6 +2506,10 @@ func (module *SdkLibraryImport) createInternalModules(mctx android.DefaultableHo if len(scopeProperties.Stub_srcs) > 0 { module.createPrebuiltStubsSources(mctx, apiScope, scopeProperties) } + + if scopeProperties.Current_api != nil { + module.createPrebuiltApiContribution(mctx, apiScope, scopeProperties) + } } javaSdkLibraries := javaSdkLibraries(mctx.Config()) @@ -2534,6 +2565,25 @@ func (module *SdkLibraryImport) createPrebuiltStubsSources(mctx android.Defaulta mctx.CreateModule(PrebuiltStubsSourcesFactory, &props) } +func (module *SdkLibraryImport) createPrebuiltApiContribution(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) { + api_file := scopeProperties.Current_api + api_surface := &apiScope.name + + props := struct { + Name *string + Api_surface *string + Api_file *string + Visibility []string + }{} + + props.Name = proptools.StringPtr(module.stubsSourceModuleName(apiScope) + ".api.contribution") + props.Api_surface = api_surface + props.Api_file = api_file + props.Visibility = []string{"//visibility:override", "//visibility:public"} + + mctx.CreateModule(ApiContributionImportFactory, &props) +} + // Add the dependencies on the child module in the component deps mutator so that it // creates references to the prebuilt and not the source modules. func (module *SdkLibraryImport) ComponentDepsMutator(ctx android.BottomUpMutatorContext) { diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go index 118f8b68c..0b46919d2 100644 --- a/java/sdk_library_test.go +++ b/java/sdk_library_test.go @@ -74,6 +74,8 @@ func TestJavaSdkLibrary(t *testing.T) { name: "quuz", public: { jars: ["c.jar"], + current_api: "api/current.txt", + removed_api: "api/removed.txt", }, } java_sdk_library_import { @@ -173,6 +175,9 @@ func TestJavaSdkLibrary(t *testing.T) { android.AssertDeepEquals(t, "qux exports (optional)", []string{}, optionalSdkLibs) } + // test if quuz have created the api_contribution module + result.ModuleForTests(apiScopePublic.stubsSourceModuleName("quuz")+".api.contribution", "") + fooDexJar := result.ModuleForTests("foo", "android_common").Rule("d8") // tests if kotlinc generated files are NOT excluded from output of foo. android.AssertStringDoesNotContain(t, "foo dex", fooDexJar.BuildParams.Args["mergeZipsFlags"], "-stripFile META-INF/*.kotlin_module") @@ -1474,3 +1479,32 @@ func TestJavaSdkLibrary_ApiLibrary(t *testing.T) { android.AssertStringEquals(t, "Module expected to contain full api surface api library", c.fullApiSurfaceStub, *m.properties.Full_api_surface_stub) } } + +func TestStaticDepStubLibrariesVisibility(t *testing.T) { + android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("foo"), + android.FixtureMergeMockFs( + map[string][]byte{ + "A.java": nil, + "dir/Android.bp": []byte( + ` + java_library { + name: "bar", + srcs: ["A.java"], + libs: ["foo.stubs.from-source"], + } + `), + "dir/A.java": nil, + }, + ).ExtendWithErrorHandler( + android.FixtureExpectsAtLeastOneErrorMatchingPattern( + `module "bar" variant "android_common": depends on //.:foo.stubs.from-source which is not visible to this module`)), + ).RunTestWithBp(t, ` + java_sdk_library { + name: "foo", + srcs: ["A.java"], + } + `) +} diff --git a/java/testing.go b/java/testing.go index 3a238d76f..f2bcccfce 100644 --- a/java/testing.go +++ b/java/testing.go @@ -225,6 +225,29 @@ func FixtureWithPrebuiltApisAndExtensions(apiLevel2Modules map[string][]string, ) } +func FixtureWithPrebuiltIncrementalApis(apiLevel2Modules map[string][]string) android.FixturePreparer { + mockFS := android.MockFS{} + path := "prebuilts/sdk/Android.bp" + + bp := fmt.Sprintf(` + prebuilt_apis { + name: "sdk", + api_dirs: ["%s"], + allow_incremental_platform_api: true, + imports_sdk_version: "none", + imports_compile_dex: true, + } + `, strings.Join(android.SortedKeys(apiLevel2Modules), `", "`)) + + for release, modules := range apiLevel2Modules { + mockFS.Merge(prebuiltApisFilesForModules([]string{release}, modules)) + } + return android.GroupFixturePreparers( + android.FixtureAddTextFile(path, bp), + android.FixtureMergeMockFs(mockFS), + ) +} + func prebuiltApisFilesForModules(apiLevels []string, modules []string) map[string][]byte { libs := append([]string{"android"}, modules...) @@ -385,6 +408,8 @@ func gatherRequiredDepsForTest() string { "kotlin-stdlib-jdk8", "kotlin-annotations", "stub-annotations", + + "aconfig-annotations-lib", } for _, extra := range extraModules { diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go index 165697dfa..dad589256 100644 --- a/linkerconfig/linkerconfig.go +++ b/linkerconfig/linkerconfig.go @@ -107,7 +107,7 @@ type linkerConfigAttributes struct { Src bazel.LabelAttribute } -func (l *linkerConfig) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (l *linkerConfig) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { if l.properties.Src == nil { ctx.PropertyErrorf("src", "empty src is not supported") ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_UNSUPPORTED, "") diff --git a/provenance/provenance_singleton.go b/provenance/provenance_singleton.go index 5d27c0cf4..97345afc3 100644 --- a/provenance/provenance_singleton.go +++ b/provenance/provenance_singleton.go @@ -38,7 +38,9 @@ var ( Command: `rm -rf $out && ` + `echo "# proto-file: build/soong/provenance/proto/provenance_metadata.proto" > $out && ` + `echo "# proto-message: ProvenanceMetaDataList" >> $out && ` + - `for file in $in; do echo '' >> $out; echo 'metadata {' | cat - $$file | grep -Ev "^#.*|^$$" >> $out; echo '}' >> $out; done`, + `cat $out.rsp | tr ' ' '\n' | while read -r file || [ -n "$$file" ]; do echo '' >> $out; echo 'metadata {' | cat - $$file | grep -Ev "^#.*|^$$" >> $out; echo '}' >> $out; done`, + Rspfile: `$out.rsp`, + RspfileContent: `$in`, }) ) diff --git a/python/bp2build.go b/python/bp2build.go index 41e9f4974..3b283e432 100644 --- a/python/bp2build.go +++ b/python/bp2build.go @@ -33,6 +33,12 @@ type bazelPythonLibraryAttributes struct { type bazelPythonProtoLibraryAttributes struct { Deps bazel.LabelListAttribute + + // A list of proto_library targets that the proto_library in `deps` depends on + // This list is overestimation. + // Overestimation is necessary since Soong includes other protos via proto.include_dirs and not + // a specific .proto file module explicitly. + Transitive_deps bazel.LabelListAttribute } type baseAttributes struct { @@ -48,7 +54,7 @@ type baseAttributes struct { Imports bazel.StringListAttribute } -func (m *PythonLibraryModule) makeArchVariantBaseAttributes(ctx android.TopDownMutatorContext) baseAttributes { +func (m *PythonLibraryModule) makeArchVariantBaseAttributes(ctx android.Bp2buildMutatorContext) baseAttributes { var attrs baseAttributes archVariantBaseProps := m.GetArchVariantProperties(ctx, &BaseProperties{}) for axis, configToProps := range archVariantBaseProps { @@ -81,7 +87,8 @@ func (m *PythonLibraryModule) makeArchVariantBaseAttributes(ctx android.TopDownM }, android.CommonAttributes{ Name: pyProtoLibraryName, }, &bazelPythonProtoLibraryAttributes{ - Deps: bazel.MakeLabelListAttribute(protoInfo.Proto_libs), + Deps: bazel.MakeLabelListAttribute(protoInfo.Proto_libs), + Transitive_deps: bazel.MakeLabelListAttribute(protoInfo.Transitive_proto_libs), }) attrs.Deps.Add(bazel.MakeLabelAttribute(":" + pyProtoLibraryName)) @@ -116,7 +123,7 @@ func (m *PythonLibraryModule) makeArchVariantBaseAttributes(ctx android.TopDownM return attrs } -func (m *PythonLibraryModule) bp2buildPythonVersion(ctx android.TopDownMutatorContext) *string { +func (m *PythonLibraryModule) bp2buildPythonVersion(ctx android.Bp2buildMutatorContext) *string { py3Enabled := proptools.BoolDefault(m.properties.Version.Py3.Enabled, true) py2Enabled := proptools.BoolDefault(m.properties.Version.Py2.Enabled, false) if py2Enabled && !py3Enabled { @@ -139,7 +146,7 @@ type bazelPythonBinaryAttributes struct { Imports bazel.StringListAttribute } -func (p *PythonLibraryModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (p *PythonLibraryModule) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { // TODO(b/182306917): this doesn't fully handle all nested props versioned // by the python version, which would have been handled by the version split // mutator. This is sufficient for very simple python_library modules under @@ -169,7 +176,7 @@ func (p *PythonLibraryModule) ConvertWithBp2build(ctx android.TopDownMutatorCont }, attrs) } -func (p *PythonBinaryModule) bp2buildBinaryProperties(ctx android.TopDownMutatorContext) (*bazelPythonBinaryAttributes, bazel.LabelListAttribute) { +func (p *PythonBinaryModule) bp2buildBinaryProperties(ctx android.Bp2buildMutatorContext) (*bazelPythonBinaryAttributes, bazel.LabelListAttribute) { // TODO(b/182306917): this doesn't fully handle all nested props versioned // by the python version, which would have been handled by the version split // mutator. This is sufficient for very simple python_binary_host modules @@ -202,7 +209,7 @@ func (p *PythonBinaryModule) bp2buildBinaryProperties(ctx android.TopDownMutator return attrs, baseAttrs.Data } -func (p *PythonBinaryModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (p *PythonBinaryModule) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { attrs, data := p.bp2buildBinaryProperties(ctx) props := bazel.BazelTargetModuleProperties{ @@ -216,7 +223,7 @@ func (p *PythonBinaryModule) ConvertWithBp2build(ctx android.TopDownMutatorConte }, attrs) } -func (p *PythonTestModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (p *PythonTestModule) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { // Python tests are currently exactly the same as binaries, but with a different module type attrs, data := p.bp2buildBinaryProperties(ctx) diff --git a/python/python.go b/python/python.go index 6c837a888..7d77ca772 100644 --- a/python/python.go +++ b/python/python.go @@ -197,6 +197,14 @@ func (p *PythonLibraryModule) getPkgPath() string { return String(p.properties.Pkg_path) } +// PkgPath is the "public" version of `getPkgPath` that is only available during bp2build +func (p *PythonLibraryModule) PkgPath(ctx android.BazelConversionContext) *string { + if ctx.Config().BuildMode != android.Bp2build { + ctx.ModuleErrorf("PkgPath is only supported in bp2build mode") + } + return p.properties.Pkg_path +} + func (p *PythonLibraryModule) getBaseProperties() *BaseProperties { return &p.properties } diff --git a/python/tests/runtest.sh b/python/tests/runtest.sh index f4abae587..c44ec582a 100755 --- a/python/tests/runtest.sh +++ b/python/tests/runtest.sh @@ -24,11 +24,16 @@ if [ -z $ANDROID_HOST_OUT ]; then fi if [[ ( ! -f $ANDROID_HOST_OUT/nativetest64/par_test/par_test ) || - ( ! -f $ANDROID_HOST_OUT/bin/py2-cmd ) || ( ! -f $ANDROID_HOST_OUT/bin/py3-cmd )]]; then echo "Run 'm par_test py2-cmd py3-cmd' first" exit 1 fi +if [ $(uname -s) = Linux ]; then + if [[ ! -f $ANDROID_HOST_OUT/bin/py2-cmd ]]; then + echo "Run 'm par_test py2-cmd py3-cmd' first" + exit 1 + fi +fi export LD_LIBRARY_PATH=$ANDROID_HOST_OUT/lib64 @@ -42,11 +47,15 @@ ARGTEST=true $ANDROID_HOST_OUT/nativetest64/par_test/par_test --arg1 arg2 cd $(dirname ${BASH_SOURCE[0]}) -PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py +if [ $(uname -s) = Linux ]; then + PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py +fi PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py3-cmd py-cmd_test.py -ARGTEST=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py arg1 arg2 -ARGTEST2=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py --arg1 arg2 +if [ $(uname -s) = Linux ]; then + ARGTEST=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py arg1 arg2 + ARGTEST2=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py --arg1 arg2 +fi ARGTEST=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py3-cmd py-cmd_test.py arg1 arg2 ARGTEST2=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py3-cmd py-cmd_test.py --arg1 arg2 diff --git a/rust/afdo_test.go b/rust/afdo_test.go index 0cdf70491..80327af2a 100644 --- a/rust/afdo_test.go +++ b/rust/afdo_test.go @@ -54,8 +54,8 @@ func TestAfdoEnabled(t *testing.T) { expectedCFlag := fmt.Sprintf(afdoFlagFormat, "afdo_profiles_package/foo.afdo") - if !strings.Contains(foo.Args["rustcFlags"], expectedCFlag) { - t.Errorf("Expected 'foo' to enable afdo, but did not find %q in cflags %q", expectedCFlag, foo.Args["rustcFlags"]) + if !strings.Contains(foo.RuleParams.Command, expectedCFlag) { + t.Errorf("Expected 'foo' to enable afdo, but did not find %q in command %q", expectedCFlag, foo.RuleParams.Command) } } @@ -96,17 +96,17 @@ func TestAfdoEnabledWithMultiArchs(t *testing.T) { rustMockedFiles.AddToFixture(), ).RunTestWithBp(t, bp) - fooArm := result.ModuleForTests("foo", "android_arm_armv7-a-neon").Rule("rustc") - fooArm64 := result.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc") + fooArm := result.ModuleForTests("foo", "android_arm_armv7-a-neon").Description("rustc") + fooArm64 := result.ModuleForTests("foo", "android_arm64_armv8-a").Description("rustc") expectedCFlagArm := fmt.Sprintf(afdoFlagFormat, "afdo_profiles_package/foo_arm.afdo") expectedCFlagArm64 := fmt.Sprintf(afdoFlagFormat, "afdo_profiles_package/foo_arm64.afdo") - if !strings.Contains(fooArm.Args["rustcFlags"], expectedCFlagArm) { - t.Errorf("Expected 'fooArm' to enable afdo, but did not find %q in cflags %q", expectedCFlagArm, fooArm.Args["rustcFlags"]) + if !strings.Contains(fooArm.RuleParams.Command, expectedCFlagArm) { + t.Errorf("Expected 'fooArm' to enable afdo, but did not find %q in command %q", expectedCFlagArm, fooArm.RuleParams.Command) } - if !strings.Contains(fooArm64.Args["rustcFlags"], expectedCFlagArm64) { - t.Errorf("Expected 'fooArm64' to enable afdo, but did not find %q in cflags %q", expectedCFlagArm64, fooArm64.Args["rustcFlags"]) + if !strings.Contains(fooArm64.RuleParams.Command, expectedCFlagArm64) { + t.Errorf("Expected 'fooArm64' to enable afdo, but did not find %q in command %q", expectedCFlagArm64, fooArm.RuleParams.Command) } } diff --git a/rust/androidmk.go b/rust/androidmk.go index 5e680b03d..c684e810b 100644 --- a/rust/androidmk.go +++ b/rust/androidmk.go @@ -61,7 +61,7 @@ func (mod *Module) AndroidMkEntries() []android.AndroidMkEntries { entries.AddStrings("LOCAL_RLIB_LIBRARIES", mod.Properties.AndroidMkRlibs...) entries.AddStrings("LOCAL_DYLIB_LIBRARIES", mod.Properties.AndroidMkDylibs...) entries.AddStrings("LOCAL_PROC_MACRO_LIBRARIES", mod.Properties.AndroidMkProcMacroLibs...) - entries.AddStrings("LOCAL_SHARED_LIBRARIES", mod.Properties.AndroidMkSharedLibs...) + entries.AddStrings("LOCAL_SHARED_LIBRARIES", mod.transitiveAndroidMkSharedLibs.ToList()...) entries.AddStrings("LOCAL_STATIC_LIBRARIES", mod.Properties.AndroidMkStaticLibs...) entries.AddStrings("LOCAL_SOONG_LINK_TYPE", mod.makeLinkType) if mod.UseVndk() { diff --git a/rust/binary.go b/rust/binary.go index e6f153996..353381d78 100644 --- a/rust/binary.go +++ b/rust/binary.go @@ -15,7 +15,10 @@ package rust import ( + "fmt" + "android/soong/android" + "android/soong/bazel" ) func init() { @@ -60,6 +63,8 @@ func RustBinaryHostFactory() android.Module { func NewRustBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) { module := newModule(hod, android.MultilibFirst) + android.InitBazelModule(module) + binary := &binaryDecorator{ baseCompiler: NewBaseCompiler("bin", "", InstallInSystem), } @@ -133,13 +138,17 @@ func (binary *binaryDecorator) preferRlib() bool { func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput { fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix() - srcPath, _ := srcPathFromModuleSrcs(ctx, binary.baseCompiler.Properties.Srcs) outputFile := android.PathForModuleOut(ctx, fileName) ret := buildOutput{outputFile: outputFile} + var crateRootPath android.Path + if binary.baseCompiler.Properties.Crate_root == nil { + crateRootPath, _ = srcPathFromModuleSrcs(ctx, binary.baseCompiler.Properties.Srcs) + } else { + crateRootPath = android.PathForModuleSrc(ctx, *binary.baseCompiler.Properties.Crate_root) + } flags.RustFlags = append(flags.RustFlags, deps.depFlags...) flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...) - flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects.Strings()...) if binary.stripper.NeedsStrip(ctx) { strippedOutputFile := outputFile @@ -150,7 +159,7 @@ func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps Path } binary.baseCompiler.unstrippedOutputFile = outputFile - ret.kytheFile = TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile).kytheFile + ret.kytheFile = TransformSrcToBinary(ctx, binary, crateRootPath, deps, flags, outputFile).kytheFile return ret } @@ -183,3 +192,88 @@ func (binary *binaryDecorator) staticallyLinked() bool { func (binary *binaryDecorator) testBinary() bool { return false } + +type rustBinaryLibraryAttributes struct { + Srcs bazel.LabelListAttribute + Compile_data bazel.LabelListAttribute + Crate_name bazel.StringAttribute + Edition bazel.StringAttribute + Crate_features bazel.StringListAttribute + Deps bazel.LabelListAttribute + Proc_macro_deps bazel.LabelListAttribute + Rustc_flags bazel.StringListAttribute +} + +func binaryBp2build(ctx android.Bp2buildMutatorContext, m *Module) { + binary := m.compiler.(*binaryDecorator) + + var srcs bazel.LabelList + var compileData bazel.LabelList + + if binary.baseCompiler.Properties.Srcs[0] == "src/main.rs" { + srcs = android.BazelLabelForModuleSrc(ctx, []string{"src/**/*.rs"}) + compileData = android.BazelLabelForModuleSrc( + ctx, + []string{ + "src/**/*.proto", + "examples/**/*.rs", + "**/*.md", + "templates/**/*.template", + }, + ) + } else { + srcs = android.BazelLabelForModuleSrc(ctx, binary.baseCompiler.Properties.Srcs) + } + + deps := android.BazelLabelForModuleDeps(ctx, append( + binary.baseCompiler.Properties.Rustlibs, + )) + + procMacroDeps := android.BazelLabelForModuleDeps(ctx, binary.baseCompiler.Properties.Proc_macros) + + var rustcFLags []string + for _, cfg := range binary.baseCompiler.Properties.Cfgs { + rustcFLags = append(rustcFLags, fmt.Sprintf("--cfg=%s", cfg)) + } + + attrs := &rustBinaryLibraryAttributes{ + Srcs: bazel.MakeLabelListAttribute( + srcs, + ), + Compile_data: bazel.MakeLabelListAttribute( + compileData, + ), + Crate_name: bazel.StringAttribute{ + Value: &binary.baseCompiler.Properties.Crate_name, + }, + Edition: bazel.StringAttribute{ + Value: binary.baseCompiler.Properties.Edition, + }, + Crate_features: bazel.StringListAttribute{ + Value: binary.baseCompiler.Properties.Features, + }, + Deps: bazel.MakeLabelListAttribute( + deps, + ), + Proc_macro_deps: bazel.MakeLabelListAttribute( + procMacroDeps, + ), + Rustc_flags: bazel.StringListAttribute{ + Value: append( + rustcFLags, + binary.baseCompiler.Properties.Flags..., + ), + }, + } + + ctx.CreateBazelTargetModule( + bazel.BazelTargetModuleProperties{ + Rule_class: "rust_binary", + Bzl_load_location: "@rules_rust//rust:defs.bzl", + }, + android.CommonAttributes{ + Name: m.Name(), + }, + attrs, + ) +} diff --git a/rust/binary_test.go b/rust/binary_test.go index fc4c56037..ab1d2bc36 100644 --- a/rust/binary_test.go +++ b/rust/binary_test.go @@ -135,7 +135,7 @@ func TestBinaryFlags(t *testing.T) { fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustc") - flags := fizzBuzz.Args["rustcFlags"] + flags := fizzBuzz.RuleParams.Command if strings.Contains(flags, "--test") { t.Errorf("extra --test flag, rustcFlags: %#v", flags) } @@ -150,11 +150,11 @@ func TestBootstrap(t *testing.T) { bootstrap: true, }`) - foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustLink") + foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc") flag := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker64" - if !strings.Contains(foo.Args["linkFlags"], flag) { - t.Errorf("missing link flag to use bootstrap linker, expecting %#v, linkFlags: %#v", flag, foo.Args["linkFlags"]) + if !strings.Contains(foo.RuleParams.Command, flag) { + t.Errorf("missing link flag to use bootstrap linker, expecting %#v, command: %#v", flag, foo.RuleParams.Command) } } @@ -167,25 +167,23 @@ func TestStaticBinaryFlags(t *testing.T) { }`) fizzOut := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc") - fizzOutLink := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustLink") fizzMod := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module) - flags := fizzOut.Args["rustcFlags"] - linkFlags := fizzOutLink.Args["linkFlags"] + flags := fizzOut.RuleParams.Command if !strings.Contains(flags, "-C relocation-model=static") { - t.Errorf("static binary missing '-C relocation-model=static' in rustcFlags, found: %#v", flags) + t.Errorf("static binary missing '-C relocation-model=static' in command, found: %#v", flags) } if !strings.Contains(flags, "-C panic=abort") { - t.Errorf("static binary missing '-C panic=abort' in rustcFlags, found: %#v", flags) + t.Errorf("static binary missing '-C panic=abort' in command, found: %#v", flags) } - if !strings.Contains(linkFlags, "-static") { - t.Errorf("static binary missing '-static' in linkFlags, found: %#v", flags) + if !strings.Contains(flags, "-static") { + t.Errorf("static binary missing '-static' in command, found: %#v", flags) } if !android.InList("libc", fizzMod.Properties.AndroidMkStaticLibs) { t.Errorf("static binary not linking against libc as a static library") } - if len(fizzMod.Properties.AndroidMkSharedLibs) > 0 { + if len(fizzMod.transitiveAndroidMkSharedLibs.ToList()) > 0 { t.Errorf("static binary incorrectly linking against shared libraries") } } @@ -201,10 +199,9 @@ func TestLinkObjects(t *testing.T) { name: "libfoo", }`) - fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Rule("rustLink") - linkFlags := fizzBuzz.Args["linkFlags"] - if !strings.Contains(linkFlags, "/libfoo.so") { - t.Errorf("missing shared dependency 'libfoo.so' in linkFlags: %#v", linkFlags) + fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Rule("rustc") + if !strings.Contains(fizzBuzz.RuleParams.Command, "/libfoo.so") { + t.Errorf("missing shared dependency 'libfoo.so' in command: %#v", fizzBuzz.RuleParams.Command) } } diff --git a/rust/bindgen.go b/rust/bindgen.go index 407f2754f..a80a587f1 100644 --- a/rust/bindgen.go +++ b/rust/bindgen.go @@ -29,7 +29,7 @@ var ( defaultBindgenFlags = []string{""} // bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures. - bindgenClangVersion = "clang-r498229" + bindgenClangVersion = "clang-r498229b" _ = pctx.VariableFunc("bindgenClangVersion", func(ctx android.PackageVarContext) string { if override := ctx.Config().Getenv("LLVM_BINDGEN_PREBUILTS_VERSION"); override != "" { diff --git a/rust/builder.go b/rust/builder.go index b1f049d15..07405183e 100644 --- a/rust/builder.go +++ b/rust/builder.go @@ -15,6 +15,7 @@ package rust import ( + "fmt" "path/filepath" "strings" @@ -25,54 +26,6 @@ import ( ) var ( - _ = pctx.SourcePathVariable("rustcCmd", "${config.RustBin}/rustc") - _ = pctx.SourcePathVariable("mkcraterspCmd", "build/soong/scripts/mkcratersp.py") - rustc = pctx.AndroidStaticRule("rustc", - blueprint.RuleParams{ - Command: "$envVars $rustcCmd " + - "-C linker=$mkcraterspCmd " + - "--emit link -o $out --emit dep-info=$out.d.raw $in ${libFlags} $rustcFlags" + - " && grep \"^$out:\" $out.d.raw > $out.d", - CommandDeps: []string{"$rustcCmd", "$mkcraterspCmd"}, - // Rustc deps-info writes out make compatible dep files: https://github.com/rust-lang/rust/issues/7633 - // Rustc emits unneeded dependency lines for the .d and input .rs files. - // Those extra lines cause ninja warning: - // "warning: depfile has multiple output paths" - // For ninja, we keep/grep only the dependency rule for the rust $out file. - Deps: blueprint.DepsGCC, - Depfile: "$out.d", - }, - "rustcFlags", "libFlags", "envVars") - rustLink = pctx.AndroidStaticRule("rustLink", - blueprint.RuleParams{ - Command: "${config.RustLinker} -o $out ${crtBegin} ${earlyLinkFlags} @$in ${linkFlags} ${crtEnd}", - }, - "earlyLinkFlags", "linkFlags", "crtBegin", "crtEnd") - - _ = pctx.SourcePathVariable("rustdocCmd", "${config.RustBin}/rustdoc") - rustdoc = pctx.AndroidStaticRule("rustdoc", - blueprint.RuleParams{ - Command: "$envVars $rustdocCmd $rustdocFlags $in -o $outDir && " + - "touch $out", - CommandDeps: []string{"$rustdocCmd"}, - }, - "rustdocFlags", "outDir", "envVars") - - _ = pctx.SourcePathVariable("clippyCmd", "${config.RustBin}/clippy-driver") - clippyDriver = pctx.AndroidStaticRule("clippy", - blueprint.RuleParams{ - Command: "$envVars $clippyCmd " + - // Because clippy-driver uses rustc as backend, we need to have some output even during the linting. - // Use the metadata output as it has the smallest footprint. - "--emit metadata -o $out --emit dep-info=$out.d.raw $in ${libFlags} " + - "$rustcFlags $clippyFlags" + - " && grep \"^$out:\" $out.d.raw > $out.d", - CommandDeps: []string{"$clippyCmd"}, - Deps: blueprint.DepsGCC, - Depfile: "$out.d", - }, - "rustcFlags", "libFlags", "clippyFlags", "envVars") - zip = pctx.AndroidStaticRule("zip", blueprint.RuleParams{ Command: "cat $out.rsp | tr ' ' '\\n' | tr -d \\' | sort -u > ${out}.tmp && ${SoongZipCmd} -o ${out} -C $$OUT_DIR -l ${out}.tmp", @@ -81,7 +34,7 @@ var ( RspfileContent: "$in", }) - cp = pctx.AndroidStaticRule("cp", + cpDir = pctx.AndroidStaticRule("cpDir", blueprint.RuleParams{ Command: "cp `cat $outDir.rsp` $outDir", Rspfile: "${outDir}.rsp", @@ -89,6 +42,12 @@ var ( }, "outDir") + cp = pctx.AndroidStaticRule("cp", + blueprint.RuleParams{ + Command: "rm -f $out && cp $in $out", + Description: "cp $out", + }) + // Cross-referencing: _ = pctx.SourcePathVariable("rustExtractor", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/rust_extractor") @@ -96,23 +55,6 @@ var ( func(ctx android.PackageVarContext) string { return ctx.Config().XrefCorpusName() }) _ = pctx.VariableFunc("kytheCuEncoding", func(ctx android.PackageVarContext) string { return ctx.Config().XrefCuEncoding() }) - _ = pctx.SourcePathVariable("kytheVnames", "build/soong/vnames.json") - kytheExtract = pctx.AndroidStaticRule("kythe", - blueprint.RuleParams{ - Command: `KYTHE_CORPUS=${kytheCorpus} ` + - `KYTHE_OUTPUT_FILE=$out ` + - `KYTHE_VNAMES=$kytheVnames ` + - `KYTHE_KZIP_ENCODING=${kytheCuEncoding} ` + - `KYTHE_CANONICALIZE_VNAME_PATHS=prefer-relative ` + - `$rustExtractor $envVars ` + - `$rustcCmd ` + - `-C linker=true ` + - `$in ${libFlags} $rustcFlags`, - CommandDeps: []string{"$rustExtractor", "$kytheVnames"}, - Rspfile: "${out}.rsp", - RspfileContent: "$in", - }, - "rustcFlags", "libFlags", "envVars") ) type buildOutput struct { @@ -124,40 +66,40 @@ func init() { pctx.HostBinToolVariable("SoongZipCmd", "soong_zip") } -func TransformSrcToBinary(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, +func TransformSrcToBinary(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath) buildOutput { flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin") - return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "bin") + return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "bin") } -func TransformSrctoRlib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, +func TransformSrctoRlib(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath) buildOutput { - return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "rlib") + return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "rlib") } -func TransformSrctoDylib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, +func TransformSrctoDylib(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath) buildOutput { flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin") - return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "dylib") + return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "dylib") } -func TransformSrctoStatic(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, +func TransformSrctoStatic(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath) buildOutput { flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin") - return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "staticlib") + return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "staticlib") } -func TransformSrctoShared(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, +func TransformSrctoShared(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath) buildOutput { flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin") - return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "cdylib") + return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "cdylib") } -func TransformSrctoProcMacro(ctx ModuleContext, mainSrc android.Path, deps PathDeps, +func TransformSrctoProcMacro(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath) buildOutput { - return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "proc-macro") + return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "proc-macro") } func rustLibsToPaths(libs RustLibraries) android.Paths { @@ -168,28 +110,46 @@ func rustLibsToPaths(libs RustLibraries) android.Paths { return paths } -func makeLibFlags(deps PathDeps) []string { +func makeLibFlags(deps PathDeps, ruleCmd *android.RuleBuilderCommand) []string { var libFlags []string // Collect library/crate flags - for _, lib := range deps.RLibs { - libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String()) + for _, lib := range deps.Rlibs.ToListDirect() { + libPath := ruleCmd.PathForInput(lib.Path) + libFlags = append(libFlags, "--extern "+lib.CrateName+"="+libPath) } - for _, lib := range deps.DyLibs { - libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String()) + for _, lib := range deps.Dylibs.ToListDirect() { + libPath := ruleCmd.PathForInput(lib.Path) + libFlags = append(libFlags, "--extern "+lib.CrateName+"="+libPath) } - for _, proc_macro := range deps.ProcMacros { - libFlags = append(libFlags, "--extern "+proc_macro.CrateName+"="+proc_macro.Path.String()) + for _, procMacro := range deps.ProcMacros.ToListDirect() { + procMacroPath := ruleCmd.PathForInput(procMacro.Path) + libFlags = append(libFlags, "--extern "+procMacro.CrateName+"="+procMacroPath) } for _, path := range deps.linkDirs { - libFlags = append(libFlags, "-L "+path) + libFlags = append(libFlags, "-L "+ruleCmd.PathForInput(path)) } return libFlags } -func rustEnvVars(ctx ModuleContext, deps PathDeps) []string { +func collectImplicits(deps PathDeps) android.Paths { + depPaths := android.Paths{} + depPaths = append(depPaths, rustLibsToPaths(deps.Rlibs.ToList())...) + depPaths = append(depPaths, rustLibsToPaths(deps.Dylibs.ToList())...) + depPaths = append(depPaths, rustLibsToPaths(deps.ProcMacros.ToList())...) + depPaths = append(depPaths, deps.AfdoProfiles...) + depPaths = append(depPaths, deps.WholeStaticLibs...) + depPaths = append(depPaths, deps.SrcDeps...) + depPaths = append(depPaths, deps.srcProviderFiles...) + depPaths = append(depPaths, deps.LibDeps...) + depPaths = append(depPaths, deps.linkObjects...) + depPaths = append(depPaths, deps.BuildToolSrcDeps...) + return depPaths +} + +func rustEnvVars(ctx ModuleContext, deps PathDeps, cmd *android.RuleBuilderCommand) []string { var envVars []string // libstd requires a specific environment variable to be set. This is @@ -203,15 +163,17 @@ func rustEnvVars(ctx ModuleContext, deps PathDeps) []string { moduleGenDir := ctx.RustModule().compiler.CargoOutDir() // We must calculate an absolute path for OUT_DIR since Rust's include! macro (which normally consumes this) // assumes that paths are relative to the source file. - var outDirPrefix string - if !filepath.IsAbs(moduleGenDir.String()) { + var outDir string + if filepath.IsAbs(moduleGenDir.String()) { + // If OUT_DIR is absolute, then moduleGenDir will be an absolute path, so we don't need to set this to anything. + outDir = moduleGenDir.String() + } else if moduleGenDir.Valid() { // If OUT_DIR is not absolute, we use $$PWD to generate an absolute path (os.Getwd() returns '/') - outDirPrefix = "$$PWD/" + outDir = filepath.Join("$$PWD/", cmd.PathForInput(moduleGenDir.Path())) } else { - // If OUT_DIR is absolute, then moduleGenDir will be an absolute path, so we don't need to set this to anything. - outDirPrefix = "" + outDir = "$$PWD/" } - envVars = append(envVars, "OUT_DIR="+filepath.Join(outDirPrefix, moduleGenDir.String())) + envVars = append(envVars, "OUT_DIR="+outDir) } else { // TODO(pcc): Change this to "OUT_DIR=" after fixing crates to not rely on this value. envVars = append(envVars, "OUT_DIR=out") @@ -242,7 +204,7 @@ func rustEnvVars(ctx ModuleContext, deps PathDeps) []string { } } - envVars = append(envVars, "AR=${cc_config.ClangBin}/llvm-ar") + envVars = append(envVars, "AR="+cmd.PathForTool(deps.Llvm_ar)) if ctx.Darwin() { envVars = append(envVars, "ANDROID_RUST_DARWIN=true") @@ -251,21 +213,18 @@ func rustEnvVars(ctx ModuleContext, deps PathDeps) []string { return envVars } -func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, flags Flags, +func transformSrctoCrate(ctx ModuleContext, comp compiler, main android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, crateType string) buildOutput { var inputs android.Paths - var implicits, linkImplicits, linkOrderOnly android.Paths var output buildOutput var rustcFlags, linkFlags []string - var earlyLinkFlags string + var earlyLinkFlags []string output.outputFile = outputFile crateName := ctx.RustModule().CrateName() targetTriple := ctx.toolchain().RustTriple() - envVars := rustEnvVars(ctx, deps) - inputs = append(inputs, main) // Collect rustc flags @@ -286,7 +245,6 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl // Enable incremental compilation if requested by user if ctx.Config().IsEnvTrue("SOONG_RUSTC_INCREMENTAL") { incrementalPath := android.PathForOutput(ctx, "rustc").String() - rustcFlags = append(rustcFlags, "-Cincremental="+incrementalPath) } @@ -298,36 +256,16 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl // Collect linker flags if !ctx.Darwin() { - earlyLinkFlags = "-Wl,--as-needed" - } - - linkFlags = append(linkFlags, flags.GlobalLinkFlags...) - linkFlags = append(linkFlags, flags.LinkFlags...) - - // Check if this module needs to use the bootstrap linker - if ctx.RustModule().Bootstrap() && !ctx.RustModule().InRecovery() && !ctx.RustModule().InRamdisk() && !ctx.RustModule().InVendorRamdisk() { - dynamicLinker := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker" - if ctx.toolchain().Is64Bit() { - dynamicLinker += "64" - } - linkFlags = append(linkFlags, dynamicLinker) + earlyLinkFlags = append(earlyLinkFlags, "-Wl,--as-needed") } - libFlags := makeLibFlags(deps) - // Collect dependencies - implicits = append(implicits, rustLibsToPaths(deps.RLibs)...) - implicits = append(implicits, rustLibsToPaths(deps.DyLibs)...) - implicits = append(implicits, rustLibsToPaths(deps.ProcMacros)...) - implicits = append(implicits, deps.AfdoProfiles...) - implicits = append(implicits, deps.srcProviderFiles...) - implicits = append(implicits, deps.WholeStaticLibs...) - - linkImplicits = append(linkImplicits, deps.LibDeps...) + var linkImplicits android.Paths + implicits := collectImplicits(deps) + toolImplicits := android.Concat(deps.BuildToolDeps) linkImplicits = append(linkImplicits, deps.CrtBegin...) linkImplicits = append(linkImplicits, deps.CrtEnd...) - - linkOrderOnly = append(linkOrderOnly, deps.linkObjects...) + implicits = append(implicits, comp.compilationSourcesAndData(ctx)...) if len(deps.SrcDeps) > 0 { moduleGenDir := ctx.RustModule().compiler.CargoOutDir() @@ -342,7 +280,7 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl } ctx.Build(pctx, android.BuildParams{ - Rule: cp, + Rule: cpDir, Description: "cp " + moduleGenDir.Path().Rel(), Outputs: outputs, Inputs: deps.SrcDeps, @@ -354,81 +292,176 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl } if flags.Clippy { + // TODO(b/298461712) remove this hack to let slim manifest branches build + if deps.Clippy_driver == nil { + deps.Clippy_driver = config.RustPath(ctx, "bin/clippy-driver") + } + + clippyRule := getRuleBuilder(ctx, pctx, false, "clippy") + clippyCmd := clippyRule.Command() clippyFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy") - ctx.Build(pctx, android.BuildParams{ - Rule: clippyDriver, - Description: "clippy " + main.Rel(), - Output: clippyFile, - Inputs: inputs, - Implicits: implicits, - Args: map[string]string{ - "rustcFlags": strings.Join(rustcFlags, " "), - "libFlags": strings.Join(libFlags, " "), - "clippyFlags": strings.Join(flags.ClippyFlags, " "), - "envVars": strings.Join(envVars, " "), - }, - }) + clippyDepInfoFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy.d.raw") + clippyDepFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy.d") + + clippyCmd. + Flags(rustEnvVars(ctx, deps, clippyCmd)). + Tool(deps.Clippy_driver). + Flag("--emit metadata"). + FlagWithOutput("-o ", clippyFile). + FlagWithOutput("--emit dep-info=", clippyDepInfoFile). + Inputs(inputs). + Flags(makeLibFlags(deps, clippyCmd)). + Flags(rustcFlags). + Flags(flags.ClippyFlags). + ImplicitTools(toolImplicits). + Implicits(implicits) + + depfileCreationCmd := clippyRule.Command() + depfileCreationCmd. + Flag(fmt.Sprintf( + `grep "^%s:" %s >`, + depfileCreationCmd.PathForOutput(clippyFile), + depfileCreationCmd.PathForOutput(clippyDepInfoFile), + )). + DepFile(clippyDepFile) + + clippyRule.BuildWithUnescapedNinjaVars("clippy", "clippy "+main.Rel()) + // Declare the clippy build as an implicit dependency of the original crate. implicits = append(implicits, clippyFile) } - rustcOutputFile := outputFile + sboxDirectory := "rustc" + rustSboxOutputFile := android.PathForModuleOut(ctx, sboxDirectory, outputFile.Base()) + depFile := android.PathForModuleOut(ctx, sboxDirectory, rustSboxOutputFile.Base()+".d") + depInfoFile := android.PathForModuleOut(ctx, sboxDirectory, rustSboxOutputFile.Base()+".d.raw") + var rustcImplicitOutputs android.WritablePaths + + sandboxedCompilation := comp.crateRoot(ctx) != nil + rustcRule := getRuleBuilder(ctx, pctx, sandboxedCompilation, sboxDirectory) + rustcCmd := rustcRule.Command() + + linkFlags = append(linkFlags, flags.GlobalLinkFlags...) + linkFlags = append(linkFlags, flags.LinkFlags...) + linkFlags = append(linkFlags, rustcCmd.PathsForInputs(deps.linkObjects)...) + + // Check if this module needs to use the bootstrap linker + if ctx.RustModule().Bootstrap() && !ctx.RustModule().InRecovery() && !ctx.RustModule().InRamdisk() && !ctx.RustModule().InVendorRamdisk() { + dynamicLinker := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker" + if ctx.toolchain().Is64Bit() { + dynamicLinker += "64" + } + linkFlags = append(linkFlags, dynamicLinker) + } + + libFlags := makeLibFlags(deps, rustcCmd) + usesLinker := crateType == "bin" || crateType == "dylib" || crateType == "cdylib" || crateType == "proc-macro" if usesLinker { - rustcOutputFile = android.PathForModuleOut(ctx, outputFile.Base()+".rsp") + rustSboxOutputFile = android.PathForModuleOut(ctx, sboxDirectory, rustSboxOutputFile.Base()+".rsp") + rustcImplicitOutputs = android.WritablePaths{ + android.PathForModuleOut(ctx, sboxDirectory, rustSboxOutputFile.Base()+".whole.a"), + android.PathForModuleOut(ctx, sboxDirectory, rustSboxOutputFile.Base()+".a"), + } } - ctx.Build(pctx, android.BuildParams{ - Rule: rustc, - Description: "rustc " + main.Rel(), - Output: rustcOutputFile, - Inputs: inputs, - Implicits: implicits, - Args: map[string]string{ - "rustcFlags": strings.Join(rustcFlags, " "), - "libFlags": strings.Join(libFlags, " "), - "envVars": strings.Join(envVars, " "), - }, - }) + // TODO(b/298461712) remove this hack to let slim manifest branches build + if deps.Rustc == nil { + deps.Rustc = config.RustPath(ctx, "bin/rustc") + } - if usesLinker { + rustcCmd. + Flags(rustEnvVars(ctx, deps, rustcCmd)). + Tool(deps.Rustc). + FlagWithInput("-C linker=", android.PathForSource(ctx, "build", "soong", "scripts", "mkcratersp.py")). + Flag("--emit link"). + Flag("-o"). + Output(rustSboxOutputFile). + FlagWithOutput("--emit dep-info=", depInfoFile). + Inputs(inputs). + Flags(libFlags). + ImplicitTools(toolImplicits). + Implicits(implicits). + Flags(rustcFlags). + ImplicitOutputs(rustcImplicitOutputs) + + depfileCreationCmd := rustcRule.Command() + depfileCreationCmd. + Flag(fmt.Sprintf( + `grep "^%s:" %s >`, + depfileCreationCmd.PathForOutput(rustSboxOutputFile), + depfileCreationCmd.PathForOutput(depInfoFile), + )). + DepFile(depFile) + + if !usesLinker { ctx.Build(pctx, android.BuildParams{ - Rule: rustLink, - Description: "rustLink " + main.Rel(), - Output: outputFile, - Inputs: android.Paths{rustcOutputFile}, - Implicits: linkImplicits, - OrderOnly: linkOrderOnly, - Args: map[string]string{ - "earlyLinkFlags": earlyLinkFlags, - "linkFlags": strings.Join(linkFlags, " "), - "crtBegin": strings.Join(deps.CrtBegin.Strings(), " "), - "crtEnd": strings.Join(deps.CrtEnd.Strings(), " "), - }, + Rule: cp, + Input: rustSboxOutputFile, + Output: outputFile, + }) + } else { + // TODO: delmerico - separate rustLink into its own rule + // mkcratersp.py hardcodes paths to files within the sandbox, so + // those need to be renamed/symlinked to something in the rustLink sandbox + // if we want to separate the rules + linkerSboxOutputFile := android.PathForModuleOut(ctx, sboxDirectory, outputFile.Base()) + rustLinkCmd := rustcRule.Command() + rustLinkCmd. + Tool(deps.Clang). + Flag("-o"). + Output(linkerSboxOutputFile). + Inputs(deps.CrtBegin). + Flags(earlyLinkFlags). + FlagWithInput("@", rustSboxOutputFile). + Flags(linkFlags). + Inputs(deps.CrtEnd). + ImplicitTools(toolImplicits). + Implicits(rustcImplicitOutputs.Paths()). + Implicits(implicits). + Implicits(linkImplicits) + ctx.Build(pctx, android.BuildParams{ + Rule: cp, + Input: linkerSboxOutputFile, + Output: outputFile, }) } + rustcRule.BuildWithUnescapedNinjaVars("rustc", "rustc "+main.Rel()) + if flags.EmitXrefs { + kytheRule := getRuleBuilder(ctx, pctx, false, "kythe") + kytheCmd := kytheRule.Command() kytheFile := android.PathForModuleOut(ctx, outputFile.Base()+".kzip") - ctx.Build(pctx, android.BuildParams{ - Rule: kytheExtract, - Description: "Xref Rust extractor " + main.Rel(), - Output: kytheFile, - Inputs: inputs, - Implicits: implicits, - Args: map[string]string{ - "rustcFlags": strings.Join(rustcFlags, " "), - "libFlags": strings.Join(libFlags, " "), - "envVars": strings.Join(envVars, " "), - }, - }) + kytheCmd. + Flag("KYTHE_CORPUS=${kytheCorpus}"). + FlagWithOutput("KYTHE_OUTPUT_FILE=", kytheFile). + FlagWithInput("KYTHE_VNAMES=", android.PathForSource(ctx, "build", "soong", "vnames.json")). + Flag("KYTHE_KZIP_ENCODING=${kytheCuEncoding}"). + Flag("KYTHE_CANONICALIZE_VNAME_PATHS=prefer-relative"). + Tool(ctx.Config().PrebuiltBuildTool(ctx, "rust_extractor")). + Flags(rustEnvVars(ctx, deps, kytheCmd)). + Tool(deps.Rustc). + Flag("-C linker=true"). + Inputs(inputs). + Flags(makeLibFlags(deps, kytheCmd)). + Flags(rustcFlags). + ImplicitTools(toolImplicits). + Implicits(implicits) + kytheRule.BuildWithUnescapedNinjaVars("kythe", "Xref Rust extractor "+main.Rel()) output.kytheFile = kytheFile } return output } -func Rustdoc(ctx ModuleContext, main android.Path, deps PathDeps, - flags Flags) android.ModuleOutPath { +func Rustdoc(ctx ModuleContext, main android.Path, deps PathDeps, flags Flags) android.ModuleOutPath { + // TODO(b/298461712) remove this hack to let slim manifest branches build + if deps.Rustdoc == nil { + deps.Rustdoc = config.RustPath(ctx, "bin/rustdoc") + } + + rustdocRule := getRuleBuilder(ctx, pctx, false, "rustdoc") + rustdocCmd := rustdocRule.Command() rustdocFlags := append([]string{}, flags.RustdocFlags...) rustdocFlags = append(rustdocFlags, "--sysroot=/dev/null") @@ -447,7 +480,7 @@ func Rustdoc(ctx ModuleContext, main android.Path, deps PathDeps, crateName := ctx.RustModule().CrateName() rustdocFlags = append(rustdocFlags, "--crate-name "+crateName) - rustdocFlags = append(rustdocFlags, makeLibFlags(deps)...) + rustdocFlags = append(rustdocFlags, makeLibFlags(deps, rustdocCmd)...) docTimestampFile := android.PathForModuleOut(ctx, "rustdoc.timestamp") // Silence warnings about renamed lints for third-party crates @@ -463,18 +496,26 @@ func Rustdoc(ctx ModuleContext, main android.Path, deps PathDeps, // https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/render/write_shared.rs#L144-L146 docDir := android.PathForOutput(ctx, "rustdoc") - ctx.Build(pctx, android.BuildParams{ - Rule: rustdoc, - Description: "rustdoc " + main.Rel(), - Output: docTimestampFile, - Input: main, - Implicit: ctx.RustModule().UnstrippedOutputFile(), - Args: map[string]string{ - "rustdocFlags": strings.Join(rustdocFlags, " "), - "outDir": docDir.String(), - "envVars": strings.Join(rustEnvVars(ctx, deps), " "), - }, - }) + rustdocCmd. + Flags(rustEnvVars(ctx, deps, rustdocCmd)). + Tool(deps.Rustdoc). + Flags(rustdocFlags). + Input(main). + Flag("-o "+docDir.String()). + FlagWithOutput("&& touch ", docTimestampFile). + Implicit(ctx.RustModule().UnstrippedOutputFile()) + rustdocRule.BuildWithUnescapedNinjaVars("rustdoc", "rustdoc "+main.Rel()) return docTimestampFile } + +func getRuleBuilder(ctx android.ModuleContext, pctx android.PackageContext, sbox bool, sboxDirectory string) *android.RuleBuilder { + r := android.NewRuleBuilder(pctx, ctx) + if sbox { + r = r.Sbox( + android.PathForModuleOut(ctx, sboxDirectory), + android.PathForModuleOut(ctx, sboxDirectory+".sbox.textproto"), + ).SandboxInputs() + } + return r +} diff --git a/rust/clippy_test.go b/rust/clippy_test.go index bd3bfb151..2703a1c6a 100644 --- a/rust/clippy_test.go +++ b/rust/clippy_test.go @@ -63,14 +63,14 @@ func TestClippy(t *testing.T) { ).RunTest(t) r := result.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("clippy") - android.AssertStringEquals(t, "libfoo flags", tc.fooFlags, r.Args["clippyFlags"]) + android.AssertStringDoesContain(t, "libfoo flags", r.RuleParams.Command, tc.fooFlags) r = result.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeRule("clippy") - android.AssertStringEquals(t, "libbar flags", "${config.ClippyDefaultLints}", r.Args["clippyFlags"]) + android.AssertStringDoesContain(t, "libbar flags", r.RuleParams.Command, "${config.ClippyDefaultLints}") r = result.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("clippy") if r.Rule != nil { - t.Errorf("libfoobar is setup to use clippy when explicitly disabled: clippyFlags=%q", r.Args["clippyFlags"]) + t.Errorf("libfoobar is setup to use clippy when explicitly disabled: command=%q", r.RuleParams.Command) } }) } diff --git a/rust/compiler.go b/rust/compiler.go index e6a7a9356..3fa3ccd69 100644 --- a/rust/compiler.go +++ b/rust/compiler.go @@ -73,6 +73,18 @@ type BaseCompilerProperties struct { // If no source file is defined, a single generated source module can be defined to be used as the main source. Srcs []string `android:"path,arch_variant"` + // Entry point that is passed to rustc to begin the compilation. E.g. main.rs or lib.rs. + // When this property is set, + // * sandboxing is enabled for this module, and + // * the srcs attribute is interpreted as a list of all source files potentially + // used in compilation, including the entrypoint, and + // * compile_data can be used to add additional files used in compilation that + // not directly used as source files. + Crate_root *string `android:"path,arch_variant"` + + // Additional data files that are used during compilation only. These are not accessible at runtime. + Compile_data []string `android:"path,arch_variant"` + // name of the lint set that should be used to validate this module. // // Possible values are "default" (for using a sensible set of lints @@ -334,6 +346,23 @@ func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathD panic(fmt.Errorf("baseCrater doesn't know how to crate things!")) } +func (compile *baseCompiler) crateRoot(ctx ModuleContext) android.Path { + if compile.Properties.Crate_root != nil { + return android.PathForModuleSrc(ctx, *compile.Properties.Crate_root) + } + return nil +} + +// compilationSourcesAndData returns a list of files necessary to complete the compilation. +// This includes the rust source files as well as any other data files that +// are referenced during the build. +func (compile *baseCompiler) compilationSourcesAndData(ctx ModuleContext) android.Paths { + return android.PathsForModuleSrc(ctx, android.Concat( + compile.Properties.Srcs, + compile.Properties.Compile_data, + )) +} + func (compiler *baseCompiler) rustdoc(ctx ModuleContext, flags Flags, deps PathDeps) android.OptionalPath { @@ -511,6 +540,8 @@ func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) (android.Path, andr ctx.PropertyErrorf("srcs", "only a single generated source module can be defined without a main source file.") } + // TODO: b/297264540 - once all modules are sandboxed, we need to select the proper + // entry point file from Srcs rather than taking the first one paths := android.PathsForModuleSrc(ctx, srcs) return paths[srcIndex], paths[1:] } diff --git a/rust/compiler_test.go b/rust/compiler_test.go index ec6829a1b..e5cc8884e 100644 --- a/rust/compiler_test.go +++ b/rust/compiler_test.go @@ -36,9 +36,9 @@ func TestFeaturesToFlags(t *testing.T) { libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") - if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"fizz\"'") || - !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"buzz\"'") { - t.Fatalf("missing fizz and buzz feature flags for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"]) + if !strings.Contains(libfooDylib.RuleParams.Command, "cfg 'feature=\"fizz\"'") || + !strings.Contains(libfooDylib.RuleParams.Command, "cfg 'feature=\"buzz\"'") { + t.Fatalf("missing fizz and buzz feature flags for libfoo dylib, command: %#v", libfooDylib.RuleParams.Command) } } @@ -57,9 +57,9 @@ func TestCfgsToFlags(t *testing.T) { libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") - if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'std'") || - !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'cfg1=\"one\"'") { - t.Fatalf("missing std and cfg1 flags for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"]) + if !strings.Contains(libfooDylib.RuleParams.Command, "cfg 'std'") || + !strings.Contains(libfooDylib.RuleParams.Command, "cfg 'cfg1=\"one\"'") { + t.Fatalf("missing std and cfg1 flags for libfoo dylib, rustcFlags: %#v", libfooDylib.RuleParams.Command) } } @@ -146,14 +146,14 @@ func TestCargoCompat(t *testing.T) { fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc") - if !strings.Contains(fizz.Args["envVars"], "CARGO_BIN_NAME=fizz") { - t.Fatalf("expected 'CARGO_BIN_NAME=fizz' in envVars, actual envVars: %#v", fizz.Args["envVars"]) + if !strings.Contains(fizz.RuleParams.Command, "CARGO_BIN_NAME=fizz") { + t.Fatalf("expected 'CARGO_BIN_NAME=fizz' in envVars, actual command: %#v", fizz.RuleParams.Command) } - if !strings.Contains(fizz.Args["envVars"], "CARGO_CRATE_NAME=foo") { - t.Fatalf("expected 'CARGO_CRATE_NAME=foo' in envVars, actual envVars: %#v", fizz.Args["envVars"]) + if !strings.Contains(fizz.RuleParams.Command, "CARGO_CRATE_NAME=foo") { + t.Fatalf("expected 'CARGO_CRATE_NAME=foo' in envVars, actual command: %#v", fizz.RuleParams.Command) } - if !strings.Contains(fizz.Args["envVars"], "CARGO_PKG_VERSION=1.0.0") { - t.Fatalf("expected 'CARGO_PKG_VERSION=1.0.0' in envVars, actual envVars: %#v", fizz.Args["envVars"]) + if !strings.Contains(fizz.RuleParams.Command, "CARGO_PKG_VERSION=1.0.0") { + t.Fatalf("expected 'CARGO_PKG_VERSION=1.0.0' in envVars, actual command: %#v", fizz.RuleParams.Command) } } @@ -230,13 +230,13 @@ func TestLints(t *testing.T) { ).RunTest(t) r := result.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("rustc") - android.AssertStringDoesContain(t, "libfoo flags", r.Args["rustcFlags"], tc.fooFlags) + android.AssertStringDoesContain(t, "libfoo flags", r.RuleParams.Command, tc.fooFlags) r = result.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeRule("rustc") - android.AssertStringDoesContain(t, "libbar flags", r.Args["rustcFlags"], "${config.RustDefaultLints}") + android.AssertStringDoesContain(t, "libbar flags", r.RuleParams.Command, "${config.RustDefaultLints}") r = result.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("rustc") - android.AssertStringDoesContain(t, "libfoobar flags", r.Args["rustcFlags"], "${config.RustAllowAllLints}") + android.AssertStringDoesContain(t, "libfoobar flags", r.RuleParams.Command, "${config.RustAllowAllLints}") }) } } diff --git a/rust/config/arm64_device.go b/rust/config/arm64_device.go index 08ac2ef7d..564168b9e 100644 --- a/rust/config/arm64_device.go +++ b/rust/config/arm64_device.go @@ -21,7 +21,9 @@ import ( ) var ( - Arm64RustFlags = []string{} + Arm64RustFlags = []string{ + "-C force-frame-pointers=y", + } Arm64ArchFeatureRustFlags = map[string][]string{} Arm64LinkFlags = []string{} diff --git a/rust/config/global.go b/rust/config/global.go index 86eb2d1cb..0ddc11637 100644 --- a/rust/config/global.go +++ b/rust/config/global.go @@ -21,10 +21,11 @@ import ( _ "android/soong/cc/config" ) -var pctx = android.NewPackageContext("android/soong/rust/config") - var ( - RustDefaultVersion = "1.71.0" + pctx = android.NewPackageContext("android/soong/rust/config") + exportedVars = android.NewExportedVariables(pctx) + + RustDefaultVersion = "1.72.0" RustDefaultBase = "prebuilts/rust/" DefaultEdition = "2021" Stdlibs = []string{ @@ -53,11 +54,11 @@ var ( "-C symbol-mangling-version=v0", "--color always", "-Zdylib-lto", + "-Z link-native-libraries=no", } deviceGlobalRustFlags = []string{ "-C panic=abort", - "-Z link-native-libraries=no", // Generate additional debug info for AutoFDO "-Z debug-info-for-profiling", } @@ -80,13 +81,7 @@ var ( func init() { pctx.SourcePathVariable("RustDefaultBase", RustDefaultBase) - pctx.VariableConfigMethod("HostPrebuiltTag", func(config android.Config) string { - if config.UseHostMusl() { - return "linux-musl-x86" - } else { - return config.PrebuiltOS() - } - }) + pctx.VariableConfigMethod("HostPrebuiltTag", HostPrebuiltTag) pctx.VariableFunc("RustBase", func(ctx android.PackageVarContext) string { if override := ctx.Config().Getenv("RUST_PREBUILTS_BASE"); override != "" { @@ -105,6 +100,15 @@ func init() { pctx.StaticVariable("DeviceGlobalLinkFlags", strings.Join(deviceGlobalLinkFlags, " ")) + exportedVars.ExportStringStaticVariable("RUST_DEFAULT_VERSION", RustDefaultVersion) +} + +func HostPrebuiltTag(config android.Config) string { + if config.UseHostMusl() { + return "linux-musl-x86" + } else { + return config.PrebuiltOS() + } } func getRustVersionPctx(ctx android.PackageVarContext) string { @@ -117,3 +121,32 @@ func GetRustVersion(ctx android.PathContext) string { } return RustDefaultVersion } + +// BazelRustToolchainVars returns a string with +func BazelRustToolchainVars(config android.Config) string { + return android.BazelToolchainVars(config, exportedVars) +} + +func RustPath(ctx android.PathContext, file string) android.SourcePath { + type rustToolKey string + key := android.NewCustomOnceKey(rustToolKey(file)) + return ctx.Config().OnceSourcePath(key, func() android.SourcePath { + return rustPath(ctx).Join(ctx, file) + }) +} + +var rustPathKey = android.NewOnceKey("clangPath") + +func rustPath(ctx android.PathContext) android.SourcePath { + return ctx.Config().OnceSourcePath(rustPathKey, func() android.SourcePath { + rustBase := RustDefaultBase + if override := ctx.Config().Getenv("RUST_PREBUILTS_BASE"); override != "" { + rustBase = override + } + rustVersion := RustDefaultVersion + if override := ctx.Config().Getenv("RUST_DEFAULT_VERSION"); override != "" { + rustVersion = override + } + return android.PathForSource(ctx, rustBase, ctx.Config().PrebuiltOS(), rustVersion) + }) +} diff --git a/rust/config/riscv64_device.go b/rust/config/riscv64_device.go index d014dbf8b..0a9c61a64 100644 --- a/rust/config/riscv64_device.go +++ b/rust/config/riscv64_device.go @@ -21,9 +21,15 @@ import ( ) var ( - Riscv64RustFlags = []string{} - Riscv64ArchFeatureRustFlags = map[string][]string{"": {}} - Riscv64LinkFlags = []string{} + Riscv64RustFlags = []string{ + "-C force-frame-pointers=y", + } + Riscv64ArchFeatureRustFlags = map[string][]string{ + "riscv64": { + "-C target-feature=+V,+Zba,+Zbb,+Zbs", + }, + } + Riscv64LinkFlags = []string{} Riscv64ArchVariantRustFlags = map[string][]string{"": {}} ) diff --git a/rust/config/x86_64_device.go b/rust/config/x86_64_device.go index 3458ec900..45d1fd0a1 100644 --- a/rust/config/x86_64_device.go +++ b/rust/config/x86_64_device.go @@ -21,7 +21,9 @@ import ( ) var ( - x86_64RustFlags = []string{} + x86_64RustFlags = []string{ + "-C force-frame-pointers=y", + } x86_64ArchFeatureRustFlags = map[string][]string{} x86_64LinkFlags = []string{} diff --git a/rust/coverage.go b/rust/coverage.go index 5216d6098..b312194f2 100644 --- a/rust/coverage.go +++ b/rust/coverage.go @@ -17,6 +17,7 @@ package rust import ( "github.com/google/blueprint" + "android/soong/android" "android/soong/cc" ) @@ -70,7 +71,10 @@ func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags // no_std modules are missing libprofiler_builtins which provides coverage, so we need to add it as a dependency. if rustModule, ok := ctx.Module().(*Module); ok && rustModule.compiler.noStdlibs() { profiler_builtins := ctx.GetDirectDepWithTag(ProfilerBuiltins, rlibDepTag).(*Module) - deps.RLibs = append(deps.RLibs, RustLibrary{Path: profiler_builtins.OutputFile().Path(), CrateName: profiler_builtins.CrateName()}) + deps.Rlibs = android.AddDirectToDepSet[RustLibrary](deps.Rlibs, RustLibrary{ + Path: profiler_builtins.OutputFile().Path(), + CrateName: profiler_builtins.CrateName(), + }) } if cc.EnableContinuousCoverage(ctx) { diff --git a/rust/coverage_test.go b/rust/coverage_test.go index 64077cf00..1466e0ce4 100644 --- a/rust/coverage_test.go +++ b/rust/coverage_test.go @@ -55,27 +55,27 @@ func TestCoverageFlags(t *testing.T) { libbarNoCov := ctx.ModuleForTests("libbar_nocov", "android_arm64_armv8-a_dylib").Rule("rustc") fizzCov := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc") buzzNoCov := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc") - libfooCovLink := ctx.ModuleForTests("libfoo_cov", "android_arm64_armv8-a_dylib_cov").Rule("rustLink") - libbarNoCovLink := ctx.ModuleForTests("libbar_nocov", "android_arm64_armv8-a_dylib").Rule("rustLink") - fizzCovLink := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustLink") - buzzNoCovLink := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustLink") + libfooCovLink := ctx.ModuleForTests("libfoo_cov", "android_arm64_armv8-a_dylib_cov").Rule("rustc") + libbarNoCovLink := ctx.ModuleForTests("libbar_nocov", "android_arm64_armv8-a_dylib").Rule("rustc") + fizzCovLink := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc") + buzzNoCovLink := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc") rustcCoverageFlags := []string{"-C instrument-coverage", " -g "} for _, flag := range rustcCoverageFlags { missingErrorStr := "missing rustc flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v" containsErrorStr := "contains rustc flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v" - if !strings.Contains(fizzCov.Args["rustcFlags"], flag) { - t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCov.Args["rustcFlags"]) + if !strings.Contains(fizzCov.RuleParams.Command, flag) { + t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCov.RuleParams.Command) } - if !strings.Contains(libfooCov.Args["rustcFlags"], flag) { - t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCov.Args["rustcFlags"]) + if !strings.Contains(libfooCov.RuleParams.Command, flag) { + t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCov.RuleParams.Command) } - if strings.Contains(buzzNoCov.Args["rustcFlags"], flag) { - t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCov.Args["rustcFlags"]) + if strings.Contains(buzzNoCov.RuleParams.Command, flag) { + t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCov.RuleParams.Command) } - if strings.Contains(libbarNoCov.Args["rustcFlags"], flag) { - t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCov.Args["rustcFlags"]) + if strings.Contains(libbarNoCov.RuleParams.Command, flag) { + t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCov.RuleParams.Command) } } @@ -84,17 +84,17 @@ func TestCoverageFlags(t *testing.T) { missingErrorStr := "missing rust linker flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v" containsErrorStr := "contains rust linker flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v" - if !strings.Contains(fizzCovLink.Args["linkFlags"], flag) { - t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCovLink.Args["linkFlags"]) + if !strings.Contains(fizzCovLink.RuleParams.Command, flag) { + t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCovLink.RuleParams.Command) } - if !strings.Contains(libfooCovLink.Args["linkFlags"], flag) { - t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCovLink.Args["linkFlags"]) + if !strings.Contains(libfooCovLink.RuleParams.Command, flag) { + t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCovLink.RuleParams.Command) } - if strings.Contains(buzzNoCovLink.Args["linkFlags"], flag) { - t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCovLink.Args["linkFlags"]) + if strings.Contains(buzzNoCovLink.RuleParams.Command, flag) { + t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCovLink.RuleParams.Command) } - if strings.Contains(libbarNoCovLink.Args["linkFlags"], flag) { - t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCovLink.Args["linkFlags"]) + if strings.Contains(libbarNoCovLink.RuleParams.Command, flag) { + t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCovLink.RuleParams.Command) } } @@ -107,8 +107,8 @@ func TestCoverageDeps(t *testing.T) { srcs: ["foo.rs"], }`) - fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("rustLink") - if !strings.Contains(fizz.Args["linkFlags"], "libprofile-clang-extras.a") { - t.Fatalf("missing expected coverage 'libprofile-clang-extras' dependency in linkFlags: %#v", fizz.Args["linkFlags"]) + fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("rustc") + if !strings.Contains(fizz.RuleParams.Command, "libprofile-clang-extras.a") { + t.Fatalf("missing expected coverage 'libprofile-clang-extras' dependency in linkFlags: %#v", fizz.RuleParams.Command) } } diff --git a/rust/fuzz.go b/rust/fuzz.go index 235f51779..4c04ce829 100644 --- a/rust/fuzz.go +++ b/rust/fuzz.go @@ -60,6 +60,25 @@ func NewRustFuzz(hod android.HostOrDeviceSupported) (*Module, *fuzzDecorator) { fuzz.binaryDecorator.baseCompiler.dir64 = "fuzz" fuzz.binaryDecorator.baseCompiler.location = InstallInData module.sanitize.SetSanitizer(cc.Fuzzer, true) + + // The fuzzer runtime is not present for darwin or bionic host modules, so disable rust_fuzz modules for these. + android.AddLoadHook(module, func(ctx android.LoadHookContext) { + + extraProps := struct { + Target struct { + Darwin struct { + Enabled *bool + } + Linux_bionic struct { + Enabled *bool + } + } + }{} + extraProps.Target.Darwin.Enabled = cc.BoolPtr(false) + extraProps.Target.Linux_bionic.Enabled = cc.BoolPtr(false) + ctx.AppendProperties(&extraProps) + }) + module.compiler = fuzz return module, fuzz } diff --git a/rust/fuzz_test.go b/rust/fuzz_test.go index ee28c6d3a..ea3590556 100644 --- a/rust/fuzz_test.go +++ b/rust/fuzz_test.go @@ -51,23 +51,23 @@ func TestRustFuzz(t *testing.T) { // Check that compiler flags are set appropriately . fuzz_libtest := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Rule("rustc") - if !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-C passes='sancov-module'") || - !strings.Contains(fuzz_libtest.Args["rustcFlags"], "--cfg fuzzing") { + if !strings.Contains(fuzz_libtest.RuleParams.Command, "-C passes='sancov-module'") || + !strings.Contains(fuzz_libtest.RuleParams.Command, "--cfg fuzzing") { t.Errorf("rust_fuzz module does not contain the expected flags (sancov-module, cfg fuzzing).") } // Check that host modules support fuzzing. host_fuzzer := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Rule("rustc") - if !strings.Contains(host_fuzzer.Args["rustcFlags"], "-C passes='sancov-module'") || - !strings.Contains(host_fuzzer.Args["rustcFlags"], "--cfg fuzzing") { + if !strings.Contains(host_fuzzer.RuleParams.Command, "-C passes='sancov-module'") || + !strings.Contains(host_fuzzer.RuleParams.Command, "--cfg fuzzing") { t.Errorf("rust_fuzz_host module does not contain the expected flags (sancov-module, cfg fuzzing).") } // Check that dependencies have 'fuzzer' variants produced for them as well. - libtest_fuzzer := ctx.ModuleForTests("libtest_fuzzing", "android_arm64_armv8-a_rlib_rlib-std_fuzzer").Output("libtest_fuzzing.rlib") - if !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-C passes='sancov-module'") || - !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "--cfg fuzzing") { - t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov-module, cfg fuzzing).") + libtest_fuzzer := ctx.ModuleForTests("libtest_fuzzing", "android_arm64_armv8-a_rlib_rlib-std_fuzzer").Rule("rustc") + if !strings.Contains(libtest_fuzzer.RuleParams.Command, "-C passes='sancov-module'") || + !strings.Contains(libtest_fuzzer.RuleParams.Command, "--cfg fuzzing") { + t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov-module, cfg fuzzing). command: %q", libtest_fuzzer.RuleParams.Command) } } diff --git a/rust/image_test.go b/rust/image_test.go index fb4d9c170..813c5bcdd 100644 --- a/rust/image_test.go +++ b/rust/image_test.go @@ -59,36 +59,36 @@ func TestImageVndkCfgFlag(t *testing.T) { vendor := ctx.ModuleForTests("libfoo", "android_vendor.29_arm64_armv8-a_static").Rule("rustc") - if !strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_vndk'") { - t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"]) + if !strings.Contains(vendor.RuleParams.Command, "--cfg 'android_vndk'") { + t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo vendor variant, rustcFlags: %#v", vendor.RuleParams.Command) } - if !strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_vendor'") { - t.Errorf("missing \"--cfg 'android_vendor'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"]) + if !strings.Contains(vendor.RuleParams.Command, "--cfg 'android_vendor'") { + t.Errorf("missing \"--cfg 'android_vendor'\" for libfoo vendor variant, rustcFlags: %#v", vendor.RuleParams.Command) } - if strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_product'") { - t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"]) + if strings.Contains(vendor.RuleParams.Command, "--cfg 'android_product'") { + t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo vendor variant, rustcFlags: %#v", vendor.RuleParams.Command) } product := ctx.ModuleForTests("libfoo", "android_product.29_arm64_armv8-a_static").Rule("rustc") - if !strings.Contains(product.Args["rustcFlags"], "--cfg 'android_vndk'") { - t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"]) + if !strings.Contains(product.RuleParams.Command, "--cfg 'android_vndk'") { + t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo product variant, rustcFlags: %#v", product.RuleParams.Command) } - if strings.Contains(product.Args["rustcFlags"], "--cfg 'android_vendor'") { - t.Errorf("unexpected \"--cfg 'android_vendor'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"]) + if strings.Contains(product.RuleParams.Command, "--cfg 'android_vendor'") { + t.Errorf("unexpected \"--cfg 'android_vendor'\" for libfoo product variant, rustcFlags: %#v", product.RuleParams.Command) } - if !strings.Contains(product.Args["rustcFlags"], "--cfg 'android_product'") { - t.Errorf("missing \"--cfg 'android_product'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"]) + if !strings.Contains(product.RuleParams.Command, "--cfg 'android_product'") { + t.Errorf("missing \"--cfg 'android_product'\" for libfoo product variant, rustcFlags: %#v", product.RuleParams.Command) } system := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static").Rule("rustc") - if strings.Contains(system.Args["rustcFlags"], "--cfg 'android_vndk'") { - t.Errorf("unexpected \"--cfg 'android_vndk'\" for libfoo system variant, rustcFlags: %#v", system.Args["rustcFlags"]) + if strings.Contains(system.RuleParams.Command, "--cfg 'android_vndk'") { + t.Errorf("unexpected \"--cfg 'android_vndk'\" for libfoo system variant, rustcFlags: %#v", system.RuleParams.Command) } - if strings.Contains(system.Args["rustcFlags"], "--cfg 'android_vendor'") { - t.Errorf("unexpected \"--cfg 'android_vendor'\" for libfoo system variant, rustcFlags: %#v", system.Args["rustcFlags"]) + if strings.Contains(system.RuleParams.Command, "--cfg 'android_vendor'") { + t.Errorf("unexpected \"--cfg 'android_vendor'\" for libfoo system variant, rustcFlags: %#v", system.RuleParams.Command) } - if strings.Contains(system.Args["rustcFlags"], "--cfg 'android_product'") { - t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo system variant, rustcFlags: %#v", product.Args["rustcFlags"]) + if strings.Contains(system.RuleParams.Command, "--cfg 'android_product'") { + t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo system variant, rustcFlags: %#v", product.RuleParams.Command) } } diff --git a/rust/library.go b/rust/library.go index 419fcfca2..7bb82bcc2 100644 --- a/rust/library.go +++ b/rust/library.go @@ -20,7 +20,10 @@ import ( "strings" "android/soong/android" + "android/soong/bazel" "android/soong/cc" + + "github.com/google/blueprint/proptools" ) var ( @@ -398,6 +401,8 @@ func (library *libraryDecorator) BuildOnlyShared() { func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) { module := newModule(hod, android.MultilibBoth) + android.InitBazelModule(module) + library := &libraryDecorator{ MutatedProperties: LibraryMutatedProperties{ BuildDylib: false, @@ -480,11 +485,28 @@ func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) F return flags } +func (library *libraryDecorator) compilationSourcesAndData(ctx ModuleContext) android.Paths { + var extraSrcs android.Paths + if library.rlib() { + extraSrcs = android.PathsForModuleSrc(ctx, library.Properties.Rlib.Srcs) + } else if library.dylib() { + extraSrcs = android.PathsForModuleSrc(ctx, library.Properties.Dylib.Srcs) + } else if library.static() { + extraSrcs = android.PathsForModuleSrc(ctx, library.Properties.Static.Srcs) + } else if library.shared() { + extraSrcs = android.PathsForModuleSrc(ctx, library.Properties.Shared.Srcs) + } + return android.Concat( + library.baseCompiler.compilationSourcesAndData(ctx), + extraSrcs, + ) +} + func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput { var outputFile android.ModuleOutPath var ret buildOutput var fileName string - srcPath := library.srcPath(ctx, deps) + crateRootPath := library.crateRootPath(ctx, deps) if library.sourceProvider != nil { deps.srcProviderFiles = append(deps.srcProviderFiles, library.sourceProvider.Srcs()...) @@ -520,7 +542,6 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa flags.RustFlags = append(flags.RustFlags, deps.depFlags...) flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...) - flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects.Strings()...) if library.dylib() { // We need prefer-dynamic for now to avoid linking in the static stdlib. See: @@ -531,13 +552,13 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa // Call the appropriate builder for this library type if library.rlib() { - ret.kytheFile = TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile).kytheFile + ret.kytheFile = TransformSrctoRlib(ctx, library, crateRootPath, deps, flags, outputFile).kytheFile } else if library.dylib() { - ret.kytheFile = TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile).kytheFile + ret.kytheFile = TransformSrctoDylib(ctx, library, crateRootPath, deps, flags, outputFile).kytheFile } else if library.static() { - ret.kytheFile = TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile).kytheFile + ret.kytheFile = TransformSrctoStatic(ctx, library, crateRootPath, deps, flags, outputFile).kytheFile } else if library.shared() { - ret.kytheFile = TransformSrctoShared(ctx, srcPath, deps, flags, outputFile).kytheFile + ret.kytheFile = TransformSrctoShared(ctx, library, crateRootPath, deps, flags, outputFile).kytheFile } if library.rlib() || library.dylib() { @@ -580,13 +601,15 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa return ret } -func (library *libraryDecorator) srcPath(ctx ModuleContext, _ PathDeps) android.Path { +func (library *libraryDecorator) crateRootPath(ctx ModuleContext, _ PathDeps) android.Path { if library.sourceProvider != nil { // Assume the first source from the source provider is the library entry point. return library.sourceProvider.Srcs()[0] - } else { + } else if library.baseCompiler.Properties.Crate_root == nil { path, _ := srcPathFromModuleSrcs(ctx, library.baseCompiler.Properties.Srcs) return path + } else { + return android.PathForModuleSrc(ctx, *library.baseCompiler.Properties.Crate_root) } } @@ -601,7 +624,7 @@ func (library *libraryDecorator) rustdoc(ctx ModuleContext, flags Flags, return android.OptionalPath{} } - return android.OptionalPathForPath(Rustdoc(ctx, library.srcPath(ctx, deps), + return android.OptionalPathForPath(Rustdoc(ctx, library.crateRootPath(ctx, deps), deps, flags)) } @@ -793,3 +816,155 @@ func (l *libraryDecorator) collectHeadersForSnapshot(ctx android.ModuleContext, // TODO(185577950): If support for generated headers is added, they need to be collected here as well. l.collectedSnapshotHeaders = ret } + +type rustLibraryAttributes struct { + Srcs bazel.LabelListAttribute + Compile_data bazel.LabelListAttribute + Crate_name bazel.StringAttribute + Edition bazel.StringAttribute + Crate_features bazel.StringListAttribute + Deps bazel.LabelListAttribute + Rustc_flags bazel.StringListAttribute + Proc_macro_deps bazel.LabelListAttribute +} + +func libraryBp2build(ctx android.Bp2buildMutatorContext, m *Module) { + lib := m.compiler.(*libraryDecorator) + + srcs, compileData := srcsAndCompileDataAttrs(ctx, *lib.baseCompiler) + + deps := android.BazelLabelForModuleDeps(ctx, append( + lib.baseCompiler.Properties.Rustlibs, + lib.baseCompiler.Properties.Rlibs..., + )) + + cargoBuildScript := cargoBuildScriptBp2build(ctx, m) + if cargoBuildScript != nil { + deps.Add(&bazel.Label{ + Label: ":" + *cargoBuildScript, + }) + } + + procMacroDeps := android.BazelLabelForModuleDeps(ctx, lib.baseCompiler.Properties.Proc_macros) + + var rustcFLags []string + for _, cfg := range lib.baseCompiler.Properties.Cfgs { + rustcFLags = append(rustcFLags, fmt.Sprintf("--cfg=%s", cfg)) + } + + attrs := &rustLibraryAttributes{ + Srcs: bazel.MakeLabelListAttribute( + srcs, + ), + Compile_data: bazel.MakeLabelListAttribute( + compileData, + ), + Crate_name: bazel.StringAttribute{ + Value: &lib.baseCompiler.Properties.Crate_name, + }, + Edition: bazel.StringAttribute{ + Value: lib.baseCompiler.Properties.Edition, + }, + Crate_features: bazel.StringListAttribute{ + Value: lib.baseCompiler.Properties.Features, + }, + Deps: bazel.MakeLabelListAttribute( + deps, + ), + Proc_macro_deps: bazel.MakeLabelListAttribute( + procMacroDeps, + ), + Rustc_flags: bazel.StringListAttribute{ + Value: append( + rustcFLags, + lib.baseCompiler.Properties.Flags..., + ), + }, + } + + // TODO(b/290790800): Remove the restriction when rust toolchain for android is implemented + var restriction bazel.BoolAttribute + restriction.SetSelectValue(bazel.OsConfigurationAxis, "android", proptools.BoolPtr(false)) + + ctx.CreateBazelTargetModuleWithRestrictions( + bazel.BazelTargetModuleProperties{ + Rule_class: "rust_library", + Bzl_load_location: "@rules_rust//rust:defs.bzl", + }, + android.CommonAttributes{ + Name: m.Name(), + }, + attrs, + restriction, + ) +} + +type cargoBuildScriptAttributes struct { + Srcs bazel.LabelListAttribute + Edition bazel.StringAttribute + Version bazel.StringAttribute +} + +func cargoBuildScriptBp2build(ctx android.Bp2buildMutatorContext, m *Module) *string { + // Soong treats some crates like libprotobuf as special in that they have + // cargo build script ran to produce an out folder and check it into AOSP + // For example, https://cs.android.com/android/platform/superproject/main/+/main:external/rust/crates/protobuf/out/ + // is produced by cargo build script https://cs.android.com/android/platform/superproject/main/+/main:external/rust/crates/protobuf/build.rs + // The out folder is then fed into `rust_library` by a genrule + // https://cs.android.com/android/platform/superproject/main/+/main:external/rust/crates/protobuf/Android.bp;l=22 + // This allows Soong to decouple from cargo completely. + + // Soong decouples from cargo so that it has control over cc compilation. + // https://cs.android.com/android/platform/superproject/main/+/main:development/scripts/cargo2android.py;l=1033-1041;drc=8449944a50a0445a5ecaf9b7aed12608c81bf3f1 + // generates a `cc_library_static` module to have custom cc flags. + // Since bp2build will convert the cc modules to cc targets which include the cflags, + // Bazel does not need to have this optimization. + + // Performance-wise: rust_library -> cargo_build_script vs rust_library -> genrule (like Soong) + // don't have any major difference in build time in Bazel. So using cargo_build_script does not slow + // down the build. + + // The benefit of using `cargo_build_script` here is that it would take care of setting correct + // `OUT_DIR` for us - similar to what Soong does here + // https://cs.android.com/android/platform/superproject/main/+/main:build/soong/rust/builder.go;l=202-218;drc=f29ca58e88c5846bbe8955e5192135e5ab4f14a1 + + // TODO(b/297364081): cargo2android.py has logic for when generate/not cc_library_static and out directory + // bp2build might be able use the same logic for when to use `cargo_build_script`. + // For now, we're building libprotobuf_build_script as a one-off until we have a more principled solution + if m.Name() != "libprotobuf" { + return nil + } + + lib := m.compiler.(*libraryDecorator) + + name := m.Name() + "_build_script" + attrs := &cargoBuildScriptAttributes{ + Srcs: bazel.MakeLabelListAttribute( + android.BazelLabelForModuleSrc(ctx, []string{"build.rs"}), + ), + Edition: bazel.StringAttribute{ + Value: lib.baseCompiler.Properties.Edition, + }, + Version: bazel.StringAttribute{ + Value: lib.baseCompiler.Properties.Cargo_pkg_version, + }, + } + + // TODO(b/290790800): Remove the restriction when rust toolchain for android is implemented + var restriction bazel.BoolAttribute + restriction.SetSelectValue(bazel.OsConfigurationAxis, "android", proptools.BoolPtr(false)) + + ctx.CreateBazelTargetModuleWithRestrictions( + bazel.BazelTargetModuleProperties{ + Rule_class: "cargo_build_script", + Bzl_load_location: "@rules_rust//cargo:cargo_build_script.bzl", + }, + android.CommonAttributes{ + Name: name, + }, + attrs, + restriction, + ) + + return &name +} diff --git a/rust/library_test.go b/rust/library_test.go index 30ef333b9..dab938159 100644 --- a/rust/library_test.go +++ b/rust/library_test.go @@ -48,23 +48,23 @@ func TestLibraryVariants(t *testing.T) { staticCrateType := "staticlib" // Test crate type for rlib is correct. - if !strings.Contains(libfooRlib.Args["rustcFlags"], "crate-type="+rlibCrateType) { - t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", rlibCrateType, libfooRlib.Args["rustcFlags"]) + if !strings.Contains(libfooRlib.RuleParams.Command, "crate-type="+rlibCrateType) { + t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", rlibCrateType, libfooRlib.RuleParams.Command) } // Test crate type for dylib is correct. - if !strings.Contains(libfooDylib.Args["rustcFlags"], "crate-type="+dylibCrateType) { - t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", dylibCrateType, libfooDylib.Args["rustcFlags"]) + if !strings.Contains(libfooDylib.RuleParams.Command, "crate-type="+dylibCrateType) { + t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", dylibCrateType, libfooDylib.RuleParams.Command) } // Test crate type for C static libraries is correct. - if !strings.Contains(libfooStatic.Args["rustcFlags"], "crate-type="+staticCrateType) { - t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", staticCrateType, libfooStatic.Args["rustcFlags"]) + if !strings.Contains(libfooStatic.RuleParams.Command, "crate-type="+staticCrateType) { + t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", staticCrateType, libfooStatic.RuleParams.Command) } // Test crate type for C shared libraries is correct. - if !strings.Contains(libfooShared.Args["rustcFlags"], "crate-type="+sharedCrateType) { - t.Errorf("missing crate-type for shared variant, expecting %#v, got rustcFlags: %#v", sharedCrateType, libfooShared.Args["rustcFlags"]) + if !strings.Contains(libfooShared.RuleParams.Command, "crate-type="+sharedCrateType) { + t.Errorf("missing crate-type for shared variant, expecting %#v, got rustcFlags: %#v", sharedCrateType, libfooShared.RuleParams.Command) } } @@ -78,10 +78,10 @@ func TestDylibPreferDynamic(t *testing.T) { crate_name: "foo", }`) - libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") + libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Description("rustc") - if !strings.Contains(libfooDylib.Args["rustcFlags"], "prefer-dynamic") { - t.Errorf("missing prefer-dynamic flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"]) + if !strings.Contains(libfooDylib.RuleParams.Command, "prefer-dynamic") { + t.Errorf("missing prefer-dynamic flag for libfoo dylib, rustcFlags: %#v", libfooDylib.RuleParams.Command) } } @@ -94,10 +94,10 @@ func TestAndroidDylib(t *testing.T) { crate_name: "foo", }`) - libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") + libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Description("rustc") - if !strings.Contains(libfooDylib.Args["rustcFlags"], "--cfg 'android_dylib'") { - t.Errorf("missing android_dylib cfg flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"]) + if !strings.Contains(libfooDylib.RuleParams.Command, "--cfg 'android_dylib'") { + t.Errorf("missing android_dylib cfg flag for libfoo dylib, rustcFlags: %#v", libfooDylib.RuleParams.Command) } } @@ -148,10 +148,10 @@ func TestSharedLibrary(t *testing.T) { libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared") - libfooOutput := libfoo.Rule("rustLink") - if !strings.Contains(libfooOutput.Args["linkFlags"], "-Wl,-soname=libfoo.so") { + libfooOutput := libfoo.Rule("rustc") + if !strings.Contains(libfooOutput.RuleParams.Command, "-Wl,-soname=libfoo.so") { t.Errorf("missing expected -Wl,-soname linker flag for libfoo shared lib, linkFlags: %#v", - libfooOutput.Args["linkFlags"]) + libfooOutput.RuleParams.Command) } if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkDylibs) { @@ -237,19 +237,21 @@ func TestNativeDependencyOfRlib(t *testing.T) { // The build system assumes the cc deps will be at the final linkage (either a shared library or binary) // Hence, these flags are no-op // TODO: We could consider removing these flags + expectedSharedFlag := "-L out/soong/.intermediates/shared_cc_dep/android_arm64_armv8-a_shared" + expectedStaticFlag := "-L out/soong/.intermediates/static_cc_dep/android_arm64_armv8-a_static" for _, module := range modules { - if !strings.Contains(module.Rule("rustc").Args["libFlags"], - "-L out/soong/.intermediates/shared_cc_dep/android_arm64_armv8-a_shared/") { + if !strings.Contains(module.Rule("rustc").RuleParams.Command, expectedSharedFlag) { t.Errorf( - "missing -L flag for shared_cc_dep, rustcFlags: %#v", - rustRlibRlibStd.Rule("rustc").Args["libFlags"], + "expected to find shared library linkdir flag %q, rustcFlags: %#v", + expectedSharedFlag, + rustRlibRlibStd.Rule("rustc").RuleParams.Command, ) } - if !strings.Contains(module.Rule("rustc").Args["libFlags"], - "-L out/soong/.intermediates/static_cc_dep/android_arm64_armv8-a_static/") { + if !strings.Contains(module.Rule("rustc").RuleParams.Command, expectedStaticFlag) { t.Errorf( - "missing -L flag for static_cc_dep, rustcFlags: %#v", - rustRlibRlibStd.Rule("rustc").Args["libFlags"], + "expected to find static library linkdir flag %q, rustcFlags: %#v", + expectedStaticFlag, + rustRlibRlibStd.Rule("rustc").RuleParams.Command, ) } } diff --git a/rust/prebuilt.go b/rust/prebuilt.go index fe9d0b5dd..d012680f0 100644 --- a/rust/prebuilt.go +++ b/rust/prebuilt.go @@ -146,7 +146,10 @@ func (prebuilt *prebuiltLibraryDecorator) compilerProps() []interface{} { } func (prebuilt *prebuiltLibraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput { - prebuilt.flagExporter.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs).Strings()...) + deps.linkDirs = append(deps.linkDirs, android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs)...) + prebuilt.flagExporter.exportLinkDirs(deps.linkDirs...) + prebuilt.flagExporter.exportLinkObjects(deps.linkObjects...) + prebuilt.flagExporter.exportLibDeps(deps.LibDeps...) prebuilt.flagExporter.setProvider(ctx) srcPath, paths := srcPathFromModuleSrcs(ctx, prebuilt.prebuiltSrcs()) @@ -203,7 +206,7 @@ func (prebuilt *prebuiltProcMacroDecorator) compilerProps() []interface{} { } func (prebuilt *prebuiltProcMacroDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput { - prebuilt.flagExporter.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs).Strings()...) + prebuilt.flagExporter.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs)...) prebuilt.flagExporter.setProvider(ctx) srcPath, paths := srcPathFromModuleSrcs(ctx, prebuilt.prebuiltSrcs()) diff --git a/rust/proc_macro.go b/rust/proc_macro.go index 832b62c36..3f0d17a73 100644 --- a/rust/proc_macro.go +++ b/rust/proc_macro.go @@ -15,7 +15,10 @@ package rust import ( + "fmt" + "android/soong/android" + "android/soong/bazel" ) func init() { @@ -47,6 +50,8 @@ func ProcMacroFactory() android.Module { func NewProcMacro(hod android.HostOrDeviceSupported) (*Module, *procMacroDecorator) { module := newModule(hod, android.MultilibFirst) + android.InitBazelModule(module) + procMacro := &procMacroDecorator{ baseCompiler: NewBaseCompiler("lib", "lib64", InstallInSystem), flagExporter: NewFlagExporter(), @@ -75,7 +80,7 @@ func (procMacro *procMacroDecorator) compile(ctx ModuleContext, flags Flags, dep outputFile := android.PathForModuleOut(ctx, fileName) srcPath, _ := srcPathFromModuleSrcs(ctx, procMacro.baseCompiler.Properties.Srcs) - ret := TransformSrctoProcMacro(ctx, srcPath, deps, flags, outputFile) + ret := TransformSrctoProcMacro(ctx, procMacro, srcPath, deps, flags, outputFile) procMacro.baseCompiler.unstrippedOutputFile = outputFile return ret } @@ -99,3 +104,65 @@ func (procMacro *procMacroDecorator) everInstallable() bool { // Proc_macros are never installed return false } + +type procMacroAttributes struct { + Srcs bazel.LabelListAttribute + Compile_data bazel.LabelListAttribute + Crate_name bazel.StringAttribute + Edition bazel.StringAttribute + Crate_features bazel.StringListAttribute + Deps bazel.LabelListAttribute + Rustc_flags bazel.StringListAttribute +} + +func procMacroBp2build(ctx android.Bp2buildMutatorContext, m *Module) { + procMacro := m.compiler.(*procMacroDecorator) + srcs, compileData := srcsAndCompileDataAttrs(ctx, *procMacro.baseCompiler) + deps := android.BazelLabelForModuleDeps(ctx, append( + procMacro.baseCompiler.Properties.Rustlibs, + procMacro.baseCompiler.Properties.Rlibs..., + )) + + var rustcFLags []string + for _, cfg := range procMacro.baseCompiler.Properties.Cfgs { + rustcFLags = append(rustcFLags, fmt.Sprintf("--cfg=%s", cfg)) + } + + attrs := &procMacroAttributes{ + Srcs: bazel.MakeLabelListAttribute( + srcs, + ), + Compile_data: bazel.MakeLabelListAttribute( + compileData, + ), + Crate_name: bazel.StringAttribute{ + Value: &procMacro.baseCompiler.Properties.Crate_name, + }, + Edition: bazel.StringAttribute{ + Value: procMacro.baseCompiler.Properties.Edition, + }, + Crate_features: bazel.StringListAttribute{ + Value: procMacro.baseCompiler.Properties.Features, + }, + Deps: bazel.MakeLabelListAttribute( + deps, + ), + Rustc_flags: bazel.StringListAttribute{ + Value: append( + rustcFLags, + procMacro.baseCompiler.Properties.Flags..., + ), + }, + } + // m.IsConvertedByBp2build() + ctx.CreateBazelTargetModule( + bazel.BazelTargetModuleProperties{ + Rule_class: "rust_proc_macro", + Bzl_load_location: "@rules_rust//rust:defs.bzl", + }, + android.CommonAttributes{ + Name: m.Name(), + }, + attrs, + ) +} diff --git a/rust/proc_macro_test.go b/rust/proc_macro_test.go index cc8193858..a547926fc 100644 --- a/rust/proc_macro_test.go +++ b/rust/proc_macro_test.go @@ -30,7 +30,7 @@ func TestRustProcMacro(t *testing.T) { libprocmacro := ctx.ModuleForTests("libprocmacro", "linux_glibc_x86_64").Rule("rustc") - if !strings.Contains(libprocmacro.Args["rustcFlags"], "--extern proc_macro") { - t.Errorf("--extern proc_macro flag not being passed to rustc for proc macro %#v", libprocmacro.Args["rustcFlags"]) + if !strings.Contains(libprocmacro.RuleParams.Command, "--extern proc_macro") { + t.Errorf("--extern proc_macro flag not being passed to rustc for proc macro %#v", libprocmacro.RuleParams.Command) } } diff --git a/rust/protobuf.go b/rust/protobuf.go index a14ebeaab..c8d2bdaeb 100644 --- a/rust/protobuf.go +++ b/rust/protobuf.go @@ -19,6 +19,9 @@ import ( "strings" "android/soong/android" + "android/soong/bazel" + + "github.com/google/blueprint/proptools" ) var ( @@ -264,5 +267,71 @@ func NewRustProtobuf(hod android.HostOrDeviceSupported) (*Module, *protobufDecor module := NewSourceProviderModule(hod, protobuf, false, false) + android.InitBazelModule(module) + return module, protobuf } + +type rustProtoAttributes struct { + Srcs bazel.LabelListAttribute + Crate_name bazel.StringAttribute + Deps bazel.LabelListAttribute +} + +type protoLibraryAttributes struct { + Srcs bazel.LabelListAttribute +} + +func protoLibraryBp2build(ctx android.Bp2buildMutatorContext, m *Module) { + var protoFiles []string + + for _, propsInterface := range m.sourceProvider.SourceProviderProps() { + if possibleProps, ok := propsInterface.(*ProtobufProperties); ok { + protoFiles = possibleProps.Protos + break + } + } + + protoLibraryName := m.Name() + "_proto" + + protoDeps := bazel.LabelListAttribute{ + Value: bazel.LabelList{ + Includes: []bazel.Label{ + { + Label: ":" + protoLibraryName, + OriginalModuleName: m.Name(), + }, + }, + }, + } + + ctx.CreateBazelTargetModule( + bazel.BazelTargetModuleProperties{ + Rule_class: "proto_library", + }, + android.CommonAttributes{ + Name: protoLibraryName, + }, + &protoLibraryAttributes{ + Srcs: bazel.MakeLabelListAttribute( + android.BazelLabelForModuleSrc(ctx, protoFiles), + ), + }, + ) + + ctx.CreateBazelTargetModule( + bazel.BazelTargetModuleProperties{ + Rule_class: "rust_proto_library", + Bzl_load_location: "@rules_rust//proto/protobuf:defs.bzl", + }, + android.CommonAttributes{ + Name: m.Name(), + }, + &rustProtoAttributes{ + Crate_name: bazel.StringAttribute{ + Value: proptools.StringPtr(m.CrateName()), + }, + Deps: protoDeps, + }, + ) +} diff --git a/rust/rust.go b/rust/rust.go index fc8db8655..6d6b55efe 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -15,10 +15,13 @@ package rust import ( - "android/soong/bloaty" "fmt" "strings" + "android/soong/bazel" + "android/soong/bloaty" + "android/soong/ui/metrics/bp2build_metrics_proto" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -66,7 +69,6 @@ type BaseProperties struct { AndroidMkRlibs []string `blueprint:"mutated"` AndroidMkDylibs []string `blueprint:"mutated"` AndroidMkProcMacroLibs []string `blueprint:"mutated"` - AndroidMkSharedLibs []string `blueprint:"mutated"` AndroidMkStaticLibs []string `blueprint:"mutated"` ImageVariationPrefix string `blueprint:"mutated"` @@ -168,6 +170,10 @@ type Module struct { // For apex variants, this is set as apex.min_sdk_version apexSdkVersion android.ApiLevel + + transitiveAndroidMkSharedLibs *android.DepSet[string] + + android.BazelModuleBase } func (mod *Module) Header() bool { @@ -432,12 +438,18 @@ type Deps struct { } type PathDeps struct { - DyLibs RustLibraries - RLibs RustLibraries + Dylibs *android.DepSet[RustLibrary] + Rlibs *android.DepSet[RustLibrary] + ProcMacros *android.DepSet[RustLibrary] LibDeps android.Paths WholeStaticLibs android.Paths - ProcMacros RustLibraries AfdoProfiles android.Paths + // These paths are files needed to run the build tools and will be located under + // __SBOX_SANDBOX_DIR__/tools/... + BuildToolDeps android.Paths + // These paths are files needed to run the build tools and will be located under + // __SBOX_SANDBOX_DIR__/... + BuildToolSrcDeps android.Paths // depFlags and depLinkFlags are rustc and linker (clang) flags. depFlags []string @@ -445,7 +457,7 @@ type PathDeps struct { // linkDirs are link paths passed via -L to rustc. linkObjects are objects passed directly to the linker. // Both of these are exported and propagate to dependencies. - linkDirs []string + linkDirs android.Paths linkObjects android.Paths // Used by bindgen modules which call clang @@ -460,6 +472,13 @@ type PathDeps struct { // Paths to generated source files SrcDeps android.Paths srcProviderFiles android.Paths + + // Paths to specific build tools + Rustc android.Path + Clang android.Path + Llvm_ar android.Path + Clippy_driver android.Path + Rustdoc android.Path } type RustLibraries []RustLibrary @@ -479,6 +498,8 @@ type compiler interface { compilerDeps(ctx DepsContext, deps Deps) Deps crateName() string rustdoc(ctx ModuleContext, flags Flags, deps PathDeps) android.OptionalPath + crateRoot(ctx ModuleContext) android.Path + compilationSourcesAndData(ctx ModuleContext) android.Paths // Output directory in which source-generated code from dependencies is // copied. This is equivalent to Cargo's OUT_DIR variable. @@ -508,7 +529,7 @@ type compiler interface { } type exportedFlagsProducer interface { - exportLinkDirs(...string) + exportLinkDirs(...android.Path) exportLinkObjects(...android.Path) } @@ -517,13 +538,13 @@ type xref interface { } type flagExporter struct { - linkDirs []string + linkDirs android.Paths linkObjects android.Paths libDeps android.Paths } -func (flagExporter *flagExporter) exportLinkDirs(dirs ...string) { - flagExporter.linkDirs = android.FirstUniqueStrings(append(flagExporter.linkDirs, dirs...)) +func (flagExporter *flagExporter) exportLinkDirs(dirs ...android.Path) { + flagExporter.linkDirs = android.FirstUniquePaths(append(flagExporter.linkDirs, dirs...)) } func (flagExporter *flagExporter) exportLinkObjects(flags ...android.Path) { @@ -550,7 +571,7 @@ func NewFlagExporter() *flagExporter { type FlagExporterInfo struct { Flags []string - LinkDirs []string // TODO: this should be android.Paths + LinkDirs android.Paths LinkObjects android.Paths LibDeps android.Paths } @@ -920,6 +941,14 @@ func (mod *Module) ccToolchain(ctx android.BaseModuleContext) cc_config.Toolchai func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) { } +type RustInfo struct { + TransitiveRlibs *android.DepSet[RustLibrary] + TransitiveDylibs *android.DepSet[RustLibrary] + TransitiveProcMacros *android.DepSet[RustLibrary] +} + +var RustInfoProvider = blueprint.NewProvider(RustInfo{}) + func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { ctx := &moduleContext{ ModuleContext: actx, @@ -1029,6 +1058,12 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { ctx.Phony("rust", ctx.RustModule().OutputFile().Path()) } + + ctx.SetProvider(RustInfoProvider, RustInfo{ + TransitiveRlibs: deps.Rlibs, + TransitiveDylibs: deps.Dylibs, + TransitiveProcMacros: deps.ProcMacros, + }) } func (mod *Module) deps(ctx DepsContext) Deps { @@ -1087,6 +1122,7 @@ func (d dependencyTag) LicenseAnnotations() []android.LicenseAnnotation { var _ android.LicenseAnnotationsDependencyTag = dependencyTag{} var ( + buildToolDepTag = dependencyTag{name: "buildToolTag"} customBindgenDepTag = dependencyTag{name: "customBindgenTag"} rlibDepTag = dependencyTag{name: "rlibTag", library: true} dylibDepTag = dependencyTag{name: "dylib", library: true, dynamic: true} @@ -1218,6 +1254,11 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { }) } + var transitiveAndroidMkSharedLibs []*android.DepSet[string] + var directAndroidMkSharedLibs []string + transitiveRlibs := android.NewDepSetBuilder[RustLibrary](android.PREORDER) + transitiveDylibs := android.NewDepSetBuilder[RustLibrary](android.PREORDER) + transitiveProcMacros := android.NewDepSetBuilder[RustLibrary](android.PREORDER) ctx.VisitDirectDeps(func(dep android.Module) { depName := ctx.OtherModuleName(dep) depTag := ctx.OtherModuleDependencyTag(dep) @@ -1230,6 +1271,17 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { return } + rustInfo := ctx.OtherModuleProvider(dep, RustInfoProvider).(RustInfo) + if rustInfo.TransitiveDylibs != nil { + transitiveDylibs.Transitive(rustInfo.TransitiveDylibs) + } + if rustInfo.TransitiveRlibs != nil { + transitiveRlibs.Transitive(rustInfo.TransitiveRlibs) + } + if rustInfo.TransitiveProcMacros != nil { + transitiveProcMacros.Transitive(rustInfo.TransitiveProcMacros) + } + if rustDep, ok := dep.(*Module); ok && !rustDep.CcLibraryInterface() { //Handle Rust Modules makeLibName := rustMakeLibName(ctx, mod, rustDep, depName+rustDep.Properties.RustSubName) @@ -1244,9 +1296,12 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { directDylibDeps = append(directDylibDeps, rustDep) mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, makeLibName) mod.Properties.SnapshotDylibs = append(mod.Properties.SnapshotDylibs, cc.BaseLibName(depName)) + transitiveDylibs.Direct(RustLibrary{ + Path: rustDep.UnstrippedOutputFile(), + CrateName: rustDep.CrateName(), + }) case rlibDepTag: - rlib, ok := rustDep.compiler.(libraryInterface) if !ok || !rlib.rlib() { ctx.ModuleErrorf("mod %q not an rlib library", makeLibName) @@ -1255,12 +1310,22 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { directRlibDeps = append(directRlibDeps, rustDep) mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, makeLibName) mod.Properties.SnapshotRlibs = append(mod.Properties.SnapshotRlibs, cc.BaseLibName(depName)) + transitiveRlibs.Direct(RustLibrary{ + Path: rustDep.UnstrippedOutputFile(), + CrateName: rustDep.CrateName(), + }) case procMacroDepTag: directProcMacroDeps = append(directProcMacroDeps, rustDep) mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, makeLibName) + transitiveProcMacros.Direct(RustLibrary{ + Path: rustDep.UnstrippedOutputFile(), + CrateName: rustDep.CrateName(), + }) } + transitiveAndroidMkSharedLibs = append(transitiveAndroidMkSharedLibs, rustDep.transitiveAndroidMkSharedLibs) + if android.IsSourceDepTagWithOutputTag(depTag, "") { // Since these deps are added in path_properties.go via AddDependencies, we need to ensure the correct // OS/Arch variant is used. @@ -1292,9 +1357,8 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag { linkFile := rustDep.UnstrippedOutputFile() - linkDir := linkPathFromFilePath(linkFile) if lib, ok := mod.compiler.(exportedFlagsProducer); ok { - lib.exportLinkDirs(linkDir) + lib.exportLinkDirs(linkFile.Dir()) } } @@ -1321,7 +1385,7 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { return } - linkPath := linkPathFromFilePath(linkObject.Path()) + linkPath := linkObject.Path().Dir() exportDep := false switch { @@ -1375,7 +1439,7 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } return } - linkPath = linkPathFromFilePath(linkObject.Path()) + linkPath = linkObject.Path().Dir() depPaths.linkDirs = append(depPaths.linkDirs, linkPath) depPaths.linkObjects = append(depPaths.linkObjects, linkObject.AsPaths()...) @@ -1388,7 +1452,7 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // Record baseLibName for snapshots. mod.Properties.SnapshotSharedLibs = append(mod.Properties.SnapshotSharedLibs, cc.BaseLibName(depName)) - mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, makeLibName) + directAndroidMkSharedLibs = append(directAndroidMkSharedLibs, makeLibName) exportDep = true case cc.IsHeaderDepTag(depTag): exportedInfo := ctx.OtherModuleProvider(dep, cc.FlagExporterInfoProvider).(cc.FlagExporterInfo) @@ -1410,6 +1474,25 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } } else { switch { + case depTag == buildToolDepTag: + buildTool := ctx.OtherModuleProvider(dep, android.PrebuiltBuildToolInfoProvider).(android.PrebuiltBuildToolInfo) + depPaths.BuildToolDeps = append(depPaths.BuildToolDeps, buildTool.Src) + depPaths.BuildToolDeps = append(depPaths.BuildToolDeps, buildTool.Deps...) + switch android.RemoveOptionalPrebuiltPrefix(dep.Name()) { + case "rustc": + depPaths.Rustc = buildTool.Src + // rustc expects the standard cc toolchain libraries (libdl, libm, libc, etc.) + // not to be under the __SBOX_SANDBOX_DIR__/ directory + depPaths.BuildToolSrcDeps = append(depPaths.BuildToolSrcDeps, buildTool.Deps...) + case "clang++": + depPaths.Clang = buildTool.Src + case "llvm-ar": + depPaths.Llvm_ar = buildTool.Src + case "clippy-driver": + depPaths.Clippy_driver = buildTool.Src + case "rustdoc": + depPaths.Rustdoc = buildTool.Src + } case depTag == cc.CrtBeginDepTag: depPaths.CrtBegin = append(depPaths.CrtBegin, android.OutputFileForModule(ctx, dep, "")) case depTag == cc.CrtEndDepTag: @@ -1425,19 +1508,6 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } }) - var rlibDepFiles RustLibraries - for _, dep := range directRlibDeps { - rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()}) - } - var dylibDepFiles RustLibraries - for _, dep := range directDylibDeps { - dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()}) - } - var procMacroDepFiles RustLibraries - for _, dep := range directProcMacroDeps { - procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()}) - } - var libDepFiles android.Paths for _, dep := range directStaticLibDeps { libDepFiles = append(libDepFiles, dep.OutputFile().Path()) @@ -1461,20 +1531,22 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { srcProviderDepFiles = append(srcProviderDepFiles, srcs...) } - depPaths.RLibs = append(depPaths.RLibs, rlibDepFiles...) - depPaths.DyLibs = append(depPaths.DyLibs, dylibDepFiles...) depPaths.LibDeps = append(depPaths.LibDeps, libDepFiles...) - depPaths.ProcMacros = append(depPaths.ProcMacros, procMacroDepFiles...) depPaths.SrcDeps = append(depPaths.SrcDeps, srcProviderDepFiles...) // Dedup exported flags from dependencies - depPaths.linkDirs = android.FirstUniqueStrings(depPaths.linkDirs) + depPaths.linkDirs = android.FirstUniquePaths(depPaths.linkDirs) depPaths.linkObjects = android.FirstUniquePaths(depPaths.linkObjects) depPaths.depFlags = android.FirstUniqueStrings(depPaths.depFlags) depPaths.depClangFlags = android.FirstUniqueStrings(depPaths.depClangFlags) depPaths.depIncludePaths = android.FirstUniquePaths(depPaths.depIncludePaths) depPaths.depSystemIncludePaths = android.FirstUniquePaths(depPaths.depSystemIncludePaths) + depPaths.Rlibs = transitiveRlibs.Build() + depPaths.Dylibs = transitiveDylibs.Build() + depPaths.ProcMacros = transitiveProcMacros.Build() + mod.transitiveAndroidMkSharedLibs = android.NewDepSet[string](android.PREORDER, directAndroidMkSharedLibs, transitiveAndroidMkSharedLibs) + return depPaths } @@ -1497,10 +1569,6 @@ func (mod *Module) InstallInRecovery() bool { return mod.InRecovery() } -func linkPathFromFilePath(filepath android.Path) string { - return strings.Split(filepath.String(), filepath.Base())[0] -} - // usePublicApi returns true if the rust variant should link against NDK (publicapi) func (r *Module) usePublicApi() bool { return r.Device() && r.UseSdk() @@ -1543,6 +1611,15 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { blueprint.Variation{Mutator: "rust_stdlinkage", Variation: stdLinkage}) } + ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "rustc") + ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "clippy-driver") + ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "rustdoc") + ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "clang++") + ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "clang++.real") + ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "lld") + ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "ld.lld") + ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "llvm-ar") + // rlibs rlibDepVariations = append(rlibDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: rlibVariation}) for _, lib := range deps.Rlibs { @@ -1833,6 +1910,46 @@ func (c *Module) Partition() string { return "" } +func (m *Module) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { + if ctx.ModuleType() == "rust_library_host" || ctx.ModuleType() == "rust_library" { + libraryBp2build(ctx, m) + } else if ctx.ModuleType() == "rust_proc_macro" { + procMacroBp2build(ctx, m) + } else if ctx.ModuleType() == "rust_binary_host" { + binaryBp2build(ctx, m) + } else if ctx.ModuleType() == "rust_protobuf_host" { + protoLibraryBp2build(ctx, m) + } else { + ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "") + } +} + +// This is a workaround by assuming the conventions that rust crate repos are structured +// while waiting for the sandboxing work to complete. +// TODO(b/297344471): When crate_root prop is set which enforces inputs sandboxing, +// always use `srcs` and `compile_data` props to generate `srcs` and `compile_data` attributes +// instead of using globs. +func srcsAndCompileDataAttrs(ctx android.Bp2buildMutatorContext, c baseCompiler) (bazel.LabelList, bazel.LabelList) { + var srcs bazel.LabelList + var compileData bazel.LabelList + + if c.Properties.Srcs[0] == "src/lib.rs" { + srcs = android.BazelLabelForModuleSrc(ctx, []string{"src/**/*.rs"}) + compileData = android.BazelLabelForModuleSrc( + ctx, + []string{ + "src/**/*.proto", + "examples/**/*.rs", + "**/*.md", + }, + ) + } else { + srcs = android.BazelLabelForModuleSrc(ctx, c.Properties.Srcs) + } + + return srcs, compileData +} + var Bool = proptools.Bool var BoolDefault = proptools.BoolDefault var String = proptools.String diff --git a/rust/rust_test.go b/rust/rust_test.go index 704bfe785..576209d04 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -15,14 +15,17 @@ package rust import ( + "fmt" "os" "runtime" "strings" "testing" "github.com/google/blueprint/proptools" + "google.golang.org/protobuf/encoding/prototext" "android/soong/android" + "android/soong/cmd/sbox/sbox_proto" "android/soong/genrule" ) @@ -64,11 +67,14 @@ var rustMockedFiles = android.MockFS{ // testRust returns a TestContext in which a basic environment has been setup. // This environment contains a few mocked files. See rustMockedFiles for the list of these files. -func testRust(t *testing.T, bp string) *android.TestContext { +func testRust(t *testing.T, bp string, preparers ...android.FixturePreparer) *android.TestContext { skipTestIfOsNotSupported(t) result := android.GroupFixturePreparers( prepareForRustTest, rustMockedFiles.AddToFixture(), + android.GroupFixturePreparers( + preparers..., + ), ). RunTestWithBp(t, bp) return result.TestContext @@ -202,11 +208,11 @@ func skipTestIfOsNotSupported(t *testing.T) { // Test that we can extract the link path from a lib path. func TestLinkPathFromFilePath(t *testing.T) { barPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so") - libName := linkPathFromFilePath(barPath) - expectedResult := "out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/" + libName := barPath.Dir() + expectedResult := "out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared" - if libName != expectedResult { - t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libName) + if libName.String() != expectedResult { + t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libName.String()) } } @@ -256,7 +262,7 @@ func TestDepsTracking(t *testing.T) { `) module := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module) rustc := ctx.ModuleForTests("librlib", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc") - rustLink := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustLink") + rustLink := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustc") // Since dependencies are added to AndroidMk* properties, we can check these to see if they've been picked up. if !android.InList("librlib.rlib-std", module.Properties.AndroidMkRlibs) { @@ -267,7 +273,7 @@ func TestDepsTracking(t *testing.T) { t.Errorf("Proc_macro dependency not detected (dependency missing from AndroidMkProcMacroLibs)") } - if !android.InList("libshared", module.Properties.AndroidMkSharedLibs) { + if !android.InList("libshared", module.transitiveAndroidMkSharedLibs.ToList()) { t.Errorf("Shared library dependency not detected (dependency missing from AndroidMkSharedLibs)") } @@ -275,16 +281,16 @@ func TestDepsTracking(t *testing.T) { t.Errorf("Static library dependency not detected (dependency missing from AndroidMkStaticLibs)") } - if !strings.Contains(rustc.Args["rustcFlags"], "-lstatic=wholestatic") { - t.Errorf("-lstatic flag not being passed to rustc for static library %#v", rustc.Args["rustcFlags"]) + if !strings.Contains(rustc.RuleParams.Command, "-lstatic=wholestatic") { + t.Errorf("-lstatic flag not being passed to rustc for static library %#v", rustc.RuleParams.Command) } - if !strings.Contains(rustLink.Args["linkFlags"], "cc_stubs_dep.so") { - t.Errorf("shared cc_library not being passed to rustc linkFlags %#v", rustLink.Args["linkFlags"]) + if !strings.Contains(rustLink.RuleParams.Command, "cc_stubs_dep.so") { + t.Errorf("shared cc_library not being passed to rustc linkFlags %#v", rustLink.RuleParams.Command) } - if !android.SuffixInList(rustLink.OrderOnly.Strings(), "cc_stubs_dep.so") { - t.Errorf("shared cc dep not being passed as order-only to rustc %#v", rustLink.OrderOnly.Strings()) + if !android.SuffixInList(rustLink.Implicits.Strings(), "cc_stubs_dep.so") { + t.Errorf("shared cc dep not being passed as implicit to rustc %#v", rustLink.OrderOnly.Strings()) } if !android.SuffixInList(rustLink.Implicits.Strings(), "cc_stubs_dep.so.toc") { @@ -427,7 +433,7 @@ func TestProcMacroDeviceDeps(t *testing.T) { `) rustc := ctx.ModuleForTests("libpm", "linux_glibc_x86_64").Rule("rustc") - if !strings.Contains(rustc.Args["libFlags"], "libbar/linux_glibc_x86_64") { + if !strings.Contains(rustc.RuleParams.Command, "libbar/linux_glibc_x86_64") { t.Errorf("Proc_macro is not using host variant of dependent modules.") } } @@ -480,3 +486,396 @@ func assertString(t *testing.T, got, expected string) { t.Errorf("expected %q got %q", expected, got) } } + +var ( + sboxCompilationFiles = []string{ + "out/soong/.intermediates/defaults/rust/libaddr2line/android_arm64_armv8-a_rlib/libaddr2line.rlib", + "out/soong/.intermediates/defaults/rust/libadler/android_arm64_armv8-a_rlib/libadler.rlib", + "out/soong/.intermediates/defaults/rust/liballoc/android_arm64_armv8-a_rlib/liballoc.rlib", + "out/soong/.intermediates/defaults/rust/libcfg_if/android_arm64_armv8-a_rlib/libcfg_if.rlib", + "out/soong/.intermediates/defaults/rust/libcompiler_builtins/android_arm64_armv8-a_rlib/libcompiler_builtins.rlib", + "out/soong/.intermediates/defaults/rust/libcore/android_arm64_armv8-a_rlib/libcore.rlib", + "out/soong/.intermediates/defaults/rust/libgimli/android_arm64_armv8-a_rlib/libgimli.rlib", + "out/soong/.intermediates/defaults/rust/libhashbrown/android_arm64_armv8-a_rlib/libhashbrown.rlib", + "out/soong/.intermediates/defaults/rust/liblibc/android_arm64_armv8-a_rlib/liblibc.rlib", + "out/soong/.intermediates/defaults/rust/libmemchr/android_arm64_armv8-a_rlib/libmemchr.rlib", + "out/soong/.intermediates/defaults/rust/libminiz_oxide/android_arm64_armv8-a_rlib/libminiz_oxide.rlib", + "out/soong/.intermediates/defaults/rust/libobject/android_arm64_armv8-a_rlib/libobject.rlib", + "out/soong/.intermediates/defaults/rust/libpanic_unwind/android_arm64_armv8-a_rlib/libpanic_unwind.rlib", + "out/soong/.intermediates/defaults/rust/librustc_demangle/android_arm64_armv8-a_rlib/librustc_demangle.rlib", + "out/soong/.intermediates/defaults/rust/librustc_std_workspace_alloc/android_arm64_armv8-a_rlib/librustc_std_workspace_alloc.rlib", + "out/soong/.intermediates/defaults/rust/librustc_std_workspace_core/android_arm64_armv8-a_rlib/librustc_std_workspace_core.rlib", + "out/soong/.intermediates/defaults/rust/libstd_detect/android_arm64_armv8-a_rlib/libstd_detect.rlib", + "build/soong/scripts/mkcratersp.py", + "defaults/rust/linux-x86/1.69.0/bin/rustc", + "defaults/rust/linux-x86/1.69.0/lib/libstd.so", + "defaults/rust/linux-x86/1.69.0/lib64/libc++.so.1", + } + sboxCompilationFilesWithCc = []string{ + "defaults/cc/common", + "out/soong/.intermediates/defaults/cc/common/libc/android_arm64_armv8-a_shared/libc.so", + "out/soong/.intermediates/defaults/cc/common/libc/android_arm64_armv8-a_shared/libc.so.toc", + "out/soong/.intermediates/defaults/cc/common/libdl/android_arm64_armv8-a_shared/libdl.so", + "out/soong/.intermediates/defaults/cc/common/libdl/android_arm64_armv8-a_shared/libdl.so.toc", + "out/soong/.intermediates/defaults/cc/common/libm/android_arm64_armv8-a_shared/libm.so", + "out/soong/.intermediates/defaults/cc/common/libm/android_arm64_armv8-a_shared/libm.so.toc", + "out/soong/.intermediates/defaults/rust/liblog/android_arm64_armv8-a_shared/liblog.so", + "out/soong/.intermediates/defaults/rust/liblog/android_arm64_armv8-a_shared/liblog.so.toc", + } +) + +func TestSandboxCompilation(t *testing.T) { + ctx := testRust(t, ` + filegroup { + name: "libsrcs1", + srcs: ["src_filegroup1.rs"], + } + filegroup { + name: "libsrcs2", + srcs: ["src_filegroup2.rs"], + } + rust_library { + name: "libfizz_buzz", + crate_name:"fizz_buzz", + crate_root: "foo.rs", + srcs: [ + "src_lib*.rs", + ":libsrcs1", + ":libsrcs2", + ], + compile_data: [ + "compile_data1.txt", + "compile_data2.txt", + ], + dylib: { + srcs: ["dylib_only.rs"], + }, + rlib: { + srcs: ["rlib_only.rs"], + }, + } + rust_binary { + name: "fizz_buzz", + crate_name:"fizz_buzz", + crate_root: "foo.rs", + srcs: [ + "src_lib*.rs", + ":libsrcs1", + ":libsrcs2", + ], + } + rust_ffi { + name: "librust_ffi", + crate_name: "rust_ffi", + crate_root: "foo.rs", + static: { + srcs: ["static_only.rs"], + }, + shared: { + srcs: ["shared_only.rs"], + }, + srcs: ["src1.rs"], + } + cc_library_static { + name: "cc_dep_static", + } + cc_library_shared { + name: "cc_dep_shared", + } + rust_library { + name: "libfizz_buzz_cc_deps", + crate_name:"fizz_buzz", + crate_root: "foo.rs", + srcs: ["src*.rs"], + shared_libs: ["cc_dep_shared"], + static_libs: ["cc_dep_static"], + } + rust_library { + name: "libfizz_buzz_intermediate_cc_deps", + crate_name:"fizz_buzz", + crate_root: "foo.rs", + srcs: ["src*.rs"], + rustlibs: ["libfizz_buzz_cc_deps"], + } + rust_library { + name: "libfizz_buzz_transitive_cc_deps", + crate_name:"fizz_buzz", + crate_root: "foo.rs", + srcs: ["src*.rs"], + rustlibs: ["libfizz_buzz_intermediate_cc_deps"], + } + `, + android.FixtureMergeMockFs(android.MockFS{ + "src_lib1.rs": nil, + "src_lib2.rs": nil, + "src_lib3.rs": nil, + "src_lib4.rs": nil, + "src_filegroup1.rs": nil, + "src_filegroup2.rs": nil, + "static_only.rs": nil, + "shared_only.rs": nil, + }), + ) + + testcases := []struct { + name string + moduleName string + variant string + rustcExpectedFilesToCopy []string + expectedFlags []string + }{ + { + name: "rust_library (dylib)", + moduleName: "libfizz_buzz", + variant: "android_arm64_armv8-a_dylib", + rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, sboxCompilationFilesWithCc, []string{ + "foo.rs", + "src_lib1.rs", + "src_lib2.rs", + "src_lib3.rs", + "src_lib4.rs", + "src_filegroup1.rs", + "src_filegroup2.rs", + "compile_data1.txt", + "compile_data2.txt", + "dylib_only.rs", + "out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/out/src_filegroup1.rs", + "out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/out/src_filegroup2.rs", + + "out/soong/.intermediates/defaults/cc/common/libc/android_arm64_armv8-a_shared/libc.so", + "out/soong/.intermediates/defaults/cc/common/libc/android_arm64_armv8-a_shared/libc.so.toc", + "out/soong/.intermediates/defaults/cc/common/libm/android_arm64_armv8-a_shared/libm.so", + "out/soong/.intermediates/defaults/cc/common/libm/android_arm64_armv8-a_shared/libm.so.toc", + "out/soong/.intermediates/defaults/cc/common/libdl/android_arm64_armv8-a_shared/libdl.so", + "out/soong/.intermediates/defaults/cc/common/libdl/android_arm64_armv8-a_shared/libdl.so.toc", + "out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_dylib/unstripped/libstd.dylib.so", + "out/soong/.intermediates/defaults/cc/common/crtbegin_so/android_arm64_armv8-a/crtbegin_so.o", + "out/soong/.intermediates/defaults/cc/common/crtend_so/android_arm64_armv8-a/crtend_so.o", + "out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/libfizz_buzz.dylib.so.clippy", + }), + expectedFlags: []string{ + "-C linker=build/soong/scripts/mkcratersp.py", + "--emit link", + "-o __SBOX_SANDBOX_DIR__/out/libfizz_buzz.dylib.so.rsp", + "--emit dep-info=__SBOX_SANDBOX_DIR__/out/libfizz_buzz.dylib.so.d.raw", + "foo.rs", // this is the entry point + }, + }, + { + name: "rust_library (rlib dylib-std)", + moduleName: "libfizz_buzz", + variant: "android_arm64_armv8-a_rlib_dylib-std", + rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, []string{ + "foo.rs", + "src_lib1.rs", + "src_lib2.rs", + "src_lib3.rs", + "src_lib4.rs", + "src_filegroup1.rs", + "src_filegroup2.rs", + "rlib_only.rs", + "out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_dylib-std/out/src_filegroup1.rs", + "out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_dylib-std/out/src_filegroup2.rs", + "out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_dylib/unstripped/libstd.dylib.so", + }), + expectedFlags: []string{ + "--emit link", + "-o __SBOX_SANDBOX_DIR__/out/libfizz_buzz.rlib", + "--emit dep-info=__SBOX_SANDBOX_DIR__/out/libfizz_buzz.rlib.d.raw", + "foo.rs", // this is the entry point + }, + }, + { + name: "rust_library (rlib rlib-std)", + moduleName: "libfizz_buzz", + variant: "android_arm64_armv8-a_rlib_rlib-std", + rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, []string{ + "foo.rs", + "src_lib1.rs", + "src_lib2.rs", + "src_lib3.rs", + "src_lib4.rs", + "src_filegroup1.rs", + "src_filegroup2.rs", + "rlib_only.rs", + "out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_rlib-std/out/src_filegroup1.rs", + "out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_rlib-std/out/src_filegroup2.rs", + "out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_rlib-std/libfizz_buzz.rlib.clippy", + "out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_rlib/libstd.rlib", + }), + expectedFlags: []string{ + "--emit link", + "-o __SBOX_SANDBOX_DIR__/out/libfizz_buzz.rlib", + "--emit dep-info=__SBOX_SANDBOX_DIR__/out/libfizz_buzz.rlib.d.raw", + "foo.rs", // this is the entry point + }, + }, + { + name: "rust_binary", + moduleName: "fizz_buzz", + variant: "android_arm64_armv8-a", + rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, sboxCompilationFilesWithCc, []string{ + "foo.rs", + "src_lib1.rs", + "src_lib2.rs", + "src_lib3.rs", + "src_lib4.rs", + "src_filegroup1.rs", + "src_filegroup2.rs", + "out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/out/src_filegroup1.rs", + "out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/out/src_filegroup2.rs", + + "out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_dylib/unstripped/libstd.dylib.so", + "out/soong/.intermediates/defaults/cc/common/crtbegin_dynamic/android_arm64_armv8-a/crtbegin_dynamic.o", + "out/soong/.intermediates/defaults/cc/common/crtend_android/android_arm64_armv8-a/crtend_android.o", + "out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/fizz_buzz.clippy", + }), + expectedFlags: []string{ + "--emit link", + "-o __SBOX_SANDBOX_DIR__/out/fizz_buzz", + "--emit dep-info=__SBOX_SANDBOX_DIR__/out/fizz_buzz.d.raw", + "foo.rs", // this is the entry point + }, + }, + { + name: "rust_ffi static lib variant", + moduleName: "librust_ffi", + variant: "android_arm64_armv8-a_static", + rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, []string{ + "foo.rs", + "src1.rs", + "static_only.rs", + "out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_static/librust_ffi.a.clippy", + "out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_rlib/libstd.rlib", + }), + expectedFlags: []string{ + "--emit link", + "-o __SBOX_SANDBOX_DIR__/out/librust_ffi.a", + "--emit dep-info=__SBOX_SANDBOX_DIR__/out/librust_ffi.a.d.raw", + "foo.rs", // this is the entry point + }, + }, + { + name: "rust_ffi shared lib variant", + moduleName: "librust_ffi", + variant: "android_arm64_armv8-a_shared", + rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, sboxCompilationFilesWithCc, []string{ + "foo.rs", + "src1.rs", + "shared_only.rs", + + "out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_dylib/unstripped/libstd.dylib.so", + "out/soong/.intermediates/defaults/cc/common/crtbegin_so/android_arm64_armv8-a/crtbegin_so.o", + "out/soong/.intermediates/defaults/cc/common/crtend_so/android_arm64_armv8-a/crtend_so.o", + "out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/librust_ffi.so.clippy", + }), + expectedFlags: []string{ + "--emit link", + "-o __SBOX_SANDBOX_DIR__/out/librust_ffi.so", + "--emit dep-info=__SBOX_SANDBOX_DIR__/out/librust_ffi.so.d.raw", + "foo.rs", // this is the entry point + }, + }, + { + name: "rust_library with cc deps (dylib)", + moduleName: "libfizz_buzz_cc_deps", + variant: "android_arm64_armv8-a_dylib", + rustcExpectedFilesToCopy: []string{ + "out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a", + "out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so", + "out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc", + }, + }, + { + name: "rust_library with cc deps (rlib rlib-std)", + moduleName: "libfizz_buzz_cc_deps", + variant: "android_arm64_armv8-a_rlib_rlib-std", + rustcExpectedFilesToCopy: []string{ + "out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a", + "out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so", + "out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc", + }, + }, + { + name: "rust_library with cc deps (rlib dylib-std)", + moduleName: "libfizz_buzz_cc_deps", + variant: "android_arm64_armv8-a_rlib_dylib-std", + rustcExpectedFilesToCopy: []string{ + "out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a", + "out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so", + "out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc", + }, + }, + { + name: "rust_library with transitive cc deps (dylib)", + moduleName: "libfizz_buzz_transitive_cc_deps", + variant: "android_arm64_armv8-a_dylib", + rustcExpectedFilesToCopy: []string{ + "out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a", + "out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so", + "out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc", + }, + }, + { + name: "rust_library with transitive cc deps (rlib rlib-std)", + moduleName: "libfizz_buzz_transitive_cc_deps", + variant: "android_arm64_armv8-a_rlib_rlib-std", + rustcExpectedFilesToCopy: []string{ + "out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a", + "out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so", + "out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc", + }, + }, + { + name: "rust_library with transitive cc deps (rlib dylib-std)", + moduleName: "libfizz_buzz_transitive_cc_deps", + variant: "android_arm64_armv8-a_rlib_dylib-std", + rustcExpectedFilesToCopy: []string{ + "out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a", + "out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so", + "out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc", + }, + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + writeFile := ctx.ModuleForTests(tc.moduleName, tc.variant).Rule("unescapedWriteFile") + contents := writeFile.BuildParams.Args["content"] + manifestProto := sbox_proto.Manifest{} + err := prototext.Unmarshal([]byte(contents), &manifestProto) + if err != nil { + t.Errorf("expected no errors unmarshaling manifest proto; got %v", err) + } + + if len(manifestProto.Commands) != 1 { + t.Errorf("expected 1 command; got %v", len(manifestProto.Commands)) + } + + // check that sandbox contains correct files + rustc := manifestProto.Commands[0] + actualFilesToCopy := []string{} + for _, copy := range rustc.CopyBefore { + actualFilesToCopy = append(actualFilesToCopy, copy.GetFrom()) + } + _, expectedFilesNotCopied, _ := android.ListSetDifference(tc.rustcExpectedFilesToCopy, actualFilesToCopy) + if len(expectedFilesNotCopied) > 0 { + t.Errorf("did not copy expected files to sbox: %v;\n files copied: %v", expectedFilesNotCopied, actualFilesToCopy) + } + + rustcCmd := proptools.String(rustc.Command) + for _, flag := range tc.expectedFlags { + android.AssertStringDoesContain( + t, + fmt.Sprintf( + "missing flag in rustc invocation; expected to find substring %q; got %q", + flag, + rustcCmd, + ), + rustcCmd, + flag, + ) + } + }) + } +} diff --git a/rust/sanitize.go b/rust/sanitize.go index cc19e6e61..2f5afd74d 100644 --- a/rust/sanitize.go +++ b/rust/sanitize.go @@ -208,6 +208,11 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { s.Memtag_heap = nil } + // Disable sanitizers for musl x86 modules, rustc does not support any sanitizers. + if ctx.Os() == android.LinuxMusl && ctx.Arch().ArchType == android.X86 { + s.Never = boolPtr(true) + } + // TODO:(b/178369775) // For now sanitizing is only supported on non-windows targets if ctx.Os() != android.Windows && (Bool(s.Hwaddress) || Bool(s.Address) || Bool(s.Memtag_heap) || Bool(s.Fuzzer)) { diff --git a/rust/sanitize_test.go b/rust/sanitize_test.go index 43e95f477..d6a14b295 100644 --- a/rust/sanitize_test.go +++ b/rust/sanitize_test.go @@ -35,7 +35,7 @@ func checkHasMemtagNote(t *testing.T, m android.TestingModule, expected MemtagNo note_sync := "note_memtag_heap_sync" found := None - implicits := m.Rule("rustLink").Implicits + implicits := m.Rule("rustc").Implicits for _, lib := range implicits { if strings.Contains(lib.Rel(), note_async) { found = Async diff --git a/rust/snapshot_prebuilt.go b/rust/snapshot_prebuilt.go index 32d391629..42e3cef38 100644 --- a/rust/snapshot_prebuilt.go +++ b/rust/snapshot_prebuilt.go @@ -15,6 +15,8 @@ package rust import ( + "fmt" + "android/soong/android" "android/soong/cc" @@ -26,17 +28,80 @@ type snapshotLibraryDecorator struct { *libraryDecorator properties cc.SnapshotLibraryProperties sanitizerProperties struct { - CfiEnabled bool `blueprint:"mutated"` + SanitizerVariation cc.SanitizerType `blueprint:"mutated"` + + //TODO: Library flags for cfi variant when CFI is supported. + //Cfi cc.SnapshotLibraryProperties `android:"arch_variant"` + + // Library flags for hwasan variant. + Hwasan cc.SnapshotLibraryProperties `android:"arch_variant"` + } +} + +var _ cc.SnapshotSanitizer = (*snapshotLibraryDecorator)(nil) + +func (library *snapshotLibraryDecorator) IsSanitizerAvailable(t cc.SanitizerType) bool { + switch t { + //TODO: When CFI is supported, add a check here as well + case cc.Hwasan: + return library.sanitizerProperties.Hwasan.Src != nil + default: + return false + } +} - // Library flags for cfi variant. - Cfi cc.SnapshotLibraryProperties `android:"arch_variant"` +func (library *snapshotLibraryDecorator) SetSanitizerVariation(t cc.SanitizerType, enabled bool) { + if !enabled || library.IsSanitizerEnabled(t) { + return + } + if !library.IsUnsanitizedVariant() { + panic(fmt.Errorf("snapshot Sanitizer must be one of Cfi or Hwasan but not both")) } + library.sanitizerProperties.SanitizerVariation = t +} + +func (library *snapshotLibraryDecorator) IsSanitizerEnabled(t cc.SanitizerType) bool { + return library.sanitizerProperties.SanitizerVariation == t +} + +func (library *snapshotLibraryDecorator) IsUnsanitizedVariant() bool { + //TODO: When CFI is supported, add a check here as well + return !library.IsSanitizerEnabled(cc.Hwasan) } func init() { registerRustSnapshotModules(android.InitRegistrationContext) } +func (mod *Module) IsSnapshotSanitizerAvailable(t cc.SanitizerType) bool { + if ss, ok := mod.compiler.(cc.SnapshotSanitizer); ok { + return ss.IsSanitizerAvailable(t) + } + return false +} + +func (mod *Module) SetSnapshotSanitizerVariation(t cc.SanitizerType, enabled bool) { + if ss, ok := mod.compiler.(cc.SnapshotSanitizer); ok { + ss.SetSanitizerVariation(t, enabled) + } else { + panic(fmt.Errorf("Calling SetSnapshotSanitizerVariation on a non-snapshotLibraryDecorator: %s", mod.Name())) + } +} + +func (mod *Module) IsSnapshotUnsanitizedVariant() bool { + if ss, ok := mod.compiler.(cc.SnapshotSanitizer); ok { + return ss.IsUnsanitizedVariant() + } + return false +} + +func (mod *Module) IsSnapshotSanitizer() bool { + if _, ok := mod.compiler.(cc.SnapshotSanitizer); ok { + return true + } + return false +} + func registerRustSnapshotModules(ctx android.RegistrationContext) { cc.VendorSnapshotImageSingleton.RegisterAdditionalModule(ctx, "vendor_snapshot_rlib", VendorSnapshotRlibFactory) @@ -81,6 +146,9 @@ func (library *snapshotLibraryDecorator) compile(ctx ModuleContext, flags Flags, library.SetSnapshotAndroidMkSuffix(ctx, variant) + if library.IsSanitizerEnabled(cc.Hwasan) { + library.properties = library.sanitizerProperties.Hwasan + } if !library.MatchesWithDevice(ctx.DeviceConfig()) { return buildOutput{} } diff --git a/rust/testing.go b/rust/testing.go index 3fe751e17..9951937be 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -52,6 +52,22 @@ var PrepareForTestWithRustIncludeVndk = android.GroupFixturePreparers( func GatherRequiredDepsForTest() string { bp := ` + prebuilt_build_tool { + name: "rustc", + src: "linux-x86/1.69.0/bin/rustc", + deps: [ + "linux-x86/1.69.0/lib/libstd.so", + "linux-x86/1.69.0/lib64/libc++.so.1", + ], + } + prebuilt_build_tool { + name: "clippy-driver", + src: "linux-x86/1.69.0/bin/clippy-driver", + } + prebuilt_build_tool { + name: "rustdoc", + src: "linux-x86/1.69.0/bin/rustdoc", + } rust_prebuilt_library { name: "libstd", crate_name: "std", @@ -63,6 +79,25 @@ func GatherRequiredDepsForTest() string { }, host_supported: true, sysroot: true, + rlibs: [ + "libaddr2line", + "libadler", + "liballoc", + "libcfg_if", + "libcompiler_builtins", + "libcore", + "libgimli", + "libhashbrown", + "liblibc", + "libmemchr", + "libminiz_oxide", + "libobject", + "libpanic_unwind", + "librustc_demangle", + "librustc_std_workspace_alloc", + "librustc_std_workspace_core", + "libstd_detect", + ], } ////////////////////////////// // Device module requirements @@ -99,6 +134,278 @@ func GatherRequiredDepsForTest() string { nocrt: true, system_shared_libs: [], } + rust_library_rlib { + name: "libaddr2line", + crate_name: "addr2line", + enabled:true, + srcs: ["foo.rs"], + no_stdlibs: true, + product_available: true, + host_supported: true, + vendor_available: true, + vendor_ramdisk_available: true, + recovery_available: true, + native_coverage: false, + sysroot: true, + apex_available: ["//apex_available:platform", "//apex_available:anyapex"], + min_sdk_version: "29", + } + rust_library_rlib { + name: "libadler", + crate_name: "adler", + enabled:true, + srcs: ["foo.rs"], + no_stdlibs: true, + product_available: true, + host_supported: true, + vendor_available: true, + vendor_ramdisk_available: true, + recovery_available: true, + native_coverage: false, + sysroot: true, + apex_available: ["//apex_available:platform", "//apex_available:anyapex"], + min_sdk_version: "29", + } + rust_library_rlib { + name: "liballoc", + crate_name: "alloc", + enabled:true, + srcs: ["foo.rs"], + no_stdlibs: true, + product_available: true, + host_supported: true, + vendor_available: true, + vendor_ramdisk_available: true, + recovery_available: true, + native_coverage: false, + sysroot: true, + apex_available: ["//apex_available:platform", "//apex_available:anyapex"], + min_sdk_version: "29", + } + rust_library_rlib { + name: "libcfg_if", + crate_name: "cfg_if", + enabled:true, + srcs: ["foo.rs"], + no_stdlibs: true, + product_available: true, + host_supported: true, + vendor_available: true, + vendor_ramdisk_available: true, + recovery_available: true, + native_coverage: false, + sysroot: true, + apex_available: ["//apex_available:platform", "//apex_available:anyapex"], + min_sdk_version: "29", + } + rust_library_rlib { + name: "libcompiler_builtins", + crate_name: "compiler_builtins", + enabled:true, + srcs: ["foo.rs"], + no_stdlibs: true, + product_available: true, + host_supported: true, + vendor_available: true, + vendor_ramdisk_available: true, + recovery_available: true, + native_coverage: false, + sysroot: true, + apex_available: ["//apex_available:platform", "//apex_available:anyapex"], + min_sdk_version: "29", + } + rust_library_rlib { + name: "libcore", + crate_name: "core", + enabled:true, + srcs: ["foo.rs"], + no_stdlibs: true, + product_available: true, + host_supported: true, + vendor_available: true, + vendor_ramdisk_available: true, + recovery_available: true, + native_coverage: false, + sysroot: true, + apex_available: ["//apex_available:platform", "//apex_available:anyapex"], + min_sdk_version: "29", + } + rust_library_rlib { + name: "libgimli", + crate_name: "gimli", + enabled:true, + srcs: ["foo.rs"], + no_stdlibs: true, + product_available: true, + host_supported: true, + vendor_available: true, + vendor_ramdisk_available: true, + recovery_available: true, + native_coverage: false, + sysroot: true, + apex_available: ["//apex_available:platform", "//apex_available:anyapex"], + min_sdk_version: "29", + } + rust_library_rlib { + name: "libhashbrown", + crate_name: "hashbrown", + enabled:true, + srcs: ["foo.rs"], + no_stdlibs: true, + product_available: true, + host_supported: true, + vendor_available: true, + vendor_ramdisk_available: true, + recovery_available: true, + native_coverage: false, + sysroot: true, + apex_available: ["//apex_available:platform", "//apex_available:anyapex"], + min_sdk_version: "29", + } + rust_library_rlib { + name: "liblibc", + crate_name: "libc", + enabled:true, + srcs: ["foo.rs"], + no_stdlibs: true, + product_available: true, + host_supported: true, + vendor_available: true, + vendor_ramdisk_available: true, + recovery_available: true, + native_coverage: false, + sysroot: true, + apex_available: ["//apex_available:platform", "//apex_available:anyapex"], + min_sdk_version: "29", + } + rust_library_rlib { + name: "libmemchr", + crate_name: "memchr", + enabled:true, + srcs: ["foo.rs"], + no_stdlibs: true, + product_available: true, + host_supported: true, + vendor_available: true, + vendor_ramdisk_available: true, + recovery_available: true, + native_coverage: false, + sysroot: true, + apex_available: ["//apex_available:platform", "//apex_available:anyapex"], + min_sdk_version: "29", + } + rust_library_rlib { + name: "libminiz_oxide", + crate_name: "miniz_oxide", + enabled:true, + srcs: ["foo.rs"], + no_stdlibs: true, + product_available: true, + host_supported: true, + vendor_available: true, + vendor_ramdisk_available: true, + recovery_available: true, + native_coverage: false, + sysroot: true, + apex_available: ["//apex_available:platform", "//apex_available:anyapex"], + min_sdk_version: "29", + } + rust_library_rlib { + name: "libobject", + crate_name: "object", + enabled:true, + srcs: ["foo.rs"], + no_stdlibs: true, + product_available: true, + host_supported: true, + vendor_available: true, + vendor_ramdisk_available: true, + recovery_available: true, + native_coverage: false, + sysroot: true, + apex_available: ["//apex_available:platform", "//apex_available:anyapex"], + min_sdk_version: "29", + } + rust_library_rlib { + name: "libpanic_unwind", + crate_name: "panic_unwind", + enabled:true, + srcs: ["foo.rs"], + no_stdlibs: true, + product_available: true, + host_supported: true, + vendor_available: true, + vendor_ramdisk_available: true, + recovery_available: true, + native_coverage: false, + sysroot: true, + apex_available: ["//apex_available:platform", "//apex_available:anyapex"], + min_sdk_version: "29", + } + rust_library_rlib { + name: "librustc_demangle", + crate_name: "rustc_demangle", + enabled:true, + srcs: ["foo.rs"], + no_stdlibs: true, + product_available: true, + host_supported: true, + vendor_available: true, + vendor_ramdisk_available: true, + recovery_available: true, + native_coverage: false, + sysroot: true, + apex_available: ["//apex_available:platform", "//apex_available:anyapex"], + min_sdk_version: "29", + } + rust_library_rlib { + name: "librustc_std_workspace_alloc", + crate_name: "rustc_std_workspace_alloc", + enabled:true, + srcs: ["foo.rs"], + no_stdlibs: true, + product_available: true, + host_supported: true, + vendor_available: true, + vendor_ramdisk_available: true, + recovery_available: true, + native_coverage: false, + sysroot: true, + apex_available: ["//apex_available:platform", "//apex_available:anyapex"], + min_sdk_version: "29", + } + rust_library_rlib { + name: "librustc_std_workspace_core", + crate_name: "rustc_std_workspace_core", + enabled:true, + srcs: ["foo.rs"], + no_stdlibs: true, + product_available: true, + host_supported: true, + vendor_available: true, + vendor_ramdisk_available: true, + recovery_available: true, + native_coverage: false, + sysroot: true, + apex_available: ["//apex_available:platform", "//apex_available:anyapex"], + min_sdk_version: "29", + } + rust_library_rlib { + name: "libstd_detect", + crate_name: "std_detect", + enabled:true, + srcs: ["foo.rs"], + no_stdlibs: true, + product_available: true, + host_supported: true, + vendor_available: true, + vendor_ramdisk_available: true, + recovery_available: true, + native_coverage: false, + sysroot: true, + apex_available: ["//apex_available:platform", "//apex_available:anyapex"], + min_sdk_version: "29", + } rust_library { name: "libstd", crate_name: "std", @@ -113,6 +420,25 @@ func GatherRequiredDepsForTest() string { sysroot: true, apex_available: ["//apex_available:platform", "//apex_available:anyapex"], min_sdk_version: "29", + rlibs: [ + "libaddr2line", + "libadler", + "liballoc", + "libcfg_if", + "libcompiler_builtins", + "libcore", + "libgimli", + "libhashbrown", + "liblibc", + "libmemchr", + "libminiz_oxide", + "libobject", + "libpanic_unwind", + "librustc_demangle", + "librustc_std_workspace_alloc", + "librustc_std_workspace_core", + "libstd_detect", + ], } rust_library { name: "libtest", diff --git a/rust/toolchain_library.go b/rust/toolchain_library.go index 326d52924..cb345a4b6 100644 --- a/rust/toolchain_library.go +++ b/rust/toolchain_library.go @@ -18,9 +18,12 @@ package rust import ( "path" + "path/filepath" "android/soong/android" "android/soong/rust/config" + + "github.com/google/blueprint/proptools" ) // This module is used to compile the rust toolchain libraries @@ -33,11 +36,15 @@ func init() { rustToolchainLibraryRlibFactory) android.RegisterModuleType("rust_toolchain_library_dylib", rustToolchainLibraryDylibFactory) + android.RegisterModuleType("rust_toolchain_rustc_prebuilt", + rustToolchainRustcPrebuiltFactory) } type toolchainLibraryProperties struct { - // path to the toolchain source, relative to the top of the toolchain source - Toolchain_src *string `android:"arch_variant"` + // path to the toolchain crate root, relative to the top of the toolchain source + Toolchain_crate_root *string `android:"arch_variant"` + // path to the rest of the toolchain srcs, relative to the top of the toolchain source + Toolchain_srcs []string `android:"arch_variant"` } type toolchainLibraryDecorator struct { @@ -82,16 +89,21 @@ func initToolchainLibrary(module *Module, library *libraryDecorator) android.Mod func rustSetToolchainSource(ctx android.LoadHookContext) { if toolchainLib, ok := ctx.Module().(*Module).compiler.(*toolchainLibraryDecorator); ok { - prefix := "linux-x86/" + GetRustPrebuiltVersion(ctx) - newSrcs := []string{path.Join(prefix, android.String(toolchainLib.Properties.Toolchain_src))} + prefix := filepath.Join(config.HostPrebuiltTag(ctx.Config()), GetRustPrebuiltVersion(ctx)) + versionedCrateRoot := path.Join(prefix, android.String(toolchainLib.Properties.Toolchain_crate_root)) + versionedSrcs := make([]string, len(toolchainLib.Properties.Toolchain_srcs)) + for i, src := range toolchainLib.Properties.Toolchain_srcs { + versionedSrcs[i] = path.Join(prefix, src) + } type props struct { - Srcs []string + Crate_root *string + Srcs []string } p := &props{} - p.Srcs = newSrcs + p.Crate_root = &versionedCrateRoot + p.Srcs = versionedSrcs ctx.AppendProperties(p) - } else { ctx.ModuleErrorf("Called rustSetToolchainSource on a non-Rust Module.") } @@ -101,3 +113,47 @@ func rustSetToolchainSource(ctx android.LoadHookContext) { func GetRustPrebuiltVersion(ctx android.LoadHookContext) string { return ctx.AConfig().GetenvWithDefault("RUST_PREBUILTS_VERSION", config.RustDefaultVersion) } + +type toolchainRustcPrebuiltProperties struct { + // path to rustc prebuilt, relative to the top of the toolchain source + Toolchain_prebuilt_src *string + // path to deps, relative to the top of the toolchain source + Toolchain_deps []string + // path to deps, relative to module directory + Deps []string +} + +func rustToolchainRustcPrebuiltFactory() android.Module { + module := android.NewPrebuiltBuildTool() + module.AddProperties(&toolchainRustcPrebuiltProperties{}) + android.AddLoadHook(module, func(ctx android.LoadHookContext) { + var toolchainProps *toolchainRustcPrebuiltProperties + for _, p := range ctx.Module().GetProperties() { + toolchainProperties, ok := p.(*toolchainRustcPrebuiltProperties) + if ok { + toolchainProps = toolchainProperties + } + } + + if toolchainProps.Toolchain_prebuilt_src == nil { + ctx.PropertyErrorf("toolchain_prebuilt_src", "must set path to rustc prebuilt") + } + + prefix := filepath.Join(config.HostPrebuiltTag(ctx.Config()), GetRustPrebuiltVersion(ctx)) + deps := make([]string, 0, len(toolchainProps.Toolchain_deps)+len(toolchainProps.Deps)) + for _, d := range toolchainProps.Toolchain_deps { + deps = append(deps, path.Join(prefix, d)) + } + deps = append(deps, toolchainProps.Deps...) + + props := struct { + Src *string + Deps []string + }{ + Src: proptools.StringPtr(path.Join(prefix, *toolchainProps.Toolchain_prebuilt_src)), + Deps: deps, + } + ctx.AppendProperties(&props) + }) + return module +} diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go index 387d17043..621a7246c 100644 --- a/rust/vendor_snapshot_test.go +++ b/rust/vendor_snapshot_test.go @@ -1051,7 +1051,7 @@ func TestVendorSnapshotUse(t *testing.T) { ctx := testRustVndkFsVersions(t, "", mockFS, "30", "current", "31") // libclient uses libvndk.vndk.30.arm64, libvendor.vendor_static.30.arm64, libvendor_without_snapshot - libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("rustLink").Args["linkFlags"] + libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("rustc").RuleParams.Command for _, input := range [][]string{ []string{sharedVariant, "libvndk.vndk.30.arm64"}, []string{staticVariant, "libvendor.vendor_static.30.arm64"}, @@ -1063,7 +1063,7 @@ func TestVendorSnapshotUse(t *testing.T) { } } - libclientAndroidMkSharedLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkSharedLibs + libclientAndroidMkSharedLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).transitiveAndroidMkSharedLibs.ToList() if g, w := libclientAndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "lib64", "liblog.vendor", "libc.vendor", "libm.vendor", "libdl.vendor"}; !reflect.DeepEqual(g, w) { t.Errorf("wanted libclient AndroidMkSharedLibs %q, got %q", w, g) } @@ -1078,7 +1078,7 @@ func TestVendorSnapshotUse(t *testing.T) { t.Errorf("wanted libclient libclientAndroidMkDylibs %q, got %q", w, libclientAndroidMkDylibs) } - libclient32AndroidMkSharedLibs := ctx.ModuleForTests("libclient", shared32Variant).Module().(*Module).Properties.AndroidMkSharedLibs + libclient32AndroidMkSharedLibs := ctx.ModuleForTests("libclient", shared32Variant).Module().(*Module).transitiveAndroidMkSharedLibs.ToList() if g, w := libclient32AndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "lib32", "liblog.vendor", "libc.vendor", "libm.vendor", "libdl.vendor"}; !reflect.DeepEqual(g, w) { t.Errorf("wanted libclient32 AndroidMkSharedLibs %q, got %q", w, g) } @@ -1119,7 +1119,7 @@ func TestVendorSnapshotUse(t *testing.T) { t.Errorf("Unexpected rust rlib name in AndroidMk: %q, expected: %q\n", rustVendorBinMkDylibName, expectedRustVendorSnapshotName) } - binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("rustLink").Args["linkFlags"] + binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("rustc").RuleParams.Command libVndkStaticOutputPaths := cc.GetOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.30.arm64"}) if !strings.Contains(binWithoutSnapshotLdFlags, libVndkStaticOutputPaths[0].String()) { t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v", diff --git a/scripts/check_prebuilt_presigned_apk.py b/scripts/check_prebuilt_presigned_apk.py new file mode 100755 index 000000000..abedfb770 --- /dev/null +++ b/scripts/check_prebuilt_presigned_apk.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 + +import subprocess +import argparse +import re +import sys +import zipfile + +def check_target_sdk_less_than_30(args): + if not args.aapt2: + sys.exit('--aapt2 is required') + regex = re.compile(r"targetSdkVersion: *'([0-9]+)'") + output = subprocess.check_output([args.aapt2, "dump", "badging", args.apk], text=True) + targetSdkVersion = None + for line in output.splitlines(): + match = regex.fullmatch(line.strip()) + if match: + targetSdkVersion = int(match.group(1)) + break + + if targetSdkVersion is None or targetSdkVersion >= 30: + sys.exit(args.apk + ": Prebuilt, presigned apks with targetSdkVersion >= 30 (or a codename targetSdkVersion) must set preprocessed: true in the Android.bp definition (because they must be signed with signature v2, and the build system would wreck that signature otherwise)") + +def has_preprocessed_issues(args, *, fail=False): + if not args.zipalign: + sys.exit('--zipalign is required') + ret = subprocess.run([args.zipalign, '-c', '-p', '4', args.apk], stdout=subprocess.DEVNULL).returncode + if ret != 0: + if fail: + sys.exit(args.apk + ': Improper zip alignment') + return True + + with zipfile.ZipFile(args.apk) as zf: + for info in zf.infolist(): + if info.filename.startswith('lib/') and info.filename.endswith('.so') and info.compress_type != zipfile.ZIP_STORED: + if fail: + sys.exit(args.apk + ': Contains compressed JNI libraries') + return True + # It's ok for non-privileged apps to have compressed dex files, see go/gms-uncompressed-jni-slides + if args.privileged: + if info.filename.endswith('.dex') and info.compress_type != zipfile.ZIP_STORED: + if fail: + sys.exit(args.apk + ': Contains compressed dex files and is privileged') + return True + return False + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--aapt2', help = "the path to the aapt2 executable") + parser.add_argument('--zipalign', help = "the path to the zipalign executable") + parser.add_argument('--skip-preprocessed-apk-checks', action = 'store_true', help = "the value of the soong property with the same name") + parser.add_argument('--preprocessed', action = 'store_true', help = "the value of the soong property with the same name") + parser.add_argument('--privileged', action = 'store_true', help = "the value of the soong property with the same name") + parser.add_argument('apk', help = "the apk to check") + parser.add_argument('stampfile', help = "a file to touch if successful") + args = parser.parse_args() + + if not args.preprocessed: + check_target_sdk_less_than_30(args) + elif args.skip_preprocessed_apk_checks: + if not has_preprocessed_issues(args): + sys.exit('This module sets `skip_preprocessed_apk_checks: true`, but does not actually have any issues. Please remove `skip_preprocessed_apk_checks`.') + else: + has_preprocessed_issues(args, fail=True) + + subprocess.check_call(["touch", args.stampfile]) + +if __name__ == "__main__": + main() diff --git a/scripts/conv_linker_config.py b/scripts/conv_linker_config.py index 3ac1b7e5e..c6aa3d0dc 100644 --- a/scripts/conv_linker_config.py +++ b/scripts/conv_linker_config.py @@ -120,6 +120,37 @@ def Merge(args): f.write(pb.SerializeToString()) +def Validate(args): + if os.path.isdir(args.input): + config_file = os.path.join(args.input, 'etc/linker.config.pb') + if os.path.exists(config_file): + args.input = config_file + Validate(args) + # OK if there's no linker config file. + return + + if not os.path.isfile(args.input): + sys.exit(f"{args.input} is not a file") + + pb = linker_config_pb2.LinkerConfig() + with open(args.input, 'rb') as f: + pb.ParseFromString(f.read()) + + if args.type == 'apex': + # Shouldn't use provideLibs/requireLibs in APEX linker.config.pb + if getattr(pb, 'provideLibs'): + sys.exit(f'{args.input}: provideLibs is set. Use provideSharedLibs in apex_manifest') + if getattr(pb, 'requireLibs'): + sys.exit(f'{args.input}: requireLibs is set. Use requireSharedLibs in apex_manifest') + elif args.type == 'system': + if getattr(pb, 'visible'): + sys.exit(f'{args.input}: do not use visible, which is for APEX') + if getattr(pb, 'permittedPaths'): + sys.exit(f'{args.input}: do not use permittedPaths, which is for APEX') + else: + sys.exit(f'Unknown type: {args.type}') + + def GetArgParser(): parser = argparse.ArgumentParser() subparsers = parser.add_subparsers() @@ -227,6 +258,18 @@ def GetArgParser(): help='Linker configuration files to merge.') append.set_defaults(func=Merge) + validate = subparsers.add_parser('validate', help='Validate configuration') + validate.add_argument( + '--type', + required=True, + choices=['apex', 'system'], + help='Type of linker configuration') + validate.add_argument( + 'input', + help='Input can be a directory which has etc/linker.config.pb or a path' + ' to the linker config file') + validate.set_defaults(func=Validate) + return parser diff --git a/sdk/systemserverclasspath_fragment_sdk_test.go b/sdk/systemserverclasspath_fragment_sdk_test.go index 7ccc11413..3c0b8ae01 100644 --- a/sdk/systemserverclasspath_fragment_sdk_test.go +++ b/sdk/systemserverclasspath_fragment_sdk_test.go @@ -86,6 +86,98 @@ func testSnapshotWithSystemServerClasspathFragment(t *testing.T, sdk string, tar ) } +func TestSnapshotWithPartialSystemServerClasspathFragment(t *testing.T) { + commonSdk := ` + apex { + name: "myapex", + key: "myapex.key", + min_sdk_version: "Tiramisu", + systemserverclasspath_fragments: ["mysystemserverclasspathfragment"], + } + systemserverclasspath_fragment { + name: "mysystemserverclasspathfragment", + apex_available: ["myapex"], + contents: [ + "mysdklibrary", + "mysdklibrary-future", + ], + } + java_sdk_library { + name: "mysdklibrary", + apex_available: ["myapex"], + srcs: ["Test.java"], + min_sdk_version: "33", // Tiramisu + } + java_sdk_library { + name: "mysdklibrary-future", + apex_available: ["myapex"], + srcs: ["Test.java"], + min_sdk_version: "34", // UpsideDownCake + } + sdk { + name: "mysdk", + apexes: ["myapex"], + } + ` + + result := android.GroupFixturePreparers( + prepareForSdkTestWithJava, + java.PrepareForTestWithJavaDefaultModules, + java.PrepareForTestWithJavaSdkLibraryFiles, + java.FixtureWithLastReleaseApis("mysdklibrary", "mysdklibrary-future"), + dexpreopt.FixtureSetApexSystemServerJars("myapex:mysdklibrary", "myapex:mysdklibrary-future"), + android.FixtureModifyEnv(func(env map[string]string) { + // targeting Tiramisu here means that we won't export mysdklibrary-future + env["SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE"] = "Tiramisu" + }), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.Platform_version_active_codenames = []string{"UpsideDownCake"} + }), + prepareForSdkTestWithApex, + android.FixtureWithRootAndroidBp(commonSdk), + ).RunTest(t) + + CheckSnapshot(t, result, "mysdk", "", checkAndroidBpContents( + `// This is auto-generated. DO NOT EDIT. + +java_sdk_library_import { + name: "mysdklibrary", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["myapex"], + shared_library: true, + public: { + jars: ["sdk_library/public/mysdklibrary-stubs.jar"], + stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"], + current_api: "sdk_library/public/mysdklibrary.txt", + removed_api: "sdk_library/public/mysdklibrary-removed.txt", + sdk_version: "current", + }, + system: { + jars: ["sdk_library/system/mysdklibrary-stubs.jar"], + stub_srcs: ["sdk_library/system/mysdklibrary_stub_sources"], + current_api: "sdk_library/system/mysdklibrary.txt", + removed_api: "sdk_library/system/mysdklibrary-removed.txt", + sdk_version: "system_current", + }, + test: { + jars: ["sdk_library/test/mysdklibrary-stubs.jar"], + stub_srcs: ["sdk_library/test/mysdklibrary_stub_sources"], + current_api: "sdk_library/test/mysdklibrary.txt", + removed_api: "sdk_library/test/mysdklibrary-removed.txt", + sdk_version: "test_current", + }, +} + +prebuilt_systemserverclasspath_fragment { + name: "mysystemserverclasspathfragment", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["myapex"], + contents: ["mysdklibrary"], +} `)) +} + func TestSnapshotWithEmptySystemServerClasspathFragment(t *testing.T) { commonSdk := ` apex { diff --git a/sh/Android.bp b/sh/Android.bp index f9198dc4f..1deedc731 100644 --- a/sh/Android.bp +++ b/sh/Android.bp @@ -10,6 +10,7 @@ bootstrap_go_package { "soong", "soong-android", "soong-cc", + "soong-java", "soong-tradefed", ], srcs: [ diff --git a/sh/sh_binary.go b/sh/sh_binary.go index d2eede65d..79a885fa9 100644 --- a/sh/sh_binary.go +++ b/sh/sh_binary.go @@ -143,6 +143,9 @@ type TestProperties struct { // Only available for host sh_test modules. Data_device_libs []string `android:"path,arch_variant"` + // list of java modules that provide data that should be installed alongside the test. + Java_data []string + // Install the test into a folder named for the module in all test suites. Per_testcase_directory *bool @@ -187,6 +190,15 @@ func (s *ShBinary) OutputFile() android.OutputPath { return s.outputFilePath } +func (s *ShBinary) OutputFiles(tag string) (android.Paths, error) { + switch tag { + case "": + return android.Paths{s.outputFilePath}, nil + default: + return nil, fmt.Errorf("unsupported module reference tag %q", tag) + } +} + func (s *ShBinary) SubDir() string { return proptools.String(s.properties.Sub_dir) } @@ -307,6 +319,7 @@ var ( shTestDataLibsTag = dependencyTag{name: "dataLibs"} shTestDataDeviceBinsTag = dependencyTag{name: "dataDeviceBins"} shTestDataDeviceLibsTag = dependencyTag{name: "dataDeviceLibs"} + shTestJavaDataTag = dependencyTag{name: "javaData"} ) var sharedLibVariations = []blueprint.Variation{{Mutator: "link", Variation: "shared"}} @@ -322,6 +335,10 @@ func (s *ShTest) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddFarVariationDependencies(deviceVariations, shTestDataDeviceBinsTag, s.testProperties.Data_device_bins...) ctx.AddFarVariationDependencies(append(deviceVariations, sharedLibVariations...), shTestDataDeviceLibsTag, s.testProperties.Data_device_libs...) + + javaDataVariation := []blueprint.Variation{{"arch", android.Common.String()}} + ctx.AddVariationDependencies(javaDataVariation, shTestJavaDataTag, s.testProperties.Java_data...) + } else if ctx.Target().Os.Class != android.Host { if len(s.testProperties.Data_device_bins) > 0 { ctx.PropertyErrorf("data_device_bins", "only available for host modules") @@ -329,6 +346,9 @@ func (s *ShTest) DepsMutator(ctx android.BottomUpMutatorContext) { if len(s.testProperties.Data_device_libs) > 0 { ctx.PropertyErrorf("data_device_libs", "only available for host modules") } + if len(s.testProperties.Java_data) > 0 { + ctx.PropertyErrorf("Java_data", "only available for host modules") + } } } @@ -361,7 +381,13 @@ func (s *ShTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { } s.installedFile = ctx.InstallExecutable(s.installDir, s.outputFilePath.Base(), s.outputFilePath) - s.data = android.PathsForModuleSrc(ctx, s.testProperties.Data) + expandedData := android.PathsForModuleSrc(ctx, s.testProperties.Data) + + // Emulate the data property for java_data dependencies. + for _, javaData := range ctx.GetDirectDepsWithTag(shTestJavaDataTag) { + expandedData = append(expandedData, android.OutputFilesForModule(ctx, javaData, "")...) + } + s.data = expandedData var configs []tradefed.Config if Bool(s.testProperties.Require_root) { @@ -502,7 +528,7 @@ func ShBinaryHostFactory() android.Module { // sh_test defines a shell script based test module. func ShTestFactory() android.Module { module := &ShTest{} - initShBinaryModule(&module.ShBinary, false) + initShBinaryModule(&module.ShBinary, true) module.AddProperties(&module.testProperties) android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst) @@ -512,7 +538,7 @@ func ShTestFactory() android.Module { // sh_test_host defines a shell script based test module that runs on a host. func ShTestHostFactory() android.Module { module := &ShTest{} - initShBinaryModule(&module.ShBinary, false) + initShBinaryModule(&module.ShBinary, true) module.AddProperties(&module.testProperties) // Default sh_test_host to unit_tests = true if module.testProperties.Test_options.Unit_test == nil { @@ -548,7 +574,16 @@ type bazelShBinaryAttributes struct { // visibility } -func (m *ShBinary) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +type bazelShTestAttributes struct { + Srcs bazel.LabelListAttribute + Data bazel.LabelListAttribute + Tags bazel.StringListAttribute + Test_config *string + Test_config_template *string + Auto_gen_config *bool +} + +func (m *ShBinary) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { srcs := bazel.MakeLabelListAttribute( android.BazelLabelForModuleSrc(ctx, []string{*m.properties.Src})) @@ -576,6 +611,41 @@ func (m *ShBinary) ConvertWithBp2build(ctx android.TopDownMutatorContext) { ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs) } +func (m *ShTest) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { + srcs := bazel.MakeLabelListAttribute( + android.BazelLabelForModuleSrc(ctx, []string{*m.properties.Src})) + + combinedData := append(m.testProperties.Data, m.testProperties.Data_bins...) + combinedData = append(combinedData, m.testProperties.Data_libs...) + + data := bazel.MakeLabelListAttribute( + android.BazelLabelForModuleSrc(ctx, combinedData)) + + tags := bazel.MakeStringListAttribute( + m.testProperties.Test_options.Tags) + + test_config := m.testProperties.Test_config + + test_config_template := m.testProperties.Test_config_template + + auto_gen_config := m.testProperties.Auto_gen_config + + attrs := &bazelShTestAttributes{ + Srcs: srcs, + Data: data, + Tags: tags, + Test_config: test_config, + Test_config_template: test_config_template, + Auto_gen_config: auto_gen_config, + } + + props := bazel.BazelTargetModuleProperties{ + Rule_class: "sh_test", + Bzl_load_location: "//build/bazel/rules:sh_test.bzl", + } + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs) +} + var Bool = proptools.Bool var _ snapshot.RelativeInstallPath = (*ShBinary)(nil) diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go index 89b8126f1..5fcb58d20 100644 --- a/sh/sh_binary_test.go +++ b/sh/sh_binary_test.go @@ -9,6 +9,7 @@ import ( "android/soong/android" "android/soong/cc" + "android/soong/java" ) func TestMain(m *testing.M) { @@ -17,6 +18,7 @@ func TestMain(m *testing.M) { var prepareForShTest = android.GroupFixturePreparers( cc.PrepareForTestWithCcBuildComponents, + java.PrepareForTestWithJavaDefaultModules, PrepareForTestWithShBuildComponents, android.FixtureMergeMockFs(android.MockFS{ "test.sh": nil, @@ -255,3 +257,39 @@ func TestShTestHost_dataDeviceModulesAutogenTradefedConfig(t *testing.T) { t.Errorf("foo extraConfings %v does not contain %q", autogen.Args["extraConfigs"], expectedBinAutogenConfig) } } + +func TestShTestHost_javaData(t *testing.T) { + ctx, config := testShBinary(t, ` + sh_test_host { + name: "foo", + src: "test.sh", + filename: "test.sh", + data: [ + "testdata/data1", + "testdata/sub/data2", + ], + java_data: [ + "javalib", + ], + } + + java_library_host { + name: "javalib", + srcs: [], + } + `) + buildOS := ctx.Config().BuildOS.String() + mod := ctx.ModuleForTests("foo", buildOS+"_x86_64").Module().(*ShTest) + if !mod.Host() { + t.Errorf("host bit is not set for a sh_test_host module.") + } + expectedData := []string{ + ":testdata/data1", + ":testdata/sub/data2", + "out/soong/.intermediates/javalib/" + buildOS + "_common/combined/:javalib.jar", + } + + entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0] + actualData := entries.EntryMap["LOCAL_TEST_DATA"] + android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData) +} diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go index a2c0fb731..d16bf32f9 100644 --- a/sysprop/sysprop_library.go +++ b/sysprop/sysprop_library.go @@ -591,7 +591,7 @@ func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) { } // TODO(b/240463568): Additional properties will be added for API validation -func (m *syspropLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (m *syspropLibrary) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { labels := cc.SyspropLibraryLabels{ SyspropLibraryLabel: m.BaseModuleName(), SharedLibraryLabel: m.CcImplementationModuleName(), diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh index 090114b97..8a64a56b9 100755 --- a/tests/bp2build_bazel_test.sh +++ b/tests/bp2build_bazel_test.sh @@ -407,38 +407,6 @@ EOF fi } -# Smoke test to verify api_bp2build worksapce does not contain any errors -function test_api_bp2build_empty_build() { - setup - run_soong api_bp2build - run_bazel build --config=android --config=api_bp2build //:empty -} - -# Verify that an *_api_contribution target can refer to an api file from -# another Bazel package. -function test_api_export_from_another_bazel_package() { - setup - # Parent dir Android.bp - mkdir -p foo - cat > foo/Android.bp << 'EOF' -cc_library { - name: "libfoo", - stubs: { - symbol_file: "api/libfoo.map.txt", - }, -} -EOF - # Child dir Android.bp - mkdir -p foo/api - cat > foo/api/Android.bp << 'EOF' -package{} -EOF - touch foo/api/libfoo.map.txt - # Run test - run_soong api_bp2build - run_bazel build --config=android --config=api_bp2build //foo:libfoo.contribution -} - function test_bazel_standalone_output_paths_contain_product_name { setup mkdir -p a diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh index 9801a8e4f..73fbeabbd 100755 --- a/tests/sbom_test.sh +++ b/tests/sbom_test.sh @@ -47,13 +47,10 @@ function run_soong { } function diff_files { - file_list_file="$1"; shift - files_in_spdx_file="$1"; shift - partition_name="$1"; shift - exclude= - if [ -v 'diff_excludes[$partition_name]' ]; then - exclude=${diff_excludes[$partition_name]} - fi + local file_list_file="$1"; shift + local files_in_spdx_file="$1"; shift + local partition_name="$1"; shift + local exclude="$1"; shift diff "$file_list_file" "$files_in_spdx_file" $exclude if [ $? != "0" ]; then @@ -84,48 +81,6 @@ function test_sbom_aosp_cf_x86_64_phone { dump_erofs=$out_dir/host/linux-x86/bin/dump.erofs lz4=$out_dir/host/linux-x86/bin/lz4 - declare -A diff_excludes - diff_excludes[vendor]="\ - -I /vendor/lib64/libkeystore2_crypto.so \ - -I /vendor/lib64/libvsock_utils.so" - diff_excludes[system]="\ - -I /system/bin/assemble_cvd \ - -I /system/bin/console_forwarder \ - -I /system/bin/kernel_log_monitor \ - -I /system/bin/logcat_receiver \ - -I /system/bin/mkenvimage_slim \ - -I /system/bin/run_cvd \ - -I /system/bin/simg2img \ - -I /system/bin/log_tee \ - -I /system/lib64/android.hardware.confirmationui@1.0.so \ - -I /system/lib64/android.hardware.confirmationui-V1-ndk.so \ - -I /system/lib64/android.hardware.keymaster@4.1.so \ - -I /system/lib64/android.hardware.security.rkp-V3-ndk.so \ - -I /system/lib64/android.hardware.security.sharedsecret-V1-ndk.so \ - -I /system/lib64/android.security.compat-ndk.so \ - -I /system/lib64/libcuttlefish_allocd_utils.so \ - -I /system/lib64/libcuttlefish_device_config_proto.so \ - -I /system/lib64/libcuttlefish_device_config.so \ - -I /system/lib64/libcuttlefish_fs.so \ - -I /system/lib64/libcuttlefish_kernel_log_monitor_utils.so \ - -I /system/lib64/libcuttlefish_utils.so \ - -I /system/lib64/libfruit.so \ - -I /system/lib64/libgflags.so \ - -I /system/lib64/libkeymaster4_1support.so \ - -I /system/lib64/libkeymaster4support.so \ - -I /system/lib64/libkeymint.so \ - -I /system/lib64/libkeystore2_aaid.so \ - -I /system/lib64/libkeystore2_apc_compat.so \ - -I /system/lib64/libkeystore2_crypto.so \ - -I /system/lib64/libkeystore-attestation-application-id.so \ - -I /system/lib64/libkm_compat_service.so \ - -I /system/lib64/libkm_compat.so \ - -I /system/lib64/vndk-29 \ - -I /system/lib64/vndk-sp-29 \ - -I /system/lib/vndk-29 \ - -I /system/lib/vndk-sp-29 \ - -I /system/usr/icu" - # Example output of dump.erofs is as below, and the data used in the test start # at line 11. Column 1 is inode id, column 2 is inode type and column 3 is name. # Each line is captured in variable "entry", awk is used to get type and name. @@ -197,7 +152,7 @@ function test_sbom_aosp_cf_x86_64_phone { sort -n -o "$files_in_spdx_file" "$files_in_spdx_file" echo ============ Diffing files in $f and SBOM - diff_files "$file_list_file" "$files_in_spdx_file" "$partition_name" + diff_files "$file_list_file" "$files_in_spdx_file" "$partition_name" "" done RAMDISK_IMAGES="$product_out/ramdisk.img" @@ -215,7 +170,7 @@ function test_sbom_aosp_cf_x86_64_phone { grep "FileName: /${partition_name}/" $product_out/sbom.spdx | sed 's/^FileName: //' | sort -n > "$files_in_spdx_file" echo ============ Diffing files in $f and SBOM - diff_files "$file_list_file" "$files_in_spdx_file" "$partition_name" + diff_files "$file_list_file" "$files_in_spdx_file" "$partition_name" "" done verify_package_verification_code "$product_out/sbom.spdx" diff --git a/third_party/zip/android.go b/third_party/zip/android.go index 0f41f6200..b97215689 100644 --- a/third_party/zip/android.go +++ b/third_party/zip/android.go @@ -56,6 +56,11 @@ func (w *Writer) CopyFrom(orig *File, newName string) error { if err := writeHeader(w.cw, fh); err != nil { return err } + + // Strip the extras again in case writeHeader added the local file header extras that are incorrect for the + // central directory. + fh.Extra = stripExtras(fh.Extra) + dataOffset, err := orig.DataOffset() if err != nil { return err diff --git a/tradefed/autogen_bazel.go b/tradefed/autogen_bazel.go index 9575f7aef..cc16176c8 100644 --- a/tradefed/autogen_bazel.go +++ b/tradefed/autogen_bazel.go @@ -39,7 +39,8 @@ const ( ) type TestConfigAttributes struct { - Test_config *bazel.Label + Test_config *bazel.Label + Dynamic_config *bazel.Label Auto_generate_test_config *bool Template_test_config *bazel.Label @@ -48,7 +49,7 @@ type TestConfigAttributes struct { } func GetTestConfigAttributes( - ctx android.TopDownMutatorContext, + ctx android.Bp2buildMutatorContext, testConfig *string, extraTestConfigs []string, autoGenConfig *bool, @@ -58,6 +59,11 @@ func GetTestConfigAttributes( templateInstallBase *string) TestConfigAttributes { attrs := TestConfigAttributes{} + + dynamicConfig := "DynamicConfig.xml" + c, _ := android.BazelStringOrLabelFromProp(ctx, &dynamicConfig) + attrs.Dynamic_config = c.Value + attrs.Test_config = GetTestConfig(ctx, testConfig) // do not generate a test config if // 1) test config already found @@ -87,7 +93,7 @@ func GetTestConfigAttributes( } func GetTestConfig( - ctx android.TopDownMutatorContext, + ctx android.Bp2buildMutatorContext, testConfig *string, ) *bazel.Label { diff --git a/ui/build/config.go b/ui/build/config.go index 5d1505abc..084d28d83 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -70,7 +70,6 @@ type configImpl struct { checkbuild bool dist bool jsonModuleGraph bool - apiBp2build bool // Generate BUILD files for Soong modules that contribute APIs bp2build bool queryview bool reportMkMetrics bool // Collect and report mk2bp migration progress metrics. @@ -869,8 +868,6 @@ func (c *configImpl) parseArgs(ctx Context, args []string) { c.jsonModuleGraph = true } else if arg == "bp2build" { c.bp2build = true - } else if arg == "api_bp2build" { - c.apiBp2build = true } else if arg == "queryview" { c.queryview = true } else if arg == "soong_docs" { @@ -970,7 +967,7 @@ func (c *configImpl) SoongBuildInvocationNeeded() bool { return true } - if !c.JsonModuleGraph() && !c.Bp2Build() && !c.Queryview() && !c.SoongDocs() && !c.ApiBp2build() { + if !c.JsonModuleGraph() && !c.Bp2Build() && !c.Queryview() && !c.SoongDocs() { // Command line was empty, the default Ninja target is built return true } @@ -1068,10 +1065,6 @@ func (c *configImpl) QueryviewMarkerFile() string { return shared.JoinPath(c.SoongOutDir(), "queryview.marker") } -func (c *configImpl) ApiBp2buildMarkerFile() string { - return shared.JoinPath(c.SoongOutDir(), "api_bp2build.marker") -} - func (c *configImpl) ModuleGraphFile() string { return shared.JoinPath(c.SoongOutDir(), "module-graph.json") } @@ -1113,10 +1106,6 @@ func (c *configImpl) Bp2Build() bool { return c.bp2build } -func (c *configImpl) ApiBp2build() bool { - return c.apiBp2build -} - func (c *configImpl) Queryview() bool { return c.queryview } @@ -1308,7 +1297,7 @@ func (c *configImpl) canSupportRBE() bool { func (c *configImpl) UseRBE() bool { // These alternate modes of running Soong do not use RBE / reclient. - if c.Bp2Build() || c.Queryview() || c.ApiBp2build() || c.JsonModuleGraph() { + if c.Bp2Build() || c.Queryview() || c.JsonModuleGraph() { return false } diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go index 681ca776f..efe747819 100644 --- a/ui/build/dumpvars.go +++ b/ui/build/dumpvars.go @@ -247,7 +247,6 @@ func runMakeProductConfig(ctx Context, config Config) { "DEFAULT_ERROR_BUILD_MODULE_TYPES", "BUILD_BROKEN_PREBUILT_ELF_FILES", "BUILD_BROKEN_TREBLE_SYSPROP_NEVERALLOW", - "BUILD_BROKEN_VENDOR_SEAPP_USES_COREDOMAIN", "BUILD_BROKEN_USES_BUILD_COPY_HEADERS", "BUILD_BROKEN_USES_BUILD_EXECUTABLE", "BUILD_BROKEN_USES_BUILD_FUZZ_TEST", diff --git a/ui/build/ninja.go b/ui/build/ninja.go index 61aaad86b..b69e938f8 100644 --- a/ui/build/ninja.go +++ b/ui/build/ninja.go @@ -194,6 +194,10 @@ func runNinjaForBuild(ctx Context, config Config) { // LLVM compiler wrapper options "TOOLCHAIN_RUSAGE_OUTPUT", + + // We don't want this build broken flag to cause reanalysis, so allow it through to the + // actions. + "BUILD_BROKEN_INCORRECT_PARTITION_IMAGES", }, config.BuildBrokenNinjaUsesEnvVars()...)...) } diff --git a/ui/build/soong.go b/ui/build/soong.go index b8543d929..44c20a013 100644 --- a/ui/build/soong.go +++ b/ui/build/soong.go @@ -41,7 +41,6 @@ const ( bp2buildWorkspaceTag = "bp2build_workspace" jsonModuleGraphTag = "modulegraph" queryviewTag = "queryview" - apiBp2buildTag = "api_bp2build" soongDocsTag = "soong_docs" // bootstrapEpoch is used to determine if an incremental build is incompatible with the current @@ -264,7 +263,6 @@ func bootstrapGlobFileList(config Config) []string { config.NamedGlobFile(bp2buildFilesTag), config.NamedGlobFile(jsonModuleGraphTag), config.NamedGlobFile(queryviewTag), - config.NamedGlobFile(apiBp2buildTag), config.NamedGlobFile(soongDocsTag), } } @@ -305,9 +303,6 @@ func bootstrapBlueprint(ctx Context, config Config) { } queryviewDir := filepath.Join(config.SoongOutDir(), "queryview") - // The BUILD files will be generated in out/soong/.api_bp2build (no symlinks to src files) - // The final workspace will be generated in out/soong/api_bp2build - apiBp2buildDir := filepath.Join(config.SoongOutDir(), ".api_bp2build") pbfs := []PrimaryBuilderFactory{ { @@ -355,15 +350,6 @@ func bootstrapBlueprint(ctx Context, config Config) { ), }, { - name: apiBp2buildTag, - description: fmt.Sprintf("generating BUILD files for API contributions at %s", apiBp2buildDir), - config: config, - output: config.ApiBp2buildMarkerFile(), - specificArgs: append(baseArgs, - "--bazel_api_bp2build_dir", apiBp2buildDir, - ), - }, - { name: soongDocsTag, description: fmt.Sprintf("generating Soong docs at %s", config.SoongDocsHtml()), config: config, @@ -533,10 +519,6 @@ func runSoong(ctx Context, config Config) { checkEnvironmentFile(ctx, soongBuildEnv, config.UsedEnvFile(queryviewTag)) } - if config.ApiBp2build() { - checkEnvironmentFile(ctx, soongBuildEnv, config.UsedEnvFile(apiBp2buildTag)) - } - if config.SoongDocs() { checkEnvironmentFile(ctx, soongBuildEnv, config.UsedEnvFile(soongDocsTag)) } @@ -608,10 +590,6 @@ func runSoong(ctx Context, config Config) { targets = append(targets, config.QueryviewMarkerFile()) } - if config.ApiBp2build() { - targets = append(targets, config.ApiBp2buildMarkerFile()) - } - if config.SoongDocs() { targets = append(targets, config.SoongDocsHtml()) } diff --git a/ui/status/ninja.go b/ui/status/ninja.go index fb760ac8f..7b25d50aa 100644 --- a/ui/status/ninja.go +++ b/ui/status/ninja.go @@ -40,10 +40,11 @@ func NewNinjaReader(ctx logger.Logger, status ToolStatus, fifo string) *NinjaRea } n := &NinjaReader{ - status: status, - fifo: fifo, - done: make(chan bool), - cancel: make(chan bool), + status: status, + fifo: fifo, + forceClose: make(chan bool), + done: make(chan bool), + cancelOpen: make(chan bool), } go n.run() @@ -52,10 +53,11 @@ func NewNinjaReader(ctx logger.Logger, status ToolStatus, fifo string) *NinjaRea } type NinjaReader struct { - status ToolStatus - fifo string - done chan bool - cancel chan bool + status ToolStatus + fifo string + forceClose chan bool + done chan bool + cancelOpen chan bool } const NINJA_READER_CLOSE_TIMEOUT = 5 * time.Second @@ -63,18 +65,34 @@ const NINJA_READER_CLOSE_TIMEOUT = 5 * time.Second // Close waits for NinjaReader to finish reading from the fifo, or 5 seconds. func (n *NinjaReader) Close() { // Signal the goroutine to stop if it is blocking opening the fifo. - close(n.cancel) + close(n.cancelOpen) + // Ninja should already have exited or been killed, wait 5 seconds for the FIFO to be closed and any + // remaining messages to be processed through the NinjaReader.run goroutine. timeoutCh := time.After(NINJA_READER_CLOSE_TIMEOUT) + select { + case <-n.done: + return + case <-timeoutCh: + // Channel is not closed yet + } + + n.status.Error(fmt.Sprintf("ninja fifo didn't finish after %s", NINJA_READER_CLOSE_TIMEOUT.String())) + + // Force close the reader even if the FIFO didn't close. + close(n.forceClose) + // Wait again for the reader thread to acknowledge the close before giving up and assuming it isn't going + // to send anything else. + timeoutCh = time.After(NINJA_READER_CLOSE_TIMEOUT) select { case <-n.done: - // Nothing + return case <-timeoutCh: - n.status.Error(fmt.Sprintf("ninja fifo didn't finish after %s", NINJA_READER_CLOSE_TIMEOUT.String())) + // Channel is not closed yet } - return + n.status.Verbose(fmt.Sprintf("ninja fifo didn't finish even after force closing after %s", NINJA_READER_CLOSE_TIMEOUT.String())) } func (n *NinjaReader) run() { @@ -98,7 +116,7 @@ func (n *NinjaReader) run() { select { case f = <-fileCh: // Nothing - case <-n.cancel: + case <-n.cancelOpen: return } @@ -108,33 +126,58 @@ func (n *NinjaReader) run() { running := map[uint32]*Action{} - for { - size, err := readVarInt(r) - if err != nil { - if err != io.EOF { - n.status.Error(fmt.Sprintf("Got error reading from ninja: %s", err)) + msgChan := make(chan *ninja_frontend.Status) + + // Read from the ninja fifo and decode the protobuf in a goroutine so the main NinjaReader.run goroutine + // can listen + go func() { + defer close(msgChan) + for { + size, err := readVarInt(r) + if err != nil { + if err != io.EOF { + n.status.Error(fmt.Sprintf("Got error reading from ninja: %s", err)) + } + return } - return - } - buf := make([]byte, size) - _, err = io.ReadFull(r, buf) - if err != nil { - if err == io.EOF { - n.status.Print(fmt.Sprintf("Missing message of size %d from ninja\n", size)) - } else { - n.status.Error(fmt.Sprintf("Got error reading from ninja: %s", err)) + buf := make([]byte, size) + _, err = io.ReadFull(r, buf) + if err != nil { + if err == io.EOF { + n.status.Print(fmt.Sprintf("Missing message of size %d from ninja\n", size)) + } else { + n.status.Error(fmt.Sprintf("Got error reading from ninja: %s", err)) + } + return } - return + + msg := &ninja_frontend.Status{} + err = proto.Unmarshal(buf, msg) + if err != nil { + n.status.Print(fmt.Sprintf("Error reading message from ninja: %v", err)) + continue + } + + msgChan <- msg } + }() - msg := &ninja_frontend.Status{} - err = proto.Unmarshal(buf, msg) - if err != nil { - n.status.Print(fmt.Sprintf("Error reading message from ninja: %v", err)) - continue + for { + var msg *ninja_frontend.Status + var msgOk bool + select { + case <-n.forceClose: + // Close() has been called, but the reader goroutine didn't get EOF after 5 seconds + break + case msg, msgOk = <-msgChan: + // msg is ready or closed } + if !msgOk { + // msgChan is closed + break + } // Ignore msg.BuildStarted if msg.TotalEdges != nil { n.status.SetTotalActions(int(msg.TotalEdges.GetTotalEdges())) diff --git a/xml/xml.go b/xml/xml.go index 8c0c07282..65fe12a8e 100644 --- a/xml/xml.go +++ b/xml/xml.go @@ -145,8 +145,12 @@ type bazelPrebuiltEtcXmlAttributes struct { Schema *string } -func (p *prebuiltEtcXml) ConvertWithBp2build(ctx android.TopDownMutatorContext) { - baseAttrs := p.PrebuiltEtc.Bp2buildHelper(ctx) +func (p *prebuiltEtcXml) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { + baseAttrs, convertible := p.PrebuiltEtc.Bp2buildHelper(ctx) + + if !convertible { + return + } var schema *string if p.properties.Schema != nil { diff --git a/zip/cmd/main.go b/zip/cmd/main.go index 5231faec9..37537ab8b 100644 --- a/zip/cmd/main.go +++ b/zip/cmd/main.go @@ -174,6 +174,7 @@ func main() { traceFile := flags.String("trace", "", "write trace to file") sha256Checksum := flags.Bool("sha256", false, "add a zip header to each file containing its SHA256 digest") doNotWrite := flags.Bool("n", false, "Nothing is written to disk -- all other work happens") + quiet := flags.Bool("quiet", false, "do not print warnings to console") flags.Var(&rootPrefix{}, "P", "path prefix within the zip at which to place files") flags.Var(&listFiles{}, "l", "file containing list of files to zip") @@ -238,6 +239,7 @@ func main() { IgnoreMissingFiles: *ignoreMissingFiles, Sha256Checksum: *sha256Checksum, DoNotWrite: *doNotWrite, + Quiet: *quiet, }) if err != nil { fmt.Fprintln(os.Stderr, "error:", err.Error()) diff --git a/zip/zip.go b/zip/zip.go index 30a2ee762..f91a5f2cb 100644 --- a/zip/zip.go +++ b/zip/zip.go @@ -283,6 +283,7 @@ type ZipArgs struct { IgnoreMissingFiles bool Sha256Checksum bool DoNotWrite bool + Quiet bool Stderr io.Writer Filesystem pathtools.FileSystem @@ -340,7 +341,9 @@ func zipTo(args ZipArgs, w io.Writer) error { Err: os.ErrNotExist, } if args.IgnoreMissingFiles { - fmt.Fprintln(z.stderr, "warning:", err) + if !args.Quiet { + fmt.Fprintln(z.stderr, "warning:", err) + } } else { return err } @@ -357,7 +360,9 @@ func zipTo(args ZipArgs, w io.Writer) error { Err: os.ErrNotExist, } if args.IgnoreMissingFiles { - fmt.Fprintln(z.stderr, "warning:", err) + if !args.Quiet { + fmt.Fprintln(z.stderr, "warning:", err) + } } else { return err } @@ -368,7 +373,9 @@ func zipTo(args ZipArgs, w io.Writer) error { Err: syscall.ENOTDIR, } if args.IgnoreMissingFiles { - fmt.Fprintln(z.stderr, "warning:", err) + if !args.Quiet { + fmt.Fprintln(z.stderr, "warning:", err) + } } else { return err } |