xref: /aosp_15_r20/external/wayland-protocols/wayland_protocol_codegen.go (revision 6c119a463dd5c45dd05bbe67429293292dde15ee)
1*6c119a46SAndroid Build Coastguard Worker// Copyright (C) 2017 The Android Open Source Project
2*6c119a46SAndroid Build Coastguard Worker//
3*6c119a46SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*6c119a46SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*6c119a46SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*6c119a46SAndroid Build Coastguard Worker//
7*6c119a46SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*6c119a46SAndroid Build Coastguard Worker//
9*6c119a46SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*6c119a46SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*6c119a46SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*6c119a46SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*6c119a46SAndroid Build Coastguard Worker// limitations under the License.
14*6c119a46SAndroid Build Coastguard Worker
15*6c119a46SAndroid Build Coastguard Worker/*
16*6c119a46SAndroid Build Coastguard WorkerPackage wayland_protocol defines an plugin module for the Soong build system,
17*6c119a46SAndroid Build Coastguard Workerwhich makes it easier to generate code from a list of Wayland protocol files.
18*6c119a46SAndroid Build Coastguard Worker
19*6c119a46SAndroid Build Coastguard WorkerThe primary build module is "wayland_protocol_codegen", which takes a list of
20*6c119a46SAndroid Build Coastguard Workerprotocol files, and runs a configurable code-generation tool to generate
21*6c119a46SAndroid Build Coastguard Workersource code for each one. There is also a "wayland_protocol_codegen_defaults"
22*6c119a46SAndroid Build Coastguard Workerfor setting common properties.
23*6c119a46SAndroid Build Coastguard Worker
24*6c119a46SAndroid Build Coastguard WorkerThis package is substantially similar to the base "android/soong/genrule"
25*6c119a46SAndroid Build Coastguard Workerpackage, which was originally used for inspiration for this one, and has
26*6c119a46SAndroid Build Coastguard Workerbeen recently restructured so that it can be kept in sync with a tool like
27*6c119a46SAndroid Build Coastguard Worker"vimdiff" to keep things in sync as needed.
28*6c119a46SAndroid Build Coastguard Worker
29*6c119a46SAndroid Build Coastguard WorkerNotable differences:
30*6c119a46SAndroid Build Coastguard Worker
31*6c119a46SAndroid Build Coastguard Worker  - This package implements a more powerful template mechanism for specifying
32*6c119a46SAndroid Build Coastguard Worker    what output path/filename should be used for each source filename. The
33*6c119a46SAndroid Build Coastguard Worker    genrule package only allows the extension on each source filename to be
34*6c119a46SAndroid Build Coastguard Worker    replaced.
35*6c119a46SAndroid Build Coastguard Worker
36*6c119a46SAndroid Build Coastguard Worker  - This package drops support for depfiles, after observing comments that
37*6c119a46SAndroid Build Coastguard Worker    they are problematic in the genrule package sources.
38*6c119a46SAndroid Build Coastguard Worker
39*6c119a46SAndroid Build Coastguard Worker  - This package drops "Extra" and "CmdModifier" from the public Module
40*6c119a46SAndroid Build Coastguard Worker    structure, as this module is not expected to be extended.
41*6c119a46SAndroid Build Coastguard Worker
42*6c119a46SAndroid Build Coastguard Worker  - This package drops "rule" from the public Module structure, as it was
43*6c119a46SAndroid Build Coastguard Worker    unused but present in genrule.
44*6c119a46SAndroid Build Coastguard Worker
45*6c119a46SAndroid Build Coastguard Worker# Usage
46*6c119a46SAndroid Build Coastguard Worker
47*6c119a46SAndroid Build Coastguard Worker	wayland_protocol_codegen {
48*6c119a46SAndroid Build Coastguard Worker		// A standard target name.
49*6c119a46SAndroid Build Coastguard Worker		name: "wayland_extension_protocol_sources",
50*6c119a46SAndroid Build Coastguard Worker
51*6c119a46SAndroid Build Coastguard Worker		// A simple template for generating output filenames.
52*6c119a46SAndroid Build Coastguard Worker		output: "$(in).c"
53*6c119a46SAndroid Build Coastguard Worker
54*6c119a46SAndroid Build Coastguard Worker		// The command line template. See "Cmd".
55*6c119a46SAndroid Build Coastguard Worker		cmd: "$(location wayland_scanner) code < $(in) > $(out)",
56*6c119a46SAndroid Build Coastguard Worker
57*6c119a46SAndroid Build Coastguard Worker		// Protocol source files for the expansion.
58*6c119a46SAndroid Build Coastguard Worker		srcs: [":wayland_extension_protocols"],
59*6c119a46SAndroid Build Coastguard Worker
60*6c119a46SAndroid Build Coastguard Worker		// Any buildable binaries to use as tools
61*6c119a46SAndroid Build Coastguard Worker		tools: ["wayland_scanner"],
62*6c119a46SAndroid Build Coastguard Worker
63*6c119a46SAndroid Build Coastguard Worker		// Any source files to be used  (scripts, template files)
64*6c119a46SAndroid Build Coastguard Worker		tools_files: [],
65*6c119a46SAndroid Build Coastguard Worker	}
66*6c119a46SAndroid Build Coastguard Worker*/
67*6c119a46SAndroid Build Coastguard Workerpackage soong_wayland_protocol_codegen
68*6c119a46SAndroid Build Coastguard Worker
69*6c119a46SAndroid Build Coastguard Workerimport (
70*6c119a46SAndroid Build Coastguard Worker	"fmt"
71*6c119a46SAndroid Build Coastguard Worker	"strconv"
72*6c119a46SAndroid Build Coastguard Worker	"strings"
73*6c119a46SAndroid Build Coastguard Worker
74*6c119a46SAndroid Build Coastguard Worker	"github.com/google/blueprint"
75*6c119a46SAndroid Build Coastguard Worker	"github.com/google/blueprint/proptools"
76*6c119a46SAndroid Build Coastguard Worker
77*6c119a46SAndroid Build Coastguard Worker	"android/soong/android"
78*6c119a46SAndroid Build Coastguard Worker	"android/soong/genrule"
79*6c119a46SAndroid Build Coastguard Worker)
80*6c119a46SAndroid Build Coastguard Worker
81*6c119a46SAndroid Build Coastguard Workerfunc init() {
82*6c119a46SAndroid Build Coastguard Worker	registerCodeGenBuildComponents(android.InitRegistrationContext)
83*6c119a46SAndroid Build Coastguard Worker}
84*6c119a46SAndroid Build Coastguard Worker
85*6c119a46SAndroid Build Coastguard Workerfunc registerCodeGenBuildComponents(ctx android.RegistrationContext) {
86*6c119a46SAndroid Build Coastguard Worker	ctx.RegisterModuleType("wayland_protocol_codegen_defaults", defaultsFactory)
87*6c119a46SAndroid Build Coastguard Worker
88*6c119a46SAndroid Build Coastguard Worker	ctx.RegisterModuleType("wayland_protocol_codegen", codegenFactory)
89*6c119a46SAndroid Build Coastguard Worker
90*6c119a46SAndroid Build Coastguard Worker	ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
91*6c119a46SAndroid Build Coastguard Worker		ctx.BottomUp("wayland_protocol_codegen_tool_deps", toolDepsMutator)
92*6c119a46SAndroid Build Coastguard Worker	})
93*6c119a46SAndroid Build Coastguard Worker}
94*6c119a46SAndroid Build Coastguard Worker
95*6c119a46SAndroid Build Coastguard Workervar (
96*6c119a46SAndroid Build Coastguard Worker	pctx = android.NewPackageContext("android/soong/external/wayland_protocol_codegen")
97*6c119a46SAndroid Build Coastguard Worker
98*6c119a46SAndroid Build Coastguard Worker	// Used by wayland_protocol_codegen when there is more than 1 shard to merge the outputs
99*6c119a46SAndroid Build Coastguard Worker	// of each shard into a zip file.
100*6c119a46SAndroid Build Coastguard Worker	gensrcsMerge = pctx.AndroidStaticRule("wayland_protocol_codegenMerge", blueprint.RuleParams{
101*6c119a46SAndroid Build Coastguard Worker		Command:        "${soongZip} -o ${tmpZip} @${tmpZip}.rsp && ${zipSync} -d ${genDir} ${tmpZip}",
102*6c119a46SAndroid Build Coastguard Worker		CommandDeps:    []string{"${soongZip}", "${zipSync}"},
103*6c119a46SAndroid Build Coastguard Worker		Rspfile:        "${tmpZip}.rsp",
104*6c119a46SAndroid Build Coastguard Worker		RspfileContent: "${zipArgs}",
105*6c119a46SAndroid Build Coastguard Worker	}, "tmpZip", "genDir", "zipArgs")
106*6c119a46SAndroid Build Coastguard Worker)
107*6c119a46SAndroid Build Coastguard Worker
108*6c119a46SAndroid Build Coastguard Workerfunc init() {
109*6c119a46SAndroid Build Coastguard Worker	pctx.Import("android/soong/android")
110*6c119a46SAndroid Build Coastguard Worker
111*6c119a46SAndroid Build Coastguard Worker	pctx.HostBinToolVariable("soongZip", "soong_zip")
112*6c119a46SAndroid Build Coastguard Worker	pctx.HostBinToolVariable("zipSync", "zipsync")
113*6c119a46SAndroid Build Coastguard Worker}
114*6c119a46SAndroid Build Coastguard Worker
115*6c119a46SAndroid Build Coastguard Workertype hostToolDependencyTag struct {
116*6c119a46SAndroid Build Coastguard Worker	blueprint.BaseDependencyTag
117*6c119a46SAndroid Build Coastguard Worker	android.LicenseAnnotationToolchainDependencyTag
118*6c119a46SAndroid Build Coastguard Worker	label string
119*6c119a46SAndroid Build Coastguard Worker}
120*6c119a46SAndroid Build Coastguard Worker
121*6c119a46SAndroid Build Coastguard Workerfunc (t hostToolDependencyTag) AllowDisabledModuleDependency(target android.Module) bool {
122*6c119a46SAndroid Build Coastguard Worker	// Allow depending on a disabled module if it's replaced by a prebuilt
123*6c119a46SAndroid Build Coastguard Worker	// counterpart. We get the prebuilt through android.PrebuiltGetPreferred in
124*6c119a46SAndroid Build Coastguard Worker	// GenerateAndroidBuildActions.
125*6c119a46SAndroid Build Coastguard Worker	return target.IsReplacedByPrebuilt()
126*6c119a46SAndroid Build Coastguard Worker}
127*6c119a46SAndroid Build Coastguard Worker
128*6c119a46SAndroid Build Coastguard Workerfunc (t hostToolDependencyTag) AllowDisabledModuleDependencyProxy(
129*6c119a46SAndroid Build Coastguard Worker	ctx android.OtherModuleProviderContext, target android.ModuleProxy) bool {
130*6c119a46SAndroid Build Coastguard Worker	return android.OtherModuleProviderOrDefault(
131*6c119a46SAndroid Build Coastguard Worker		ctx, target, android.CommonModuleInfoKey).ReplacedByPrebuilt
132*6c119a46SAndroid Build Coastguard Worker}
133*6c119a46SAndroid Build Coastguard Worker
134*6c119a46SAndroid Build Coastguard Workervar _ android.AllowDisabledModuleDependency = (*hostToolDependencyTag)(nil)
135*6c119a46SAndroid Build Coastguard Worker
136*6c119a46SAndroid Build Coastguard Workertype generatorProperties struct {
137*6c119a46SAndroid Build Coastguard Worker	// The command to run on one or more input files. Cmd supports
138*6c119a46SAndroid Build Coastguard Worker	// substitution of a few variables (the actual substitution is implemented
139*6c119a46SAndroid Build Coastguard Worker	// in GenerateAndroidBuildActions below)
140*6c119a46SAndroid Build Coastguard Worker	//
141*6c119a46SAndroid Build Coastguard Worker	// Available variables for substitution:
142*6c119a46SAndroid Build Coastguard Worker	//
143*6c119a46SAndroid Build Coastguard Worker	//	- $(location)
144*6c119a46SAndroid Build Coastguard Worker	//		the path to the first entry in tools or tool_files
145*6c119a46SAndroid Build Coastguard Worker	//	- $(location <label>)
146*6c119a46SAndroid Build Coastguard Worker	//		the path to the tool, tool_file, input or output with name <label>. Use
147*6c119a46SAndroid Build Coastguard Worker	//		$(location) if <label> refers to a rule that outputs exactly one file.
148*6c119a46SAndroid Build Coastguard Worker	//	- $(locations <label>)
149*6c119a46SAndroid Build Coastguard Worker	//		the paths to the tools, tool_files, inputs or outputs with name
150*6c119a46SAndroid Build Coastguard Worker	//		<label>. Use $(locations) if <label> refers to a rule that outputs two
151*6c119a46SAndroid Build Coastguard Worker	//		or more files.
152*6c119a46SAndroid Build Coastguard Worker	//	- $(in)
153*6c119a46SAndroid Build Coastguard Worker	//		one or more input files
154*6c119a46SAndroid Build Coastguard Worker	//	- $(out)
155*6c119a46SAndroid Build Coastguard Worker	//		a single output file
156*6c119a46SAndroid Build Coastguard Worker	//	- $(genDir)
157*6c119a46SAndroid Build Coastguard Worker	//		the sandbox directory for this tool; contains $(out)
158*6c119a46SAndroid Build Coastguard Worker	//	- $$
159*6c119a46SAndroid Build Coastguard Worker	//		a literal '$'
160*6c119a46SAndroid Build Coastguard Worker	//
161*6c119a46SAndroid Build Coastguard Worker	// All files used must be declared as inputs (to ensure proper up-to-date
162*6c119a46SAndroid Build Coastguard Worker	// checks). Use "$(in)" directly in Cmd to ensure that all inputs used are
163*6c119a46SAndroid Build Coastguard Worker	// declared.
164*6c119a46SAndroid Build Coastguard Worker	Cmd *string
165*6c119a46SAndroid Build Coastguard Worker
166*6c119a46SAndroid Build Coastguard Worker	// name of the modules (if any) that produces the host executable. Leave
167*6c119a46SAndroid Build Coastguard Worker	// empty for prebuilts or scripts that do not need a module to build them.
168*6c119a46SAndroid Build Coastguard Worker	Tools []string
169*6c119a46SAndroid Build Coastguard Worker
170*6c119a46SAndroid Build Coastguard Worker	// Local source files that are used as scripts or other input files needed
171*6c119a46SAndroid Build Coastguard Worker	// by a tool.
172*6c119a46SAndroid Build Coastguard Worker	Tool_files []string `android:"path"`
173*6c119a46SAndroid Build Coastguard Worker
174*6c119a46SAndroid Build Coastguard Worker	// List of directories to export generated headers from.
175*6c119a46SAndroid Build Coastguard Worker	Export_include_dirs []string
176*6c119a46SAndroid Build Coastguard Worker
177*6c119a46SAndroid Build Coastguard Worker	// List of input files.
178*6c119a46SAndroid Build Coastguard Worker	Srcs []string `android:"path,arch_variant"`
179*6c119a46SAndroid Build Coastguard Worker
180*6c119a46SAndroid Build Coastguard Worker	// Input files to exclude.
181*6c119a46SAndroid Build Coastguard Worker	Exclude_srcs []string `android:"path,arch_variant"`
182*6c119a46SAndroid Build Coastguard Worker}
183*6c119a46SAndroid Build Coastguard Worker
184*6c119a46SAndroid Build Coastguard Workertype Module struct {
185*6c119a46SAndroid Build Coastguard Worker	android.ModuleBase
186*6c119a46SAndroid Build Coastguard Worker	android.DefaultableModuleBase
187*6c119a46SAndroid Build Coastguard Worker	android.ApexModuleBase
188*6c119a46SAndroid Build Coastguard Worker
189*6c119a46SAndroid Build Coastguard Worker	android.ImageInterface
190*6c119a46SAndroid Build Coastguard Worker
191*6c119a46SAndroid Build Coastguard Worker	properties generatorProperties
192*6c119a46SAndroid Build Coastguard Worker
193*6c119a46SAndroid Build Coastguard Worker	taskGenerator taskFunc
194*6c119a46SAndroid Build Coastguard Worker
195*6c119a46SAndroid Build Coastguard Worker	rawCommands []string
196*6c119a46SAndroid Build Coastguard Worker
197*6c119a46SAndroid Build Coastguard Worker	exportedIncludeDirs android.Paths
198*6c119a46SAndroid Build Coastguard Worker
199*6c119a46SAndroid Build Coastguard Worker	outputFiles android.Paths
200*6c119a46SAndroid Build Coastguard Worker	outputDeps  android.Paths
201*6c119a46SAndroid Build Coastguard Worker
202*6c119a46SAndroid Build Coastguard Worker	subName string
203*6c119a46SAndroid Build Coastguard Worker	subDir  string
204*6c119a46SAndroid Build Coastguard Worker
205*6c119a46SAndroid Build Coastguard Worker	// Collect the module directory for IDE info in java/jdeps.go.
206*6c119a46SAndroid Build Coastguard Worker	modulePaths []string
207*6c119a46SAndroid Build Coastguard Worker}
208*6c119a46SAndroid Build Coastguard Worker
209*6c119a46SAndroid Build Coastguard Workertype taskFunc func(ctx android.ModuleContext, rawCommand string, srcFiles android.Paths) []generateTask
210*6c119a46SAndroid Build Coastguard Worker
211*6c119a46SAndroid Build Coastguard Workertype generateTask struct {
212*6c119a46SAndroid Build Coastguard Worker	in     android.Paths
213*6c119a46SAndroid Build Coastguard Worker	out    android.WritablePaths
214*6c119a46SAndroid Build Coastguard Worker	copyTo android.WritablePaths
215*6c119a46SAndroid Build Coastguard Worker	genDir android.WritablePath
216*6c119a46SAndroid Build Coastguard Worker	cmd    string
217*6c119a46SAndroid Build Coastguard Worker
218*6c119a46SAndroid Build Coastguard Worker	shard  int
219*6c119a46SAndroid Build Coastguard Worker	shards int
220*6c119a46SAndroid Build Coastguard Worker}
221*6c119a46SAndroid Build Coastguard Worker
222*6c119a46SAndroid Build Coastguard Worker// Part of genrule.SourceFileGenerator.
223*6c119a46SAndroid Build Coastguard Worker// Returns the list of generated source files.
224*6c119a46SAndroid Build Coastguard Workerfunc (g *Module) GeneratedSourceFiles() android.Paths {
225*6c119a46SAndroid Build Coastguard Worker	return g.outputFiles
226*6c119a46SAndroid Build Coastguard Worker}
227*6c119a46SAndroid Build Coastguard Worker
228*6c119a46SAndroid Build Coastguard Worker// Part of genrule.SourceFileGenerator.
229*6c119a46SAndroid Build Coastguard Worker// Returns the list of input source files.
230*6c119a46SAndroid Build Coastguard Workerfunc (g *Module) Srcs() android.Paths {
231*6c119a46SAndroid Build Coastguard Worker	return append(android.Paths{}, g.outputFiles...)
232*6c119a46SAndroid Build Coastguard Worker}
233*6c119a46SAndroid Build Coastguard Worker
234*6c119a46SAndroid Build Coastguard Worker// Part of genrule.SourceFileGenerator.
235*6c119a46SAndroid Build Coastguard Worker// Returns the list of the list of exported include paths.
236*6c119a46SAndroid Build Coastguard Workerfunc (g *Module) GeneratedHeaderDirs() android.Paths {
237*6c119a46SAndroid Build Coastguard Worker	return g.exportedIncludeDirs
238*6c119a46SAndroid Build Coastguard Worker}
239*6c119a46SAndroid Build Coastguard Worker
240*6c119a46SAndroid Build Coastguard Worker// Part of genrule.SourceFileGenerator.
241*6c119a46SAndroid Build Coastguard Worker// Returns the list of files to be used as dependencies when using
242*6c119a46SAndroid Build Coastguard Worker// GeneratedHeaderDirs
243*6c119a46SAndroid Build Coastguard Workerfunc (g *Module) GeneratedDeps() android.Paths {
244*6c119a46SAndroid Build Coastguard Worker	return g.outputDeps
245*6c119a46SAndroid Build Coastguard Worker}
246*6c119a46SAndroid Build Coastguard Worker
247*6c119a46SAndroid Build Coastguard Worker// Ensure Module implements the genrule.SourceFileGenerator interface.
248*6c119a46SAndroid Build Coastguard Workervar _ genrule.SourceFileGenerator = (*Module)(nil)
249*6c119a46SAndroid Build Coastguard Worker
250*6c119a46SAndroid Build Coastguard Worker// Ensure Module implements the android.SourceFileProducer interface.
251*6c119a46SAndroid Build Coastguard Workervar _ android.SourceFileProducer = (*Module)(nil)
252*6c119a46SAndroid Build Coastguard Worker
253*6c119a46SAndroid Build Coastguard Workerfunc toolDepsMutator(ctx android.BottomUpMutatorContext) {
254*6c119a46SAndroid Build Coastguard Worker	if g, ok := ctx.Module().(*Module); ok {
255*6c119a46SAndroid Build Coastguard Worker		for _, tool := range g.properties.Tools {
256*6c119a46SAndroid Build Coastguard Worker			tag := hostToolDependencyTag{label: tool}
257*6c119a46SAndroid Build Coastguard Worker			if m := android.SrcIsModule(tool); m != "" {
258*6c119a46SAndroid Build Coastguard Worker				tool = m
259*6c119a46SAndroid Build Coastguard Worker			}
260*6c119a46SAndroid Build Coastguard Worker			ctx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), tag, tool)
261*6c119a46SAndroid Build Coastguard Worker		}
262*6c119a46SAndroid Build Coastguard Worker	}
263*6c119a46SAndroid Build Coastguard Worker}
264*6c119a46SAndroid Build Coastguard Worker
265*6c119a46SAndroid Build Coastguard Worker// Part of android.Module.
266*6c119a46SAndroid Build Coastguard Worker// Generates all the rules and builds commands used by this module instance.
267*6c119a46SAndroid Build Coastguard Workerfunc (g *Module) generateCommonBuildActions(ctx android.ModuleContext) {
268*6c119a46SAndroid Build Coastguard Worker	g.subName = ctx.ModuleSubDir()
269*6c119a46SAndroid Build Coastguard Worker
270*6c119a46SAndroid Build Coastguard Worker	// Collect the module directory for IDE info in java/jdeps.go.
271*6c119a46SAndroid Build Coastguard Worker	g.modulePaths = append(g.modulePaths, ctx.ModuleDir())
272*6c119a46SAndroid Build Coastguard Worker
273*6c119a46SAndroid Build Coastguard Worker	if len(g.properties.Export_include_dirs) > 0 {
274*6c119a46SAndroid Build Coastguard Worker		for _, dir := range g.properties.Export_include_dirs {
275*6c119a46SAndroid Build Coastguard Worker			g.exportedIncludeDirs = append(g.exportedIncludeDirs,
276*6c119a46SAndroid Build Coastguard Worker				android.PathForModuleGen(ctx, g.subDir, ctx.ModuleDir(), dir))
277*6c119a46SAndroid Build Coastguard Worker		}
278*6c119a46SAndroid Build Coastguard Worker	} else {
279*6c119a46SAndroid Build Coastguard Worker		g.exportedIncludeDirs = append(g.exportedIncludeDirs, android.PathForModuleGen(ctx, g.subDir))
280*6c119a46SAndroid Build Coastguard Worker	}
281*6c119a46SAndroid Build Coastguard Worker
282*6c119a46SAndroid Build Coastguard Worker	locationLabels := map[string]location{}
283*6c119a46SAndroid Build Coastguard Worker	firstLabel := ""
284*6c119a46SAndroid Build Coastguard Worker
285*6c119a46SAndroid Build Coastguard Worker	addLocationLabel := func(label string, loc location) {
286*6c119a46SAndroid Build Coastguard Worker		if firstLabel == "" {
287*6c119a46SAndroid Build Coastguard Worker			firstLabel = label
288*6c119a46SAndroid Build Coastguard Worker		}
289*6c119a46SAndroid Build Coastguard Worker		if _, exists := locationLabels[label]; !exists {
290*6c119a46SAndroid Build Coastguard Worker			locationLabels[label] = loc
291*6c119a46SAndroid Build Coastguard Worker		} else {
292*6c119a46SAndroid Build Coastguard Worker			ctx.ModuleErrorf("multiple locations for label %q: %q and %q (do you have duplicate srcs entries?)",
293*6c119a46SAndroid Build Coastguard Worker				label, locationLabels[label], loc)
294*6c119a46SAndroid Build Coastguard Worker		}
295*6c119a46SAndroid Build Coastguard Worker	}
296*6c119a46SAndroid Build Coastguard Worker
297*6c119a46SAndroid Build Coastguard Worker	var tools android.Paths
298*6c119a46SAndroid Build Coastguard Worker	var packagedTools []android.PackagingSpec
299*6c119a46SAndroid Build Coastguard Worker	if len(g.properties.Tools) > 0 {
300*6c119a46SAndroid Build Coastguard Worker		seenTools := make(map[string]bool)
301*6c119a46SAndroid Build Coastguard Worker
302*6c119a46SAndroid Build Coastguard Worker		ctx.VisitDirectDepsProxyAllowDisabled(func(proxy android.ModuleProxy) {
303*6c119a46SAndroid Build Coastguard Worker			switch tag := ctx.OtherModuleDependencyTag(proxy).(type) {
304*6c119a46SAndroid Build Coastguard Worker			case hostToolDependencyTag:
305*6c119a46SAndroid Build Coastguard Worker				// Necessary to retrieve any prebuilt replacement for the tool, since
306*6c119a46SAndroid Build Coastguard Worker				// toolDepsMutator runs too late for the prebuilt mutators to have
307*6c119a46SAndroid Build Coastguard Worker				// replaced the dependency.
308*6c119a46SAndroid Build Coastguard Worker				module := android.PrebuiltGetPreferred(ctx, proxy)
309*6c119a46SAndroid Build Coastguard Worker				tool := ctx.OtherModuleName(module)
310*6c119a46SAndroid Build Coastguard Worker				if h, ok := android.OtherModuleProvider(ctx, module, android.HostToolProviderKey); ok {
311*6c119a46SAndroid Build Coastguard Worker					// A HostToolProvider provides the path to a tool, which will be copied
312*6c119a46SAndroid Build Coastguard Worker					// into the sandbox.
313*6c119a46SAndroid Build Coastguard Worker					if !android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey).Enabled {
314*6c119a46SAndroid Build Coastguard Worker						if ctx.Config().AllowMissingDependencies() {
315*6c119a46SAndroid Build Coastguard Worker							ctx.AddMissingDependencies([]string{tool})
316*6c119a46SAndroid Build Coastguard Worker						} else {
317*6c119a46SAndroid Build Coastguard Worker							ctx.ModuleErrorf("depends on disabled module %q", tool)
318*6c119a46SAndroid Build Coastguard Worker						}
319*6c119a46SAndroid Build Coastguard Worker						return
320*6c119a46SAndroid Build Coastguard Worker					}
321*6c119a46SAndroid Build Coastguard Worker					path := h.HostToolPath
322*6c119a46SAndroid Build Coastguard Worker					if !path.Valid() {
323*6c119a46SAndroid Build Coastguard Worker						ctx.ModuleErrorf("host tool %q missing output file", tool)
324*6c119a46SAndroid Build Coastguard Worker						return
325*6c119a46SAndroid Build Coastguard Worker					}
326*6c119a46SAndroid Build Coastguard Worker					if specs := android.OtherModuleProviderOrDefault(
327*6c119a46SAndroid Build Coastguard Worker						ctx, module, android.InstallFilesProvider).TransitivePackagingSpecs.ToList(); specs != nil {
328*6c119a46SAndroid Build Coastguard Worker						// If the HostToolProvider has PackgingSpecs, which are definitions of the
329*6c119a46SAndroid Build Coastguard Worker						// required relative locations of the tool and its dependencies, use those
330*6c119a46SAndroid Build Coastguard Worker						// instead.  They will be copied to those relative locations in the sbox
331*6c119a46SAndroid Build Coastguard Worker						// sandbox.
332*6c119a46SAndroid Build Coastguard Worker						// Care must be taken since TransitivePackagingSpec may return device-side
333*6c119a46SAndroid Build Coastguard Worker						// paths via the required property. Filter them out.
334*6c119a46SAndroid Build Coastguard Worker						for i, ps := range specs {
335*6c119a46SAndroid Build Coastguard Worker							if ps.Partition() != "" {
336*6c119a46SAndroid Build Coastguard Worker								if i == 0 {
337*6c119a46SAndroid Build Coastguard Worker									panic("first PackagingSpec is assumed to be the host-side tool")
338*6c119a46SAndroid Build Coastguard Worker								}
339*6c119a46SAndroid Build Coastguard Worker								continue
340*6c119a46SAndroid Build Coastguard Worker							}
341*6c119a46SAndroid Build Coastguard Worker							packagedTools = append(packagedTools, ps)
342*6c119a46SAndroid Build Coastguard Worker						}
343*6c119a46SAndroid Build Coastguard Worker						// Assume that the first PackagingSpec of the module is the tool.
344*6c119a46SAndroid Build Coastguard Worker						addLocationLabel(tag.label, packagedToolLocation{specs[0]})
345*6c119a46SAndroid Build Coastguard Worker					} else {
346*6c119a46SAndroid Build Coastguard Worker						tools = append(tools, path.Path())
347*6c119a46SAndroid Build Coastguard Worker						addLocationLabel(tag.label, toolLocation{android.Paths{path.Path()}})
348*6c119a46SAndroid Build Coastguard Worker					}
349*6c119a46SAndroid Build Coastguard Worker				} else {
350*6c119a46SAndroid Build Coastguard Worker					ctx.ModuleErrorf("%q is not a host tool provider", tool)
351*6c119a46SAndroid Build Coastguard Worker					return
352*6c119a46SAndroid Build Coastguard Worker				}
353*6c119a46SAndroid Build Coastguard Worker
354*6c119a46SAndroid Build Coastguard Worker				seenTools[tag.label] = true
355*6c119a46SAndroid Build Coastguard Worker			}
356*6c119a46SAndroid Build Coastguard Worker		})
357*6c119a46SAndroid Build Coastguard Worker
358*6c119a46SAndroid Build Coastguard Worker		// If AllowMissingDependencies is enabled, the build will not have stopped when
359*6c119a46SAndroid Build Coastguard Worker		// AddFarVariationDependencies was called on a missing tool, which will result in nonsensical
360*6c119a46SAndroid Build Coastguard Worker		// "cmd: unknown location label ..." errors later.  Add a placeholder file to the local label.
361*6c119a46SAndroid Build Coastguard Worker		// The command that uses this placeholder file will never be executed because the rule will be
362*6c119a46SAndroid Build Coastguard Worker		// replaced with an android.Error rule reporting the missing dependencies.
363*6c119a46SAndroid Build Coastguard Worker		if ctx.Config().AllowMissingDependencies() {
364*6c119a46SAndroid Build Coastguard Worker			for _, tool := range g.properties.Tools {
365*6c119a46SAndroid Build Coastguard Worker				if !seenTools[tool] {
366*6c119a46SAndroid Build Coastguard Worker					addLocationLabel(tool, errorLocation{"***missing tool " + tool + "***"})
367*6c119a46SAndroid Build Coastguard Worker				}
368*6c119a46SAndroid Build Coastguard Worker			}
369*6c119a46SAndroid Build Coastguard Worker		}
370*6c119a46SAndroid Build Coastguard Worker	}
371*6c119a46SAndroid Build Coastguard Worker
372*6c119a46SAndroid Build Coastguard Worker	if ctx.Failed() {
373*6c119a46SAndroid Build Coastguard Worker		return
374*6c119a46SAndroid Build Coastguard Worker	}
375*6c119a46SAndroid Build Coastguard Worker
376*6c119a46SAndroid Build Coastguard Worker	for _, toolFile := range g.properties.Tool_files {
377*6c119a46SAndroid Build Coastguard Worker		paths := android.PathsForModuleSrc(ctx, []string{toolFile})
378*6c119a46SAndroid Build Coastguard Worker		tools = append(tools, paths...)
379*6c119a46SAndroid Build Coastguard Worker		addLocationLabel(toolFile, toolLocation{paths})
380*6c119a46SAndroid Build Coastguard Worker	}
381*6c119a46SAndroid Build Coastguard Worker
382*6c119a46SAndroid Build Coastguard Worker	includeDirInPaths := ctx.DeviceConfig().BuildBrokenInputDir(g.Name())
383*6c119a46SAndroid Build Coastguard Worker	var srcFiles android.Paths
384*6c119a46SAndroid Build Coastguard Worker	for _, in := range g.properties.Srcs {
385*6c119a46SAndroid Build Coastguard Worker		paths, missingDeps := android.PathsAndMissingDepsRelativeToModuleSourceDir(android.SourceInput{
386*6c119a46SAndroid Build Coastguard Worker			Context: ctx, Paths: []string{in}, ExcludePaths: g.properties.Exclude_srcs, IncludeDirs: includeDirInPaths,
387*6c119a46SAndroid Build Coastguard Worker		})
388*6c119a46SAndroid Build Coastguard Worker		if len(missingDeps) > 0 {
389*6c119a46SAndroid Build Coastguard Worker			if !ctx.Config().AllowMissingDependencies() {
390*6c119a46SAndroid Build Coastguard Worker				panic(fmt.Errorf("should never get here, the missing dependencies %q should have been reported in DepsMutator",
391*6c119a46SAndroid Build Coastguard Worker					missingDeps))
392*6c119a46SAndroid Build Coastguard Worker			}
393*6c119a46SAndroid Build Coastguard Worker
394*6c119a46SAndroid Build Coastguard Worker			// If AllowMissingDependencies is enabled, the build will not have stopped when
395*6c119a46SAndroid Build Coastguard Worker			// the dependency was added on a missing SourceFileProducer module, which will result in nonsensical
396*6c119a46SAndroid Build Coastguard Worker			// "cmd: label ":..." has no files" errors later.  Add a placeholder file to the local label.
397*6c119a46SAndroid Build Coastguard Worker			// The command that uses this placeholder file will never be executed because the rule will be
398*6c119a46SAndroid Build Coastguard Worker			// replaced with an android.Error rule reporting the missing dependencies.
399*6c119a46SAndroid Build Coastguard Worker			ctx.AddMissingDependencies(missingDeps)
400*6c119a46SAndroid Build Coastguard Worker			addLocationLabel(in, errorLocation{"***missing srcs " + in + "***"})
401*6c119a46SAndroid Build Coastguard Worker		} else {
402*6c119a46SAndroid Build Coastguard Worker			srcFiles = append(srcFiles, paths...)
403*6c119a46SAndroid Build Coastguard Worker			addLocationLabel(in, inputLocation{paths})
404*6c119a46SAndroid Build Coastguard Worker		}
405*6c119a46SAndroid Build Coastguard Worker	}
406*6c119a46SAndroid Build Coastguard Worker
407*6c119a46SAndroid Build Coastguard Worker	var copyFrom android.Paths
408*6c119a46SAndroid Build Coastguard Worker	var outputFiles android.WritablePaths
409*6c119a46SAndroid Build Coastguard Worker	var zipArgs strings.Builder
410*6c119a46SAndroid Build Coastguard Worker
411*6c119a46SAndroid Build Coastguard Worker	cmd := proptools.String(g.properties.Cmd)
412*6c119a46SAndroid Build Coastguard Worker
413*6c119a46SAndroid Build Coastguard Worker	tasks := g.taskGenerator(ctx, cmd, srcFiles)
414*6c119a46SAndroid Build Coastguard Worker	if ctx.Failed() {
415*6c119a46SAndroid Build Coastguard Worker		return
416*6c119a46SAndroid Build Coastguard Worker	}
417*6c119a46SAndroid Build Coastguard Worker
418*6c119a46SAndroid Build Coastguard Worker	for _, task := range tasks {
419*6c119a46SAndroid Build Coastguard Worker		if len(task.out) == 0 {
420*6c119a46SAndroid Build Coastguard Worker			ctx.ModuleErrorf("must have at least one output file")
421*6c119a46SAndroid Build Coastguard Worker			return
422*6c119a46SAndroid Build Coastguard Worker		}
423*6c119a46SAndroid Build Coastguard Worker
424*6c119a46SAndroid Build Coastguard Worker		// Pick a unique path outside the task.genDir for the sbox manifest textproto,
425*6c119a46SAndroid Build Coastguard Worker		// a unique rule name, and the user-visible description.
426*6c119a46SAndroid Build Coastguard Worker		manifestName := "wayland_protocol_codegen.sbox.textproto"
427*6c119a46SAndroid Build Coastguard Worker		desc := "generate"
428*6c119a46SAndroid Build Coastguard Worker		name := "generator"
429*6c119a46SAndroid Build Coastguard Worker		if task.shards > 0 {
430*6c119a46SAndroid Build Coastguard Worker			manifestName = "wayland_protocol_codegen_" + strconv.Itoa(task.shard) + ".sbox.textproto"
431*6c119a46SAndroid Build Coastguard Worker			desc += " " + strconv.Itoa(task.shard)
432*6c119a46SAndroid Build Coastguard Worker			name += strconv.Itoa(task.shard)
433*6c119a46SAndroid Build Coastguard Worker		} else if len(task.out) == 1 {
434*6c119a46SAndroid Build Coastguard Worker			desc += " " + task.out[0].Base()
435*6c119a46SAndroid Build Coastguard Worker		}
436*6c119a46SAndroid Build Coastguard Worker
437*6c119a46SAndroid Build Coastguard Worker		manifestPath := android.PathForModuleOut(ctx, manifestName)
438*6c119a46SAndroid Build Coastguard Worker
439*6c119a46SAndroid Build Coastguard Worker		// Use a RuleBuilder to create a rule that runs the command inside an sbox sandbox.
440*6c119a46SAndroid Build Coastguard Worker		rule := android.NewRuleBuilder(pctx, ctx).Sbox(task.genDir, manifestPath).SandboxTools()
441*6c119a46SAndroid Build Coastguard Worker		cmd := rule.Command()
442*6c119a46SAndroid Build Coastguard Worker
443*6c119a46SAndroid Build Coastguard Worker		for _, out := range task.out {
444*6c119a46SAndroid Build Coastguard Worker			addLocationLabel(out.Rel(), outputLocation{out})
445*6c119a46SAndroid Build Coastguard Worker		}
446*6c119a46SAndroid Build Coastguard Worker
447*6c119a46SAndroid Build Coastguard Worker		rawCommand, err := android.Expand(task.cmd, func(name string) (string, error) {
448*6c119a46SAndroid Build Coastguard Worker			// Report the error directly without returning an error to android.Expand to catch multiple errors in a
449*6c119a46SAndroid Build Coastguard Worker			// single run
450*6c119a46SAndroid Build Coastguard Worker			reportError := func(fmt string, args ...interface{}) (string, error) {
451*6c119a46SAndroid Build Coastguard Worker				ctx.PropertyErrorf("cmd", fmt, args...)
452*6c119a46SAndroid Build Coastguard Worker				return "SOONG_ERROR", nil
453*6c119a46SAndroid Build Coastguard Worker			}
454*6c119a46SAndroid Build Coastguard Worker
455*6c119a46SAndroid Build Coastguard Worker			// Apply shell escape to each cases to prevent source file paths containing $ from being evaluated in shell
456*6c119a46SAndroid Build Coastguard Worker			switch name {
457*6c119a46SAndroid Build Coastguard Worker			case "location":
458*6c119a46SAndroid Build Coastguard Worker				if len(g.properties.Tools) == 0 && len(g.properties.Tool_files) == 0 {
459*6c119a46SAndroid Build Coastguard Worker					return reportError("at least one `tools` or `tool_files` is required if $(location) is used")
460*6c119a46SAndroid Build Coastguard Worker				}
461*6c119a46SAndroid Build Coastguard Worker				loc := locationLabels[firstLabel]
462*6c119a46SAndroid Build Coastguard Worker				paths := loc.Paths(cmd)
463*6c119a46SAndroid Build Coastguard Worker				if len(paths) == 0 {
464*6c119a46SAndroid Build Coastguard Worker					return reportError("default label %q has no files", firstLabel)
465*6c119a46SAndroid Build Coastguard Worker				} else if len(paths) > 1 {
466*6c119a46SAndroid Build Coastguard Worker					return reportError("default label %q has multiple files, use $(locations %s) to reference it",
467*6c119a46SAndroid Build Coastguard Worker						firstLabel, firstLabel)
468*6c119a46SAndroid Build Coastguard Worker				}
469*6c119a46SAndroid Build Coastguard Worker				return proptools.ShellEscape(paths[0]), nil
470*6c119a46SAndroid Build Coastguard Worker			case "in":
471*6c119a46SAndroid Build Coastguard Worker				return strings.Join(proptools.ShellEscapeList(cmd.PathsForInputs(srcFiles)), " "), nil
472*6c119a46SAndroid Build Coastguard Worker			case "out":
473*6c119a46SAndroid Build Coastguard Worker				var sandboxOuts []string
474*6c119a46SAndroid Build Coastguard Worker				for _, out := range task.out {
475*6c119a46SAndroid Build Coastguard Worker					sandboxOuts = append(sandboxOuts, cmd.PathForOutput(out))
476*6c119a46SAndroid Build Coastguard Worker				}
477*6c119a46SAndroid Build Coastguard Worker				return strings.Join(proptools.ShellEscapeList(sandboxOuts), " "), nil
478*6c119a46SAndroid Build Coastguard Worker			case "genDir":
479*6c119a46SAndroid Build Coastguard Worker				return proptools.ShellEscape(cmd.PathForOutput(task.genDir)), nil
480*6c119a46SAndroid Build Coastguard Worker			default:
481*6c119a46SAndroid Build Coastguard Worker				if strings.HasPrefix(name, "location ") {
482*6c119a46SAndroid Build Coastguard Worker					label := strings.TrimSpace(strings.TrimPrefix(name, "location "))
483*6c119a46SAndroid Build Coastguard Worker					if loc, ok := locationLabels[label]; ok {
484*6c119a46SAndroid Build Coastguard Worker						paths := loc.Paths(cmd)
485*6c119a46SAndroid Build Coastguard Worker						if len(paths) == 0 {
486*6c119a46SAndroid Build Coastguard Worker							return reportError("label %q has no files", label)
487*6c119a46SAndroid Build Coastguard Worker						} else if len(paths) > 1 {
488*6c119a46SAndroid Build Coastguard Worker							return reportError("label %q has multiple files, use $(locations %s) to reference it",
489*6c119a46SAndroid Build Coastguard Worker								label, label)
490*6c119a46SAndroid Build Coastguard Worker						}
491*6c119a46SAndroid Build Coastguard Worker						return proptools.ShellEscape(paths[0]), nil
492*6c119a46SAndroid Build Coastguard Worker					} else {
493*6c119a46SAndroid Build Coastguard Worker						return reportError("unknown location label %q is not in srcs, out, tools or tool_files.", label)
494*6c119a46SAndroid Build Coastguard Worker					}
495*6c119a46SAndroid Build Coastguard Worker				} else if strings.HasPrefix(name, "locations ") {
496*6c119a46SAndroid Build Coastguard Worker					label := strings.TrimSpace(strings.TrimPrefix(name, "locations "))
497*6c119a46SAndroid Build Coastguard Worker					if loc, ok := locationLabels[label]; ok {
498*6c119a46SAndroid Build Coastguard Worker						paths := loc.Paths(cmd)
499*6c119a46SAndroid Build Coastguard Worker						if len(paths) == 0 {
500*6c119a46SAndroid Build Coastguard Worker							return reportError("label %q has no files", label)
501*6c119a46SAndroid Build Coastguard Worker						}
502*6c119a46SAndroid Build Coastguard Worker						return proptools.ShellEscape(strings.Join(paths, " ")), nil
503*6c119a46SAndroid Build Coastguard Worker					} else {
504*6c119a46SAndroid Build Coastguard Worker						return reportError("unknown locations label %q is not in srcs, out, tools or tool_files.", label)
505*6c119a46SAndroid Build Coastguard Worker					}
506*6c119a46SAndroid Build Coastguard Worker				} else {
507*6c119a46SAndroid Build Coastguard Worker					return reportError("unknown variable '$(%s)'", name)
508*6c119a46SAndroid Build Coastguard Worker				}
509*6c119a46SAndroid Build Coastguard Worker			}
510*6c119a46SAndroid Build Coastguard Worker		})
511*6c119a46SAndroid Build Coastguard Worker
512*6c119a46SAndroid Build Coastguard Worker		if err != nil {
513*6c119a46SAndroid Build Coastguard Worker			ctx.PropertyErrorf("cmd", "%s", err.Error())
514*6c119a46SAndroid Build Coastguard Worker			return
515*6c119a46SAndroid Build Coastguard Worker		}
516*6c119a46SAndroid Build Coastguard Worker
517*6c119a46SAndroid Build Coastguard Worker		g.rawCommands = append(g.rawCommands, rawCommand)
518*6c119a46SAndroid Build Coastguard Worker
519*6c119a46SAndroid Build Coastguard Worker		cmd.Text(rawCommand)
520*6c119a46SAndroid Build Coastguard Worker		cmd.ImplicitOutputs(task.out)
521*6c119a46SAndroid Build Coastguard Worker		cmd.Implicits(task.in)
522*6c119a46SAndroid Build Coastguard Worker		cmd.ImplicitTools(tools)
523*6c119a46SAndroid Build Coastguard Worker		cmd.ImplicitPackagedTools(packagedTools)
524*6c119a46SAndroid Build Coastguard Worker
525*6c119a46SAndroid Build Coastguard Worker		// Create the rule to run the genrule command inside sbox.
526*6c119a46SAndroid Build Coastguard Worker		rule.Build(name, desc)
527*6c119a46SAndroid Build Coastguard Worker
528*6c119a46SAndroid Build Coastguard Worker		if len(task.copyTo) > 0 {
529*6c119a46SAndroid Build Coastguard Worker			// If copyTo is set, multiple shards need to be copied into a single directory.
530*6c119a46SAndroid Build Coastguard Worker			// task.out contains the per-shard paths, and copyTo contains the corresponding
531*6c119a46SAndroid Build Coastguard Worker			// final path.  The files need to be copied into the final directory by a
532*6c119a46SAndroid Build Coastguard Worker			// single rule so it can remove the directory before it starts to ensure no
533*6c119a46SAndroid Build Coastguard Worker			// old files remain.  zipsync already does this, so build up zipArgs that
534*6c119a46SAndroid Build Coastguard Worker			// zip all the per-shard directories into a single zip.
535*6c119a46SAndroid Build Coastguard Worker			outputFiles = append(outputFiles, task.copyTo...)
536*6c119a46SAndroid Build Coastguard Worker			copyFrom = append(copyFrom, task.out.Paths()...)
537*6c119a46SAndroid Build Coastguard Worker			zipArgs.WriteString(" -C " + task.genDir.String())
538*6c119a46SAndroid Build Coastguard Worker			zipArgs.WriteString(android.JoinWithPrefix(task.out.Strings(), " -f "))
539*6c119a46SAndroid Build Coastguard Worker		} else {
540*6c119a46SAndroid Build Coastguard Worker			outputFiles = append(outputFiles, task.out...)
541*6c119a46SAndroid Build Coastguard Worker		}
542*6c119a46SAndroid Build Coastguard Worker	}
543*6c119a46SAndroid Build Coastguard Worker
544*6c119a46SAndroid Build Coastguard Worker	if len(copyFrom) > 0 {
545*6c119a46SAndroid Build Coastguard Worker		// Create a rule that zips all the per-shard directories into a single zip and then
546*6c119a46SAndroid Build Coastguard Worker		// uses zipsync to unzip it into the final directory.
547*6c119a46SAndroid Build Coastguard Worker		ctx.Build(pctx, android.BuildParams{
548*6c119a46SAndroid Build Coastguard Worker			Rule:        gensrcsMerge,
549*6c119a46SAndroid Build Coastguard Worker			Implicits:   copyFrom,
550*6c119a46SAndroid Build Coastguard Worker			Outputs:     outputFiles,
551*6c119a46SAndroid Build Coastguard Worker			Description: "merge shards",
552*6c119a46SAndroid Build Coastguard Worker			Args: map[string]string{
553*6c119a46SAndroid Build Coastguard Worker				"zipArgs": zipArgs.String(),
554*6c119a46SAndroid Build Coastguard Worker				"tmpZip":  android.PathForModuleGen(ctx, g.subDir+".zip").String(),
555*6c119a46SAndroid Build Coastguard Worker				"genDir":  android.PathForModuleGen(ctx, g.subDir).String(),
556*6c119a46SAndroid Build Coastguard Worker			},
557*6c119a46SAndroid Build Coastguard Worker		})
558*6c119a46SAndroid Build Coastguard Worker	}
559*6c119a46SAndroid Build Coastguard Worker
560*6c119a46SAndroid Build Coastguard Worker	g.outputFiles = outputFiles.Paths()
561*6c119a46SAndroid Build Coastguard Worker}
562*6c119a46SAndroid Build Coastguard Worker
563*6c119a46SAndroid Build Coastguard Workerfunc (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
564*6c119a46SAndroid Build Coastguard Worker	g.generateCommonBuildActions(ctx)
565*6c119a46SAndroid Build Coastguard Worker
566*6c119a46SAndroid Build Coastguard Worker	// When there are less than six outputs, we directly give those as the
567*6c119a46SAndroid Build Coastguard Worker	// output dependency for this module. However, if there are more outputs,
568*6c119a46SAndroid Build Coastguard Worker	// we inject a phony target. This potentially saves space in the generated
569*6c119a46SAndroid Build Coastguard Worker	// ninja file, as well as simplifying any visualizations of the dependency
570*6c119a46SAndroid Build Coastguard Worker	// graph.
571*6c119a46SAndroid Build Coastguard Worker	if len(g.outputFiles) <= 6 {
572*6c119a46SAndroid Build Coastguard Worker		g.outputDeps = g.outputFiles
573*6c119a46SAndroid Build Coastguard Worker	} else {
574*6c119a46SAndroid Build Coastguard Worker		phonyFile := android.PathForModuleGen(ctx, "genrule-phony")
575*6c119a46SAndroid Build Coastguard Worker		ctx.Build(pctx, android.BuildParams{
576*6c119a46SAndroid Build Coastguard Worker			Rule:   blueprint.Phony,
577*6c119a46SAndroid Build Coastguard Worker			Output: phonyFile,
578*6c119a46SAndroid Build Coastguard Worker			Inputs: g.outputFiles,
579*6c119a46SAndroid Build Coastguard Worker		})
580*6c119a46SAndroid Build Coastguard Worker		g.outputDeps = android.Paths{phonyFile}
581*6c119a46SAndroid Build Coastguard Worker	}
582*6c119a46SAndroid Build Coastguard Worker
583*6c119a46SAndroid Build Coastguard Worker	g.setOutputFiles(ctx)
584*6c119a46SAndroid Build Coastguard Worker}
585*6c119a46SAndroid Build Coastguard Worker
586*6c119a46SAndroid Build Coastguard Workerfunc (g *Module) setOutputFiles(ctx android.ModuleContext) {
587*6c119a46SAndroid Build Coastguard Worker	if len(g.outputFiles) == 0 {
588*6c119a46SAndroid Build Coastguard Worker		return
589*6c119a46SAndroid Build Coastguard Worker	}
590*6c119a46SAndroid Build Coastguard Worker	ctx.SetOutputFiles(g.outputFiles, "")
591*6c119a46SAndroid Build Coastguard Worker	// non-empty-string-tag should match one of the outputs
592*6c119a46SAndroid Build Coastguard Worker	for _, files := range g.outputFiles {
593*6c119a46SAndroid Build Coastguard Worker		ctx.SetOutputFiles(android.Paths{files}, files.Rel())
594*6c119a46SAndroid Build Coastguard Worker	}
595*6c119a46SAndroid Build Coastguard Worker}
596*6c119a46SAndroid Build Coastguard Worker
597*6c119a46SAndroid Build Coastguard Worker// Part of android.IDEInfo.
598*6c119a46SAndroid Build Coastguard Worker// Collect information for opening IDE project files in java/jdeps.go.
599*6c119a46SAndroid Build Coastguard Workerfunc (g *Module) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
600*6c119a46SAndroid Build Coastguard Worker	dpInfo.Srcs = append(dpInfo.Srcs, g.Srcs().Strings()...)
601*6c119a46SAndroid Build Coastguard Worker	for _, src := range g.properties.Srcs {
602*6c119a46SAndroid Build Coastguard Worker		if strings.HasPrefix(src, ":") {
603*6c119a46SAndroid Build Coastguard Worker			src = strings.Trim(src, ":")
604*6c119a46SAndroid Build Coastguard Worker			dpInfo.Deps = append(dpInfo.Deps, src)
605*6c119a46SAndroid Build Coastguard Worker		}
606*6c119a46SAndroid Build Coastguard Worker	}
607*6c119a46SAndroid Build Coastguard Worker	dpInfo.Paths = append(dpInfo.Paths, g.modulePaths...)
608*6c119a46SAndroid Build Coastguard Worker}
609*6c119a46SAndroid Build Coastguard Worker
610*6c119a46SAndroid Build Coastguard Workervar _ android.IDEInfo = (*Module)(nil)
611*6c119a46SAndroid Build Coastguard Worker
612*6c119a46SAndroid Build Coastguard Worker// Ensure Module implements android.ApexModule
613*6c119a46SAndroid Build Coastguard Worker// Note: gensrcs implements it but it's possible we do not actually need to.
614*6c119a46SAndroid Build Coastguard Workervar _ android.ApexModule = (*Module)(nil)
615*6c119a46SAndroid Build Coastguard Worker
616*6c119a46SAndroid Build Coastguard Worker// Part of android.ApexModule.
617*6c119a46SAndroid Build Coastguard Workerfunc (g *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
618*6c119a46SAndroid Build Coastguard Worker	sdkVersion android.ApiLevel) error {
619*6c119a46SAndroid Build Coastguard Worker	// Because generated outputs are checked by client modules(e.g. cc_library, ...)
620*6c119a46SAndroid Build Coastguard Worker	// we can safely ignore the check here.
621*6c119a46SAndroid Build Coastguard Worker	return nil
622*6c119a46SAndroid Build Coastguard Worker}
623*6c119a46SAndroid Build Coastguard Worker
624*6c119a46SAndroid Build Coastguard Workerfunc generatorFactory(taskGenerator taskFunc, props ...interface{}) *Module {
625*6c119a46SAndroid Build Coastguard Worker	module := &Module{
626*6c119a46SAndroid Build Coastguard Worker		taskGenerator: taskGenerator,
627*6c119a46SAndroid Build Coastguard Worker	}
628*6c119a46SAndroid Build Coastguard Worker
629*6c119a46SAndroid Build Coastguard Worker	module.AddProperties(props...)
630*6c119a46SAndroid Build Coastguard Worker	module.AddProperties(&module.properties)
631*6c119a46SAndroid Build Coastguard Worker
632*6c119a46SAndroid Build Coastguard Worker	module.ImageInterface = noopImageInterface{}
633*6c119a46SAndroid Build Coastguard Worker
634*6c119a46SAndroid Build Coastguard Worker	return module
635*6c119a46SAndroid Build Coastguard Worker}
636*6c119a46SAndroid Build Coastguard Worker
637*6c119a46SAndroid Build Coastguard Workertype noopImageInterface struct{}
638*6c119a46SAndroid Build Coastguard Worker
639*6c119a46SAndroid Build Coastguard Workerfunc (x noopImageInterface) ImageMutatorBegin(android.ImageInterfaceContext)                 {}
640*6c119a46SAndroid Build Coastguard Workerfunc (x noopImageInterface) VendorVariantNeeded(android.ImageInterfaceContext) bool          { return false }
641*6c119a46SAndroid Build Coastguard Workerfunc (x noopImageInterface) ProductVariantNeeded(android.ImageInterfaceContext) bool         { return false }
642*6c119a46SAndroid Build Coastguard Workerfunc (x noopImageInterface) CoreVariantNeeded(android.ImageInterfaceContext) bool            { return false }
643*6c119a46SAndroid Build Coastguard Workerfunc (x noopImageInterface) RamdiskVariantNeeded(android.ImageInterfaceContext) bool         { return false }
644*6c119a46SAndroid Build Coastguard Workerfunc (x noopImageInterface) VendorRamdiskVariantNeeded(android.ImageInterfaceContext) bool   { return false }
645*6c119a46SAndroid Build Coastguard Workerfunc (x noopImageInterface) DebugRamdiskVariantNeeded(android.ImageInterfaceContext) bool    { return false }
646*6c119a46SAndroid Build Coastguard Workerfunc (x noopImageInterface) RecoveryVariantNeeded(android.ImageInterfaceContext) bool        { return false }
647*6c119a46SAndroid Build Coastguard Workerfunc (x noopImageInterface) ExtraImageVariations(ctx android.ImageInterfaceContext) []string { return nil }
648*6c119a46SAndroid Build Coastguard Workerfunc (x noopImageInterface) SetImageVariation(ctx android.ImageInterfaceContext, variation string) {
649*6c119a46SAndroid Build Coastguard Worker}
650*6c119a46SAndroid Build Coastguard Worker
651*6c119a46SAndroid Build Coastguard Worker// Constructs a Module for handling the code generation.
652*6c119a46SAndroid Build Coastguard Workerfunc newCodegen() *Module {
653*6c119a46SAndroid Build Coastguard Worker	properties := &codegenProperties{}
654*6c119a46SAndroid Build Coastguard Worker
655*6c119a46SAndroid Build Coastguard Worker	// finalSubDir is the name of the subdirectory that output files will be generated into.
656*6c119a46SAndroid Build Coastguard Worker	// It is used so that per-shard directories can be placed alongside it an then finally
657*6c119a46SAndroid Build Coastguard Worker	// merged into it.
658*6c119a46SAndroid Build Coastguard Worker	const finalSubDir = "wayland_protocol_codegen"
659*6c119a46SAndroid Build Coastguard Worker
660*6c119a46SAndroid Build Coastguard Worker	// Code generation commands are sharded so that up to this many files
661*6c119a46SAndroid Build Coastguard Worker	// are generated as part of one sandbox process.
662*6c119a46SAndroid Build Coastguard Worker	const defaultShardSize = 100
663*6c119a46SAndroid Build Coastguard Worker
664*6c119a46SAndroid Build Coastguard Worker	taskGenerator := func(ctx android.ModuleContext, rawCommand string, srcFiles android.Paths) []generateTask {
665*6c119a46SAndroid Build Coastguard Worker		shardSize := defaultShardSize
666*6c119a46SAndroid Build Coastguard Worker
667*6c119a46SAndroid Build Coastguard Worker		if len(srcFiles) == 0 {
668*6c119a46SAndroid Build Coastguard Worker			ctx.ModuleErrorf("must have at least one source file")
669*6c119a46SAndroid Build Coastguard Worker			return []generateTask{}
670*6c119a46SAndroid Build Coastguard Worker		}
671*6c119a46SAndroid Build Coastguard Worker
672*6c119a46SAndroid Build Coastguard Worker		// wayland_protocol_codegen rules can easily hit command line limits by
673*6c119a46SAndroid Build Coastguard Worker		// repeating the command for every input file.  Shard the input files into
674*6c119a46SAndroid Build Coastguard Worker		// groups.
675*6c119a46SAndroid Build Coastguard Worker		shards := android.ShardPaths(srcFiles, shardSize)
676*6c119a46SAndroid Build Coastguard Worker		var generateTasks []generateTask
677*6c119a46SAndroid Build Coastguard Worker
678*6c119a46SAndroid Build Coastguard Worker		distinctOutputs := make(map[string]android.Path)
679*6c119a46SAndroid Build Coastguard Worker
680*6c119a46SAndroid Build Coastguard Worker		for i, shard := range shards {
681*6c119a46SAndroid Build Coastguard Worker			var commands []string
682*6c119a46SAndroid Build Coastguard Worker			var outFiles android.WritablePaths
683*6c119a46SAndroid Build Coastguard Worker			var copyTo android.WritablePaths
684*6c119a46SAndroid Build Coastguard Worker
685*6c119a46SAndroid Build Coastguard Worker			// When sharding is enabled (i.e. len(shards) > 1), the sbox rules for each
686*6c119a46SAndroid Build Coastguard Worker			// shard will be write to their own directories and then be merged together
687*6c119a46SAndroid Build Coastguard Worker			// into finalSubDir.  If sharding is not enabled (i.e. len(shards) == 1),
688*6c119a46SAndroid Build Coastguard Worker			// the sbox rule will write directly to finalSubDir.
689*6c119a46SAndroid Build Coastguard Worker			genSubDir := finalSubDir
690*6c119a46SAndroid Build Coastguard Worker			if len(shards) > 1 {
691*6c119a46SAndroid Build Coastguard Worker				genSubDir = strconv.Itoa(i)
692*6c119a46SAndroid Build Coastguard Worker			}
693*6c119a46SAndroid Build Coastguard Worker
694*6c119a46SAndroid Build Coastguard Worker			genDir := android.PathForModuleGen(ctx, genSubDir)
695*6c119a46SAndroid Build Coastguard Worker			// NOTE: This TODO is copied from gensrcs, as applies here too.
696*6c119a46SAndroid Build Coastguard Worker			// TODO(ccross): this RuleBuilder is a hack to be able to call
697*6c119a46SAndroid Build Coastguard Worker			// rule.Command().PathForOutput.  Replace this with passing the rule into the
698*6c119a46SAndroid Build Coastguard Worker			// generator.
699*6c119a46SAndroid Build Coastguard Worker			rule := android.NewRuleBuilder(pctx, ctx).Sbox(genDir, nil).SandboxTools()
700*6c119a46SAndroid Build Coastguard Worker
701*6c119a46SAndroid Build Coastguard Worker			for _, in := range shard {
702*6c119a46SAndroid Build Coastguard Worker				outFileRaw := expandOutputPath(ctx, *properties, in)
703*6c119a46SAndroid Build Coastguard Worker
704*6c119a46SAndroid Build Coastguard Worker				if conflictWith, hasKey := distinctOutputs[outFileRaw]; hasKey {
705*6c119a46SAndroid Build Coastguard Worker					ctx.ModuleErrorf("generation conflict: both '%v' and '%v' generate '%v'",
706*6c119a46SAndroid Build Coastguard Worker						conflictWith.String(), in.String(), outFileRaw)
707*6c119a46SAndroid Build Coastguard Worker				}
708*6c119a46SAndroid Build Coastguard Worker
709*6c119a46SAndroid Build Coastguard Worker				distinctOutputs[outFileRaw] = in
710*6c119a46SAndroid Build Coastguard Worker
711*6c119a46SAndroid Build Coastguard Worker				outFile := android.PathForModuleGen(ctx, finalSubDir, outFileRaw)
712*6c119a46SAndroid Build Coastguard Worker
713*6c119a46SAndroid Build Coastguard Worker				// If sharding is enabled, then outFile is the path to the output file in
714*6c119a46SAndroid Build Coastguard Worker				// the shard directory, and copyTo is the path to the output file in the
715*6c119a46SAndroid Build Coastguard Worker				// final directory.
716*6c119a46SAndroid Build Coastguard Worker				if len(shards) > 1 {
717*6c119a46SAndroid Build Coastguard Worker					shardFile := android.PathForModuleGen(ctx, genSubDir, outFileRaw)
718*6c119a46SAndroid Build Coastguard Worker					copyTo = append(copyTo, outFile)
719*6c119a46SAndroid Build Coastguard Worker					outFile = shardFile
720*6c119a46SAndroid Build Coastguard Worker				}
721*6c119a46SAndroid Build Coastguard Worker
722*6c119a46SAndroid Build Coastguard Worker				outFiles = append(outFiles, outFile)
723*6c119a46SAndroid Build Coastguard Worker
724*6c119a46SAndroid Build Coastguard Worker				// pre-expand the command line to replace $in and $out with references to
725*6c119a46SAndroid Build Coastguard Worker				// a single input and output file.
726*6c119a46SAndroid Build Coastguard Worker				command, err := android.Expand(rawCommand, func(name string) (string, error) {
727*6c119a46SAndroid Build Coastguard Worker					switch name {
728*6c119a46SAndroid Build Coastguard Worker					case "in":
729*6c119a46SAndroid Build Coastguard Worker						return in.String(), nil
730*6c119a46SAndroid Build Coastguard Worker					case "out":
731*6c119a46SAndroid Build Coastguard Worker						return rule.Command().PathForOutput(outFile), nil
732*6c119a46SAndroid Build Coastguard Worker					default:
733*6c119a46SAndroid Build Coastguard Worker						return "$(" + name + ")", nil
734*6c119a46SAndroid Build Coastguard Worker					}
735*6c119a46SAndroid Build Coastguard Worker				})
736*6c119a46SAndroid Build Coastguard Worker				if err != nil {
737*6c119a46SAndroid Build Coastguard Worker					ctx.PropertyErrorf("cmd", err.Error())
738*6c119a46SAndroid Build Coastguard Worker				}
739*6c119a46SAndroid Build Coastguard Worker
740*6c119a46SAndroid Build Coastguard Worker				// escape the command in case for example it contains '#', an odd number of '"', etc
741*6c119a46SAndroid Build Coastguard Worker				command = fmt.Sprintf("bash -c %v", proptools.ShellEscape(command))
742*6c119a46SAndroid Build Coastguard Worker				commands = append(commands, command)
743*6c119a46SAndroid Build Coastguard Worker			}
744*6c119a46SAndroid Build Coastguard Worker			fullCommand := strings.Join(commands, " && ")
745*6c119a46SAndroid Build Coastguard Worker
746*6c119a46SAndroid Build Coastguard Worker			generateTasks = append(generateTasks, generateTask{
747*6c119a46SAndroid Build Coastguard Worker				in:     shard,
748*6c119a46SAndroid Build Coastguard Worker				out:    outFiles,
749*6c119a46SAndroid Build Coastguard Worker				copyTo: copyTo,
750*6c119a46SAndroid Build Coastguard Worker				genDir: genDir,
751*6c119a46SAndroid Build Coastguard Worker				cmd:    fullCommand,
752*6c119a46SAndroid Build Coastguard Worker				shard:  i,
753*6c119a46SAndroid Build Coastguard Worker				shards: len(shards),
754*6c119a46SAndroid Build Coastguard Worker			})
755*6c119a46SAndroid Build Coastguard Worker		}
756*6c119a46SAndroid Build Coastguard Worker
757*6c119a46SAndroid Build Coastguard Worker		return generateTasks
758*6c119a46SAndroid Build Coastguard Worker	}
759*6c119a46SAndroid Build Coastguard Worker
760*6c119a46SAndroid Build Coastguard Worker	g := generatorFactory(taskGenerator, properties)
761*6c119a46SAndroid Build Coastguard Worker	g.subDir = finalSubDir
762*6c119a46SAndroid Build Coastguard Worker	return g
763*6c119a46SAndroid Build Coastguard Worker}
764*6c119a46SAndroid Build Coastguard Worker
765*6c119a46SAndroid Build Coastguard Worker// Factory for code generation modules
766*6c119a46SAndroid Build Coastguard Workerfunc codegenFactory() android.Module {
767*6c119a46SAndroid Build Coastguard Worker	m := newCodegen()
768*6c119a46SAndroid Build Coastguard Worker	android.InitAndroidModule(m)
769*6c119a46SAndroid Build Coastguard Worker	android.InitDefaultableModule(m)
770*6c119a46SAndroid Build Coastguard Worker	return m
771*6c119a46SAndroid Build Coastguard Worker}
772*6c119a46SAndroid Build Coastguard Worker
773*6c119a46SAndroid Build Coastguard Worker// The custom properties specific to this code generation module.
774*6c119a46SAndroid Build Coastguard Workertype codegenProperties struct {
775*6c119a46SAndroid Build Coastguard Worker	// The string to prepend to every protocol filename to generate the
776*6c119a46SAndroid Build Coastguard Worker	// corresponding output filename. The empty string by default.
777*6c119a46SAndroid Build Coastguard Worker	// Deprecated. Prefer "Output" instead.
778*6c119a46SAndroid Build Coastguard Worker	Prefix *string
779*6c119a46SAndroid Build Coastguard Worker
780*6c119a46SAndroid Build Coastguard Worker	// The suffix to append to every protocol filename to generate the
781*6c119a46SAndroid Build Coastguard Worker	// corresponding output filename. The empty string by default.
782*6c119a46SAndroid Build Coastguard Worker	// Deprecated. Prefer "Output" instead.
783*6c119a46SAndroid Build Coastguard Worker	Suffix *string
784*6c119a46SAndroid Build Coastguard Worker
785*6c119a46SAndroid Build Coastguard Worker	// The output filename template.
786*6c119a46SAndroid Build Coastguard Worker	//
787*6c119a46SAndroid Build Coastguard Worker	// This template string allows the output file name to be generated for
788*6c119a46SAndroid Build Coastguard Worker	// each source file, using some limited properties of the source file.
789*6c119a46SAndroid Build Coastguard Worker	//
790*6c119a46SAndroid Build Coastguard Worker	//	$(in:base): The base filename, no path or extension
791*6c119a46SAndroid Build Coastguard Worker	//	$(in:base.ext): The filename, no path
792*6c119a46SAndroid Build Coastguard Worker	//	$(in:path/base): The filename with path but no extension
793*6c119a46SAndroid Build Coastguard Worker	//	$(in:path/base.ext): The full source filename
794*6c119a46SAndroid Build Coastguard Worker	//	$(in): An alias for $(in:base) for the base filename, no extension
795*6c119a46SAndroid Build Coastguard Worker	//
796*6c119a46SAndroid Build Coastguard Worker	// Note that the path that is maintained is the relative path used when
797*6c119a46SAndroid Build Coastguard Worker	// including the source in an Android.bp file.
798*6c119a46SAndroid Build Coastguard Worker	//
799*6c119a46SAndroid Build Coastguard Worker	// The template allows arbitrary prefixes and suffixes to be added to the
800*6c119a46SAndroid Build Coastguard Worker	// output filename. For example, "a_$(in).d" would take an source filename
801*6c119a46SAndroid Build Coastguard Worker	// of "b.c" and turn it into "a_b.d".
802*6c119a46SAndroid Build Coastguard Worker	//
803*6c119a46SAndroid Build Coastguard Worker	// The output template does not have to generate a unique filename,
804*6c119a46SAndroid Build Coastguard Worker	// however the implementation will raise an error if the same output file
805*6c119a46SAndroid Build Coastguard Worker	// is generated by more than one source file.
806*6c119a46SAndroid Build Coastguard Worker	Output *string
807*6c119a46SAndroid Build Coastguard Worker}
808*6c119a46SAndroid Build Coastguard Worker
809*6c119a46SAndroid Build Coastguard Worker// Expands the output path pattern to form the output path for the given
810*6c119a46SAndroid Build Coastguard Worker// input path.
811*6c119a46SAndroid Build Coastguard Workerfunc expandOutputPath(ctx android.ModuleContext, properties codegenProperties, in android.Path) string {
812*6c119a46SAndroid Build Coastguard Worker	template := proptools.String(properties.Output)
813*6c119a46SAndroid Build Coastguard Worker	if len(template) == 0 {
814*6c119a46SAndroid Build Coastguard Worker		prefix := proptools.String(properties.Prefix)
815*6c119a46SAndroid Build Coastguard Worker		suffix := proptools.String(properties.Suffix)
816*6c119a46SAndroid Build Coastguard Worker		return prefix + removeExtension(in.Base()) + suffix
817*6c119a46SAndroid Build Coastguard Worker	}
818*6c119a46SAndroid Build Coastguard Worker
819*6c119a46SAndroid Build Coastguard Worker	outPath, _ := android.Expand(template, func(name string) (string, error) {
820*6c119a46SAndroid Build Coastguard Worker		// Report the error directly without returning an error to
821*6c119a46SAndroid Build Coastguard Worker		// android.Expand to catch multiple errors in a single run.
822*6c119a46SAndroid Build Coastguard Worker		reportError := func(fmt string, args ...interface{}) (string, error) {
823*6c119a46SAndroid Build Coastguard Worker			ctx.PropertyErrorf("output", fmt, args...)
824*6c119a46SAndroid Build Coastguard Worker			return "EXPANSION_ERROR", nil
825*6c119a46SAndroid Build Coastguard Worker		}
826*6c119a46SAndroid Build Coastguard Worker
827*6c119a46SAndroid Build Coastguard Worker		switch name {
828*6c119a46SAndroid Build Coastguard Worker		case "in":
829*6c119a46SAndroid Build Coastguard Worker			return removeExtension(in.Base()), nil
830*6c119a46SAndroid Build Coastguard Worker		case "in:base":
831*6c119a46SAndroid Build Coastguard Worker			return removeExtension(in.Base()), nil
832*6c119a46SAndroid Build Coastguard Worker		case "in:base.ext":
833*6c119a46SAndroid Build Coastguard Worker			return in.Base(), nil
834*6c119a46SAndroid Build Coastguard Worker		case "in:path/base":
835*6c119a46SAndroid Build Coastguard Worker			return removeExtension(in.Rel()), nil
836*6c119a46SAndroid Build Coastguard Worker		case "in:path/base.ext":
837*6c119a46SAndroid Build Coastguard Worker			return in.Rel(), nil
838*6c119a46SAndroid Build Coastguard Worker		default:
839*6c119a46SAndroid Build Coastguard Worker			return reportError("unknown variable '$(%s)'", name)
840*6c119a46SAndroid Build Coastguard Worker		}
841*6c119a46SAndroid Build Coastguard Worker	})
842*6c119a46SAndroid Build Coastguard Worker
843*6c119a46SAndroid Build Coastguard Worker	return outPath
844*6c119a46SAndroid Build Coastguard Worker}
845*6c119a46SAndroid Build Coastguard Worker
846*6c119a46SAndroid Build Coastguard Worker// Removes any extension from the final component of a path.
847*6c119a46SAndroid Build Coastguard Workerfunc removeExtension(path string) string {
848*6c119a46SAndroid Build Coastguard Worker	// Note: This implementation does not handle files like ".bashrc" correctly.
849*6c119a46SAndroid Build Coastguard Worker	if dot := strings.LastIndex(path, "."); dot != -1 {
850*6c119a46SAndroid Build Coastguard Worker		return path[:dot]
851*6c119a46SAndroid Build Coastguard Worker	}
852*6c119a46SAndroid Build Coastguard Worker	return path
853*6c119a46SAndroid Build Coastguard Worker}
854*6c119a46SAndroid Build Coastguard Worker
855*6c119a46SAndroid Build Coastguard Worker// Defaults module.
856*6c119a46SAndroid Build Coastguard Workertype Defaults struct {
857*6c119a46SAndroid Build Coastguard Worker	android.ModuleBase
858*6c119a46SAndroid Build Coastguard Worker	android.DefaultsModuleBase
859*6c119a46SAndroid Build Coastguard Worker}
860*6c119a46SAndroid Build Coastguard Worker
861*6c119a46SAndroid Build Coastguard Workerfunc defaultsFactory() android.Module {
862*6c119a46SAndroid Build Coastguard Worker	return DefaultsFactory()
863*6c119a46SAndroid Build Coastguard Worker}
864*6c119a46SAndroid Build Coastguard Worker
865*6c119a46SAndroid Build Coastguard Workerfunc DefaultsFactory(props ...interface{}) android.Module {
866*6c119a46SAndroid Build Coastguard Worker	module := &Defaults{}
867*6c119a46SAndroid Build Coastguard Worker
868*6c119a46SAndroid Build Coastguard Worker	module.AddProperties(props...)
869*6c119a46SAndroid Build Coastguard Worker	module.AddProperties(
870*6c119a46SAndroid Build Coastguard Worker		&generatorProperties{},
871*6c119a46SAndroid Build Coastguard Worker		&codegenProperties{},
872*6c119a46SAndroid Build Coastguard Worker	)
873*6c119a46SAndroid Build Coastguard Worker
874*6c119a46SAndroid Build Coastguard Worker	android.InitDefaultsModule(module)
875*6c119a46SAndroid Build Coastguard Worker
876*6c119a46SAndroid Build Coastguard Worker	return module
877*6c119a46SAndroid Build Coastguard Worker}
878