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 15 package genrule 16 17 import ( 18 "github.com/google/blueprint" 19 20 "android/soong" 21 "android/soong/common" 22 ) 23 24 func init() { 25 soong.RegisterModuleType("gensrcs", GenSrcsFactory) 26 soong.RegisterModuleType("genrule", GenRuleFactory) 27 28 common.RegisterBottomUpMutator("genrule_deps", genruleDepsMutator) 29 } 30 31 var ( 32 pctx = common.NewPackageContext("android/soong/genrule") 33 ) 34 35 func init() { 36 pctx.SourcePathVariable("srcDir", "") 37 pctx.HostBinToolVariable("hostBin", "") 38 } 39 40 type SourceFileGenerator interface { 41 GeneratedSourceFiles() common.Paths 42 } 43 44 type HostToolProvider interface { 45 HostToolPath() common.OptionalPath 46 } 47 48 type 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 61 type 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 74 type taskFunc func(ctx common.AndroidModuleContext) []generateTask 75 76 type generateTask struct { 77 in common.Paths 78 out common.ModuleGenPath 79 } 80 81 func (g *generator) GeneratedSourceFiles() common.Paths { 82 return g.outputFiles 83 } 84 85 func 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 96 func (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 119 func (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 130 func 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 140 func 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 158 type 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 166 func 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 181 type 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