diff --git a/aconfig/Android.bp b/aconfig/Android.bp index ae8276f39..e0859e176 100644 --- a/aconfig/Android.bp +++ b/aconfig/Android.bp @@ -20,6 +20,7 @@ bootstrap_go_package { "aconfig_values.go", "aconfig_value_set.go", "all_aconfig_declarations.go", + "cc_aconfig_library.go", "init.go", "java_aconfig_library.go", "testing.go", diff --git a/aconfig/cc_aconfig_library.go b/aconfig/cc_aconfig_library.go new file mode 100644 index 000000000..14090bc90 --- /dev/null +++ b/aconfig/cc_aconfig_library.go @@ -0,0 +1,128 @@ +// 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 ( + "android/soong/android" + "android/soong/cc" + "github.com/google/blueprint" + + "fmt" + "strings" +) + +type ccDeclarationsTagType struct { + blueprint.BaseDependencyTag +} + +var ccDeclarationsTag = ccDeclarationsTagType{} + +type CcAconfigLibraryProperties struct { + // name of the aconfig_declarations module to generate a library for + Aconfig_declarations 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, "server_configurable_flags") + // 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], declarationsProviderKey).(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], declarationsProviderKey).(declarationsProviderData) + + 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(), + }, + }) +} diff --git a/aconfig/init.go b/aconfig/init.go index 634612d63..3ed5faf6a 100644 --- a/aconfig/init.go +++ b/aconfig/init.go @@ -39,7 +39,7 @@ var ( }, "release_version", "package", "declarations", "values") // For java_aconfig_library: Generate java file - srcJarRule = pctx.AndroidStaticRule("aconfig_srcjar", + javaRule = pctx.AndroidStaticRule("java_aconfig_library", blueprint.RuleParams{ Command: `rm -rf ${out}.tmp` + ` && mkdir -p ${out}.tmp` + @@ -55,6 +55,20 @@ var ( Restat: true, }) + // For java_aconfig_library: Generate java file + cppRule = pctx.AndroidStaticRule("cc_aconfig_library", + blueprint.RuleParams{ + Command: `rm -rf ${gendir}` + + ` && mkdir -p ${gendir}` + + ` && ${aconfig} create-cpp-lib` + + ` --cache ${in}` + + ` --out ${gendir}`, + CommandDeps: []string{ + "$aconfig", + "$soong_zip", + }, + }, "gendir") + // For all_aconfig_declarations allDeclarationsRule = pctx.AndroidStaticRule("all_aconfig_declarations_dump", blueprint.RuleParams{ @@ -75,6 +89,7 @@ func registerBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("aconfig_declarations", DeclarationsFactory) ctx.RegisterModuleType("aconfig_values", ValuesFactory) ctx.RegisterModuleType("aconfig_value_set", ValueSetFactory) + ctx.RegisterModuleType("cc_aconfig_library", CcAconfigLibraryFactory) ctx.RegisterModuleType("java_aconfig_library", JavaDeclarationsLibraryFactory) ctx.RegisterParallelSingletonType("all_aconfig_declarations", AllAconfigDeclarationsFactory) } diff --git a/aconfig/java_aconfig_library.go b/aconfig/java_aconfig_library.go index 0eeb14ffc..7c0ac888f 100644 --- a/aconfig/java_aconfig_library.go +++ b/aconfig/java_aconfig_library.go @@ -61,7 +61,7 @@ func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuild srcJarPath := android.PathForModuleGen(ctx, ctx.ModuleName()+".srcjar") ctx.Build(pctx, android.BuildParams{ - Rule: srcJarRule, + Rule: javaRule, Input: declarations.IntermediatePath, Output: srcJarPath, Description: "aconfig.srcjar", diff --git a/cc/Android.bp b/cc/Android.bp index f49dc1a9e..e88ea03b3 100644 --- a/cc/Android.bp +++ b/cc/Android.bp @@ -32,6 +32,7 @@ bootstrap_go_package { "check.go", "coverage.go", "gen.go", + "generated_cc_library.go", "image.go", "linkable.go", "lto.go", diff --git a/cc/cc.go b/cc/cc.go index 84b80a10c..be67286c6 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -569,6 +569,24 @@ type feature interface { props() []interface{} } +// Information returned from Generator about the source code it's generating +type GeneratedSource struct { + IncludeDirs android.Paths + Sources android.Paths + Headers android.Paths + ReexportedDirs android.Paths +} + +// generator allows injection of generated code +type Generator interface { + GeneratorProps() []interface{} + GeneratorInit(ctx BaseModuleContext) + GeneratorDeps(ctx DepsContext, deps Deps) Deps + GeneratorFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags + GeneratorSources(ctx ModuleContext) GeneratedSource + GeneratorBuildActions(ctx ModuleContext, flags Flags, deps PathDeps) +} + // compiler is the interface for a compiler helper object. Different module decorators may implement // this helper differently. type compiler interface { @@ -851,6 +869,7 @@ type Module struct { // type-specific logic. These members may reference different objects or the same object. // Functions of these decorators will be invoked to initialize and register type-specific // build statements. + generators []Generator compiler compiler linker linker installer installer @@ -1201,6 +1220,9 @@ func (c *Module) VndkVersion() string { func (c *Module) Init() android.Module { c.AddProperties(&c.Properties, &c.VendorProperties) + for _, generator := range c.generators { + c.AddProperties(generator.GeneratorProps()...) + } if c.compiler != nil { c.AddProperties(c.compiler.compilerProps()...) } @@ -2149,6 +2171,25 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { return } + for _, generator := range c.generators { + gen := generator.GeneratorSources(ctx) + deps.IncludeDirs = append(deps.IncludeDirs, gen.IncludeDirs...) + deps.ReexportedDirs = append(deps.ReexportedDirs, gen.ReexportedDirs...) + deps.GeneratedDeps = append(deps.GeneratedDeps, gen.Headers...) + deps.ReexportedGeneratedHeaders = append(deps.ReexportedGeneratedHeaders, gen.Headers...) + deps.ReexportedDeps = append(deps.ReexportedDeps, gen.Headers...) + if len(deps.Objs.objFiles) == 0 { + // If we are reusuing object files (which happens when we're a shared library and we're + // reusing our static variant's object files), then skip adding the actual source files, + // because we already have the object for it. + deps.GeneratedSources = append(deps.GeneratedSources, gen.Sources...) + } + } + + if ctx.Failed() { + return + } + if c.stubLibraryMultipleApexViolation(actx) { actx.PropertyErrorf("apex_available", "Stub libraries should have a single apex_available (test apexes excluded). Got %v", c.ApexAvailable()) @@ -2163,6 +2204,9 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { Toolchain: c.toolchain(ctx), EmitXrefs: ctx.Config().EmitXrefRules(), } + for _, generator := range c.generators { + flags = generator.GeneratorFlags(ctx, flags, deps) + } if c.compiler != nil { flags = c.compiler.compilerFlags(ctx, flags, deps) } @@ -2220,6 +2264,10 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { flags.AssemblerWithCpp = inList("-xassembler-with-cpp", flags.Local.AsFlags) + for _, generator := range c.generators { + generator.GeneratorBuildActions(ctx, flags, deps) + } + var objs Objects if c.compiler != nil { objs = c.compiler.compile(ctx, flags, deps) @@ -2307,6 +2355,9 @@ func (c *Module) toolchain(ctx android.BaseModuleContext) config.Toolchain { } func (c *Module) begin(ctx BaseModuleContext) { + for _, generator := range c.generators { + generator.GeneratorInit(ctx) + } if c.compiler != nil { c.compiler.compilerInit(ctx) } @@ -2342,6 +2393,9 @@ func (c *Module) begin(ctx BaseModuleContext) { func (c *Module) deps(ctx DepsContext) Deps { deps := Deps{} + for _, generator := range c.generators { + deps = generator.GeneratorDeps(ctx, deps) + } if c.compiler != nil { deps = c.compiler.compilerDeps(ctx, deps) } diff --git a/cc/generated_cc_library.go b/cc/generated_cc_library.go new file mode 100644 index 000000000..55e19f9a9 --- /dev/null +++ b/cc/generated_cc_library.go @@ -0,0 +1,38 @@ +// 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 cc + +import ( + "android/soong/android" +) + +func GeneratedCcLibraryModuleFactory(moduleName string, callbacks Generator) android.Module { + module, _ := NewLibrary(android.HostAndDeviceSupported) + + // Can be used as both a static and a shared library. + module.sdkMemberTypes = []android.SdkMemberType{ + sharedLibrarySdkMemberType, + staticLibrarySdkMemberType, + staticAndSharedLibrarySdkMemberType, + } + + // TODO: Need to be bazelable + // module.bazelable = true + // module.bazelHandler = &ccLibraryBazelHandler{module: module} + + module.generators = append(module.generators, callbacks) + + return module.Init() +}