1// Copyright 2015 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 cc
16
17import (
18	"path/filepath"
19	"strings"
20
21	"github.com/google/blueprint"
22
23	"android/soong/android"
24)
25
26func init() {
27	pctx.SourcePathVariable("lexCmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/flex")
28	pctx.SourcePathVariable("m4Cmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/m4")
29
30	pctx.HostBinToolVariable("aidlCmd", "aidl-cpp")
31	pctx.HostBinToolVariable("syspropCmd", "sysprop_cpp")
32}
33
34var (
35	lex = pctx.AndroidStaticRule("lex",
36		blueprint.RuleParams{
37			Command:     "M4=$m4Cmd $lexCmd $flags -o$out $in",
38			CommandDeps: []string{"$lexCmd", "$m4Cmd"},
39		}, "flags")
40
41	sysprop = pctx.AndroidStaticRule("sysprop",
42		blueprint.RuleParams{
43			Command: "$syspropCmd --header-dir=$headerOutDir --public-header-dir=$publicOutDir " +
44				"--source-dir=$srcOutDir --include-name=$includeName $in",
45			CommandDeps: []string{"$syspropCmd"},
46		},
47		"headerOutDir", "publicOutDir", "srcOutDir", "includeName")
48
49	windmc = pctx.AndroidStaticRule("windmc",
50		blueprint.RuleParams{
51			Command:     "$windmcCmd -r$$(dirname $out) -h$$(dirname $out) $in",
52			CommandDeps: []string{"$windmcCmd"},
53		},
54		"windmcCmd")
55)
56
57type YaccProperties struct {
58	// list of module-specific flags that will be used for .y and .yy compiles
59	Flags []string
60
61	// whether the yacc files will produce a location.hh file
62	Gen_location_hh *bool
63
64	// whether the yacc files will product a position.hh file
65	Gen_position_hh *bool
66}
67
68func genYacc(ctx android.ModuleContext, rule *android.RuleBuilder, yaccFile android.Path,
69	outFile android.ModuleGenPath, props *YaccProperties) (headerFiles android.Paths) {
70
71	outDir := android.PathForModuleGen(ctx, "yacc")
72	headerFile := android.GenPathWithExt(ctx, "yacc", yaccFile, "h")
73	ret := android.Paths{headerFile}
74
75	cmd := rule.Command()
76
77	// Fix up #line markers to not use the sbox temporary directory
78	// android.sboxPathForOutput(outDir, outDir) returns the sbox placeholder for the out
79	// directory itself, without any filename appended.
80	sboxOutDir := cmd.PathForOutput(outDir)
81	sedCmd := "sed -i.bak 's#" + sboxOutDir + "#" + outDir.String() + "#'"
82	rule.Command().Text(sedCmd).Input(outFile)
83	rule.Command().Text(sedCmd).Input(headerFile)
84
85	var flags []string
86	if props != nil {
87		flags = props.Flags
88
89		if Bool(props.Gen_location_hh) {
90			locationHeader := outFile.InSameDir(ctx, "location.hh")
91			ret = append(ret, locationHeader)
92			cmd.ImplicitOutput(locationHeader)
93			rule.Command().Text(sedCmd).Input(locationHeader)
94		}
95		if Bool(props.Gen_position_hh) {
96			positionHeader := outFile.InSameDir(ctx, "position.hh")
97			ret = append(ret, positionHeader)
98			cmd.ImplicitOutput(positionHeader)
99			rule.Command().Text(sedCmd).Input(positionHeader)
100		}
101	}
102
103	cmd.Text("BISON_PKGDATADIR=prebuilts/build-tools/common/bison").
104		FlagWithInput("M4=", ctx.Config().PrebuiltBuildTool(ctx, "m4")).
105		PrebuiltBuildTool(ctx, "bison").
106		Flag("-d").
107		Flags(flags).
108		FlagWithOutput("--defines=", headerFile).
109		Flag("-o").Output(outFile).Input(yaccFile)
110
111	return ret
112}
113
114func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile android.Path, aidlFlags string) (cppFile android.OutputPath, headerFiles android.Paths) {
115	aidlPackage := strings.TrimSuffix(aidlFile.Rel(), aidlFile.Base())
116	baseName := strings.TrimSuffix(aidlFile.Base(), aidlFile.Ext())
117	shortName := baseName
118	// TODO(b/111362593): aidl_to_cpp_common.cpp uses heuristics to figure out if
119	//   an interface name has a leading I. Those same heuristics have been
120	//   moved here.
121	if len(baseName) >= 2 && baseName[0] == 'I' &&
122		strings.ToUpper(baseName)[1] == baseName[1] {
123		shortName = strings.TrimPrefix(baseName, "I")
124	}
125
126	outDir := android.PathForModuleGen(ctx, "aidl")
127	cppFile = outDir.Join(ctx, aidlPackage, baseName+".cpp")
128	depFile := outDir.Join(ctx, aidlPackage, baseName+".cpp.d")
129	headerI := outDir.Join(ctx, aidlPackage, baseName+".h")
130	headerBn := outDir.Join(ctx, aidlPackage, "Bn"+shortName+".h")
131	headerBp := outDir.Join(ctx, aidlPackage, "Bp"+shortName+".h")
132
133	baseDir := strings.TrimSuffix(aidlFile.String(), aidlFile.Rel())
134	if baseDir != "" {
135		aidlFlags += " -I" + baseDir
136	}
137
138	cmd := rule.Command()
139	cmd.BuiltTool("aidl-cpp").
140		FlagWithDepFile("-d", depFile).
141		Flag("--ninja").
142		Flag(aidlFlags).
143		Input(aidlFile).
144		OutputDir().
145		Output(cppFile).
146		ImplicitOutputs(android.WritablePaths{
147			headerI,
148			headerBn,
149			headerBp,
150		})
151
152	return cppFile, android.Paths{
153		headerI,
154		headerBn,
155		headerBp,
156	}
157}
158
159type LexProperties struct {
160	// list of module-specific flags that will be used for .l and .ll compiles
161	Flags []string
162}
163
164func genLex(ctx android.ModuleContext, lexFile android.Path, outFile android.ModuleGenPath, props *LexProperties) {
165	var flags []string
166	if props != nil {
167		flags = props.Flags
168	}
169	flagsString := strings.Join(flags[:], " ")
170	ctx.Build(pctx, android.BuildParams{
171		Rule:        lex,
172		Description: "lex " + lexFile.Rel(),
173		Output:      outFile,
174		Input:       lexFile,
175		Args:        map[string]string{"flags": flagsString},
176	})
177}
178
179func genSysprop(ctx android.ModuleContext, syspropFile android.Path) (android.Path, android.Paths) {
180	headerFile := android.PathForModuleGen(ctx, "sysprop", "include", syspropFile.Rel()+".h")
181	publicHeaderFile := android.PathForModuleGen(ctx, "sysprop/public", "include", syspropFile.Rel()+".h")
182	cppFile := android.PathForModuleGen(ctx, "sysprop", syspropFile.Rel()+".cpp")
183
184	headers := android.WritablePaths{headerFile, publicHeaderFile}
185
186	ctx.Build(pctx, android.BuildParams{
187		Rule:            sysprop,
188		Description:     "sysprop " + syspropFile.Rel(),
189		Output:          cppFile,
190		ImplicitOutputs: headers,
191		Input:           syspropFile,
192		Args: map[string]string{
193			"headerOutDir": filepath.Dir(headerFile.String()),
194			"publicOutDir": filepath.Dir(publicHeaderFile.String()),
195			"srcOutDir":    filepath.Dir(cppFile.String()),
196			"includeName":  syspropFile.Rel() + ".h",
197		},
198	})
199
200	return cppFile, headers.Paths()
201}
202
203func genWinMsg(ctx android.ModuleContext, srcFile android.Path, flags builderFlags) (android.Path, android.Path) {
204	headerFile := android.GenPathWithExt(ctx, "windmc", srcFile, "h")
205	rcFile := android.GenPathWithExt(ctx, "windmc", srcFile, "rc")
206
207	windmcCmd := gccCmd(flags.toolchain, "windmc")
208
209	ctx.Build(pctx, android.BuildParams{
210		Rule:           windmc,
211		Description:    "windmc " + srcFile.Rel(),
212		Output:         rcFile,
213		ImplicitOutput: headerFile,
214		Input:          srcFile,
215		Args: map[string]string{
216			"windmcCmd": windmcCmd,
217		},
218	})
219
220	return rcFile, headerFile
221}
222
223// Used to communicate information from the genSources method back to the library code that uses
224// it.
225type generatedSourceInfo struct {
226	// The headers created from .proto files
227	protoHeaders android.Paths
228
229	// The files that can be used as order only dependencies in order to ensure that the proto header
230	// files are up to date.
231	protoOrderOnlyDeps android.Paths
232
233	// The headers created from .aidl files
234	aidlHeaders android.Paths
235
236	// The files that can be used as order only dependencies in order to ensure that the aidl header
237	// files are up to date.
238	aidlOrderOnlyDeps android.Paths
239
240	// The headers created from .sysprop files
241	syspropHeaders android.Paths
242
243	// The files that can be used as order only dependencies in order to ensure that the sysprop
244	// header files are up to date.
245	syspropOrderOnlyDeps android.Paths
246}
247
248func genSources(ctx android.ModuleContext, srcFiles android.Paths,
249	buildFlags builderFlags) (android.Paths, android.Paths, generatedSourceInfo) {
250
251	var info generatedSourceInfo
252
253	var deps android.Paths
254	var rsFiles android.Paths
255
256	var aidlRule *android.RuleBuilder
257
258	var yaccRule_ *android.RuleBuilder
259	yaccRule := func() *android.RuleBuilder {
260		if yaccRule_ == nil {
261			yaccRule_ = android.NewRuleBuilder(pctx, ctx).Sbox(android.PathForModuleGen(ctx, "yacc"),
262				android.PathForModuleGen(ctx, "yacc.sbox.textproto"))
263		}
264		return yaccRule_
265	}
266
267	for i, srcFile := range srcFiles {
268		switch srcFile.Ext() {
269		case ".y":
270			cFile := android.GenPathWithExt(ctx, "yacc", srcFile, "c")
271			srcFiles[i] = cFile
272			deps = append(deps, genYacc(ctx, yaccRule(), srcFile, cFile, buildFlags.yacc)...)
273		case ".yy":
274			cppFile := android.GenPathWithExt(ctx, "yacc", srcFile, "cpp")
275			srcFiles[i] = cppFile
276			deps = append(deps, genYacc(ctx, yaccRule(), srcFile, cppFile, buildFlags.yacc)...)
277		case ".l":
278			cFile := android.GenPathWithExt(ctx, "lex", srcFile, "c")
279			srcFiles[i] = cFile
280			genLex(ctx, srcFile, cFile, buildFlags.lex)
281		case ".ll":
282			cppFile := android.GenPathWithExt(ctx, "lex", srcFile, "cpp")
283			srcFiles[i] = cppFile
284			genLex(ctx, srcFile, cppFile, buildFlags.lex)
285		case ".proto":
286			ccFile, headerFile := genProto(ctx, srcFile, buildFlags)
287			srcFiles[i] = ccFile
288			info.protoHeaders = append(info.protoHeaders, headerFile)
289			// Use the generated header as an order only dep to ensure that it is up to date when needed.
290			info.protoOrderOnlyDeps = append(info.protoOrderOnlyDeps, headerFile)
291		case ".aidl":
292			if aidlRule == nil {
293				aidlRule = android.NewRuleBuilder(pctx, ctx).Sbox(android.PathForModuleGen(ctx, "aidl"),
294					android.PathForModuleGen(ctx, "aidl.sbox.textproto"))
295			}
296			cppFile, aidlHeaders := genAidl(ctx, aidlRule, srcFile, buildFlags.aidlFlags)
297			srcFiles[i] = cppFile
298
299			info.aidlHeaders = append(info.aidlHeaders, aidlHeaders...)
300			// Use the generated headers as order only deps to ensure that they are up to date when
301			// needed.
302			// TODO: Reduce the size of the ninja file by using one order only dep for the whole rule
303			info.aidlOrderOnlyDeps = append(info.aidlOrderOnlyDeps, aidlHeaders...)
304		case ".rscript", ".fs":
305			cppFile := rsGeneratedCppFile(ctx, srcFile)
306			rsFiles = append(rsFiles, srcFiles[i])
307			srcFiles[i] = cppFile
308		case ".mc":
309			rcFile, headerFile := genWinMsg(ctx, srcFile, buildFlags)
310			srcFiles[i] = rcFile
311			deps = append(deps, headerFile)
312		case ".sysprop":
313			cppFile, headerFiles := genSysprop(ctx, srcFile)
314			srcFiles[i] = cppFile
315			info.syspropHeaders = append(info.syspropHeaders, headerFiles...)
316			// Use the generated headers as order only deps to ensure that they are up to date when
317			// needed.
318			info.syspropOrderOnlyDeps = append(info.syspropOrderOnlyDeps, headerFiles...)
319		}
320	}
321
322	if aidlRule != nil {
323		aidlRule.Build("aidl", "gen aidl")
324	}
325
326	if yaccRule_ != nil {
327		yaccRule_.Build("yacc", "gen yacc")
328	}
329
330	deps = append(deps, info.protoOrderOnlyDeps...)
331	deps = append(deps, info.aidlOrderOnlyDeps...)
332	deps = append(deps, info.syspropOrderOnlyDeps...)
333
334	if len(rsFiles) > 0 {
335		deps = append(deps, rsGenerateCpp(ctx, rsFiles, buildFlags.rsFlags)...)
336	}
337
338	return srcFiles, deps, info
339}
340