1package libchrome
2
3import (
4	"fmt"
5	"path"
6	"strings"
7
8	"android/soong/android"
9	"android/soong/genrule"
10
11	"github.com/google/blueprint"
12)
13
14func init() {
15	android.RegisterModuleType("generate_mojom_pickles", mojomPicklesFactory)
16	android.RegisterModuleType("generate_mojom_headers", mojomHeadersFactory)
17	android.RegisterModuleType("generate_mojom_srcs", mojomSrcsFactory)
18	android.RegisterModuleType("generate_mojom_srcjar", mojomSrcjarFactory)
19}
20
21var (
22	pctx = android.NewPackageContext("android/soong/external/libchrome")
23
24	mojomBindingsGenerator = pctx.HostBinToolVariable("mojomBindingsGenerator", "mojom_bindings_generator")
25	mergeZips              = pctx.HostBinToolVariable("mergeZips", "merge_zips")
26
27	generateMojomPicklesRule = pctx.StaticRule("generateMojomPicklesRule", blueprint.RuleParams{
28		Command: `${mojomBindingsGenerator}
29		--use_bundled_pylibs parse
30		-d ${package}
31		${flags}
32		-o ${outDir}
33		${in}`,
34		CommandDeps: []string{
35			"${mojomBindingsGenerator}",
36		},
37		Description: "Mojo pickles generation $in => $out",
38		Restat:      true,
39	}, "package", "flags", "outDir")
40
41	generateMojomSrcsRule = pctx.StaticRule("generateMojomSrcsRule", blueprint.RuleParams{
42		Command: `${mojomBindingsGenerator}
43		--use_bundled_pylibs generate
44		-o ${outDir}
45		-I=${package}:${package}
46		-d ${package}
47		${flags}
48		--bytecode_path=${templateDir}
49		--generators=${mojomGenerator}
50		--use_new_wrapper_types
51		${in}`,
52		CommandDeps: []string{
53			"${mojomBindingsGenerator}",
54		},
55		Description: "Mojo sources generation $in => $out",
56		Restat:      true,
57	}, "mojomGenerator", "package", "flags", "outDir", "templateDir")
58
59	mergeSrcjarsRule = pctx.StaticRule("mergeSrcjarsRule", blueprint.RuleParams{
60		Command: "${mergeZips} ${out} ${in}",
61		CommandDeps: []string{
62			"${mergeZips}",
63		},
64		Description: "Merge .srcjars $in => $out",
65	})
66)
67
68type mojomPicklesProperties struct {
69	// list of input files
70	Srcs []string
71}
72
73type mojomPickles struct {
74	android.ModuleBase
75
76	properties mojomPicklesProperties
77
78	generatedSrcs android.Paths
79	outDir        android.Path
80}
81
82var _ genrule.SourceFileGenerator = (*mojomPickles)(nil)
83
84func (m *mojomPickles) DepsMutator(ctx android.BottomUpMutatorContext) {
85	android.ExtractSourcesDeps(ctx, m.properties.Srcs)
86}
87
88func (m *mojomPickles) GenerateAndroidBuildActions(ctx android.ModuleContext) {
89	m.outDir = android.PathForModuleGen(ctx, "")
90
91	packagePath := android.PathForModuleSrc(ctx, "")
92
93	for _, in := range ctx.ExpandSources(m.properties.Srcs, nil) {
94		if !strings.HasSuffix(in.Rel(), ".mojom") {
95			ctx.PropertyErrorf("srcs", "Source is not a .mojom file: %s", in.Rel())
96			continue
97		}
98		relStem := strings.TrimSuffix(in.Rel(), ".mojom")
99
100		out := android.PathForModuleGen(ctx, relStem+".p")
101		m.generatedSrcs = append(m.generatedSrcs, out)
102
103		ctx.ModuleBuild(pctx, android.ModuleBuildParams{
104			Rule:   generateMojomPicklesRule,
105			Input:  in,
106			Output: out,
107			Args: map[string]string{
108				"package": packagePath.Rel(),
109				"outDir":  m.outDir.String(),
110				"flags":   fmt.Sprintf("-I=%s:%s", packagePath, packagePath),
111			},
112		})
113	}
114}
115
116func (m *mojomPickles) GeneratedHeaderDirs() android.Paths {
117	return nil
118}
119
120func (m *mojomPickles) GeneratedDeps() android.Paths {
121	return append(android.Paths{}, m.generatedSrcs...)
122}
123
124func (m *mojomPickles) GeneratedSourceFiles() android.Paths {
125	return append(android.Paths{}, m.generatedSrcs...)
126}
127
128func (m *mojomPickles) Srcs() android.Paths {
129	return append(android.Paths{}, m.generatedSrcs...)
130}
131
132func mojomPicklesFactory() android.Module {
133	m := &mojomPickles{}
134	m.AddProperties(&m.properties)
135	android.InitAndroidModule(m)
136	return m
137}
138
139// mojomGenerationProperties are the common properties across the header,
140// source and Java source modules.
141type mojomGenerationProperties struct {
142	// list of input files
143	Srcs []string
144
145	// name of the output .srcjar
146	Srcjar string
147
148	// name of the templates module
149	Templates string
150
151	// Additional flags to pass to the bindings generation script
152	Flags string
153
154	// list of pickles modules that will be imported
155	Pickles []string
156
157	// list of include paths
158	Includes []string
159
160	// list of typemaps modules that will be imported
161	Typemaps []string
162
163	// If true, set --use_once_callback flag to the generator.
164	// This works only on C++ generation.
165	Use_once_callback bool
166}
167
168// extractSources adds any necessary dependencies to satisfy filegroup or
169// generated sources modules listed in the properties using ":module" syntax,
170// if any.
171func (p *mojomGenerationProperties) extractSources(ctx android.BottomUpMutatorContext) {
172	android.ExtractSourcesDeps(ctx, p.Srcs)
173	android.ExtractSourcesDeps(ctx, p.Typemaps)
174	android.ExtractSourcesDeps(ctx, p.Pickles)
175	android.ExtractSourceDeps(ctx, &p.Templates)
176}
177
178// flags generates all needed flags for the build rule.
179func (p *mojomGenerationProperties) flags(ctx android.ModuleContext) string {
180	flags := []string{}
181
182	for _, typemap := range ctx.ExpandSources(p.Typemaps, nil) {
183		flags = append(flags, fmt.Sprintf("--typemap=%s", typemap.String()))
184	}
185	for _, include := range android.PathsForSource(ctx, p.Includes) {
186		flags = append(flags, fmt.Sprintf("-I=%s:%s", include, include))
187	}
188	for _, pickle := range p.Pickles {
189		m := android.SrcIsModule(pickle)
190		if m == "" {
191			ctx.PropertyErrorf("pickles", "not a module: %q", m)
192			continue
193		}
194		module := ctx.GetDirectDepWithTag(m, android.SourceDepTag).(*mojomPickles)
195		flags = append(flags, fmt.Sprintf("--gen_dir=%s", module.outDir.String()))
196	}
197	if p.Flags != "" {
198		flags = append(flags, p.Flags)
199	}
200	if p.Use_once_callback {
201		flags = append(flags, "--use_once_callback")
202	}
203
204	return strings.Join(flags, " ")
205}
206
207// implicitDeps collects all dependencies of the module.
208func (p *mojomGenerationProperties) implicitDeps(ctx android.ModuleContext) android.Paths {
209	deps := android.Paths{}
210	deps = append(deps, ctx.ExpandSources(p.Pickles, nil)...)
211	deps = append(deps, ctx.ExpandSources(p.Typemaps, nil)...)
212	deps = append(deps, ctx.ExpandSources([]string{p.Templates}, nil)...)
213	return deps
214}
215
216// templateDir returns the path where the template .zips are located.
217func (p *mojomGenerationProperties) templateDir(ctx android.ModuleContext) string {
218	srcFiles := ctx.ExpandSources([]string{p.Templates}, nil)
219	if len(srcFiles) == 0 {
220		ctx.PropertyErrorf("templates", "module %s does not produce any files", p.Templates)
221		return ""
222	}
223	return path.Dir(srcFiles[0].String())
224}
225
226// mojomSrcsRuleDescription has the necessary arguments to perform one
227// invocation of generateMojomSrcsRule.
228type mojomSrcsRuleDescription struct {
229	generatedExtensions []string
230	extraFlags          string
231}
232
233// generateBuildActions generates all the necessary build actions for the
234// current module.
235func (p *mojomGenerationProperties) generateBuildActions(
236	ctx android.ModuleContext,
237	mojomGenerator string,
238	descriptions []mojomSrcsRuleDescription,
239) android.Paths {
240	packageName := android.PathForModuleSrc(ctx, "").Rel()
241	outDir := android.PathForModuleGen(ctx, "")
242	implicitDeps := p.implicitDeps(ctx)
243	templateDir := p.templateDir(ctx)
244	generatedSrcs := android.Paths{}
245
246	for _, in := range ctx.ExpandSources(p.Srcs, nil) {
247		if !strings.HasSuffix(in.Rel(), ".mojom") {
248			ctx.PropertyErrorf("srcs", "Source is not a .mojom file: %s", in.Rel())
249			continue
250		}
251		relStem := strings.TrimSuffix(in.Rel(), ".mojom")
252
253		for _, description := range descriptions {
254			outs := android.WritablePaths{}
255			for _, ext := range description.generatedExtensions {
256				out := android.PathForModuleGen(ctx, relStem+ext)
257				outs = append(outs, out)
258				generatedSrcs = append(generatedSrcs, out)
259			}
260			ctx.ModuleBuild(pctx, android.ModuleBuildParams{
261				Rule:      generateMojomSrcsRule,
262				Input:     in,
263				Implicits: implicitDeps,
264				Outputs:   outs,
265				Args: map[string]string{
266					"mojomGenerator": mojomGenerator,
267					"package":        packageName,
268					"flags":          fmt.Sprintf("%s %s", p.flags(ctx), description.extraFlags),
269					"outDir":         outDir.String(),
270					"templateDir":    templateDir,
271				},
272			})
273		}
274	}
275
276	return generatedSrcs
277}
278
279// mojomHeaders generates all the .h files for a .mojom source.
280type mojomHeaders struct {
281	android.ModuleBase
282
283	properties mojomGenerationProperties
284
285	exportedHeaderDirs android.Paths
286	generatedSrcs      android.Paths
287}
288
289var _ genrule.SourceFileGenerator = (*mojomHeaders)(nil)
290
291func (m *mojomHeaders) DepsMutator(ctx android.BottomUpMutatorContext) {
292	m.properties.extractSources(ctx)
293}
294
295func (m *mojomHeaders) GenerateAndroidBuildActions(ctx android.ModuleContext) {
296	m.generatedSrcs = m.properties.generateBuildActions(
297		ctx,
298		"c++",
299		[]mojomSrcsRuleDescription{
300			{
301				generatedExtensions: []string{".mojom.h"},
302				extraFlags:          "",
303			},
304			{
305				generatedExtensions: []string{".mojom-shared.h", ".mojom-shared-internal.h"},
306				extraFlags:          "--generate_non_variant_code",
307			},
308			{
309				generatedExtensions: []string{".mojom-shared-message-ids.h"},
310				extraFlags:          "--generate_message_ids --generate_non_variant_code",
311			},
312		},
313	)
314	m.exportedHeaderDirs = append(m.exportedHeaderDirs, android.PathForModuleGen(ctx, ""))
315}
316
317func (m *mojomHeaders) GeneratedHeaderDirs() android.Paths {
318	return m.exportedHeaderDirs
319}
320
321func (m *mojomHeaders) GeneratedDeps() android.Paths {
322	return append(android.Paths{}, m.generatedSrcs...)
323}
324
325func (m *mojomHeaders) GeneratedSourceFiles() android.Paths {
326	return append(android.Paths{}, m.generatedSrcs...)
327}
328
329func (m *mojomHeaders) Srcs() android.Paths {
330	return append(android.Paths{}, m.generatedSrcs...)
331}
332
333func mojomHeadersFactory() android.Module {
334	m := &mojomHeaders{}
335	m.AddProperties(&m.properties)
336	android.InitAndroidModule(m)
337	return m
338}
339
340// mojomHeaders generates all the .cc files for a .mojom source.
341type mojomSrcs struct {
342	android.ModuleBase
343
344	properties mojomGenerationProperties
345
346	generatedSrcs android.Paths
347}
348
349var _ genrule.SourceFileGenerator = (*mojomSrcs)(nil)
350
351func (m *mojomSrcs) DepsMutator(ctx android.BottomUpMutatorContext) {
352	m.properties.extractSources(ctx)
353}
354
355func (m *mojomSrcs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
356	m.generatedSrcs = m.properties.generateBuildActions(
357		ctx,
358		"c++",
359		[]mojomSrcsRuleDescription{
360			{
361				generatedExtensions: []string{".mojom.cc"},
362				extraFlags:          "",
363			},
364			{
365				generatedExtensions: []string{".mojom-shared.cc"},
366				extraFlags:          "--generate_non_variant_code",
367			},
368		},
369	)
370}
371
372func (m *mojomSrcs) GeneratedHeaderDirs() android.Paths {
373	return nil
374}
375
376func (m *mojomSrcs) GeneratedDeps() android.Paths {
377	return append(android.Paths{}, m.generatedSrcs...)
378}
379
380func (m *mojomSrcs) GeneratedSourceFiles() android.Paths {
381	return append(android.Paths{}, m.generatedSrcs...)
382}
383
384func (m *mojomSrcs) Srcs() android.Paths {
385	return append(android.Paths{}, m.generatedSrcs...)
386}
387
388func mojomSrcsFactory() android.Module {
389	m := &mojomSrcs{}
390	m.AddProperties(&m.properties)
391	android.InitAndroidModule(m)
392	return m
393}
394
395// mojomHeaders generates the .srcjar file for a set of .mojom source.
396type mojomSrcjar struct {
397	android.ModuleBase
398
399	properties mojomGenerationProperties
400
401	outDir        android.Path
402	generatedSrcs android.Paths
403}
404
405var _ genrule.SourceFileGenerator = (*mojomSrcjar)(nil)
406
407func (m *mojomSrcjar) DepsMutator(ctx android.BottomUpMutatorContext) {
408	m.properties.extractSources(ctx)
409}
410
411func (m *mojomSrcjar) GenerateAndroidBuildActions(ctx android.ModuleContext) {
412	srcjars := m.properties.generateBuildActions(
413		ctx,
414		"java",
415		[]mojomSrcsRuleDescription{
416			{
417				generatedExtensions: []string{".mojom.srcjar"},
418				extraFlags:          "",
419			},
420		},
421	)
422
423	out := android.PathForModuleGen(ctx, m.properties.Srcjar)
424	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
425		Rule:   mergeSrcjarsRule,
426		Inputs: srcjars,
427		Output: out,
428	})
429	m.generatedSrcs = append(m.generatedSrcs, out)
430}
431
432func (m *mojomSrcjar) GeneratedHeaderDirs() android.Paths {
433	return nil
434}
435
436func (m *mojomSrcjar) GeneratedDeps() android.Paths {
437	return append(android.Paths{}, m.generatedSrcs...)
438}
439
440func (m *mojomSrcjar) GeneratedSourceFiles() android.Paths {
441	return append(android.Paths{}, m.generatedSrcs...)
442}
443
444func (m *mojomSrcjar) Srcs() android.Paths {
445	return append(android.Paths{}, m.generatedSrcs...)
446}
447
448func mojomSrcjarFactory() android.Module {
449	m := &mojomSrcjar{}
450	m.AddProperties(&m.properties)
451	android.InitAndroidModule(m)
452	return m
453}
454