blob: 42ab047a0426e4372ad7172ef6117c2b3543225c [file] [log] [blame]
Colin Cross5049f022015-03-18 13:28:46 -07001// 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 "path/filepath"
19
Colin Cross70b40592015-03-23 12:57:34 -070020 "github.com/google/blueprint"
21 "github.com/google/blueprint/pathtools"
Colin Cross5049f022015-03-18 13:28:46 -070022
23 "android/soong/common"
24)
25
Colin Cross5049f022015-03-18 13:28:46 -070026var (
27 pctx = blueprint.NewPackageContext("android/soong/genrule")
28)
29
30func init() {
Colin Cross1332b002015-04-07 17:11:30 -070031 pctx.VariableConfigMethod("srcDir", common.Config.SrcDir)
Colin Crossd350ecd2015-04-28 13:25:36 -070032 pctx.VariableConfigMethod("hostBin", common.Config.HostBin)
Colin Cross5049f022015-03-18 13:28:46 -070033}
34
35type SourceFileGenerator interface {
36 GeneratedSourceFiles() []string
37}
38
Colin Crossd350ecd2015-04-28 13:25:36 -070039type HostToolProvider interface {
40 HostToolPath() string
41}
Colin Cross5049f022015-03-18 13:28:46 -070042
Colin Crossd350ecd2015-04-28 13:25:36 -070043type generator struct {
44 common.AndroidModuleBase
45
46 properties struct {
47 // cmd: command to run on one or more input files. Available variables for substitution:
48 // $in: one or more input files
49 // $out: a single output file
50 // $srcDir: the root directory of the source tree
51 // The host bin directory will be in the path
52 Cmd string
53
54 // tool: name of the module (if any) that produces the host executable. Leave empty for
55 // prebuilts or scripts that do not need a module to build them.
56 Tool string
57 }
58
59 tasks taskFunc
60
61 deps []string
62 rule blueprint.Rule
63
64 outputFiles []string
65}
66
67type taskFunc func(ctx common.AndroidModuleContext) []generateTask
68
69type generateTask struct {
70 in []string
71 out string
72}
73
74func (g *generator) GeneratedSourceFiles() []string {
75 return g.outputFiles
76}
77
78func (g *generator) AndroidDynamicDependencies(ctx common.AndroidDynamicDependerModuleContext) []string {
79 if g.properties.Tool != "" {
Colin Crossf9964d52015-05-11 13:38:59 -070080 ctx.AddFarVariationDependencies([]blueprint.Variation{{"hostordevice", common.Host.String()}},
81 g.properties.Tool)
Colin Crossd350ecd2015-04-28 13:25:36 -070082 }
83 return nil
84}
85
86func (g *generator) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) {
87 g.rule = ctx.Rule(pctx, "generator", blueprint.RuleParams{
88 Command: "PATH=$$PATH:$hostBin " + g.properties.Cmd,
89 })
90
91 ctx.VisitDirectDeps(func(module blueprint.Module) {
92 if t, ok := module.(HostToolProvider); ok {
93 p := t.HostToolPath()
94 if p != "" {
95 g.deps = append(g.deps, p)
96 } else {
97 ctx.ModuleErrorf("host tool %q missing output file", ctx.OtherModuleName(module))
98 }
99 } else {
100 ctx.ModuleErrorf("unknown dependency %q", ctx.OtherModuleName(module))
101 }
102 })
103
104 for _, task := range g.tasks(ctx) {
105 g.generateSourceFile(ctx, task)
106 }
107}
108
109func (g *generator) generateSourceFile(ctx common.AndroidModuleContext, task generateTask) {
110
111 ctx.Build(pctx, blueprint.BuildParams{
112 Rule: g.rule,
113 Inputs: task.in,
114 Implicits: g.deps,
115 Outputs: []string{task.out},
116 })
117
118 g.outputFiles = append(g.outputFiles, task.out)
119}
120
121func generatorFactory(tasks taskFunc, props ...interface{}) (blueprint.Module, []interface{}) {
122 module := &generator{
123 tasks: tasks,
124 }
125
126 props = append(props, &module.properties)
127
128 return common.InitAndroidModule(module, props...)
129}
130
131func GenSrcsFactory() (blueprint.Module, []interface{}) {
132 properties := &genSrcsProperties{}
133
134 tasks := func(ctx common.AndroidModuleContext) []generateTask {
135 srcFiles := common.ExpandSources(ctx, properties.Srcs)
136 tasks := make([]generateTask, 0, len(srcFiles))
137 for _, in := range srcFiles {
138 out := pathtools.ReplaceExtension(in, properties.Output_extension)
139 out = filepath.Join(common.ModuleGenDir(ctx), out)
140 tasks = append(tasks, generateTask{[]string{in}, out})
141 }
142 return tasks
143 }
144
145 return generatorFactory(tasks, properties)
146}
147
148type genSrcsProperties struct {
Colin Cross5049f022015-03-18 13:28:46 -0700149 // srcs: list of input files
150 Srcs []string
151
152 // output_extension: extension that will be substituted for each output file
153 Output_extension string
154}
155
Colin Crossd350ecd2015-04-28 13:25:36 -0700156func GenRuleFactory() (blueprint.Module, []interface{}) {
157 properties := &genRuleProperties{}
Colin Cross5049f022015-03-18 13:28:46 -0700158
Colin Crossd350ecd2015-04-28 13:25:36 -0700159 tasks := func(ctx common.AndroidModuleContext) []generateTask {
160 return []generateTask{
161 {
162 in: common.ExpandSources(ctx, properties.Srcs),
163 out: filepath.Join(common.ModuleGenDir(ctx), properties.Out),
164 },
165 }
Colin Cross5049f022015-03-18 13:28:46 -0700166 }
Colin Crossd350ecd2015-04-28 13:25:36 -0700167
168 return generatorFactory(tasks, properties)
Colin Cross5049f022015-03-18 13:28:46 -0700169}
170
Colin Crossd350ecd2015-04-28 13:25:36 -0700171type genRuleProperties struct {
172 // srcs: list of input files
173 Srcs []string
Colin Cross5049f022015-03-18 13:28:46 -0700174
Colin Crossd350ecd2015-04-28 13:25:36 -0700175 // out: name of the output file that will be generated
176 Out string
Colin Cross5049f022015-03-18 13:28:46 -0700177}