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 genrule 16 17import ( 18 "github.com/google/blueprint" 19 20 "android/soong" 21 "android/soong/common" 22) 23 24func init() { 25 soong.RegisterModuleType("gensrcs", GenSrcsFactory) 26 soong.RegisterModuleType("genrule", GenRuleFactory) 27 28 common.RegisterBottomUpMutator("genrule_deps", genruleDepsMutator) 29} 30 31var ( 32 pctx = common.NewPackageContext("android/soong/genrule") 33) 34 35func init() { 36 pctx.SourcePathVariable("srcDir", "") 37 pctx.HostBinToolVariable("hostBin", "") 38} 39 40type SourceFileGenerator interface { 41 GeneratedSourceFiles() common.Paths 42} 43 44type HostToolProvider interface { 45 HostToolPath() common.OptionalPath 46} 47 48type generatorProperties struct { 49 // command to run on one or more input files. Available variables for substitution: 50 // $in: one or more input files 51 // $out: a single output file 52 // $srcDir: the root directory of the source tree 53 // The host bin directory will be in the path 54 Cmd string 55 56 // name of the module (if any) that produces the host executable. Leave empty for 57 // prebuilts or scripts that do not need a module to build them. 58 Tool string 59} 60 61type generator struct { 62 common.AndroidModuleBase 63 64 properties generatorProperties 65 66 tasks taskFunc 67 68 deps common.Paths 69 rule blueprint.Rule 70 71 outputFiles common.Paths 72} 73 74type taskFunc func(ctx common.AndroidModuleContext) []generateTask 75 76type generateTask struct { 77 in common.Paths 78 out common.ModuleGenPath 79} 80 81func (g *generator) GeneratedSourceFiles() common.Paths { 82 return g.outputFiles 83} 84 85func genruleDepsMutator(ctx common.AndroidBottomUpMutatorContext) { 86 if g, ok := ctx.Module().(*generator); ok { 87 if g.properties.Tool != "" { 88 ctx.AddFarVariationDependencies([]blueprint.Variation{ 89 {"host_or_device", common.Host.String()}, 90 {"host_type", common.CurrentHostType().String()}, 91 }, g.properties.Tool) 92 } 93 } 94} 95 96func (g *generator) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) { 97 g.rule = ctx.Rule(pctx, "generator", blueprint.RuleParams{ 98 Command: "PATH=$$PATH:$hostBin " + g.properties.Cmd, 99 }) 100 101 ctx.VisitDirectDeps(func(module blueprint.Module) { 102 if t, ok := module.(HostToolProvider); ok { 103 p := t.HostToolPath() 104 if p.Valid() { 105 g.deps = append(g.deps, p.Path()) 106 } else { 107 ctx.ModuleErrorf("host tool %q missing output file", ctx.OtherModuleName(module)) 108 } 109 } else { 110 ctx.ModuleErrorf("unknown dependency %q", ctx.OtherModuleName(module)) 111 } 112 }) 113 114 for _, task := range g.tasks(ctx) { 115 g.generateSourceFile(ctx, task) 116 } 117} 118 119func (g *generator) generateSourceFile(ctx common.AndroidModuleContext, task generateTask) { 120 ctx.ModuleBuild(pctx, common.ModuleBuildParams{ 121 Rule: g.rule, 122 Output: task.out, 123 Inputs: task.in, 124 Implicits: g.deps, 125 }) 126 127 g.outputFiles = append(g.outputFiles, task.out) 128} 129 130func generatorFactory(tasks taskFunc, props ...interface{}) (blueprint.Module, []interface{}) { 131 module := &generator{ 132 tasks: tasks, 133 } 134 135 props = append(props, &module.properties) 136 137 return common.InitAndroidModule(module, props...) 138} 139 140func GenSrcsFactory() (blueprint.Module, []interface{}) { 141 properties := &genSrcsProperties{} 142 143 tasks := func(ctx common.AndroidModuleContext) []generateTask { 144 srcFiles := ctx.ExpandSources(properties.Srcs, nil) 145 tasks := make([]generateTask, 0, len(srcFiles)) 146 for _, in := range srcFiles { 147 tasks = append(tasks, generateTask{ 148 in: common.Paths{in}, 149 out: common.GenPathWithExt(ctx, in, properties.Output_extension), 150 }) 151 } 152 return tasks 153 } 154 155 return generatorFactory(tasks, properties) 156} 157 158type genSrcsProperties struct { 159 // list of input files 160 Srcs []string 161 162 // extension that will be substituted for each output file 163 Output_extension string 164} 165 166func GenRuleFactory() (blueprint.Module, []interface{}) { 167 properties := &genRuleProperties{} 168 169 tasks := func(ctx common.AndroidModuleContext) []generateTask { 170 return []generateTask{ 171 { 172 in: ctx.ExpandSources(properties.Srcs, nil), 173 out: properties.Out, 174 }, 175 } 176 } 177 178 return generatorFactory(tasks, properties) 179} 180 181type genRuleProperties struct { 182 // list of input files 183 Srcs []string 184 185 // name of the output file that will be generated 186 Out common.ModuleGenPath 187} 188