package libchrome
import (
"fmt"
"path"
"strings"
"android/soong/android"
"android/soong/genrule"
"github.com/google/blueprint"
)
func init() {
android.RegisterModuleType("generate_mojom_pickles", mojomPicklesFactory)
android.RegisterModuleType("generate_mojom_headers", mojomHeadersFactory)
android.RegisterModuleType("generate_mojom_srcs", mojomSrcsFactory)
android.RegisterModuleType("generate_mojom_srcjar", mojomSrcjarFactory)
}
var (
pctx = android.NewPackageContext("android/soong/external/libchrome")
mojomBindingsGenerator = pctx.HostBinToolVariable("mojomBindingsGenerator", "mojom_bindings_generator")
mergeZips = pctx.HostBinToolVariable("mergeZips", "merge_zips")
generateMojomPicklesRule = pctx.StaticRule("generateMojomPicklesRule", blueprint.RuleParams{
Command: `${mojomBindingsGenerator}
--use_bundled_pylibs parse
-d ${package}
${flags}
-o ${outDir}
${in}`,
CommandDeps: []string{
"${mojomBindingsGenerator}",
},
Description: "Mojo pickles generation $in => $out",
Restat: true,
}, "package", "flags", "outDir")
generateMojomSrcsRule = pctx.StaticRule("generateMojomSrcsRule", blueprint.RuleParams{
Command: `${mojomBindingsGenerator}
--use_bundled_pylibs generate
-o ${outDir}
-I=${package}:${package}
-d ${package}
${flags}
--bytecode_path=${templateDir}
--generators=${mojomGenerator}
--use_new_wrapper_types
${in}`,
CommandDeps: []string{
"${mojomBindingsGenerator}",
},
Description: "Mojo sources generation $in => $out",
Restat: true,
}, "mojomGenerator", "package", "flags", "outDir", "templateDir")
mergeSrcjarsRule = pctx.StaticRule("mergeSrcjarsRule", blueprint.RuleParams{
Command: "${mergeZips} ${out} ${in}",
CommandDeps: []string{
"${mergeZips}",
},
Description: "Merge .srcjars $in => $out",
})
)
type mojomPicklesProperties struct {
// list of input files
Srcs []string
}
type mojomPickles struct {
android.ModuleBase
properties mojomPicklesProperties
generatedSrcs android.Paths
outDir android.Path
}
var _ genrule.SourceFileGenerator = (*mojomPickles)(nil)
func (m *mojomPickles) DepsMutator(ctx android.BottomUpMutatorContext) {
android.ExtractSourcesDeps(ctx, m.properties.Srcs)
}
func (m *mojomPickles) GenerateAndroidBuildActions(ctx android.ModuleContext) {
m.outDir = android.PathForModuleGen(ctx, "")
packagePath := android.PathForModuleSrc(ctx, "")
for _, in := range ctx.ExpandSources(m.properties.Srcs, nil) {
if !strings.HasSuffix(in.Rel(), ".mojom") {
ctx.PropertyErrorf("srcs", "Source is not a .mojom file: %s", in.Rel())
continue
}
relStem := strings.TrimSuffix(in.Rel(), ".mojom")
out := android.PathForModuleGen(ctx, relStem+".p")
m.generatedSrcs = append(m.generatedSrcs, out)
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
Rule: generateMojomPicklesRule,
Input: in,
Output: out,
Args: map[string]string{
"package": packagePath.Rel(),
"outDir": m.outDir.String(),
"flags": fmt.Sprintf("-I=%s:%s", packagePath, packagePath),
},
})
}
}
func (m *mojomPickles) GeneratedHeaderDirs() android.Paths {
return nil
}
func (m *mojomPickles) GeneratedDeps() android.Paths {
return append(android.Paths{}, m.generatedSrcs...)
}
func (m *mojomPickles) GeneratedSourceFiles() android.Paths {
return append(android.Paths{}, m.generatedSrcs...)
}
func (m *mojomPickles) Srcs() android.Paths {
return append(android.Paths{}, m.generatedSrcs...)
}
func mojomPicklesFactory() android.Module {
m := &mojomPickles{}
m.AddProperties(&m.properties)
android.InitAndroidModule(m)
return m
}
// mojomGenerationProperties are the common properties across the header,
// source and Java source modules.
type mojomGenerationProperties struct {
// list of input files
Srcs []string
// name of the output .srcjar
Srcjar string
// name of the templates module
Templates string
// Additional flags to pass to the bindings generation script
Flags string
// list of pickles modules that will be imported
Pickles []string
// list of include paths
Includes []string
// list of typemaps modules that will be imported
Typemaps []string
// If true, set --use_once_callback flag to the generator.
// This works only on C++ generation.
Use_once_callback bool
}
// extractSources adds any necessary dependencies to satisfy filegroup or
// generated sources modules listed in the properties using ":module" syntax,
// if any.
func (p *mojomGenerationProperties) extractSources(ctx android.BottomUpMutatorContext) {
android.ExtractSourcesDeps(ctx, p.Srcs)
android.ExtractSourcesDeps(ctx, p.Typemaps)
android.ExtractSourcesDeps(ctx, p.Pickles)
android.ExtractSourceDeps(ctx, &p.Templates)
}
// flags generates all needed flags for the build rule.
func (p *mojomGenerationProperties) flags(ctx android.ModuleContext) string {
flags := []string{}
for _, typemap := range ctx.ExpandSources(p.Typemaps, nil) {
flags = append(flags, fmt.Sprintf("--typemap=%s", typemap.String()))
}
for _, include := range android.PathsForSource(ctx, p.Includes) {
flags = append(flags, fmt.Sprintf("-I=%s:%s", include, include))
}
for _, pickle := range p.Pickles {
m := android.SrcIsModule(pickle)
if m == "" {
ctx.PropertyErrorf("pickles", "not a module: %q", m)
continue
}
module := ctx.GetDirectDepWithTag(m, android.SourceDepTag).(*mojomPickles)
flags = append(flags, fmt.Sprintf("--gen_dir=%s", module.outDir.String()))
}
if p.Flags != "" {
flags = append(flags, p.Flags)
}
if p.Use_once_callback {
flags = append(flags, "--use_once_callback")
}
return strings.Join(flags, " ")
}
// implicitDeps collects all dependencies of the module.
func (p *mojomGenerationProperties) implicitDeps(ctx android.ModuleContext) android.Paths {
deps := android.Paths{}
deps = append(deps, ctx.ExpandSources(p.Pickles, nil)...)
deps = append(deps, ctx.ExpandSources(p.Typemaps, nil)...)
deps = append(deps, ctx.ExpandSources([]string{p.Templates}, nil)...)
return deps
}
// templateDir returns the path where the template .zips are located.
func (p *mojomGenerationProperties) templateDir(ctx android.ModuleContext) string {
srcFiles := ctx.ExpandSources([]string{p.Templates}, nil)
if len(srcFiles) == 0 {
ctx.PropertyErrorf("templates", "module %s does not produce any files", p.Templates)
return ""
}
return path.Dir(srcFiles[0].String())
}
// mojomSrcsRuleDescription has the necessary arguments to perform one
// invocation of generateMojomSrcsRule.
type mojomSrcsRuleDescription struct {
generatedExtensions []string
extraFlags string
}
// generateBuildActions generates all the necessary build actions for the
// current module.
func (p *mojomGenerationProperties) generateBuildActions(
ctx android.ModuleContext,
mojomGenerator string,
descriptions []mojomSrcsRuleDescription,
) android.Paths {
packageName := android.PathForModuleSrc(ctx, "").Rel()
outDir := android.PathForModuleGen(ctx, "")
implicitDeps := p.implicitDeps(ctx)
templateDir := p.templateDir(ctx)
generatedSrcs := android.Paths{}
for _, in := range ctx.ExpandSources(p.Srcs, nil) {
if !strings.HasSuffix(in.Rel(), ".mojom") {
ctx.PropertyErrorf("srcs", "Source is not a .mojom file: %s", in.Rel())
continue
}
relStem := strings.TrimSuffix(in.Rel(), ".mojom")
for _, description := range descriptions {
outs := android.WritablePaths{}
for _, ext := range description.generatedExtensions {
out := android.PathForModuleGen(ctx, relStem+ext)
outs = append(outs, out)
generatedSrcs = append(generatedSrcs, out)
}
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
Rule: generateMojomSrcsRule,
Input: in,
Implicits: implicitDeps,
Outputs: outs,
Args: map[string]string{
"mojomGenerator": mojomGenerator,
"package": packageName,
"flags": fmt.Sprintf("%s %s", p.flags(ctx), description.extraFlags),
"outDir": outDir.String(),
"templateDir": templateDir,
},
})
}
}
return generatedSrcs
}
// mojomHeaders generates all the .h files for a .mojom source.
type mojomHeaders struct {
android.ModuleBase
properties mojomGenerationProperties
exportedHeaderDirs android.Paths
generatedSrcs android.Paths
}
var _ genrule.SourceFileGenerator = (*mojomHeaders)(nil)
func (m *mojomHeaders) DepsMutator(ctx android.BottomUpMutatorContext) {
m.properties.extractSources(ctx)
}
func (m *mojomHeaders) GenerateAndroidBuildActions(ctx android.ModuleContext) {
m.generatedSrcs = m.properties.generateBuildActions(
ctx,
"c++",
[]mojomSrcsRuleDescription{
{
generatedExtensions: []string{".mojom.h"},
extraFlags: "",
},
{
generatedExtensions: []string{".mojom-shared.h", ".mojom-shared-internal.h"},
extraFlags: "--generate_non_variant_code",
},
{
generatedExtensions: []string{".mojom-shared-message-ids.h"},
extraFlags: "--generate_message_ids --generate_non_variant_code",
},
},
)
m.exportedHeaderDirs = append(m.exportedHeaderDirs, android.PathForModuleGen(ctx, ""))
}
func (m *mojomHeaders) GeneratedHeaderDirs() android.Paths {
return m.exportedHeaderDirs
}
func (m *mojomHeaders) GeneratedDeps() android.Paths {
return append(android.Paths{}, m.generatedSrcs...)
}
func (m *mojomHeaders) GeneratedSourceFiles() android.Paths {
return append(android.Paths{}, m.generatedSrcs...)
}
func (m *mojomHeaders) Srcs() android.Paths {
return append(android.Paths{}, m.generatedSrcs...)
}
func mojomHeadersFactory() android.Module {
m := &mojomHeaders{}
m.AddProperties(&m.properties)
android.InitAndroidModule(m)
return m
}
// mojomHeaders generates all the .cc files for a .mojom source.
type mojomSrcs struct {
android.ModuleBase
properties mojomGenerationProperties
generatedSrcs android.Paths
}
var _ genrule.SourceFileGenerator = (*mojomSrcs)(nil)
func (m *mojomSrcs) DepsMutator(ctx android.BottomUpMutatorContext) {
m.properties.extractSources(ctx)
}
func (m *mojomSrcs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
m.generatedSrcs = m.properties.generateBuildActions(
ctx,
"c++",
[]mojomSrcsRuleDescription{
{
generatedExtensions: []string{".mojom.cc"},
extraFlags: "",
},
{
generatedExtensions: []string{".mojom-shared.cc"},
extraFlags: "--generate_non_variant_code",
},
},
)
}
func (m *mojomSrcs) GeneratedHeaderDirs() android.Paths {
return nil
}
func (m *mojomSrcs) GeneratedDeps() android.Paths {
return append(android.Paths{}, m.generatedSrcs...)
}
func (m *mojomSrcs) GeneratedSourceFiles() android.Paths {
return append(android.Paths{}, m.generatedSrcs...)
}
func (m *mojomSrcs) Srcs() android.Paths {
return append(android.Paths{}, m.generatedSrcs...)
}
func mojomSrcsFactory() android.Module {
m := &mojomSrcs{}
m.AddProperties(&m.properties)
android.InitAndroidModule(m)
return m
}
// mojomHeaders generates the .srcjar file for a set of .mojom source.
type mojomSrcjar struct {
android.ModuleBase
properties mojomGenerationProperties
outDir android.Path
generatedSrcs android.Paths
}
var _ genrule.SourceFileGenerator = (*mojomSrcjar)(nil)
func (m *mojomSrcjar) DepsMutator(ctx android.BottomUpMutatorContext) {
m.properties.extractSources(ctx)
}
func (m *mojomSrcjar) GenerateAndroidBuildActions(ctx android.ModuleContext) {
srcjars := m.properties.generateBuildActions(
ctx,
"java",
[]mojomSrcsRuleDescription{
{
generatedExtensions: []string{".mojom.srcjar"},
extraFlags: "",
},
},
)
out := android.PathForModuleGen(ctx, m.properties.Srcjar)
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
Rule: mergeSrcjarsRule,
Inputs: srcjars,
Output: out,
})
m.generatedSrcs = append(m.generatedSrcs, out)
}
func (m *mojomSrcjar) GeneratedHeaderDirs() android.Paths {
return nil
}
func (m *mojomSrcjar) GeneratedDeps() android.Paths {
return append(android.Paths{}, m.generatedSrcs...)
}
func (m *mojomSrcjar) GeneratedSourceFiles() android.Paths {
return append(android.Paths{}, m.generatedSrcs...)
}
func (m *mojomSrcjar) Srcs() android.Paths {
return append(android.Paths{}, m.generatedSrcs...)
}
func mojomSrcjarFactory() android.Module {
m := &mojomSrcjar{}
m.AddProperties(&m.properties)
android.InitAndroidModule(m)
return m
}