| // 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/common" |
| ) |
| |
| func init() { |
| soong.RegisterModuleType("gensrcs", GenSrcsFactory) |
| soong.RegisterModuleType("genrule", GenRuleFactory) |
| |
| common.RegisterBottomUpMutator("genrule_deps", genruleDepsMutator) |
| } |
| |
| var ( |
| pctx = common.NewPackageContext("android/soong/genrule") |
| ) |
| |
| func init() { |
| pctx.SourcePathVariable("srcDir", "") |
| pctx.HostBinToolVariable("hostBin", "") |
| } |
| |
| type SourceFileGenerator interface { |
| GeneratedSourceFiles() common.Paths |
| GeneratedHeaderDir() common.Path |
| } |
| |
| type HostToolProvider interface { |
| HostToolPath() common.OptionalPath |
| } |
| |
| type generatorProperties struct { |
| // command to run on one or more input files. Available variables for substitution: |
| // $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 |
| } |
| |
| type generator struct { |
| common.AndroidModuleBase |
| |
| properties generatorProperties |
| |
| tasks taskFunc |
| |
| deps common.Paths |
| rule blueprint.Rule |
| |
| genPath common.Path |
| |
| outputFiles common.Paths |
| } |
| |
| type taskFunc func(ctx common.AndroidModuleContext) []generateTask |
| |
| type generateTask struct { |
| in common.Paths |
| out common.ModuleGenPath |
| } |
| |
| func (g *generator) GeneratedSourceFiles() common.Paths { |
| return g.outputFiles |
| } |
| |
| func (g *generator) GeneratedHeaderDir() common.Path { |
| return g.genPath |
| } |
| |
| func genruleDepsMutator(ctx common.AndroidBottomUpMutatorContext) { |
| if g, ok := ctx.Module().(*generator); ok { |
| if g.properties.Tool != "" { |
| ctx.AddFarVariationDependencies([]blueprint.Variation{ |
| {"host_or_device", common.Host.String()}, |
| {"host_type", common.CurrentHostType().String()}, |
| }, nil, g.properties.Tool) |
| } |
| } |
| } |
| |
| func (g *generator) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) { |
| g.rule = ctx.Rule(pctx, "generator", blueprint.RuleParams{ |
| Command: "PATH=$$PATH:$hostBin " + g.properties.Cmd, |
| }) |
| |
| 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()) |
| } else { |
| ctx.ModuleErrorf("host tool %q missing output file", ctx.OtherModuleName(module)) |
| } |
| } else { |
| ctx.ModuleErrorf("unknown dependency %q", ctx.OtherModuleName(module)) |
| } |
| }) |
| |
| g.genPath = common.PathForModuleGen(ctx, "") |
| |
| for _, task := range g.tasks(ctx) { |
| g.generateSourceFile(ctx, task) |
| } |
| } |
| |
| func (g *generator) generateSourceFile(ctx common.AndroidModuleContext, task generateTask) { |
| ctx.ModuleBuild(pctx, common.ModuleBuildParams{ |
| Rule: g.rule, |
| Output: task.out, |
| Inputs: task.in, |
| Implicits: g.deps, |
| }) |
| |
| 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 common.InitAndroidModule(module, props...) |
| } |
| |
| func GenSrcsFactory() (blueprint.Module, []interface{}) { |
| properties := &genSrcsProperties{} |
| |
| tasks := func(ctx common.AndroidModuleContext) []generateTask { |
| srcFiles := ctx.ExpandSources(properties.Srcs, nil) |
| tasks := make([]generateTask, 0, len(srcFiles)) |
| for _, in := range srcFiles { |
| tasks = append(tasks, generateTask{ |
| in: common.Paths{in}, |
| out: common.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 common.AndroidModuleContext) []generateTask { |
| return []generateTask{ |
| { |
| in: ctx.ExpandSources(properties.Srcs, nil), |
| out: 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 common.ModuleGenPath |
| } |