Add container property to aconfig_declarations.
Bug: 311155208 Test: Unit test Change-Id: I7b187138856d0144203961e82b6dad5e2f8eed9d
This commit is contained in:
32
aconfig/codegen/Android.bp
Normal file
32
aconfig/codegen/Android.bp
Normal file
@@ -0,0 +1,32 @@
|
||||
package {
|
||||
default_applicable_licenses: ["Android-Apache-2.0"],
|
||||
}
|
||||
|
||||
bootstrap_go_package {
|
||||
name: "soong-aconfig-codegen",
|
||||
pkgPath: "android/soong/aconfig/codegen",
|
||||
deps: [
|
||||
"blueprint",
|
||||
"blueprint-pathtools",
|
||||
"sbox_proto",
|
||||
"soong",
|
||||
"soong-aconfig",
|
||||
"soong-android",
|
||||
"soong-bazel",
|
||||
"soong-java",
|
||||
"soong-rust",
|
||||
],
|
||||
srcs: [
|
||||
"cc_aconfig_library.go",
|
||||
"init.go",
|
||||
"java_aconfig_library.go",
|
||||
"rust_aconfig_library.go",
|
||||
"testing.go",
|
||||
],
|
||||
testSrcs: [
|
||||
"java_aconfig_library_test.go",
|
||||
"cc_aconfig_library_test.go",
|
||||
"rust_aconfig_library_test.go",
|
||||
],
|
||||
pluginFor: ["soong_build"],
|
||||
}
|
184
aconfig/codegen/cc_aconfig_library.go
Normal file
184
aconfig/codegen/cc_aconfig_library.go
Normal file
@@ -0,0 +1,184 @@
|
||||
// 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 codegen
|
||||
|
||||
import (
|
||||
"android/soong/aconfig"
|
||||
"android/soong/android"
|
||||
"android/soong/bazel"
|
||||
"android/soong/cc"
|
||||
|
||||
"github.com/google/blueprint"
|
||||
"github.com/google/blueprint/proptools"
|
||||
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ccDeclarationsTagType struct {
|
||||
blueprint.BaseDependencyTag
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
// default mode is "production", the other accepted modes are:
|
||||
// "test": to generate test mode version of the library
|
||||
// "exported": to generate exported mode version of the library
|
||||
// an error will be thrown if the mode is not supported
|
||||
Mode *string
|
||||
}
|
||||
|
||||
type CcAconfigLibraryCallbacks struct {
|
||||
properties *CcAconfigLibraryProperties
|
||||
|
||||
generatedDir android.WritablePath
|
||||
headerDir android.WritablePath
|
||||
generatedCpp android.WritablePath
|
||||
generatedH android.WritablePath
|
||||
}
|
||||
|
||||
func CcAconfigLibraryFactory() android.Module {
|
||||
callbacks := &CcAconfigLibraryCallbacks{
|
||||
properties: &CcAconfigLibraryProperties{},
|
||||
}
|
||||
return cc.GeneratedCcLibraryModuleFactory("cc_aconfig_library", callbacks)
|
||||
}
|
||||
|
||||
func (this *CcAconfigLibraryCallbacks) GeneratorInit(ctx cc.BaseModuleContext) {
|
||||
}
|
||||
|
||||
func (this *CcAconfigLibraryCallbacks) GeneratorProps() []interface{} {
|
||||
return []interface{}{this.properties}
|
||||
}
|
||||
|
||||
func (this *CcAconfigLibraryCallbacks) GeneratorDeps(ctx cc.DepsContext, deps cc.Deps) cc.Deps {
|
||||
// Add a dependency for the declarations module
|
||||
declarations := this.properties.Aconfig_declarations
|
||||
if len(declarations) == 0 {
|
||||
ctx.PropertyErrorf("aconfig_declarations", "aconfig_declarations property required")
|
||||
} else {
|
||||
ctx.AddDependency(ctx.Module(), ccDeclarationsTag, declarations)
|
||||
}
|
||||
|
||||
// Add a dependency for the aconfig flags base library
|
||||
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
|
||||
}
|
||||
|
||||
func (this *CcAconfigLibraryCallbacks) GeneratorSources(ctx cc.ModuleContext) cc.GeneratedSource {
|
||||
result := cc.GeneratedSource{}
|
||||
|
||||
// Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag
|
||||
declarationsModules := ctx.GetDirectDepsWithTag(ccDeclarationsTag)
|
||||
if len(declarationsModules) != 1 {
|
||||
panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
|
||||
}
|
||||
declarations := ctx.OtherModuleProvider(declarationsModules[0], aconfig.DeclarationsProviderKey).(aconfig.DeclarationsProviderData)
|
||||
|
||||
// Figure out the generated file paths. This has to match aconfig's codegen_cpp.rs.
|
||||
this.generatedDir = android.PathForModuleGen(ctx)
|
||||
|
||||
this.headerDir = android.PathForModuleGen(ctx, "include")
|
||||
result.IncludeDirs = []android.Path{this.headerDir}
|
||||
result.ReexportedDirs = []android.Path{this.headerDir}
|
||||
|
||||
basename := strings.ReplaceAll(declarations.Package, ".", "_")
|
||||
|
||||
this.generatedCpp = android.PathForModuleGen(ctx, basename+".cc")
|
||||
result.Sources = []android.Path{this.generatedCpp}
|
||||
|
||||
this.generatedH = android.PathForModuleGen(ctx, "include", basename+".h")
|
||||
result.Headers = []android.Path{this.generatedH}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (this *CcAconfigLibraryCallbacks) GeneratorFlags(ctx cc.ModuleContext, flags cc.Flags, deps cc.PathDeps) cc.Flags {
|
||||
return flags
|
||||
}
|
||||
|
||||
func (this *CcAconfigLibraryCallbacks) GeneratorBuildActions(ctx cc.ModuleContext, flags cc.Flags, deps cc.PathDeps) {
|
||||
// Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag
|
||||
declarationsModules := ctx.GetDirectDepsWithTag(ccDeclarationsTag)
|
||||
if len(declarationsModules) != 1 {
|
||||
panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
|
||||
}
|
||||
declarations := ctx.OtherModuleProvider(declarationsModules[0], aconfig.DeclarationsProviderKey).(aconfig.DeclarationsProviderData)
|
||||
|
||||
mode := proptools.StringDefault(this.properties.Mode, "production")
|
||||
if !isModeSupported(mode) {
|
||||
ctx.PropertyErrorf("mode", "%q is not a supported mode", mode)
|
||||
}
|
||||
|
||||
ctx.Build(pctx, android.BuildParams{
|
||||
Rule: cppRule,
|
||||
Input: declarations.IntermediatePath,
|
||||
Outputs: []android.WritablePath{
|
||||
this.generatedCpp,
|
||||
this.generatedH,
|
||||
},
|
||||
Description: "cc_aconfig_library",
|
||||
Args: map[string]string{
|
||||
"gendir": this.generatedDir.String(),
|
||||
"mode": mode,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
type bazelCcAconfigLibraryAttributes struct {
|
||||
cc.SdkAttributes
|
||||
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, module *cc.Module) bool {
|
||||
if ctx.ModuleType() != "cc_aconfig_library" {
|
||||
return false
|
||||
}
|
||||
|
||||
attrs := bazelCcAconfigLibraryAttributes{
|
||||
SdkAttributes: cc.Bp2BuildParseSdkAttributes(module),
|
||||
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(),
|
||||
Tags: android.ApexAvailableTagsWithoutTestApexes(ctx, module),
|
||||
},
|
||||
&attrs)
|
||||
return true
|
||||
}
|
106
aconfig/codegen/cc_aconfig_library_test.go
Normal file
106
aconfig/codegen/cc_aconfig_library_test.go
Normal file
@@ -0,0 +1,106 @@
|
||||
// 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 codegen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"android/soong/android"
|
||||
"android/soong/cc"
|
||||
)
|
||||
|
||||
var ccCodegenModeTestData = []struct {
|
||||
setting, expected string
|
||||
}{
|
||||
{"", "production"},
|
||||
{"mode: `production`,", "production"},
|
||||
{"mode: `test`,", "test"},
|
||||
{"mode: `exported`,", "exported"},
|
||||
}
|
||||
|
||||
func TestCCCodegenMode(t *testing.T) {
|
||||
for _, testData := range ccCodegenModeTestData {
|
||||
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)
|
||||
}
|
||||
|
||||
var incorrectCCCodegenModeTestData = []struct {
|
||||
setting, expectedErr string
|
||||
}{
|
||||
{"mode: `unsupported`,", "mode: \"unsupported\" is not a supported mode"},
|
||||
}
|
||||
|
||||
func TestIncorrectCCCodegenMode(t *testing.T) {
|
||||
for _, testData := range incorrectCCCodegenModeTestData {
|
||||
testIncorrectCCCodegenModeHelper(t, testData.setting, testData.expectedErr)
|
||||
}
|
||||
}
|
||||
|
||||
func testIncorrectCCCodegenModeHelper(t *testing.T, bpMode string, err string) {
|
||||
t.Helper()
|
||||
android.GroupFixturePreparers(
|
||||
PrepareForTestWithAconfigBuildComponents,
|
||||
cc.PrepareForTestWithCcDefaultModules).
|
||||
ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(err)).
|
||||
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))
|
||||
}
|
83
aconfig/codegen/init.go
Normal file
83
aconfig/codegen/init.go
Normal file
@@ -0,0 +1,83 @@
|
||||
// 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 codegen
|
||||
|
||||
import (
|
||||
"android/soong/android"
|
||||
|
||||
"github.com/google/blueprint"
|
||||
)
|
||||
|
||||
var (
|
||||
pctx = android.NewPackageContext("android/soong/aconfig/codegen")
|
||||
|
||||
// For java_aconfig_library: Generate java library
|
||||
javaRule = pctx.AndroidStaticRule("java_aconfig_library",
|
||||
blueprint.RuleParams{
|
||||
Command: `rm -rf ${out}.tmp` +
|
||||
` && mkdir -p ${out}.tmp` +
|
||||
` && ${aconfig} create-java-lib` +
|
||||
` --mode ${mode}` +
|
||||
` --cache ${in}` +
|
||||
` --out ${out}.tmp` +
|
||||
` && $soong_zip -write_if_changed -jar -o ${out} -C ${out}.tmp -D ${out}.tmp` +
|
||||
` && rm -rf ${out}.tmp`,
|
||||
CommandDeps: []string{
|
||||
"$aconfig",
|
||||
"$soong_zip",
|
||||
},
|
||||
Restat: true,
|
||||
}, "mode")
|
||||
|
||||
// For cc_aconfig_library: Generate C++ library
|
||||
cppRule = pctx.AndroidStaticRule("cc_aconfig_library",
|
||||
blueprint.RuleParams{
|
||||
Command: `rm -rf ${gendir}` +
|
||||
` && mkdir -p ${gendir}` +
|
||||
` && ${aconfig} create-cpp-lib` +
|
||||
` --mode ${mode}` +
|
||||
` --cache ${in}` +
|
||||
` --out ${gendir}`,
|
||||
CommandDeps: []string{
|
||||
"$aconfig",
|
||||
},
|
||||
}, "gendir", "mode")
|
||||
|
||||
// For rust_aconfig_library: Generate Rust library
|
||||
rustRule = pctx.AndroidStaticRule("rust_aconfig_library",
|
||||
blueprint.RuleParams{
|
||||
Command: `rm -rf ${gendir}` +
|
||||
` && mkdir -p ${gendir}` +
|
||||
` && ${aconfig} create-rust-lib` +
|
||||
` --mode ${mode}` +
|
||||
` --cache ${in}` +
|
||||
` --out ${gendir}`,
|
||||
CommandDeps: []string{
|
||||
"$aconfig",
|
||||
},
|
||||
}, "gendir", "mode")
|
||||
)
|
||||
|
||||
func init() {
|
||||
RegisterBuildComponents(android.InitRegistrationContext)
|
||||
pctx.HostBinToolVariable("aconfig", "aconfig")
|
||||
pctx.HostBinToolVariable("soong_zip", "soong_zip")
|
||||
}
|
||||
|
||||
func RegisterBuildComponents(ctx android.RegistrationContext) {
|
||||
ctx.RegisterModuleType("cc_aconfig_library", CcAconfigLibraryFactory)
|
||||
ctx.RegisterModuleType("java_aconfig_library", JavaDeclarationsLibraryFactory)
|
||||
ctx.RegisterModuleType("rust_aconfig_library", RustAconfigLibraryFactory)
|
||||
}
|
155
aconfig/codegen/java_aconfig_library.go
Normal file
155
aconfig/codegen/java_aconfig_library.go
Normal file
@@ -0,0 +1,155 @@
|
||||
// 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 codegen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"android/soong/aconfig"
|
||||
"android/soong/android"
|
||||
"android/soong/bazel"
|
||||
"android/soong/java"
|
||||
"github.com/google/blueprint"
|
||||
"github.com/google/blueprint/proptools"
|
||||
)
|
||||
|
||||
type declarationsTagType struct {
|
||||
blueprint.BaseDependencyTag
|
||||
}
|
||||
|
||||
var declarationsTag = declarationsTagType{}
|
||||
|
||||
var aconfigSupportedModes = []string{"production", "test", "exported"}
|
||||
|
||||
type JavaAconfigDeclarationsLibraryProperties struct {
|
||||
// name of the aconfig_declarations module to generate a library for
|
||||
Aconfig_declarations string
|
||||
|
||||
// default mode is "production", the other accepted modes are:
|
||||
// "test": to generate test mode version of the library
|
||||
// "exported": to generate exported mode version of the library
|
||||
// an error will be thrown if the mode is not supported
|
||||
Mode *string
|
||||
}
|
||||
|
||||
type JavaAconfigDeclarationsLibraryCallbacks struct {
|
||||
properties JavaAconfigDeclarationsLibraryProperties
|
||||
}
|
||||
|
||||
func JavaDeclarationsLibraryFactory() android.Module {
|
||||
callbacks := &JavaAconfigDeclarationsLibraryCallbacks{}
|
||||
return java.GeneratedJavaLibraryModuleFactory("java_aconfig_library", callbacks, &callbacks.properties)
|
||||
}
|
||||
|
||||
func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) DepsMutator(module *java.GeneratedJavaLibraryModule, ctx android.BottomUpMutatorContext) {
|
||||
declarations := callbacks.properties.Aconfig_declarations
|
||||
if len(declarations) == 0 {
|
||||
// TODO: Add test for this case
|
||||
ctx.PropertyErrorf("aconfig_declarations", "aconfig_declarations property required")
|
||||
} 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")
|
||||
// TODO(b/303773055): Remove the annotation after access issue is resolved.
|
||||
module.AddSharedLibrary("unsupportedappusage")
|
||||
}
|
||||
|
||||
func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuildActions(module *java.GeneratedJavaLibraryModule, ctx android.ModuleContext) android.Path {
|
||||
// Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag
|
||||
declarationsModules := ctx.GetDirectDepsWithTag(declarationsTag)
|
||||
if len(declarationsModules) != 1 {
|
||||
panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
|
||||
}
|
||||
declarations := ctx.OtherModuleProvider(declarationsModules[0], aconfig.DeclarationsProviderKey).(aconfig.DeclarationsProviderData)
|
||||
|
||||
// Generate the action to build the srcjar
|
||||
srcJarPath := android.PathForModuleGen(ctx, ctx.ModuleName()+".srcjar")
|
||||
|
||||
mode := proptools.StringDefault(callbacks.properties.Mode, "production")
|
||||
if !isModeSupported(mode) {
|
||||
ctx.PropertyErrorf("mode", "%q is not a supported mode", mode)
|
||||
}
|
||||
|
||||
ctx.Build(pctx, android.BuildParams{
|
||||
Rule: javaRule,
|
||||
Input: declarations.IntermediatePath,
|
||||
Output: srcJarPath,
|
||||
Description: "aconfig.srcjar",
|
||||
Args: map[string]string{
|
||||
"mode": mode,
|
||||
},
|
||||
})
|
||||
|
||||
return srcJarPath
|
||||
}
|
||||
|
||||
func isModeSupported(mode string) bool {
|
||||
return android.InList(mode, aconfigSupportedModes)
|
||||
}
|
||||
|
||||
type bazelJavaAconfigLibraryAttributes struct {
|
||||
Aconfig_declarations bazel.LabelAttribute
|
||||
Sdk_version *string
|
||||
Libs bazel.LabelListAttribute
|
||||
}
|
||||
|
||||
func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) Bp2build(ctx android.Bp2buildMutatorContext, module *java.GeneratedJavaLibraryModule) {
|
||||
if ctx.ModuleType() != "java_aconfig_library" {
|
||||
return
|
||||
}
|
||||
|
||||
// By default, soong builds the aconfig java library with private_current, however
|
||||
// bazel currently doesn't support it so we default it to system_current. One reason
|
||||
// is that the dependency of all java_aconfig_library aconfig-annotations-lib is
|
||||
// built with system_current. For the java aconfig library itself it doesn't really
|
||||
// matter whether it uses private API or system API because the only module it uses
|
||||
// is DeviceConfig which is in system, and the rdeps of the java aconfig library
|
||||
// won't change its sdk version either, so this should be fine.
|
||||
// Ideally we should only use the default value if it is not set by the user, but
|
||||
// bazel only supports a limited sdk versions, for example, the java_aconfig_library
|
||||
// modules in framework/base use core_platform which is not supported by bazel yet.
|
||||
// TODO(b/302148527): change soong to default to system_current as well.
|
||||
sdkVersion := "system_current"
|
||||
|
||||
var libs bazel.LabelListAttribute
|
||||
archVariantProps := module.GetArchVariantProperties(ctx, &java.CommonProperties{})
|
||||
for axis, configToProps := range archVariantProps {
|
||||
for config, p := range configToProps {
|
||||
if archProps, ok := p.(*java.CommonProperties); ok {
|
||||
var libLabels []bazel.Label
|
||||
for _, d := range archProps.Libs {
|
||||
neverlinkLabel := android.BazelLabelForModuleDepSingle(ctx, d)
|
||||
neverlinkLabel.Label = neverlinkLabel.Label + "-neverlink"
|
||||
libLabels = append(libLabels, neverlinkLabel)
|
||||
}
|
||||
libs.SetSelectValue(axis, config, (bazel.MakeLabelList(libLabels)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
attrs := bazelJavaAconfigLibraryAttributes{
|
||||
Aconfig_declarations: *bazel.MakeLabelAttribute(android.BazelLabelForModuleDepSingle(ctx, callbacks.properties.Aconfig_declarations).Label),
|
||||
Sdk_version: &sdkVersion,
|
||||
Libs: libs,
|
||||
}
|
||||
props := bazel.BazelTargetModuleProperties{
|
||||
Rule_class: "java_aconfig_library",
|
||||
Bzl_load_location: "//build/bazel/rules/java:java_aconfig_library.bzl",
|
||||
}
|
||||
|
||||
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: ctx.ModuleName()}, &attrs)
|
||||
}
|
233
aconfig/codegen/java_aconfig_library_test.go
Normal file
233
aconfig/codegen/java_aconfig_library_test.go
Normal file
@@ -0,0 +1,233 @@
|
||||
// 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 codegen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"android/soong/android"
|
||||
"android/soong/java"
|
||||
)
|
||||
|
||||
// Note: These tests cover the code in the java package. It'd be ideal of that code could
|
||||
// be in the aconfig package.
|
||||
|
||||
// With the bp parameter that defines a my_module, make sure it has the LOCAL_ACONFIG_FILES entries
|
||||
func runJavaAndroidMkTest(t *testing.T, bp string) {
|
||||
result := android.GroupFixturePreparers(
|
||||
PrepareForTestWithAconfigBuildComponents,
|
||||
java.PrepareForTestWithJavaDefaultModules).
|
||||
ExtendWithErrorHandler(android.FixtureExpectsNoErrors).
|
||||
RunTestWithBp(t, bp+`
|
||||
aconfig_declarations {
|
||||
name: "my_aconfig_declarations_foo",
|
||||
package: "com.example.package",
|
||||
srcs: ["foo.aconfig"],
|
||||
}
|
||||
|
||||
java_aconfig_library {
|
||||
name: "my_java_aconfig_library_foo",
|
||||
aconfig_declarations: "my_aconfig_declarations_foo",
|
||||
}
|
||||
|
||||
aconfig_declarations {
|
||||
name: "my_aconfig_declarations_bar",
|
||||
package: "com.example.package",
|
||||
srcs: ["bar.aconfig"],
|
||||
}
|
||||
|
||||
java_aconfig_library {
|
||||
name: "my_java_aconfig_library_bar",
|
||||
aconfig_declarations: "my_aconfig_declarations_bar",
|
||||
}
|
||||
`)
|
||||
|
||||
module := result.ModuleForTests("my_module", "android_common").Module()
|
||||
|
||||
entry := android.AndroidMkEntriesForTest(t, result.TestContext, module)[0]
|
||||
|
||||
makeVar := entry.EntryMap["LOCAL_ACONFIG_FILES"]
|
||||
android.AssertIntEquals(t, "len(LOCAL_ACONFIG_FILES)", 2, len(makeVar))
|
||||
android.EnsureListContainsSuffix(t, makeVar, "my_aconfig_declarations_foo/intermediate.pb")
|
||||
android.EnsureListContainsSuffix(t, makeVar, "my_aconfig_declarations_bar/intermediate.pb")
|
||||
}
|
||||
|
||||
func TestAndroidMkJavaLibrary(t *testing.T) {
|
||||
bp := `
|
||||
java_library {
|
||||
name: "my_module",
|
||||
srcs: [
|
||||
"src/foo.java",
|
||||
],
|
||||
static_libs: [
|
||||
"my_java_aconfig_library_foo",
|
||||
"my_java_aconfig_library_bar",
|
||||
],
|
||||
platform_apis: true,
|
||||
}
|
||||
`
|
||||
|
||||
runJavaAndroidMkTest(t, bp)
|
||||
}
|
||||
|
||||
func TestAndroidMkAndroidApp(t *testing.T) {
|
||||
bp := `
|
||||
android_app {
|
||||
name: "my_module",
|
||||
srcs: [
|
||||
"src/foo.java",
|
||||
],
|
||||
static_libs: [
|
||||
"my_java_aconfig_library_foo",
|
||||
"my_java_aconfig_library_bar",
|
||||
],
|
||||
platform_apis: true,
|
||||
}
|
||||
`
|
||||
|
||||
runJavaAndroidMkTest(t, bp)
|
||||
}
|
||||
|
||||
func TestAndroidMkBinary(t *testing.T) {
|
||||
bp := `
|
||||
java_binary {
|
||||
name: "my_module",
|
||||
srcs: [
|
||||
"src/foo.java",
|
||||
],
|
||||
static_libs: [
|
||||
"my_java_aconfig_library_foo",
|
||||
"my_java_aconfig_library_bar",
|
||||
],
|
||||
platform_apis: true,
|
||||
main_class: "foo",
|
||||
}
|
||||
`
|
||||
|
||||
runJavaAndroidMkTest(t, bp)
|
||||
}
|
||||
|
||||
func TestAndroidMkAndroidLibrary(t *testing.T) {
|
||||
bp := `
|
||||
android_library {
|
||||
name: "my_module",
|
||||
srcs: [
|
||||
"src/foo.java",
|
||||
],
|
||||
static_libs: [
|
||||
"my_java_aconfig_library_foo",
|
||||
"my_java_aconfig_library_bar",
|
||||
],
|
||||
platform_apis: true,
|
||||
}
|
||||
`
|
||||
|
||||
runJavaAndroidMkTest(t, bp)
|
||||
}
|
||||
|
||||
func TestAndroidMkBinaryThatLinksAgainstAar(t *testing.T) {
|
||||
// Tests AndroidLibrary's propagation of flags through JavaInfo
|
||||
bp := `
|
||||
android_library {
|
||||
name: "some_library",
|
||||
srcs: [
|
||||
"src/foo.java",
|
||||
],
|
||||
static_libs: [
|
||||
"my_java_aconfig_library_foo",
|
||||
"my_java_aconfig_library_bar",
|
||||
],
|
||||
platform_apis: true,
|
||||
}
|
||||
java_binary {
|
||||
name: "my_module",
|
||||
srcs: [
|
||||
"src/bar.java",
|
||||
],
|
||||
static_libs: [
|
||||
"some_library",
|
||||
],
|
||||
platform_apis: true,
|
||||
main_class: "foo",
|
||||
}
|
||||
`
|
||||
|
||||
runJavaAndroidMkTest(t, bp)
|
||||
}
|
||||
|
||||
func testCodegenMode(t *testing.T, bpMode string, ruleMode string) {
|
||||
result := android.GroupFixturePreparers(
|
||||
PrepareForTestWithAconfigBuildComponents,
|
||||
java.PrepareForTestWithJavaDefaultModules).
|
||||
ExtendWithErrorHandler(android.FixtureExpectsNoErrors).
|
||||
RunTestWithBp(t, fmt.Sprintf(`
|
||||
aconfig_declarations {
|
||||
name: "my_aconfig_declarations",
|
||||
package: "com.example.package",
|
||||
srcs: ["foo.aconfig"],
|
||||
}
|
||||
|
||||
java_aconfig_library {
|
||||
name: "my_java_aconfig_library",
|
||||
aconfig_declarations: "my_aconfig_declarations",
|
||||
%s
|
||||
}
|
||||
`, bpMode))
|
||||
|
||||
module := result.ModuleForTests("my_java_aconfig_library", "android_common")
|
||||
rule := module.Rule("java_aconfig_library")
|
||||
android.AssertStringEquals(t, "rule must contain test mode", rule.Args["mode"], ruleMode)
|
||||
}
|
||||
|
||||
func testCodegenModeWithError(t *testing.T, bpMode string, err string) {
|
||||
android.GroupFixturePreparers(
|
||||
PrepareForTestWithAconfigBuildComponents,
|
||||
java.PrepareForTestWithJavaDefaultModules).
|
||||
ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(err)).
|
||||
RunTestWithBp(t, fmt.Sprintf(`
|
||||
aconfig_declarations {
|
||||
name: "my_aconfig_declarations",
|
||||
package: "com.example.package",
|
||||
srcs: ["foo.aconfig"],
|
||||
}
|
||||
|
||||
java_aconfig_library {
|
||||
name: "my_java_aconfig_library",
|
||||
aconfig_declarations: "my_aconfig_declarations",
|
||||
%s
|
||||
}
|
||||
`, bpMode))
|
||||
}
|
||||
|
||||
func TestDefaultProdMode(t *testing.T) {
|
||||
testCodegenMode(t, "", "production")
|
||||
}
|
||||
|
||||
func TestProdMode(t *testing.T) {
|
||||
testCodegenMode(t, "mode: `production`,", "production")
|
||||
}
|
||||
|
||||
func TestTestMode(t *testing.T) {
|
||||
testCodegenMode(t, "mode: `test`,", "test")
|
||||
}
|
||||
|
||||
func TestExportedMode(t *testing.T) {
|
||||
testCodegenMode(t, "mode: `exported`,", "exported")
|
||||
}
|
||||
|
||||
func TestUnsupportedMode(t *testing.T) {
|
||||
testCodegenModeWithError(t, "mode: `unsupported`,", "mode: \"unsupported\" is not a supported mode")
|
||||
}
|
97
aconfig/codegen/rust_aconfig_library.go
Normal file
97
aconfig/codegen/rust_aconfig_library.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package codegen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"android/soong/aconfig"
|
||||
"android/soong/android"
|
||||
"android/soong/rust"
|
||||
|
||||
"github.com/google/blueprint"
|
||||
"github.com/google/blueprint/proptools"
|
||||
)
|
||||
|
||||
type rustDeclarationsTagType struct {
|
||||
blueprint.BaseDependencyTag
|
||||
}
|
||||
|
||||
var rustDeclarationsTag = rustDeclarationsTagType{}
|
||||
|
||||
type RustAconfigLibraryProperties struct {
|
||||
// name of the aconfig_declarations module to generate a library for
|
||||
Aconfig_declarations string
|
||||
|
||||
// default mode is "production", the other accepted modes are:
|
||||
// "test": to generate test mode version of the library
|
||||
// "exported": to generate exported mode version of the library
|
||||
// an error will be thrown if the mode is not supported
|
||||
Mode *string
|
||||
}
|
||||
|
||||
type aconfigDecorator struct {
|
||||
*rust.BaseSourceProvider
|
||||
|
||||
Properties RustAconfigLibraryProperties
|
||||
}
|
||||
|
||||
func NewRustAconfigLibrary(hod android.HostOrDeviceSupported) (*rust.Module, *aconfigDecorator) {
|
||||
aconfig := &aconfigDecorator{
|
||||
BaseSourceProvider: rust.NewSourceProvider(),
|
||||
Properties: RustAconfigLibraryProperties{},
|
||||
}
|
||||
|
||||
module := rust.NewSourceProviderModule(android.HostAndDeviceSupported, aconfig, false, false)
|
||||
return module, aconfig
|
||||
}
|
||||
|
||||
// rust_aconfig_library generates aconfig rust code from the provided aconfig declaration. This module type will
|
||||
// create library variants that can be used as a crate dependency by adding it to the rlibs, dylibs, and rustlibs
|
||||
// properties of other modules.
|
||||
func RustAconfigLibraryFactory() android.Module {
|
||||
module, _ := NewRustAconfigLibrary(android.HostAndDeviceSupported)
|
||||
return module.Init()
|
||||
}
|
||||
|
||||
func (a *aconfigDecorator) SourceProviderProps() []interface{} {
|
||||
return append(a.BaseSourceProvider.SourceProviderProps(), &a.Properties)
|
||||
}
|
||||
|
||||
func (a *aconfigDecorator) GenerateSource(ctx rust.ModuleContext, deps rust.PathDeps) android.Path {
|
||||
generatedDir := android.PathForModuleGen(ctx)
|
||||
generatedSource := android.PathForModuleGen(ctx, "src", "lib.rs")
|
||||
|
||||
declarationsModules := ctx.GetDirectDepsWithTag(rustDeclarationsTag)
|
||||
|
||||
if len(declarationsModules) != 1 {
|
||||
panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
|
||||
}
|
||||
declarations := ctx.OtherModuleProvider(declarationsModules[0], aconfig.DeclarationsProviderKey).(aconfig.DeclarationsProviderData)
|
||||
|
||||
mode := proptools.StringDefault(a.Properties.Mode, "production")
|
||||
if !isModeSupported(mode) {
|
||||
ctx.PropertyErrorf("mode", "%q is not a supported mode", mode)
|
||||
}
|
||||
|
||||
ctx.Build(pctx, android.BuildParams{
|
||||
Rule: rustRule,
|
||||
Input: declarations.IntermediatePath,
|
||||
Outputs: []android.WritablePath{
|
||||
generatedSource,
|
||||
},
|
||||
Description: "rust_aconfig_library",
|
||||
Args: map[string]string{
|
||||
"gendir": generatedDir.String(),
|
||||
"mode": mode,
|
||||
},
|
||||
})
|
||||
a.BaseSourceProvider.OutputFiles = android.Paths{generatedSource}
|
||||
return generatedSource
|
||||
}
|
||||
|
||||
func (a *aconfigDecorator) SourceProviderDeps(ctx rust.DepsContext, deps rust.Deps) rust.Deps {
|
||||
deps = a.BaseSourceProvider.SourceProviderDeps(ctx, deps)
|
||||
deps.Rustlibs = append(deps.Rustlibs, "libflags_rust")
|
||||
deps.Rustlibs = append(deps.Rustlibs, "liblazy_static")
|
||||
ctx.AddDependency(ctx.Module(), rustDeclarationsTag, a.Properties.Aconfig_declarations)
|
||||
return deps
|
||||
}
|
159
aconfig/codegen/rust_aconfig_library_test.go
Normal file
159
aconfig/codegen/rust_aconfig_library_test.go
Normal file
@@ -0,0 +1,159 @@
|
||||
package codegen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"android/soong/android"
|
||||
"android/soong/rust"
|
||||
)
|
||||
|
||||
func TestRustAconfigLibrary(t *testing.T) {
|
||||
result := android.GroupFixturePreparers(
|
||||
PrepareForTestWithAconfigBuildComponents,
|
||||
rust.PrepareForTestWithRustIncludeVndk,
|
||||
android.PrepareForTestWithArchMutator,
|
||||
android.PrepareForTestWithDefaults,
|
||||
android.PrepareForTestWithPrebuilts,
|
||||
).
|
||||
ExtendWithErrorHandler(android.FixtureExpectsNoErrors).
|
||||
RunTestWithBp(t, fmt.Sprintf(`
|
||||
rust_library {
|
||||
name: "libflags_rust", // test mock
|
||||
crate_name: "flags_rust",
|
||||
srcs: ["lib.rs"],
|
||||
}
|
||||
rust_library {
|
||||
name: "liblazy_static", // test mock
|
||||
crate_name: "lazy_static",
|
||||
srcs: ["src/lib.rs"],
|
||||
}
|
||||
aconfig_declarations {
|
||||
name: "my_aconfig_declarations",
|
||||
package: "com.example.package",
|
||||
srcs: ["foo.aconfig"],
|
||||
}
|
||||
|
||||
rust_aconfig_library {
|
||||
name: "libmy_rust_aconfig_library",
|
||||
crate_name: "my_rust_aconfig_library",
|
||||
aconfig_declarations: "my_aconfig_declarations",
|
||||
}
|
||||
`))
|
||||
|
||||
sourceVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_source")
|
||||
rule := sourceVariant.Rule("rust_aconfig_library")
|
||||
android.AssertStringEquals(t, "rule must contain production mode", rule.Args["mode"], "production")
|
||||
|
||||
dylibVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_dylib")
|
||||
rlibRlibStdVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_rlib_rlib-std")
|
||||
rlibDylibStdVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_rlib_dylib-std")
|
||||
|
||||
variants := []android.TestingModule{
|
||||
dylibVariant,
|
||||
rlibDylibStdVariant,
|
||||
rlibRlibStdVariant,
|
||||
}
|
||||
|
||||
for _, variant := range variants {
|
||||
android.AssertStringEquals(
|
||||
t,
|
||||
"dylib variant builds from generated rust code",
|
||||
"out/soong/.intermediates/libmy_rust_aconfig_library/android_arm64_armv8-a_source/gen/src/lib.rs",
|
||||
variant.Rule("rustc").Inputs[0].RelativeToTop().String(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
var rustCodegenModeTestData = []struct {
|
||||
setting, expected string
|
||||
}{
|
||||
{"", "production"},
|
||||
{"mode: `production`,", "production"},
|
||||
{"mode: `test`,", "test"},
|
||||
{"mode: `exported`,", "exported"},
|
||||
}
|
||||
|
||||
func TestRustCodegenMode(t *testing.T) {
|
||||
for _, testData := range rustCodegenModeTestData {
|
||||
testRustCodegenModeHelper(t, testData.setting, testData.expected)
|
||||
}
|
||||
}
|
||||
|
||||
func testRustCodegenModeHelper(t *testing.T, bpMode string, ruleMode string) {
|
||||
t.Helper()
|
||||
result := android.GroupFixturePreparers(
|
||||
PrepareForTestWithAconfigBuildComponents,
|
||||
rust.PrepareForTestWithRustIncludeVndk).
|
||||
ExtendWithErrorHandler(android.FixtureExpectsNoErrors).
|
||||
RunTestWithBp(t, fmt.Sprintf(`
|
||||
rust_library {
|
||||
name: "libflags_rust", // test mock
|
||||
crate_name: "flags_rust",
|
||||
srcs: ["lib.rs"],
|
||||
}
|
||||
rust_library {
|
||||
name: "liblazy_static", // test mock
|
||||
crate_name: "lazy_static",
|
||||
srcs: ["src/lib.rs"],
|
||||
}
|
||||
aconfig_declarations {
|
||||
name: "my_aconfig_declarations",
|
||||
package: "com.example.package",
|
||||
srcs: ["foo.aconfig"],
|
||||
}
|
||||
rust_aconfig_library {
|
||||
name: "libmy_rust_aconfig_library",
|
||||
crate_name: "my_rust_aconfig_library",
|
||||
aconfig_declarations: "my_aconfig_declarations",
|
||||
%s
|
||||
}
|
||||
`, bpMode))
|
||||
|
||||
module := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_source")
|
||||
rule := module.Rule("rust_aconfig_library")
|
||||
android.AssertStringEquals(t, "rule must contain test mode", rule.Args["mode"], ruleMode)
|
||||
}
|
||||
|
||||
var incorrectRustCodegenModeTestData = []struct {
|
||||
setting, expectedErr string
|
||||
}{
|
||||
{"mode: `unsupported`,", "mode: \"unsupported\" is not a supported mode"},
|
||||
}
|
||||
|
||||
func TestIncorrectRustCodegenMode(t *testing.T) {
|
||||
for _, testData := range incorrectRustCodegenModeTestData {
|
||||
testIncorrectRustCodegenModeHelper(t, testData.setting, testData.expectedErr)
|
||||
}
|
||||
}
|
||||
|
||||
func testIncorrectRustCodegenModeHelper(t *testing.T, bpMode string, err string) {
|
||||
t.Helper()
|
||||
android.GroupFixturePreparers(
|
||||
PrepareForTestWithAconfigBuildComponents,
|
||||
rust.PrepareForTestWithRustIncludeVndk).
|
||||
ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(err)).
|
||||
RunTestWithBp(t, fmt.Sprintf(`
|
||||
rust_library {
|
||||
name: "libflags_rust", // test mock
|
||||
crate_name: "flags_rust",
|
||||
srcs: ["lib.rs"],
|
||||
}
|
||||
rust_library {
|
||||
name: "liblazy_static", // test mock
|
||||
crate_name: "lazy_static",
|
||||
srcs: ["src/lib.rs"],
|
||||
}
|
||||
aconfig_declarations {
|
||||
name: "my_aconfig_declarations",
|
||||
package: "com.example.package",
|
||||
srcs: ["foo.aconfig"],
|
||||
}
|
||||
rust_aconfig_library {
|
||||
name: "libmy_rust_aconfig_library",
|
||||
crate_name: "my_rust_aconfig_library",
|
||||
aconfig_declarations: "my_aconfig_declarations",
|
||||
%s
|
||||
}
|
||||
`, bpMode))
|
||||
}
|
25
aconfig/codegen/testing.go
Normal file
25
aconfig/codegen/testing.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright (C) 2021 The Android Open Source Project
|
||||
//
|
||||
// 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 codegen
|
||||
|
||||
import (
|
||||
"android/soong/aconfig"
|
||||
"android/soong/android"
|
||||
)
|
||||
|
||||
var PrepareForTestWithAconfigBuildComponents = android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
|
||||
ctx.RegisterModuleType("aconfig_declarations", aconfig.DeclarationsFactory)
|
||||
RegisterBuildComponents(ctx)
|
||||
})
|
Reference in New Issue
Block a user