blob: 2d0fac16861fe62b322bd55ae6ef21b856f5b3f1 [file] [log] [blame]
Colin Crossfeec25b2019-01-30 17:32:39 -08001// Copyright 2018 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 android
16
17import (
18 "fmt"
Colin Crossfeec25b2019-01-30 17:32:39 -080019 "sort"
20 "strings"
21
22 "github.com/google/blueprint"
23 "github.com/google/blueprint/proptools"
24)
25
Colin Cross758290d2019-02-01 16:42:32 -080026// RuleBuilder provides an alternative to ModuleContext.Rule and ModuleContext.Build to add a command line to the build
27// graph.
Colin Crossfeec25b2019-01-30 17:32:39 -080028type RuleBuilder struct {
Colin Cross5cb5b092019-02-02 21:25:18 -080029 commands []*RuleBuilderCommand
Colin Crossdeabb942019-02-11 14:11:09 -080030 installs RuleBuilderInstalls
Colin Cross69f59a32019-02-15 10:39:37 -080031 temporariesSet map[WritablePath]bool
Colin Cross5cb5b092019-02-02 21:25:18 -080032 restat bool
Colin Cross0d2f40a2019-02-05 22:31:15 -080033 missingDeps []string
Colin Crossfeec25b2019-01-30 17:32:39 -080034}
35
Colin Cross758290d2019-02-01 16:42:32 -080036// NewRuleBuilder returns a newly created RuleBuilder.
37func NewRuleBuilder() *RuleBuilder {
Colin Cross5cb5b092019-02-02 21:25:18 -080038 return &RuleBuilder{
Colin Cross69f59a32019-02-15 10:39:37 -080039 temporariesSet: make(map[WritablePath]bool),
Colin Cross5cb5b092019-02-02 21:25:18 -080040 }
Colin Cross758290d2019-02-01 16:42:32 -080041}
42
43// RuleBuilderInstall is a tuple of install from and to locations.
44type RuleBuilderInstall struct {
Colin Cross69f59a32019-02-15 10:39:37 -080045 From Path
46 To string
Colin Cross758290d2019-02-01 16:42:32 -080047}
48
Colin Crossdeabb942019-02-11 14:11:09 -080049type RuleBuilderInstalls []RuleBuilderInstall
50
51// String returns the RuleBuilderInstalls in the form used by $(call copy-many-files) in Make, a space separated
52// list of from:to tuples.
53func (installs RuleBuilderInstalls) String() string {
54 sb := strings.Builder{}
55 for i, install := range installs {
56 if i != 0 {
57 sb.WriteRune(' ')
58 }
Colin Cross69f59a32019-02-15 10:39:37 -080059 sb.WriteString(install.From.String())
Colin Crossdeabb942019-02-11 14:11:09 -080060 sb.WriteRune(':')
61 sb.WriteString(install.To)
62 }
63 return sb.String()
64}
65
Colin Cross0d2f40a2019-02-05 22:31:15 -080066// MissingDeps adds modules to the list of missing dependencies. If MissingDeps
67// is called with a non-empty input, any call to Build will result in a rule
68// that will print an error listing the missing dependencies and fail.
69// MissingDeps should only be called if Config.AllowMissingDependencies() is
70// true.
71func (r *RuleBuilder) MissingDeps(missingDeps []string) {
72 r.missingDeps = append(r.missingDeps, missingDeps...)
73}
74
Colin Cross758290d2019-02-01 16:42:32 -080075// Restat marks the rule as a restat rule, which will be passed to ModuleContext.Rule in BuildParams.Restat.
Colin Crossfeec25b2019-01-30 17:32:39 -080076func (r *RuleBuilder) Restat() *RuleBuilder {
77 r.restat = true
78 return r
79}
80
Colin Cross758290d2019-02-01 16:42:32 -080081// Install associates an output of the rule with an install location, which can be retrieved later using
82// RuleBuilder.Installs.
Colin Cross69f59a32019-02-15 10:39:37 -080083func (r *RuleBuilder) Install(from Path, to string) {
Colin Crossfeec25b2019-01-30 17:32:39 -080084 r.installs = append(r.installs, RuleBuilderInstall{from, to})
85}
86
Colin Cross758290d2019-02-01 16:42:32 -080087// Command returns a new RuleBuilderCommand for the rule. The commands will be ordered in the rule by when they were
88// created by this method. That can be mutated through their methods in any order, as long as the mutations do not
89// race with any call to Build.
Colin Crossfeec25b2019-01-30 17:32:39 -080090func (r *RuleBuilder) Command() *RuleBuilderCommand {
91 command := &RuleBuilderCommand{}
92 r.commands = append(r.commands, command)
93 return command
94}
95
Colin Cross5cb5b092019-02-02 21:25:18 -080096// Temporary marks an output of a command as an intermediate file that will be used as an input to another command
97// in the same rule, and should not be listed in Outputs.
Colin Cross69f59a32019-02-15 10:39:37 -080098func (r *RuleBuilder) Temporary(path WritablePath) {
Colin Cross5cb5b092019-02-02 21:25:18 -080099 r.temporariesSet[path] = true
100}
101
102// DeleteTemporaryFiles adds a command to the rule that deletes any outputs that have been marked using Temporary
103// when the rule runs. DeleteTemporaryFiles should be called after all calls to Temporary.
104func (r *RuleBuilder) DeleteTemporaryFiles() {
Colin Cross69f59a32019-02-15 10:39:37 -0800105 var temporariesList WritablePaths
Colin Cross5cb5b092019-02-02 21:25:18 -0800106
107 for intermediate := range r.temporariesSet {
108 temporariesList = append(temporariesList, intermediate)
109 }
Colin Cross69f59a32019-02-15 10:39:37 -0800110
111 sort.Slice(temporariesList, func(i, j int) bool {
112 return temporariesList[i].String() < temporariesList[j].String()
113 })
Colin Cross5cb5b092019-02-02 21:25:18 -0800114
115 r.Command().Text("rm").Flag("-f").Outputs(temporariesList)
116}
117
Colin Cross758290d2019-02-01 16:42:32 -0800118// Inputs returns the list of paths that were passed to the RuleBuilderCommand methods that take input paths, such
119// as RuleBuilderCommand.Input, RuleBuilderComand.Implicit, or RuleBuilderCommand.FlagWithInput. Inputs to a command
120// that are also outputs of another command in the same RuleBuilder are filtered out.
Colin Cross69f59a32019-02-15 10:39:37 -0800121func (r *RuleBuilder) Inputs() Paths {
Colin Crossfeec25b2019-01-30 17:32:39 -0800122 outputs := r.outputSet()
123
Colin Cross69f59a32019-02-15 10:39:37 -0800124 inputs := make(map[string]Path)
Colin Crossfeec25b2019-01-30 17:32:39 -0800125 for _, c := range r.commands {
126 for _, input := range c.inputs {
Colin Cross69f59a32019-02-15 10:39:37 -0800127 if _, isOutput := outputs[input.String()]; !isOutput {
128 inputs[input.String()] = input
Colin Crossfeec25b2019-01-30 17:32:39 -0800129 }
130 }
131 }
132
Colin Cross69f59a32019-02-15 10:39:37 -0800133 var inputList Paths
134 for _, input := range inputs {
Colin Crossfeec25b2019-01-30 17:32:39 -0800135 inputList = append(inputList, input)
136 }
Colin Cross69f59a32019-02-15 10:39:37 -0800137
138 sort.Slice(inputList, func(i, j int) bool {
139 return inputList[i].String() < inputList[j].String()
140 })
Colin Crossfeec25b2019-01-30 17:32:39 -0800141
142 return inputList
143}
144
Colin Cross69f59a32019-02-15 10:39:37 -0800145func (r *RuleBuilder) outputSet() map[string]WritablePath {
146 outputs := make(map[string]WritablePath)
Colin Crossfeec25b2019-01-30 17:32:39 -0800147 for _, c := range r.commands {
148 for _, output := range c.outputs {
Colin Cross69f59a32019-02-15 10:39:37 -0800149 outputs[output.String()] = output
Colin Crossfeec25b2019-01-30 17:32:39 -0800150 }
151 }
152 return outputs
153}
154
Colin Cross758290d2019-02-01 16:42:32 -0800155// Outputs returns the list of paths that were passed to the RuleBuilderCommand methods that take output paths, such
156// as RuleBuilderCommand.Output, RuleBuilderCommand.ImplicitOutput, or RuleBuilderCommand.FlagWithInput.
Colin Cross69f59a32019-02-15 10:39:37 -0800157func (r *RuleBuilder) Outputs() WritablePaths {
Colin Crossfeec25b2019-01-30 17:32:39 -0800158 outputs := r.outputSet()
159
Colin Cross69f59a32019-02-15 10:39:37 -0800160 var outputList WritablePaths
161 for _, output := range outputs {
Colin Cross5cb5b092019-02-02 21:25:18 -0800162 if !r.temporariesSet[output] {
163 outputList = append(outputList, output)
164 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800165 }
Colin Cross69f59a32019-02-15 10:39:37 -0800166
167 sort.Slice(outputList, func(i, j int) bool {
168 return outputList[i].String() < outputList[j].String()
169 })
170
Colin Crossfeec25b2019-01-30 17:32:39 -0800171 return outputList
172}
173
Colin Cross1d2cf042019-03-29 15:33:06 -0700174// DepFiles returns the list of paths that were passed to the RuleBuilderCommand methods that take depfile paths, such
175// as RuleBuilderCommand.DepFile or RuleBuilderCommand.FlagWithDepFile.
176func (r *RuleBuilder) DepFiles() WritablePaths {
177 var depFiles WritablePaths
178
179 for _, c := range r.commands {
180 for _, depFile := range c.depFiles {
181 depFiles = append(depFiles, depFile)
182 }
183 }
184
185 return depFiles
186}
187
Colin Cross758290d2019-02-01 16:42:32 -0800188// Installs returns the list of tuples passed to Install.
Colin Crossdeabb942019-02-11 14:11:09 -0800189func (r *RuleBuilder) Installs() RuleBuilderInstalls {
190 return append(RuleBuilderInstalls(nil), r.installs...)
Colin Crossfeec25b2019-01-30 17:32:39 -0800191}
192
Colin Cross69f59a32019-02-15 10:39:37 -0800193func (r *RuleBuilder) toolsSet() map[string]Path {
194 tools := make(map[string]Path)
Colin Cross5cb5b092019-02-02 21:25:18 -0800195 for _, c := range r.commands {
196 for _, tool := range c.tools {
Colin Cross69f59a32019-02-15 10:39:37 -0800197 tools[tool.String()] = tool
Colin Cross5cb5b092019-02-02 21:25:18 -0800198 }
199 }
200
201 return tools
202}
203
Colin Cross758290d2019-02-01 16:42:32 -0800204// Tools returns the list of paths that were passed to the RuleBuilderCommand.Tool method.
Colin Cross69f59a32019-02-15 10:39:37 -0800205func (r *RuleBuilder) Tools() Paths {
Colin Cross5cb5b092019-02-02 21:25:18 -0800206 toolsSet := r.toolsSet()
207
Colin Cross69f59a32019-02-15 10:39:37 -0800208 var toolsList Paths
209 for _, tool := range toolsSet {
Colin Cross5cb5b092019-02-02 21:25:18 -0800210 toolsList = append(toolsList, tool)
Colin Crossfeec25b2019-01-30 17:32:39 -0800211 }
Colin Cross69f59a32019-02-15 10:39:37 -0800212
213 sort.Slice(toolsList, func(i, j int) bool {
214 return toolsList[i].String() < toolsList[j].String()
215 })
216
Colin Cross5cb5b092019-02-02 21:25:18 -0800217 return toolsList
Colin Crossfeec25b2019-01-30 17:32:39 -0800218}
219
Colin Cross758290d2019-02-01 16:42:32 -0800220// Commands returns a slice containing a the built command line for each call to RuleBuilder.Command.
Colin Crossfeec25b2019-01-30 17:32:39 -0800221func (r *RuleBuilder) Commands() []string {
222 var commands []string
223 for _, c := range r.commands {
224 commands = append(commands, string(c.buf))
225 }
226 return commands
227}
228
Colin Cross758290d2019-02-01 16:42:32 -0800229// BuilderContext is a subset of ModuleContext and SingletonContext.
Colin Cross786cd6d2019-02-01 16:41:11 -0800230type BuilderContext interface {
231 PathContext
232 Rule(PackageContext, string, blueprint.RuleParams, ...string) blueprint.Rule
233 Build(PackageContext, BuildParams)
234}
235
Colin Cross758290d2019-02-01 16:42:32 -0800236var _ BuilderContext = ModuleContext(nil)
237var _ BuilderContext = SingletonContext(nil)
238
Colin Cross1d2cf042019-03-29 15:33:06 -0700239func (r *RuleBuilder) depFileMergerCmd(ctx PathContext, depFiles WritablePaths) *RuleBuilderCommand {
240 return (&RuleBuilderCommand{}).
241 Tool(ctx.Config().HostToolPath(ctx, "dep_fixer")).
242 Flags(depFiles.Strings())
243}
244
Colin Cross758290d2019-02-01 16:42:32 -0800245// Build adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for
246// Outputs.
Colin Cross786cd6d2019-02-01 16:41:11 -0800247func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string, desc string) {
Colin Cross1d2cf042019-03-29 15:33:06 -0700248 name = ninjaNameEscape(name)
249
Colin Cross0d2f40a2019-02-05 22:31:15 -0800250 if len(r.missingDeps) > 0 {
251 ctx.Build(pctx, BuildParams{
252 Rule: ErrorRule,
Colin Cross69f59a32019-02-15 10:39:37 -0800253 Outputs: r.Outputs(),
Colin Cross0d2f40a2019-02-05 22:31:15 -0800254 Description: desc,
255 Args: map[string]string{
256 "error": "missing dependencies: " + strings.Join(r.missingDeps, ", "),
257 },
258 })
259 return
260 }
261
Colin Cross1d2cf042019-03-29 15:33:06 -0700262 tools := r.Tools()
263 commands := r.Commands()
264
265 var depFile WritablePath
266 var depFormat blueprint.Deps
267 if depFiles := r.DepFiles(); len(depFiles) > 0 {
268 depFile = depFiles[0]
269 depFormat = blueprint.DepsGCC
270 if len(depFiles) > 1 {
271 // Add a command locally that merges all depfiles together into the first depfile.
272 cmd := r.depFileMergerCmd(ctx, depFiles)
273 commands = append(commands, string(cmd.buf))
274 tools = append(tools, cmd.tools...)
275 }
276 }
277
278 // Ninja doesn't like multiple outputs when depfiles are enabled, move all but the first output to
279 // ImplicitOutputs. RuleBuilder never uses "$out", so the distinction between Outputs and ImplicitOutputs
280 // doesn't matter.
281 var output WritablePath
282 var implicitOutputs WritablePaths
283 if outputs := r.Outputs(); len(outputs) > 0 {
284 output = outputs[0]
285 implicitOutputs = outputs[1:]
286 }
287
288 if len(commands) > 0 {
Colin Crossfeec25b2019-01-30 17:32:39 -0800289 ctx.Build(pctx, BuildParams{
290 Rule: ctx.Rule(pctx, name, blueprint.RuleParams{
Colin Cross1d2cf042019-03-29 15:33:06 -0700291 Command: strings.Join(proptools.NinjaEscapeList(commands), " && "),
292 CommandDeps: tools.Strings(),
Colin Crossbaa676f2019-02-25 14:56:01 -0800293 Restat: r.restat,
Colin Crossfeec25b2019-01-30 17:32:39 -0800294 }),
Colin Cross1d2cf042019-03-29 15:33:06 -0700295 Implicits: r.Inputs(),
296 Output: output,
297 ImplicitOutputs: implicitOutputs,
298 Depfile: depFile,
299 Deps: depFormat,
300 Description: desc,
Colin Crossfeec25b2019-01-30 17:32:39 -0800301 })
302 }
303}
304
Colin Cross758290d2019-02-01 16:42:32 -0800305// RuleBuilderCommand is a builder for a command in a command line. It can be mutated by its methods to add to the
306// command and track dependencies. The methods mutate the RuleBuilderCommand in place, as well as return the
307// RuleBuilderCommand, so they can be used chained or unchained. All methods that add text implicitly add a single
308// space as a separator from the previous method.
Colin Crossfeec25b2019-01-30 17:32:39 -0800309type RuleBuilderCommand struct {
Colin Cross1d2cf042019-03-29 15:33:06 -0700310 buf []byte
311 inputs Paths
312 outputs WritablePaths
313 depFiles WritablePaths
314 tools Paths
Colin Crossfeec25b2019-01-30 17:32:39 -0800315}
316
Colin Cross758290d2019-02-01 16:42:32 -0800317// Text adds the specified raw text to the command line. The text should not contain input or output paths or the
318// rule will not have them listed in its dependencies or outputs.
Colin Crossfeec25b2019-01-30 17:32:39 -0800319func (c *RuleBuilderCommand) Text(text string) *RuleBuilderCommand {
320 if len(c.buf) > 0 {
321 c.buf = append(c.buf, ' ')
322 }
323 c.buf = append(c.buf, text...)
324 return c
325}
326
Colin Cross758290d2019-02-01 16:42:32 -0800327// Textf adds the specified formatted text to the command line. The text should not contain input or output paths or
328// the rule will not have them listed in its dependencies or outputs.
Colin Crossfeec25b2019-01-30 17:32:39 -0800329func (c *RuleBuilderCommand) Textf(format string, a ...interface{}) *RuleBuilderCommand {
330 return c.Text(fmt.Sprintf(format, a...))
331}
332
Colin Cross758290d2019-02-01 16:42:32 -0800333// Flag adds the specified raw text to the command line. The text should not contain input or output paths or the
334// rule will not have them listed in its dependencies or outputs.
Colin Crossfeec25b2019-01-30 17:32:39 -0800335func (c *RuleBuilderCommand) Flag(flag string) *RuleBuilderCommand {
336 return c.Text(flag)
337}
338
Colin Cross92b7d582019-03-29 15:32:51 -0700339// Flags adds the specified raw text to the command line. The text should not contain input or output paths or the
340// rule will not have them listed in its dependencies or outputs.
341func (c *RuleBuilderCommand) Flags(flags []string) *RuleBuilderCommand {
342 for _, flag := range flags {
343 c.Text(flag)
344 }
345 return c
346}
347
Colin Cross758290d2019-02-01 16:42:32 -0800348// FlagWithArg adds the specified flag and argument text to the command line, with no separator between them. The flag
349// and argument should not contain input or output paths or the rule will not have them listed in its dependencies or
350// outputs.
Colin Crossfeec25b2019-01-30 17:32:39 -0800351func (c *RuleBuilderCommand) FlagWithArg(flag, arg string) *RuleBuilderCommand {
352 return c.Text(flag + arg)
353}
354
Colin Crossc7ed0042019-02-11 14:11:09 -0800355// FlagForEachArg adds the specified flag joined with each argument to the command line. The result is identical to
356// calling FlagWithArg for argument.
357func (c *RuleBuilderCommand) FlagForEachArg(flag string, args []string) *RuleBuilderCommand {
358 for _, arg := range args {
359 c.FlagWithArg(flag, arg)
360 }
361 return c
362}
363
Roland Levillain2da5d9a2019-02-27 16:56:41 +0000364// FlagWithList adds the specified flag and list of arguments to the command line, with the arguments joined by sep
Colin Cross758290d2019-02-01 16:42:32 -0800365// and no separator between the flag and arguments. The flag and arguments should not contain input or output paths or
366// the rule will not have them listed in its dependencies or outputs.
Colin Crossfeec25b2019-01-30 17:32:39 -0800367func (c *RuleBuilderCommand) FlagWithList(flag string, list []string, sep string) *RuleBuilderCommand {
368 return c.Text(flag + strings.Join(list, sep))
369}
370
Colin Cross758290d2019-02-01 16:42:32 -0800371// Tool adds the specified tool path to the command line. The path will be also added to the dependencies returned by
372// RuleBuilder.Tools.
Colin Cross69f59a32019-02-15 10:39:37 -0800373func (c *RuleBuilderCommand) Tool(path Path) *RuleBuilderCommand {
Colin Crossfeec25b2019-01-30 17:32:39 -0800374 c.tools = append(c.tools, path)
Colin Cross69f59a32019-02-15 10:39:37 -0800375 return c.Text(path.String())
Colin Crossfeec25b2019-01-30 17:32:39 -0800376}
377
Colin Cross758290d2019-02-01 16:42:32 -0800378// Input adds the specified input path to the command line. The path will also be added to the dependencies returned by
379// RuleBuilder.Inputs.
Colin Cross69f59a32019-02-15 10:39:37 -0800380func (c *RuleBuilderCommand) Input(path Path) *RuleBuilderCommand {
Colin Crossfeec25b2019-01-30 17:32:39 -0800381 c.inputs = append(c.inputs, path)
Colin Cross69f59a32019-02-15 10:39:37 -0800382 return c.Text(path.String())
Colin Crossfeec25b2019-01-30 17:32:39 -0800383}
384
Colin Cross758290d2019-02-01 16:42:32 -0800385// Inputs adds the specified input paths to the command line, separated by spaces. The paths will also be added to the
386// dependencies returned by RuleBuilder.Inputs.
Colin Cross69f59a32019-02-15 10:39:37 -0800387func (c *RuleBuilderCommand) Inputs(paths Paths) *RuleBuilderCommand {
Colin Cross758290d2019-02-01 16:42:32 -0800388 for _, path := range paths {
389 c.Input(path)
390 }
391 return c
392}
393
394// Implicit adds the specified input path to the dependencies returned by RuleBuilder.Inputs without modifying the
395// command line.
Colin Cross69f59a32019-02-15 10:39:37 -0800396func (c *RuleBuilderCommand) Implicit(path Path) *RuleBuilderCommand {
Colin Crossfeec25b2019-01-30 17:32:39 -0800397 c.inputs = append(c.inputs, path)
398 return c
399}
400
Colin Cross758290d2019-02-01 16:42:32 -0800401// Implicits adds the specified input paths to the dependencies returned by RuleBuilder.Inputs without modifying the
402// command line.
Colin Cross69f59a32019-02-15 10:39:37 -0800403func (c *RuleBuilderCommand) Implicits(paths Paths) *RuleBuilderCommand {
Colin Crossfeec25b2019-01-30 17:32:39 -0800404 c.inputs = append(c.inputs, paths...)
405 return c
406}
407
Colin Cross758290d2019-02-01 16:42:32 -0800408// Output adds the specified output path to the command line. The path will also be added to the outputs returned by
409// RuleBuilder.Outputs.
Colin Cross69f59a32019-02-15 10:39:37 -0800410func (c *RuleBuilderCommand) Output(path WritablePath) *RuleBuilderCommand {
Colin Crossfeec25b2019-01-30 17:32:39 -0800411 c.outputs = append(c.outputs, path)
Colin Cross69f59a32019-02-15 10:39:37 -0800412 return c.Text(path.String())
Colin Crossfeec25b2019-01-30 17:32:39 -0800413}
414
Colin Cross758290d2019-02-01 16:42:32 -0800415// Outputs adds the specified output paths to the command line, separated by spaces. The paths will also be added to
416// the outputs returned by RuleBuilder.Outputs.
Colin Cross69f59a32019-02-15 10:39:37 -0800417func (c *RuleBuilderCommand) Outputs(paths WritablePaths) *RuleBuilderCommand {
Colin Cross758290d2019-02-01 16:42:32 -0800418 for _, path := range paths {
419 c.Output(path)
420 }
421 return c
422}
423
Colin Cross1d2cf042019-03-29 15:33:06 -0700424// DepFile adds the specified depfile path to the paths returned by RuleBuilder.DepFiles and adds it to the command
425// line, and causes RuleBuilder.Build file to set the depfile flag for ninja. If multiple depfiles are added to
426// commands in a single RuleBuilder then RuleBuilder.Build will add an extra command to merge the depfiles together.
427func (c *RuleBuilderCommand) DepFile(path WritablePath) *RuleBuilderCommand {
428 c.depFiles = append(c.depFiles, path)
429 return c.Text(path.String())
430}
431
Colin Cross758290d2019-02-01 16:42:32 -0800432// ImplicitOutput adds the specified output path to the dependencies returned by RuleBuilder.Outputs without modifying
433// the command line.
Colin Cross69f59a32019-02-15 10:39:37 -0800434func (c *RuleBuilderCommand) ImplicitOutput(path WritablePath) *RuleBuilderCommand {
Colin Crossfeec25b2019-01-30 17:32:39 -0800435 c.outputs = append(c.outputs, path)
436 return c
437}
438
Colin Cross758290d2019-02-01 16:42:32 -0800439// ImplicitOutputs adds the specified output paths to the dependencies returned by RuleBuilder.Outputs without modifying
440// the command line.
Colin Cross69f59a32019-02-15 10:39:37 -0800441func (c *RuleBuilderCommand) ImplicitOutputs(paths WritablePaths) *RuleBuilderCommand {
Colin Cross758290d2019-02-01 16:42:32 -0800442 c.outputs = append(c.outputs, paths...)
443 return c
444}
445
Colin Cross1d2cf042019-03-29 15:33:06 -0700446// ImplicitDepFile adds the specified depfile path to the paths returned by RuleBuilder.DepFiles without modifying
447// the command line, and causes RuleBuilder.Build file to set the depfile flag for ninja. If multiple depfiles
448// are added to commands in a single RuleBuilder then RuleBuilder.Build will add an extra command to merge the
449// depfiles together.
450func (c *RuleBuilderCommand) ImplicitDepFile(path WritablePath) *RuleBuilderCommand {
451 c.depFiles = append(c.depFiles, path)
452 return c
453}
454
Colin Cross758290d2019-02-01 16:42:32 -0800455// FlagWithInput adds the specified flag and input path to the command line, with no separator between them. The path
456// will also be added to the dependencies returned by RuleBuilder.Inputs.
Colin Cross69f59a32019-02-15 10:39:37 -0800457func (c *RuleBuilderCommand) FlagWithInput(flag string, path Path) *RuleBuilderCommand {
Colin Crossfeec25b2019-01-30 17:32:39 -0800458 c.inputs = append(c.inputs, path)
Colin Cross69f59a32019-02-15 10:39:37 -0800459 return c.Text(flag + path.String())
Colin Crossfeec25b2019-01-30 17:32:39 -0800460}
461
Colin Cross758290d2019-02-01 16:42:32 -0800462// FlagWithInputList adds the specified flag and input paths to the command line, with the inputs joined by sep
463// and no separator between the flag and inputs. The input paths will also be added to the dependencies returned by
464// RuleBuilder.Inputs.
Colin Cross69f59a32019-02-15 10:39:37 -0800465func (c *RuleBuilderCommand) FlagWithInputList(flag string, paths Paths, sep string) *RuleBuilderCommand {
Colin Crossfeec25b2019-01-30 17:32:39 -0800466 c.inputs = append(c.inputs, paths...)
Colin Cross69f59a32019-02-15 10:39:37 -0800467 return c.FlagWithList(flag, paths.Strings(), sep)
Colin Crossfeec25b2019-01-30 17:32:39 -0800468}
469
Colin Cross758290d2019-02-01 16:42:32 -0800470// FlagForEachInput adds the specified flag joined with each input path to the command line. The input paths will also
471// be added to the dependencies returned by RuleBuilder.Inputs. The result is identical to calling FlagWithInput for
472// each input path.
Colin Cross69f59a32019-02-15 10:39:37 -0800473func (c *RuleBuilderCommand) FlagForEachInput(flag string, paths Paths) *RuleBuilderCommand {
Colin Cross758290d2019-02-01 16:42:32 -0800474 for _, path := range paths {
475 c.FlagWithInput(flag, path)
476 }
477 return c
478}
479
480// FlagWithOutput adds the specified flag and output path to the command line, with no separator between them. The path
481// will also be added to the outputs returned by RuleBuilder.Outputs.
Colin Cross69f59a32019-02-15 10:39:37 -0800482func (c *RuleBuilderCommand) FlagWithOutput(flag string, path WritablePath) *RuleBuilderCommand {
Colin Crossfeec25b2019-01-30 17:32:39 -0800483 c.outputs = append(c.outputs, path)
Colin Cross69f59a32019-02-15 10:39:37 -0800484 return c.Text(flag + path.String())
Colin Crossfeec25b2019-01-30 17:32:39 -0800485}
486
Colin Cross1d2cf042019-03-29 15:33:06 -0700487// FlagWithDepFile adds the specified flag and depfile path to the command line, with no separator between them. The path
488// will also be added to the outputs returned by RuleBuilder.Outputs.
489func (c *RuleBuilderCommand) FlagWithDepFile(flag string, path WritablePath) *RuleBuilderCommand {
490 c.depFiles = append(c.depFiles, path)
491 return c.Text(flag + path.String())
492}
493
Colin Cross758290d2019-02-01 16:42:32 -0800494// String returns the command line.
495func (c *RuleBuilderCommand) String() string {
496 return string(c.buf)
497}
Colin Cross1d2cf042019-03-29 15:33:06 -0700498
499func ninjaNameEscape(s string) string {
500 b := []byte(s)
501 escaped := false
502 for i, c := range b {
503 valid := (c >= 'a' && c <= 'z') ||
504 (c >= 'A' && c <= 'Z') ||
505 (c >= '0' && c <= '9') ||
506 (c == '_') ||
507 (c == '-') ||
508 (c == '.')
509 if !valid {
510 b[i] = '_'
511 escaped = true
512 }
513 }
514 if escaped {
515 s = string(b)
516 }
517 return s
518}