• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2023 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package codegen
16
17import (
18	"android/soong/android"
19	"android/soong/cc"
20
21	"github.com/google/blueprint"
22	"github.com/google/blueprint/proptools"
23
24	"fmt"
25	"strings"
26)
27
28type ccDeclarationsTagType struct {
29	blueprint.BaseDependencyTag
30}
31
32var ccDeclarationsTag = ccDeclarationsTagType{}
33
34const libBaseDep = "libbase"
35const libLogDep = "liblog"
36const libAconfigStorageReadApiCcDep = "libaconfig_storage_read_api_cc"
37
38type CcAconfigLibraryProperties struct {
39	// name of the aconfig_declarations module to generate a library for
40	Aconfig_declarations string
41
42	// default mode is "production", the other accepted modes are:
43	// "test": to generate test mode version of the library
44	// "exported": to generate exported mode version of the library
45	// "force-read-only": to generate force-read-only mode version of the library
46	// an error will be thrown if the mode is not supported
47	Mode *string
48}
49
50type CcAconfigLibraryCallbacks struct {
51	properties *CcAconfigLibraryProperties
52
53	generatedDir android.WritablePath
54	headerDir    android.WritablePath
55	generatedCpp android.WritablePath
56	generatedH   android.WritablePath
57}
58
59func CcAconfigLibraryFactory() android.Module {
60	callbacks := &CcAconfigLibraryCallbacks{
61		properties: &CcAconfigLibraryProperties{},
62	}
63	return cc.GeneratedCcLibraryModuleFactory(callbacks)
64}
65
66func (this *CcAconfigLibraryCallbacks) GeneratorInit(ctx cc.BaseModuleContext) {
67}
68
69func (this *CcAconfigLibraryCallbacks) GeneratorProps() []interface{} {
70	return []interface{}{this.properties}
71}
72
73func (this *CcAconfigLibraryCallbacks) GeneratorDeps(ctx cc.DepsContext, deps cc.Deps) cc.Deps {
74	// Add a dependency for the declarations module
75	declarations := this.properties.Aconfig_declarations
76	if len(declarations) == 0 {
77		ctx.PropertyErrorf("aconfig_declarations", "aconfig_declarations property required")
78	} else {
79		ctx.AddDependency(ctx.Module(), ccDeclarationsTag, declarations)
80	}
81
82	mode := proptools.StringDefault(this.properties.Mode, "production")
83
84	// Add a dependency for the aconfig flags base library if it is not forced read only
85	if mode != "force-read-only" {
86		deps.SharedLibs = append(deps.SharedLibs, libAconfigStorageReadApiCcDep)
87		deps.SharedLibs = append(deps.SharedLibs, libBaseDep)
88		deps.SharedLibs = append(deps.SharedLibs, libLogDep)
89	}
90
91	// TODO: It'd be really nice if we could reexport this library and not make everyone do it.
92
93	return deps
94}
95
96func (this *CcAconfigLibraryCallbacks) GeneratorSources(ctx cc.ModuleContext) cc.GeneratedSource {
97	result := cc.GeneratedSource{}
98
99	// Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag
100	declarationsModules := ctx.GetDirectDepsProxyWithTag(ccDeclarationsTag)
101	if len(declarationsModules) != 1 {
102		panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
103	}
104	declarations, _ := android.OtherModuleProvider(ctx, declarationsModules[0], android.AconfigDeclarationsProviderKey)
105
106	// Figure out the generated file paths.  This has to match aconfig's codegen_cpp.rs.
107	this.generatedDir = android.PathForModuleGen(ctx)
108
109	this.headerDir = android.PathForModuleGen(ctx, "include")
110	result.IncludeDirs = []android.Path{this.headerDir}
111	result.ReexportedDirs = []android.Path{this.headerDir}
112
113	basename := strings.ReplaceAll(declarations.Package, ".", "_")
114
115	this.generatedCpp = android.PathForModuleGen(ctx, basename+".cc")
116	result.Sources = []android.Path{this.generatedCpp}
117
118	this.generatedH = android.PathForModuleGen(ctx, "include", basename+".h")
119	result.Headers = []android.Path{this.generatedH}
120
121	return result
122}
123
124func (this *CcAconfigLibraryCallbacks) GeneratorFlags(ctx cc.ModuleContext, flags cc.Flags, deps cc.PathDeps) cc.Flags {
125	return flags
126}
127
128func (this *CcAconfigLibraryCallbacks) GeneratorBuildActions(ctx cc.ModuleContext, flags cc.Flags, deps cc.PathDeps) {
129	// Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag
130	declarationsModules := ctx.GetDirectDepsProxyWithTag(ccDeclarationsTag)
131	if len(declarationsModules) != 1 {
132		panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
133	}
134	declarations, _ := android.OtherModuleProvider(ctx, declarationsModules[0], android.AconfigDeclarationsProviderKey)
135
136	mode := proptools.StringDefault(this.properties.Mode, "production")
137	if !isModeSupported(mode) {
138		ctx.PropertyErrorf("mode", "%q is not a supported mode", mode)
139	}
140
141	ctx.Build(pctx, android.BuildParams{
142		Rule:  cppRule,
143		Input: declarations.IntermediateCacheOutputPath,
144		Outputs: []android.WritablePath{
145			this.generatedCpp,
146			this.generatedH,
147		},
148		Description: "cc_aconfig_library",
149		Args: map[string]string{
150			"gendir": this.generatedDir.String(),
151			"mode":   mode,
152		},
153	})
154
155	android.SetProvider(ctx, android.CodegenInfoProvider, android.CodegenInfo{
156		ModeInfos: map[string]android.ModeInfo{
157			ctx.ModuleName(): {
158				Container: declarations.Container,
159				Mode:      mode,
160			}},
161	})
162}
163