// Copyright 2015 Google Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package genrule import ( "github.com/google/blueprint" "android/soong" "android/soong/android" ) func init() { soong.RegisterModuleType("gensrcs", GenSrcsFactory) soong.RegisterModuleType("genrule", GenRuleFactory) android.RegisterBottomUpMutator("genrule_deps", genruleDepsMutator) } var ( pctx = android.NewPackageContext("android/soong/genrule") ) func init() { pctx.SourcePathVariable("srcDir", "") pctx.HostBinToolVariable("hostBin", "") } type SourceFileGenerator interface { GeneratedSourceFiles() android.Paths GeneratedHeaderDir() android.Path } type HostToolProvider interface { HostToolPath() android.OptionalPath } type generatorProperties struct { // command to run on one or more input files. Available variables for substitution: // $tool: the path to the `tool` or `tool_file` // $in: one or more input files // $out: a single output file // $srcDir: the root directory of the source tree // The host bin directory will be in the path Cmd string // name of the module (if any) that produces the host executable. Leave empty for // prebuilts or scripts that do not need a module to build them. Tool string // Local file that is used as the tool Tool_file string } type generator struct { android.ModuleBase properties generatorProperties tasks taskFunc deps android.Paths rule blueprint.Rule genPath android.Path outputFiles android.Paths } type taskFunc func(ctx android.ModuleContext) []generateTask type generateTask struct { in android.Paths out android.ModuleGenPath } func (g *generator) GeneratedSourceFiles() android.Paths { return g.outputFiles } func (g *generator) GeneratedHeaderDir() android.Path { return g.genPath } func genruleDepsMutator(ctx android.BottomUpMutatorContext) { if g, ok := ctx.Module().(*generator); ok { if g.properties.Tool != "" { ctx.AddFarVariationDependencies([]blueprint.Variation{ {"arch", ctx.AConfig().BuildOsVariant}, }, nil, g.properties.Tool) } } } func (g *generator) GenerateAndroidBuildActions(ctx android.ModuleContext) { if g.properties.Tool != "" && g.properties.Tool_file != "" { ctx.ModuleErrorf("`tool` and `tool_file` may not be specified at the same time") return } g.rule = ctx.Rule(pctx, "generator", blueprint.RuleParams{ Command: "PATH=$$PATH:$hostBin " + g.properties.Cmd, }, "tool") var tool string if g.properties.Tool_file != "" { toolpath := android.PathForModuleSrc(ctx, g.properties.Tool_file) g.deps = append(g.deps, toolpath) tool = toolpath.String() } else if g.properties.Tool != "" { ctx.VisitDirectDeps(func(module blueprint.Module) { if t, ok := module.(HostToolProvider); ok { p := t.HostToolPath() if p.Valid() { g.deps = append(g.deps, p.Path()) tool = p.String() } else { ctx.ModuleErrorf("host tool %q missing output file", ctx.OtherModuleName(module)) } } else { ctx.ModuleErrorf("unknown dependency %q", ctx.OtherModuleName(module)) } }) } g.genPath = android.PathForModuleGen(ctx, "") for _, task := range g.tasks(ctx) { g.generateSourceFile(ctx, task, tool) } } func (g *generator) generateSourceFile(ctx android.ModuleContext, task generateTask, tool string) { ctx.ModuleBuild(pctx, android.ModuleBuildParams{ Rule: g.rule, Output: task.out, Inputs: task.in, Implicits: g.deps, Args: map[string]string{ "tool": tool, }, }) g.outputFiles = append(g.outputFiles, task.out) } func generatorFactory(tasks taskFunc, props ...interface{}) (blueprint.Module, []interface{}) { module := &generator{ tasks: tasks, } props = append(props, &module.properties) return android.InitAndroidModule(module, props...) } func GenSrcsFactory() (blueprint.Module, []interface{}) { properties := &genSrcsProperties{} tasks := func(ctx android.ModuleContext) []generateTask { srcFiles := ctx.ExpandSources(properties.Srcs, nil) tasks := make([]generateTask, 0, len(srcFiles)) for _, in := range srcFiles { tasks = append(tasks, generateTask{ in: android.Paths{in}, out: android.GenPathWithExt(ctx, in, properties.Output_extension), }) } return tasks } return generatorFactory(tasks, properties) } type genSrcsProperties struct { // list of input files Srcs []string // extension that will be substituted for each output file Output_extension string } func GenRuleFactory() (blueprint.Module, []interface{}) { properties := &genRuleProperties{} tasks := func(ctx android.ModuleContext) []generateTask { return []generateTask{ { in: ctx.ExpandSources(properties.Srcs, nil), out: android.PathForModuleGen(ctx, properties.Out), }, } } return generatorFactory(tasks, properties) } type genRuleProperties struct { // list of input files Srcs []string // name of the output file that will be generated Out string }