blob: 0438eb8c79151c548d9dd6a5a16275168526afd5 [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 (
Colin Cross3d680512020-11-13 16:23:53 -080018 "crypto/sha256"
Colin Crossfeec25b2019-01-30 17:32:39 -080019 "fmt"
Colin Cross3d680512020-11-13 16:23:53 -080020 "path/filepath"
Colin Crossfeec25b2019-01-30 17:32:39 -080021 "sort"
22 "strings"
Colin Crosse16ce362020-11-12 08:29:30 -080023 "testing"
Colin Crossfeec25b2019-01-30 17:32:39 -080024
25 "github.com/google/blueprint"
26 "github.com/google/blueprint/proptools"
Dan Willemsen4591b642021-05-24 14:24:12 -070027 "google.golang.org/protobuf/encoding/prototext"
28 "google.golang.org/protobuf/proto"
Dan Willemsen633c5022019-04-12 11:11:38 -070029
Colin Crosse16ce362020-11-12 08:29:30 -080030 "android/soong/cmd/sbox/sbox_proto"
Colin Crossef972742021-03-12 17:24:45 -080031 "android/soong/remoteexec"
Colin Crosse55bd422021-03-23 13:44:30 -070032 "android/soong/response"
Dan Willemsen633c5022019-04-12 11:11:38 -070033 "android/soong/shared"
Colin Crossfeec25b2019-01-30 17:32:39 -080034)
35
Colin Crosse16ce362020-11-12 08:29:30 -080036const sboxSandboxBaseDir = "__SBOX_SANDBOX_DIR__"
37const sboxOutSubDir = "out"
Colin Crossba9e4032020-11-24 16:32:22 -080038const sboxToolsSubDir = "tools"
Colin Crosse16ce362020-11-12 08:29:30 -080039const sboxOutDir = sboxSandboxBaseDir + "/" + sboxOutSubDir
Colin Cross3d680512020-11-13 16:23:53 -080040
Colin Cross758290d2019-02-01 16:42:32 -080041// RuleBuilder provides an alternative to ModuleContext.Rule and ModuleContext.Build to add a command line to the build
42// graph.
Colin Crossfeec25b2019-01-30 17:32:39 -080043type RuleBuilder struct {
Colin Crossf1a035e2020-11-16 17:32:30 -080044 pctx PackageContext
45 ctx BuilderContext
46
Colin Crosse16ce362020-11-12 08:29:30 -080047 commands []*RuleBuilderCommand
48 installs RuleBuilderInstalls
49 temporariesSet map[WritablePath]bool
50 restat bool
51 sbox bool
52 highmem bool
53 remoteable RemoteRuleSupports
Colin Crossef972742021-03-12 17:24:45 -080054 rbeParams *remoteexec.REParams
Colin Crossf1a035e2020-11-16 17:32:30 -080055 outDir WritablePath
Colin Crossba9e4032020-11-24 16:32:22 -080056 sboxTools bool
Colin Crossab020a72021-03-12 17:52:23 -080057 sboxInputs bool
Colin Crosse16ce362020-11-12 08:29:30 -080058 sboxManifestPath WritablePath
59 missingDeps []string
Colin Crossfeec25b2019-01-30 17:32:39 -080060}
61
Colin Cross758290d2019-02-01 16:42:32 -080062// NewRuleBuilder returns a newly created RuleBuilder.
Colin Crossf1a035e2020-11-16 17:32:30 -080063func NewRuleBuilder(pctx PackageContext, ctx BuilderContext) *RuleBuilder {
Colin Cross5cb5b092019-02-02 21:25:18 -080064 return &RuleBuilder{
Colin Crossf1a035e2020-11-16 17:32:30 -080065 pctx: pctx,
66 ctx: ctx,
Colin Cross69f59a32019-02-15 10:39:37 -080067 temporariesSet: make(map[WritablePath]bool),
Colin Cross5cb5b092019-02-02 21:25:18 -080068 }
Colin Cross758290d2019-02-01 16:42:32 -080069}
70
71// RuleBuilderInstall is a tuple of install from and to locations.
72type RuleBuilderInstall struct {
Colin Cross69f59a32019-02-15 10:39:37 -080073 From Path
74 To string
Colin Cross758290d2019-02-01 16:42:32 -080075}
76
Colin Crossdeabb942019-02-11 14:11:09 -080077type RuleBuilderInstalls []RuleBuilderInstall
78
79// String returns the RuleBuilderInstalls in the form used by $(call copy-many-files) in Make, a space separated
80// list of from:to tuples.
81func (installs RuleBuilderInstalls) String() string {
82 sb := strings.Builder{}
83 for i, install := range installs {
84 if i != 0 {
85 sb.WriteRune(' ')
86 }
Colin Cross69f59a32019-02-15 10:39:37 -080087 sb.WriteString(install.From.String())
Colin Crossdeabb942019-02-11 14:11:09 -080088 sb.WriteRune(':')
89 sb.WriteString(install.To)
90 }
91 return sb.String()
92}
93
Colin Cross0d2f40a2019-02-05 22:31:15 -080094// MissingDeps adds modules to the list of missing dependencies. If MissingDeps
95// is called with a non-empty input, any call to Build will result in a rule
96// that will print an error listing the missing dependencies and fail.
97// MissingDeps should only be called if Config.AllowMissingDependencies() is
98// true.
99func (r *RuleBuilder) MissingDeps(missingDeps []string) {
100 r.missingDeps = append(r.missingDeps, missingDeps...)
101}
102
Colin Cross758290d2019-02-01 16:42:32 -0800103// 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 -0800104func (r *RuleBuilder) Restat() *RuleBuilder {
105 r.restat = true
106 return r
107}
108
Colin Cross8b8bec32019-11-15 13:18:43 -0800109// HighMem marks the rule as a high memory rule, which will limit how many run in parallel with other high memory
110// rules.
111func (r *RuleBuilder) HighMem() *RuleBuilder {
112 r.highmem = true
113 return r
114}
115
116// Remoteable marks the rule as supporting remote execution.
117func (r *RuleBuilder) Remoteable(supports RemoteRuleSupports) *RuleBuilder {
118 r.remoteable = supports
119 return r
120}
121
Colin Crossef972742021-03-12 17:24:45 -0800122// Rewrapper marks the rule as running inside rewrapper using the given params in order to support
123// running on RBE. During RuleBuilder.Build the params will be combined with the inputs, outputs
124// and tools known to RuleBuilder to prepend an appropriate rewrapper command line to the rule's
125// command line.
126func (r *RuleBuilder) Rewrapper(params *remoteexec.REParams) *RuleBuilder {
127 if !r.sboxInputs {
128 panic(fmt.Errorf("RuleBuilder.Rewrapper must be called after RuleBuilder.SandboxInputs"))
129 }
130 r.rbeParams = params
131 return r
132}
133
Colin Crosse16ce362020-11-12 08:29:30 -0800134// Sbox marks the rule as needing to be wrapped by sbox. The outputDir should point to the output
135// directory that sbox will wipe. It should not be written to by any other rule. manifestPath should
136// point to a location where sbox's manifest will be written and must be outside outputDir. sbox
137// will ensure that all outputs have been written, and will discard any output files that were not
138// specified.
Colin Crosse16ce362020-11-12 08:29:30 -0800139func (r *RuleBuilder) Sbox(outputDir WritablePath, manifestPath WritablePath) *RuleBuilder {
Dan Willemsen633c5022019-04-12 11:11:38 -0700140 if r.sbox {
141 panic("Sbox() may not be called more than once")
142 }
143 if len(r.commands) > 0 {
144 panic("Sbox() may not be called after Command()")
145 }
Dan Willemsen633c5022019-04-12 11:11:38 -0700146 r.sbox = true
Colin Crossf1a035e2020-11-16 17:32:30 -0800147 r.outDir = outputDir
Colin Crosse16ce362020-11-12 08:29:30 -0800148 r.sboxManifestPath = manifestPath
Dan Willemsen633c5022019-04-12 11:11:38 -0700149 return r
150}
151
Colin Crossba9e4032020-11-24 16:32:22 -0800152// SandboxTools enables tool sandboxing for the rule by copying any referenced tools into the
153// sandbox.
154func (r *RuleBuilder) SandboxTools() *RuleBuilder {
155 if !r.sbox {
156 panic("SandboxTools() must be called after Sbox()")
157 }
158 if len(r.commands) > 0 {
159 panic("SandboxTools() may not be called after Command()")
160 }
161 r.sboxTools = true
162 return r
163}
164
Colin Crossab020a72021-03-12 17:52:23 -0800165// SandboxInputs enables input sandboxing for the rule by copying any referenced inputs into the
166// sandbox. It also implies SandboxTools().
167//
168// Sandboxing inputs requires RuleBuilder to be aware of all references to input paths. Paths
169// that are passed to RuleBuilder outside of the methods that expect inputs, for example
170// FlagWithArg, must use RuleBuilderCommand.PathForInput to translate the path to one that matches
171// the sandbox layout.
172func (r *RuleBuilder) SandboxInputs() *RuleBuilder {
173 if !r.sbox {
174 panic("SandboxInputs() must be called after Sbox()")
175 }
176 if len(r.commands) > 0 {
177 panic("SandboxInputs() may not be called after Command()")
178 }
179 r.sboxTools = true
180 r.sboxInputs = true
181 return r
182}
183
Colin Cross758290d2019-02-01 16:42:32 -0800184// Install associates an output of the rule with an install location, which can be retrieved later using
185// RuleBuilder.Installs.
Colin Cross69f59a32019-02-15 10:39:37 -0800186func (r *RuleBuilder) Install(from Path, to string) {
Colin Crossfeec25b2019-01-30 17:32:39 -0800187 r.installs = append(r.installs, RuleBuilderInstall{from, to})
188}
189
Colin Cross758290d2019-02-01 16:42:32 -0800190// Command returns a new RuleBuilderCommand for the rule. The commands will be ordered in the rule by when they were
191// created by this method. That can be mutated through their methods in any order, as long as the mutations do not
192// race with any call to Build.
Colin Crossfeec25b2019-01-30 17:32:39 -0800193func (r *RuleBuilder) Command() *RuleBuilderCommand {
Dan Willemsen633c5022019-04-12 11:11:38 -0700194 command := &RuleBuilderCommand{
Colin Crossf1a035e2020-11-16 17:32:30 -0800195 rule: r,
Dan Willemsen633c5022019-04-12 11:11:38 -0700196 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800197 r.commands = append(r.commands, command)
198 return command
199}
200
Colin Cross5cb5b092019-02-02 21:25:18 -0800201// Temporary marks an output of a command as an intermediate file that will be used as an input to another command
202// in the same rule, and should not be listed in Outputs.
Colin Cross69f59a32019-02-15 10:39:37 -0800203func (r *RuleBuilder) Temporary(path WritablePath) {
Colin Cross5cb5b092019-02-02 21:25:18 -0800204 r.temporariesSet[path] = true
205}
206
207// DeleteTemporaryFiles adds a command to the rule that deletes any outputs that have been marked using Temporary
208// when the rule runs. DeleteTemporaryFiles should be called after all calls to Temporary.
209func (r *RuleBuilder) DeleteTemporaryFiles() {
Colin Cross69f59a32019-02-15 10:39:37 -0800210 var temporariesList WritablePaths
Colin Cross5cb5b092019-02-02 21:25:18 -0800211
212 for intermediate := range r.temporariesSet {
213 temporariesList = append(temporariesList, intermediate)
214 }
Colin Cross69f59a32019-02-15 10:39:37 -0800215
216 sort.Slice(temporariesList, func(i, j int) bool {
217 return temporariesList[i].String() < temporariesList[j].String()
218 })
Colin Cross5cb5b092019-02-02 21:25:18 -0800219
220 r.Command().Text("rm").Flag("-f").Outputs(temporariesList)
221}
222
Colin Crossda71eda2020-02-21 16:55:19 -0800223// Inputs returns the list of paths that were passed to the RuleBuilderCommand methods that take
Colin Cross3d680512020-11-13 16:23:53 -0800224// input paths, such as RuleBuilderCommand.Input, RuleBuilderCommand.Implicit, or
Colin Crossda71eda2020-02-21 16:55:19 -0800225// RuleBuilderCommand.FlagWithInput. Inputs to a command that are also outputs of another command
226// in the same RuleBuilder are filtered out. The list is sorted and duplicates removed.
Colin Cross69f59a32019-02-15 10:39:37 -0800227func (r *RuleBuilder) Inputs() Paths {
Colin Crossfeec25b2019-01-30 17:32:39 -0800228 outputs := r.outputSet()
Dan Willemsen633c5022019-04-12 11:11:38 -0700229 depFiles := r.depFileSet()
Colin Crossfeec25b2019-01-30 17:32:39 -0800230
Colin Cross69f59a32019-02-15 10:39:37 -0800231 inputs := make(map[string]Path)
Colin Crossfeec25b2019-01-30 17:32:39 -0800232 for _, c := range r.commands {
Ramy Medhat2f99eec2020-06-13 17:38:27 -0400233 for _, input := range append(c.inputs, c.implicits...) {
Dan Willemsen633c5022019-04-12 11:11:38 -0700234 inputStr := input.String()
235 if _, isOutput := outputs[inputStr]; !isOutput {
236 if _, isDepFile := depFiles[inputStr]; !isDepFile {
237 inputs[input.String()] = input
238 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800239 }
240 }
241 }
242
Colin Cross69f59a32019-02-15 10:39:37 -0800243 var inputList Paths
244 for _, input := range inputs {
Colin Crossfeec25b2019-01-30 17:32:39 -0800245 inputList = append(inputList, input)
246 }
Colin Cross69f59a32019-02-15 10:39:37 -0800247
248 sort.Slice(inputList, func(i, j int) bool {
249 return inputList[i].String() < inputList[j].String()
250 })
Colin Crossfeec25b2019-01-30 17:32:39 -0800251
252 return inputList
253}
254
Colin Crossda71eda2020-02-21 16:55:19 -0800255// OrderOnlys returns the list of paths that were passed to the RuleBuilderCommand.OrderOnly or
256// RuleBuilderCommand.OrderOnlys. The list is sorted and duplicates removed.
257func (r *RuleBuilder) OrderOnlys() Paths {
258 orderOnlys := make(map[string]Path)
259 for _, c := range r.commands {
260 for _, orderOnly := range c.orderOnlys {
261 orderOnlys[orderOnly.String()] = orderOnly
262 }
263 }
264
265 var orderOnlyList Paths
266 for _, orderOnly := range orderOnlys {
267 orderOnlyList = append(orderOnlyList, orderOnly)
268 }
269
270 sort.Slice(orderOnlyList, func(i, j int) bool {
271 return orderOnlyList[i].String() < orderOnlyList[j].String()
272 })
273
274 return orderOnlyList
275}
276
Colin Crossae89abe2021-04-21 11:45:23 -0700277// Validations returns the list of paths that were passed to RuleBuilderCommand.Validation or
278// RuleBuilderCommand.Validations. The list is sorted and duplicates removed.
279func (r *RuleBuilder) Validations() Paths {
280 validations := make(map[string]Path)
281 for _, c := range r.commands {
282 for _, validation := range c.validations {
283 validations[validation.String()] = validation
284 }
285 }
286
287 var validationList Paths
288 for _, validation := range validations {
289 validationList = append(validationList, validation)
290 }
291
292 sort.Slice(validationList, func(i, j int) bool {
293 return validationList[i].String() < validationList[j].String()
294 })
295
296 return validationList
297}
298
Colin Cross69f59a32019-02-15 10:39:37 -0800299func (r *RuleBuilder) outputSet() map[string]WritablePath {
300 outputs := make(map[string]WritablePath)
Colin Crossfeec25b2019-01-30 17:32:39 -0800301 for _, c := range r.commands {
302 for _, output := range c.outputs {
Colin Cross69f59a32019-02-15 10:39:37 -0800303 outputs[output.String()] = output
Colin Crossfeec25b2019-01-30 17:32:39 -0800304 }
305 }
306 return outputs
307}
308
Colin Crossda71eda2020-02-21 16:55:19 -0800309// Outputs returns the list of paths that were passed to the RuleBuilderCommand methods that take
310// output paths, such as RuleBuilderCommand.Output, RuleBuilderCommand.ImplicitOutput, or
311// RuleBuilderCommand.FlagWithInput. The list is sorted and duplicates removed.
Colin Cross69f59a32019-02-15 10:39:37 -0800312func (r *RuleBuilder) Outputs() WritablePaths {
Colin Crossfeec25b2019-01-30 17:32:39 -0800313 outputs := r.outputSet()
314
Colin Cross69f59a32019-02-15 10:39:37 -0800315 var outputList WritablePaths
316 for _, output := range outputs {
Colin Cross5cb5b092019-02-02 21:25:18 -0800317 if !r.temporariesSet[output] {
318 outputList = append(outputList, output)
319 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800320 }
Colin Cross69f59a32019-02-15 10:39:37 -0800321
322 sort.Slice(outputList, func(i, j int) bool {
323 return outputList[i].String() < outputList[j].String()
324 })
325
Colin Crossfeec25b2019-01-30 17:32:39 -0800326 return outputList
327}
328
Jingwen Chence679d22020-09-23 04:30:02 +0000329func (r *RuleBuilder) symlinkOutputSet() map[string]WritablePath {
330 symlinkOutputs := make(map[string]WritablePath)
331 for _, c := range r.commands {
332 for _, symlinkOutput := range c.symlinkOutputs {
333 symlinkOutputs[symlinkOutput.String()] = symlinkOutput
334 }
335 }
336 return symlinkOutputs
337}
338
339// SymlinkOutputs returns the list of paths that the executor (Ninja) would
340// verify, after build edge completion, that:
341//
342// 1) Created output symlinks match the list of paths in this list exactly (no more, no fewer)
343// 2) Created output files are *not* declared in this list.
344//
345// These symlink outputs are expected to be a subset of outputs or implicit
346// outputs, or they would fail validation at build param construction time
347// later, to support other non-rule-builder approaches for constructing
348// statements.
349func (r *RuleBuilder) SymlinkOutputs() WritablePaths {
350 symlinkOutputs := r.symlinkOutputSet()
351
352 var symlinkOutputList WritablePaths
353 for _, symlinkOutput := range symlinkOutputs {
354 symlinkOutputList = append(symlinkOutputList, symlinkOutput)
355 }
356
357 sort.Slice(symlinkOutputList, func(i, j int) bool {
358 return symlinkOutputList[i].String() < symlinkOutputList[j].String()
359 })
360
361 return symlinkOutputList
362}
363
Dan Willemsen633c5022019-04-12 11:11:38 -0700364func (r *RuleBuilder) depFileSet() map[string]WritablePath {
365 depFiles := make(map[string]WritablePath)
366 for _, c := range r.commands {
367 for _, depFile := range c.depFiles {
368 depFiles[depFile.String()] = depFile
369 }
370 }
371 return depFiles
372}
373
Colin Cross1d2cf042019-03-29 15:33:06 -0700374// DepFiles returns the list of paths that were passed to the RuleBuilderCommand methods that take depfile paths, such
375// as RuleBuilderCommand.DepFile or RuleBuilderCommand.FlagWithDepFile.
376func (r *RuleBuilder) DepFiles() WritablePaths {
377 var depFiles WritablePaths
378
379 for _, c := range r.commands {
380 for _, depFile := range c.depFiles {
381 depFiles = append(depFiles, depFile)
382 }
383 }
384
385 return depFiles
386}
387
Colin Cross758290d2019-02-01 16:42:32 -0800388// Installs returns the list of tuples passed to Install.
Colin Crossdeabb942019-02-11 14:11:09 -0800389func (r *RuleBuilder) Installs() RuleBuilderInstalls {
390 return append(RuleBuilderInstalls(nil), r.installs...)
Colin Crossfeec25b2019-01-30 17:32:39 -0800391}
392
Colin Cross69f59a32019-02-15 10:39:37 -0800393func (r *RuleBuilder) toolsSet() map[string]Path {
394 tools := make(map[string]Path)
Colin Cross5cb5b092019-02-02 21:25:18 -0800395 for _, c := range r.commands {
396 for _, tool := range c.tools {
Colin Cross69f59a32019-02-15 10:39:37 -0800397 tools[tool.String()] = tool
Colin Cross5cb5b092019-02-02 21:25:18 -0800398 }
399 }
400
401 return tools
402}
403
Colin Crossda71eda2020-02-21 16:55:19 -0800404// Tools returns the list of paths that were passed to the RuleBuilderCommand.Tool method. The
405// list is sorted and duplicates removed.
Colin Cross69f59a32019-02-15 10:39:37 -0800406func (r *RuleBuilder) Tools() Paths {
Colin Cross5cb5b092019-02-02 21:25:18 -0800407 toolsSet := r.toolsSet()
408
Colin Cross69f59a32019-02-15 10:39:37 -0800409 var toolsList Paths
410 for _, tool := range toolsSet {
Colin Cross5cb5b092019-02-02 21:25:18 -0800411 toolsList = append(toolsList, tool)
Colin Crossfeec25b2019-01-30 17:32:39 -0800412 }
Colin Cross69f59a32019-02-15 10:39:37 -0800413
414 sort.Slice(toolsList, func(i, j int) bool {
415 return toolsList[i].String() < toolsList[j].String()
416 })
417
Colin Cross5cb5b092019-02-02 21:25:18 -0800418 return toolsList
Colin Crossfeec25b2019-01-30 17:32:39 -0800419}
420
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700421// RspFileInputs returns the list of paths that were passed to the RuleBuilderCommand.FlagWithRspFileInputList method.
422func (r *RuleBuilder) RspFileInputs() Paths {
423 var rspFileInputs Paths
424 for _, c := range r.commands {
Colin Crossce3a51d2021-03-19 16:22:12 -0700425 for _, rspFile := range c.rspFiles {
426 rspFileInputs = append(rspFileInputs, rspFile.paths...)
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700427 }
428 }
429
430 return rspFileInputs
431}
432
Colin Crossce3a51d2021-03-19 16:22:12 -0700433func (r *RuleBuilder) rspFiles() []rspFileAndPaths {
434 var rspFiles []rspFileAndPaths
Colin Cross70c47412021-03-12 17:48:14 -0800435 for _, c := range r.commands {
Colin Crossce3a51d2021-03-19 16:22:12 -0700436 rspFiles = append(rspFiles, c.rspFiles...)
Colin Cross70c47412021-03-12 17:48:14 -0800437 }
438
Colin Crossce3a51d2021-03-19 16:22:12 -0700439 return rspFiles
Colin Cross70c47412021-03-12 17:48:14 -0800440}
441
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700442// Commands returns a slice containing the built command line for each call to RuleBuilder.Command.
Colin Crossfeec25b2019-01-30 17:32:39 -0800443func (r *RuleBuilder) Commands() []string {
444 var commands []string
445 for _, c := range r.commands {
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700446 commands = append(commands, c.String())
447 }
448 return commands
449}
450
Colin Cross758290d2019-02-01 16:42:32 -0800451// BuilderContext is a subset of ModuleContext and SingletonContext.
Colin Cross786cd6d2019-02-01 16:41:11 -0800452type BuilderContext interface {
453 PathContext
454 Rule(PackageContext, string, blueprint.RuleParams, ...string) blueprint.Rule
455 Build(PackageContext, BuildParams)
456}
457
Colin Cross758290d2019-02-01 16:42:32 -0800458var _ BuilderContext = ModuleContext(nil)
459var _ BuilderContext = SingletonContext(nil)
460
Colin Crossf1a035e2020-11-16 17:32:30 -0800461func (r *RuleBuilder) depFileMergerCmd(depFiles WritablePaths) *RuleBuilderCommand {
Dan Willemsen633c5022019-04-12 11:11:38 -0700462 return r.Command().
Colin Cross9b698b62021-12-22 09:55:32 -0800463 builtToolWithoutDeps("dep_fixer").
Dan Willemsen633c5022019-04-12 11:11:38 -0700464 Inputs(depFiles.Paths())
Colin Cross1d2cf042019-03-29 15:33:06 -0700465}
466
Colin Cross758290d2019-02-01 16:42:32 -0800467// Build adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for
468// Outputs.
Colin Crossf1a035e2020-11-16 17:32:30 -0800469func (r *RuleBuilder) Build(name string, desc string) {
Colin Cross1d2cf042019-03-29 15:33:06 -0700470 name = ninjaNameEscape(name)
471
Colin Cross0d2f40a2019-02-05 22:31:15 -0800472 if len(r.missingDeps) > 0 {
Colin Crossf1a035e2020-11-16 17:32:30 -0800473 r.ctx.Build(pctx, BuildParams{
Colin Cross0d2f40a2019-02-05 22:31:15 -0800474 Rule: ErrorRule,
Colin Cross69f59a32019-02-15 10:39:37 -0800475 Outputs: r.Outputs(),
Colin Cross0d2f40a2019-02-05 22:31:15 -0800476 Description: desc,
477 Args: map[string]string{
478 "error": "missing dependencies: " + strings.Join(r.missingDeps, ", "),
479 },
480 })
481 return
482 }
483
Colin Cross1d2cf042019-03-29 15:33:06 -0700484 var depFile WritablePath
485 var depFormat blueprint.Deps
486 if depFiles := r.DepFiles(); len(depFiles) > 0 {
487 depFile = depFiles[0]
488 depFormat = blueprint.DepsGCC
489 if len(depFiles) > 1 {
490 // Add a command locally that merges all depfiles together into the first depfile.
Colin Crossf1a035e2020-11-16 17:32:30 -0800491 r.depFileMergerCmd(depFiles)
Dan Willemsen633c5022019-04-12 11:11:38 -0700492
493 if r.sbox {
Colin Crosse16ce362020-11-12 08:29:30 -0800494 // Check for Rel() errors, as all depfiles should be in the output dir. Errors
495 // will be reported to the ctx.
Dan Willemsen633c5022019-04-12 11:11:38 -0700496 for _, path := range depFiles[1:] {
Colin Crossf1a035e2020-11-16 17:32:30 -0800497 Rel(r.ctx, r.outDir.String(), path.String())
Dan Willemsen633c5022019-04-12 11:11:38 -0700498 }
499 }
Colin Cross1d2cf042019-03-29 15:33:06 -0700500 }
501 }
502
Dan Willemsen633c5022019-04-12 11:11:38 -0700503 tools := r.Tools()
Colin Crossb70a1a92021-03-12 17:51:32 -0800504 commands := r.Commands()
Dan Willemsen633c5022019-04-12 11:11:38 -0700505 outputs := r.Outputs()
Colin Cross3d680512020-11-13 16:23:53 -0800506 inputs := r.Inputs()
Colin Crossce3a51d2021-03-19 16:22:12 -0700507 rspFiles := r.rspFiles()
Dan Willemsen633c5022019-04-12 11:11:38 -0700508
509 if len(commands) == 0 {
510 return
511 }
512 if len(outputs) == 0 {
513 panic("No outputs specified from any Commands")
514 }
515
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700516 commandString := strings.Join(commands, " && ")
Dan Willemsen633c5022019-04-12 11:11:38 -0700517
518 if r.sbox {
Colin Crosse16ce362020-11-12 08:29:30 -0800519 // If running the command inside sbox, write the rule data out to an sbox
520 // manifest.textproto.
521 manifest := sbox_proto.Manifest{}
522 command := sbox_proto.Command{}
523 manifest.Commands = append(manifest.Commands, &command)
524 command.Command = proto.String(commandString)
Colin Cross151b9ff2020-11-12 08:29:30 -0800525
Colin Cross619b9ab2020-11-20 18:44:31 +0000526 if depFile != nil {
Colin Crosse16ce362020-11-12 08:29:30 -0800527 manifest.OutputDepfile = proto.String(depFile.String())
Colin Cross619b9ab2020-11-20 18:44:31 +0000528 }
529
Colin Crossba9e4032020-11-24 16:32:22 -0800530 // If sandboxing tools is enabled, add copy rules to the manifest to copy each tool
531 // into the sbox directory.
532 if r.sboxTools {
533 for _, tool := range tools {
534 command.CopyBefore = append(command.CopyBefore, &sbox_proto.Copy{
535 From: proto.String(tool.String()),
536 To: proto.String(sboxPathForToolRel(r.ctx, tool)),
537 })
538 }
539 for _, c := range r.commands {
540 for _, tool := range c.packagedTools {
541 command.CopyBefore = append(command.CopyBefore, &sbox_proto.Copy{
542 From: proto.String(tool.srcPath.String()),
543 To: proto.String(sboxPathForPackagedToolRel(tool)),
544 Executable: proto.Bool(tool.executable),
545 })
546 tools = append(tools, tool.srcPath)
547 }
548 }
549 }
550
Colin Crossab020a72021-03-12 17:52:23 -0800551 // If sandboxing inputs is enabled, add copy rules to the manifest to copy each input
552 // into the sbox directory.
553 if r.sboxInputs {
554 for _, input := range inputs {
555 command.CopyBefore = append(command.CopyBefore, &sbox_proto.Copy{
556 From: proto.String(input.String()),
557 To: proto.String(r.sboxPathForInputRel(input)),
558 })
559 }
560
Colin Crossce3a51d2021-03-19 16:22:12 -0700561 // If using rsp files copy them and their contents into the sbox directory with
562 // the appropriate path mappings.
563 for _, rspFile := range rspFiles {
Colin Crosse55bd422021-03-23 13:44:30 -0700564 command.RspFiles = append(command.RspFiles, &sbox_proto.RspFile{
Colin Crossce3a51d2021-03-19 16:22:12 -0700565 File: proto.String(rspFile.file.String()),
Colin Crosse55bd422021-03-23 13:44:30 -0700566 // These have to match the logic in sboxPathForInputRel
567 PathMappings: []*sbox_proto.PathMapping{
568 {
569 From: proto.String(r.outDir.String()),
570 To: proto.String(sboxOutSubDir),
571 },
572 {
573 From: proto.String(PathForOutput(r.ctx).String()),
574 To: proto.String(sboxOutSubDir),
575 },
576 },
Colin Crossab020a72021-03-12 17:52:23 -0800577 })
578 }
579
580 command.Chdir = proto.Bool(true)
581 }
582
Colin Crosse16ce362020-11-12 08:29:30 -0800583 // Add copy rules to the manifest to copy each output file from the sbox directory.
Colin Crossba9e4032020-11-24 16:32:22 -0800584 // to the output directory after running the commands.
Spandan Das33e30972023-07-13 21:19:12 +0000585 for _, output := range outputs {
Colin Crossf1a035e2020-11-16 17:32:30 -0800586 rel := Rel(r.ctx, r.outDir.String(), output.String())
Colin Crosse16ce362020-11-12 08:29:30 -0800587 command.CopyAfter = append(command.CopyAfter, &sbox_proto.Copy{
588 From: proto.String(filepath.Join(sboxOutSubDir, rel)),
589 To: proto.String(output.String()),
590 })
591 }
Colin Cross619b9ab2020-11-20 18:44:31 +0000592
Colin Cross5334edd2021-03-11 17:18:21 -0800593 // Outputs that were marked Temporary will not be checked that they are in the output
594 // directory by the loop above, check them here.
595 for path := range r.temporariesSet {
596 Rel(r.ctx, r.outDir.String(), path.String())
597 }
598
Colin Crosse16ce362020-11-12 08:29:30 -0800599 // Add a hash of the list of input files to the manifest so that the textproto file
600 // changes when the list of input files changes and causes the sbox rule that
601 // depends on it to rerun.
602 command.InputHash = proto.String(hashSrcFiles(inputs))
Colin Cross619b9ab2020-11-20 18:44:31 +0000603
Colin Crosse16ce362020-11-12 08:29:30 -0800604 // Verify that the manifest textproto is not inside the sbox output directory, otherwise
605 // it will get deleted when the sbox rule clears its output directory.
Colin Crossf1a035e2020-11-16 17:32:30 -0800606 _, manifestInOutDir := MaybeRel(r.ctx, r.outDir.String(), r.sboxManifestPath.String())
Colin Crosse16ce362020-11-12 08:29:30 -0800607 if manifestInOutDir {
Colin Crossf1a035e2020-11-16 17:32:30 -0800608 ReportPathErrorf(r.ctx, "sbox rule %q manifestPath %q must not be in outputDir %q",
609 name, r.sboxManifestPath.String(), r.outDir.String())
Colin Crosse16ce362020-11-12 08:29:30 -0800610 }
611
612 // Create a rule to write the manifest as a the textproto.
Dan Willemsen4591b642021-05-24 14:24:12 -0700613 pbText, err := prototext.Marshal(&manifest)
614 if err != nil {
615 ReportPathErrorf(r.ctx, "sbox manifest failed to marshal: %q", err)
616 }
617 WriteFileRule(r.ctx, r.sboxManifestPath, string(pbText))
Colin Crosse16ce362020-11-12 08:29:30 -0800618
619 // Generate a new string to use as the command line of the sbox rule. This uses
620 // a RuleBuilderCommand as a convenience method of building the command line, then
621 // converts it to a string to replace commandString.
Colin Crossf1a035e2020-11-16 17:32:30 -0800622 sboxCmd := &RuleBuilderCommand{
623 rule: &RuleBuilder{
624 ctx: r.ctx,
625 },
626 }
Colin Cross9b698b62021-12-22 09:55:32 -0800627 sboxCmd.builtToolWithoutDeps("sbox").
Colin Crosse52c2ac2022-03-28 17:03:35 -0700628 FlagWithArg("--sandbox-path ", shared.TempDirForOutDir(PathForOutput(r.ctx).String())).
629 FlagWithArg("--output-dir ", r.outDir.String()).
630 FlagWithInput("--manifest ", r.sboxManifestPath)
631
632 if r.restat {
633 sboxCmd.Flag("--write-if-changed")
634 }
Colin Crosse16ce362020-11-12 08:29:30 -0800635
636 // Replace the command string, and add the sbox tool and manifest textproto to the
637 // dependencies of the final sbox rule.
Colin Crosscfec40c2019-07-08 17:07:18 -0700638 commandString = sboxCmd.buf.String()
Dan Willemsen633c5022019-04-12 11:11:38 -0700639 tools = append(tools, sboxCmd.tools...)
Colin Crosse16ce362020-11-12 08:29:30 -0800640 inputs = append(inputs, sboxCmd.inputs...)
Colin Crossef972742021-03-12 17:24:45 -0800641
642 if r.rbeParams != nil {
Colin Crosse55bd422021-03-23 13:44:30 -0700643 // RBE needs a list of input files to copy to the remote builder. For inputs already
644 // listed in an rsp file, pass the rsp file directly to rewrapper. For the rest,
645 // create a new rsp file to pass to rewrapper.
646 var remoteRspFiles Paths
647 var remoteInputs Paths
648
649 remoteInputs = append(remoteInputs, inputs...)
650 remoteInputs = append(remoteInputs, tools...)
651
Colin Crossce3a51d2021-03-19 16:22:12 -0700652 for _, rspFile := range rspFiles {
653 remoteInputs = append(remoteInputs, rspFile.file)
654 remoteRspFiles = append(remoteRspFiles, rspFile.file)
Colin Crossef972742021-03-12 17:24:45 -0800655 }
Colin Crosse55bd422021-03-23 13:44:30 -0700656
657 if len(remoteInputs) > 0 {
658 inputsListFile := r.sboxManifestPath.ReplaceExtension(r.ctx, "rbe_inputs.list")
659 writeRspFileRule(r.ctx, inputsListFile, remoteInputs)
660 remoteRspFiles = append(remoteRspFiles, inputsListFile)
661 // Add the new rsp file as an extra input to the rule.
662 inputs = append(inputs, inputsListFile)
663 }
Colin Crossef972742021-03-12 17:24:45 -0800664
665 r.rbeParams.OutputFiles = outputs.Strings()
Colin Crosse55bd422021-03-23 13:44:30 -0700666 r.rbeParams.RSPFiles = remoteRspFiles.Strings()
Colin Crossef972742021-03-12 17:24:45 -0800667 rewrapperCommand := r.rbeParams.NoVarTemplate(r.ctx.Config().RBEWrapper())
668 commandString = rewrapperCommand + " bash -c '" + strings.ReplaceAll(commandString, `'`, `'\''`) + "'"
669 }
Colin Cross3d680512020-11-13 16:23:53 -0800670 } else {
671 // If not using sbox the rule will run the command directly, put the hash of the
672 // list of input files in a comment at the end of the command line to ensure ninja
673 // reruns the rule when the list of input files changes.
674 commandString += " # hash of input list: " + hashSrcFiles(inputs)
Dan Willemsen633c5022019-04-12 11:11:38 -0700675 }
676
Colin Cross1d2cf042019-03-29 15:33:06 -0700677 // Ninja doesn't like multiple outputs when depfiles are enabled, move all but the first output to
Colin Cross70c47412021-03-12 17:48:14 -0800678 // ImplicitOutputs. RuleBuilder doesn't use "$out", so the distinction between Outputs and
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700679 // ImplicitOutputs doesn't matter.
Dan Willemsen633c5022019-04-12 11:11:38 -0700680 output := outputs[0]
681 implicitOutputs := outputs[1:]
Colin Cross1d2cf042019-03-29 15:33:06 -0700682
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700683 var rspFile, rspFileContent string
Colin Crossce3a51d2021-03-19 16:22:12 -0700684 var rspFileInputs Paths
685 if len(rspFiles) > 0 {
686 // The first rsp files uses Ninja's rsp file support for the rule
687 rspFile = rspFiles[0].file.String()
Colin Crosse55bd422021-03-23 13:44:30 -0700688 // Use "$in" for rspFileContent to avoid duplicating the list of files in the dependency
689 // list and in the contents of the rsp file. Inputs to the rule that are not in the
690 // rsp file will be listed in Implicits instead of Inputs so they don't show up in "$in".
691 rspFileContent = "$in"
Colin Crossce3a51d2021-03-19 16:22:12 -0700692 rspFileInputs = append(rspFileInputs, rspFiles[0].paths...)
693
694 for _, rspFile := range rspFiles[1:] {
695 // Any additional rsp files need an extra rule to write the file.
696 writeRspFileRule(r.ctx, rspFile.file, rspFile.paths)
697 // The main rule needs to depend on the inputs listed in the extra rsp file.
698 inputs = append(inputs, rspFile.paths...)
699 // The main rule needs to depend on the extra rsp file.
700 inputs = append(inputs, rspFile.file)
701 }
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700702 }
703
Colin Cross8b8bec32019-11-15 13:18:43 -0800704 var pool blueprint.Pool
Colin Crossf1a035e2020-11-16 17:32:30 -0800705 if r.ctx.Config().UseGoma() && r.remoteable.Goma {
Colin Cross8b8bec32019-11-15 13:18:43 -0800706 // When USE_GOMA=true is set and the rule is supported by goma, allow jobs to run outside the local pool.
Colin Crossf1a035e2020-11-16 17:32:30 -0800707 } else if r.ctx.Config().UseRBE() && r.remoteable.RBE {
Ramy Medhat944839a2020-03-31 22:14:52 -0400708 // When USE_RBE=true is set and the rule is supported by RBE, use the remotePool.
709 pool = remotePool
Colin Cross8b8bec32019-11-15 13:18:43 -0800710 } else if r.highmem {
711 pool = highmemPool
Colin Crossf1a035e2020-11-16 17:32:30 -0800712 } else if r.ctx.Config().UseRemoteBuild() {
Colin Cross8b8bec32019-11-15 13:18:43 -0800713 pool = localPool
714 }
715
Colin Crossf1a035e2020-11-16 17:32:30 -0800716 r.ctx.Build(r.pctx, BuildParams{
717 Rule: r.ctx.Rule(pctx, name, blueprint.RuleParams{
Colin Crossb70a1a92021-03-12 17:51:32 -0800718 Command: proptools.NinjaEscape(commandString),
Colin Cross45029782021-03-16 16:49:52 -0700719 CommandDeps: proptools.NinjaEscapeList(tools.Strings()),
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700720 Restat: r.restat,
Colin Cross45029782021-03-16 16:49:52 -0700721 Rspfile: proptools.NinjaEscape(rspFile),
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700722 RspfileContent: rspFileContent,
Colin Cross8b8bec32019-11-15 13:18:43 -0800723 Pool: pool,
Dan Willemsen633c5022019-04-12 11:11:38 -0700724 }),
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700725 Inputs: rspFileInputs,
Colin Cross3d680512020-11-13 16:23:53 -0800726 Implicits: inputs,
Colin Crossda6401b2021-04-21 11:32:19 -0700727 OrderOnly: r.OrderOnlys(),
Colin Crossae89abe2021-04-21 11:45:23 -0700728 Validations: r.Validations(),
Dan Willemsen633c5022019-04-12 11:11:38 -0700729 Output: output,
730 ImplicitOutputs: implicitOutputs,
Jingwen Chence679d22020-09-23 04:30:02 +0000731 SymlinkOutputs: r.SymlinkOutputs(),
Dan Willemsen633c5022019-04-12 11:11:38 -0700732 Depfile: depFile,
733 Deps: depFormat,
734 Description: desc,
735 })
Colin Crossfeec25b2019-01-30 17:32:39 -0800736}
737
Colin Cross758290d2019-02-01 16:42:32 -0800738// RuleBuilderCommand is a builder for a command in a command line. It can be mutated by its methods to add to the
739// command and track dependencies. The methods mutate the RuleBuilderCommand in place, as well as return the
740// RuleBuilderCommand, so they can be used chained or unchained. All methods that add text implicitly add a single
741// space as a separator from the previous method.
Colin Crossfeec25b2019-01-30 17:32:39 -0800742type RuleBuilderCommand struct {
Colin Crossf1a035e2020-11-16 17:32:30 -0800743 rule *RuleBuilder
744
Jingwen Chence679d22020-09-23 04:30:02 +0000745 buf strings.Builder
746 inputs Paths
747 implicits Paths
748 orderOnlys Paths
Colin Crossae89abe2021-04-21 11:45:23 -0700749 validations Paths
Jingwen Chence679d22020-09-23 04:30:02 +0000750 outputs WritablePaths
751 symlinkOutputs WritablePaths
752 depFiles WritablePaths
753 tools Paths
Colin Crossba9e4032020-11-24 16:32:22 -0800754 packagedTools []PackagingSpec
Colin Crossce3a51d2021-03-19 16:22:12 -0700755 rspFiles []rspFileAndPaths
756}
757
758type rspFileAndPaths struct {
759 file WritablePath
760 paths Paths
Dan Willemsen633c5022019-04-12 11:11:38 -0700761}
762
Paul Duffin3866b892021-10-04 11:24:48 +0100763func checkPathNotNil(path Path) {
764 if path == nil {
765 panic("rule_builder paths cannot be nil")
766 }
767}
768
Dan Willemsen633c5022019-04-12 11:11:38 -0700769func (c *RuleBuilderCommand) addInput(path Path) string {
Paul Duffin3866b892021-10-04 11:24:48 +0100770 checkPathNotNil(path)
Dan Willemsen633c5022019-04-12 11:11:38 -0700771 c.inputs = append(c.inputs, path)
Colin Crossab020a72021-03-12 17:52:23 -0800772 return c.PathForInput(path)
Dan Willemsen633c5022019-04-12 11:11:38 -0700773}
774
Colin Crossab020a72021-03-12 17:52:23 -0800775func (c *RuleBuilderCommand) addImplicit(path Path) {
Paul Duffin3866b892021-10-04 11:24:48 +0100776 checkPathNotNil(path)
Ramy Medhat2f99eec2020-06-13 17:38:27 -0400777 c.implicits = append(c.implicits, path)
Ramy Medhat2f99eec2020-06-13 17:38:27 -0400778}
779
Colin Crossda71eda2020-02-21 16:55:19 -0800780func (c *RuleBuilderCommand) addOrderOnly(path Path) {
Paul Duffin3866b892021-10-04 11:24:48 +0100781 checkPathNotNil(path)
Colin Crossda71eda2020-02-21 16:55:19 -0800782 c.orderOnlys = append(c.orderOnlys, path)
783}
784
Colin Crossab020a72021-03-12 17:52:23 -0800785// PathForInput takes an input path and returns the appropriate path to use on the command line. If
786// sbox was enabled via a call to RuleBuilder.Sbox() and the path was an output path it returns a
787// path with the placeholder prefix used for outputs in sbox. If sbox is not enabled it returns the
788// original path.
789func (c *RuleBuilderCommand) PathForInput(path Path) string {
790 if c.rule.sbox {
791 rel, inSandbox := c.rule._sboxPathForInputRel(path)
792 if inSandbox {
793 rel = filepath.Join(sboxSandboxBaseDir, rel)
794 }
795 return rel
796 }
797 return path.String()
798}
799
800// PathsForInputs takes a list of input paths and returns the appropriate paths to use on the
801// command line. If sbox was enabled via a call to RuleBuilder.Sbox() a path was an output path, it
802// returns the path with the placeholder prefix used for outputs in sbox. If sbox is not enabled it
803// returns the original paths.
804func (c *RuleBuilderCommand) PathsForInputs(paths Paths) []string {
805 ret := make([]string, len(paths))
806 for i, path := range paths {
807 ret[i] = c.PathForInput(path)
808 }
809 return ret
810}
811
Colin Crossf1a035e2020-11-16 17:32:30 -0800812// PathForOutput takes an output path and returns the appropriate path to use on the command
813// line. If sbox was enabled via a call to RuleBuilder.Sbox(), it returns a path with the
814// placeholder prefix used for outputs in sbox. If sbox is not enabled it returns the
815// original path.
816func (c *RuleBuilderCommand) PathForOutput(path WritablePath) string {
817 if c.rule.sbox {
818 // Errors will be handled in RuleBuilder.Build where we have a context to report them
819 rel, _, _ := maybeRelErr(c.rule.outDir.String(), path.String())
820 return filepath.Join(sboxOutDir, rel)
Dan Willemsen633c5022019-04-12 11:11:38 -0700821 }
822 return path.String()
Colin Crossfeec25b2019-01-30 17:32:39 -0800823}
824
Colin Crossba9e4032020-11-24 16:32:22 -0800825func sboxPathForToolRel(ctx BuilderContext, path Path) string {
826 // Errors will be handled in RuleBuilder.Build where we have a context to report them
Colin Cross790ef352021-10-25 19:15:55 -0700827 toolDir := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "", false)
828 relOutSoong, isRelOutSoong, _ := maybeRelErr(toolDir.String(), path.String())
829 if isRelOutSoong {
830 // The tool is in the Soong output directory, it will be copied to __SBOX_OUT_DIR__/tools/out
831 return filepath.Join(sboxToolsSubDir, "out", relOutSoong)
Colin Crossba9e4032020-11-24 16:32:22 -0800832 }
833 // The tool is in the source directory, it will be copied to __SBOX_OUT_DIR__/tools/src
834 return filepath.Join(sboxToolsSubDir, "src", path.String())
835}
836
Colin Crossab020a72021-03-12 17:52:23 -0800837func (r *RuleBuilder) _sboxPathForInputRel(path Path) (rel string, inSandbox bool) {
838 // Errors will be handled in RuleBuilder.Build where we have a context to report them
839 rel, isRelSboxOut, _ := maybeRelErr(r.outDir.String(), path.String())
840 if isRelSboxOut {
841 return filepath.Join(sboxOutSubDir, rel), true
842 }
843 if r.sboxInputs {
844 // When sandboxing inputs all inputs have to be copied into the sandbox. Input files that
845 // are outputs of other rules could be an arbitrary absolute path if OUT_DIR is set, so they
846 // will be copied to relative paths under __SBOX_OUT_DIR__/out.
847 rel, isRelOut, _ := maybeRelErr(PathForOutput(r.ctx).String(), path.String())
848 if isRelOut {
849 return filepath.Join(sboxOutSubDir, rel), true
850 }
851 }
852 return path.String(), false
853}
854
855func (r *RuleBuilder) sboxPathForInputRel(path Path) string {
856 rel, _ := r._sboxPathForInputRel(path)
857 return rel
858}
859
860func (r *RuleBuilder) sboxPathsForInputsRel(paths Paths) []string {
861 ret := make([]string, len(paths))
862 for i, path := range paths {
863 ret[i] = r.sboxPathForInputRel(path)
864 }
865 return ret
866}
867
Colin Crossba9e4032020-11-24 16:32:22 -0800868func sboxPathForPackagedToolRel(spec PackagingSpec) string {
869 return filepath.Join(sboxToolsSubDir, "out", spec.relPathInPackage)
870}
871
Colin Crossd11cf622021-03-23 22:30:35 -0700872// PathForPackagedTool takes a PackageSpec for a tool and returns the corresponding path for the
873// tool after copying it into the sandbox. This can be used on the RuleBuilder command line to
874// reference the tool.
875func (c *RuleBuilderCommand) PathForPackagedTool(spec PackagingSpec) string {
876 if !c.rule.sboxTools {
877 panic("PathForPackagedTool() requires SandboxTools()")
878 }
879
880 return filepath.Join(sboxSandboxBaseDir, sboxPathForPackagedToolRel(spec))
881}
882
Colin Crossba9e4032020-11-24 16:32:22 -0800883// PathForTool takes a path to a tool, which may be an output file or a source file, and returns
884// the corresponding path for the tool in the sbox sandbox if sbox is enabled, or the original path
885// if it is not. This can be used on the RuleBuilder command line to reference the tool.
886func (c *RuleBuilderCommand) PathForTool(path Path) string {
887 if c.rule.sbox && c.rule.sboxTools {
888 return filepath.Join(sboxSandboxBaseDir, sboxPathForToolRel(c.rule.ctx, path))
889 }
890 return path.String()
891}
892
Colin Crossd11cf622021-03-23 22:30:35 -0700893// PathsForTools takes a list of paths to tools, which may be output files or source files, and
894// returns the corresponding paths for the tools in the sbox sandbox if sbox is enabled, or the
895// original paths if it is not. This can be used on the RuleBuilder command line to reference the tool.
896func (c *RuleBuilderCommand) PathsForTools(paths Paths) []string {
897 if c.rule.sbox && c.rule.sboxTools {
898 var ret []string
899 for _, path := range paths {
900 ret = append(ret, filepath.Join(sboxSandboxBaseDir, sboxPathForToolRel(c.rule.ctx, path)))
901 }
902 return ret
903 }
904 return paths.Strings()
905}
906
Colin Crossba9e4032020-11-24 16:32:22 -0800907// PackagedTool adds the specified tool path to the command line. It can only be used with tool
908// sandboxing enabled by SandboxTools(), and will copy the tool into the sandbox.
909func (c *RuleBuilderCommand) PackagedTool(spec PackagingSpec) *RuleBuilderCommand {
910 if !c.rule.sboxTools {
911 panic("PackagedTool() requires SandboxTools()")
912 }
913
914 c.packagedTools = append(c.packagedTools, spec)
915 c.Text(sboxPathForPackagedToolRel(spec))
916 return c
917}
918
919// ImplicitPackagedTool copies the specified tool into the sandbox without modifying the command
920// line. It can only be used with tool sandboxing enabled by SandboxTools().
921func (c *RuleBuilderCommand) ImplicitPackagedTool(spec PackagingSpec) *RuleBuilderCommand {
922 if !c.rule.sboxTools {
923 panic("ImplicitPackagedTool() requires SandboxTools()")
924 }
925
926 c.packagedTools = append(c.packagedTools, spec)
927 return c
928}
929
930// ImplicitPackagedTools copies the specified tools into the sandbox without modifying the command
931// line. It can only be used with tool sandboxing enabled by SandboxTools().
932func (c *RuleBuilderCommand) ImplicitPackagedTools(specs []PackagingSpec) *RuleBuilderCommand {
933 if !c.rule.sboxTools {
934 panic("ImplicitPackagedTools() requires SandboxTools()")
935 }
936
937 c.packagedTools = append(c.packagedTools, specs...)
938 return c
939}
940
Colin Cross758290d2019-02-01 16:42:32 -0800941// Text adds the specified raw text to the command line. The text should not contain input or output paths or the
942// rule will not have them listed in its dependencies or outputs.
Colin Crossfeec25b2019-01-30 17:32:39 -0800943func (c *RuleBuilderCommand) Text(text string) *RuleBuilderCommand {
Colin Crosscfec40c2019-07-08 17:07:18 -0700944 if c.buf.Len() > 0 {
945 c.buf.WriteByte(' ')
Colin Crossfeec25b2019-01-30 17:32:39 -0800946 }
Colin Crosscfec40c2019-07-08 17:07:18 -0700947 c.buf.WriteString(text)
Colin Crossfeec25b2019-01-30 17:32:39 -0800948 return c
949}
950
Colin Cross758290d2019-02-01 16:42:32 -0800951// Textf adds the specified formatted text to the command line. The text should not contain input or output paths or
952// the rule will not have them listed in its dependencies or outputs.
Colin Crossfeec25b2019-01-30 17:32:39 -0800953func (c *RuleBuilderCommand) Textf(format string, a ...interface{}) *RuleBuilderCommand {
954 return c.Text(fmt.Sprintf(format, a...))
955}
956
Colin Cross758290d2019-02-01 16:42:32 -0800957// Flag adds the specified raw text to the command line. The text should not contain input or output paths or the
958// rule will not have them listed in its dependencies or outputs.
Colin Crossfeec25b2019-01-30 17:32:39 -0800959func (c *RuleBuilderCommand) Flag(flag string) *RuleBuilderCommand {
960 return c.Text(flag)
961}
962
Colin Crossab054432019-07-15 16:13:59 -0700963// OptionalFlag adds the specified raw text to the command line if it is not nil. The text should not contain input or
964// output paths or the rule will not have them listed in its dependencies or outputs.
965func (c *RuleBuilderCommand) OptionalFlag(flag *string) *RuleBuilderCommand {
966 if flag != nil {
967 c.Text(*flag)
968 }
969
970 return c
971}
972
Colin Cross92b7d582019-03-29 15:32:51 -0700973// Flags adds the specified raw text to the command line. The text should not contain input or output paths or the
974// rule will not have them listed in its dependencies or outputs.
975func (c *RuleBuilderCommand) Flags(flags []string) *RuleBuilderCommand {
976 for _, flag := range flags {
977 c.Text(flag)
978 }
979 return c
980}
981
Colin Cross758290d2019-02-01 16:42:32 -0800982// FlagWithArg adds the specified flag and argument text to the command line, with no separator between them. The flag
983// and argument should not contain input or output paths or the rule will not have them listed in its dependencies or
984// outputs.
Colin Crossfeec25b2019-01-30 17:32:39 -0800985func (c *RuleBuilderCommand) FlagWithArg(flag, arg string) *RuleBuilderCommand {
986 return c.Text(flag + arg)
987}
988
Colin Crossc7ed0042019-02-11 14:11:09 -0800989// FlagForEachArg adds the specified flag joined with each argument to the command line. The result is identical to
990// calling FlagWithArg for argument.
991func (c *RuleBuilderCommand) FlagForEachArg(flag string, args []string) *RuleBuilderCommand {
992 for _, arg := range args {
993 c.FlagWithArg(flag, arg)
994 }
995 return c
996}
997
Roland Levillain2da5d9a2019-02-27 16:56:41 +0000998// 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 -0800999// and no separator between the flag and arguments. The flag and arguments should not contain input or output paths or
1000// the rule will not have them listed in its dependencies or outputs.
Colin Crossfeec25b2019-01-30 17:32:39 -08001001func (c *RuleBuilderCommand) FlagWithList(flag string, list []string, sep string) *RuleBuilderCommand {
1002 return c.Text(flag + strings.Join(list, sep))
1003}
1004
Colin Cross758290d2019-02-01 16:42:32 -08001005// Tool adds the specified tool path to the command line. The path will be also added to the dependencies returned by
1006// RuleBuilder.Tools.
Colin Cross69f59a32019-02-15 10:39:37 -08001007func (c *RuleBuilderCommand) Tool(path Path) *RuleBuilderCommand {
Paul Duffin3866b892021-10-04 11:24:48 +01001008 checkPathNotNil(path)
Colin Crossfeec25b2019-01-30 17:32:39 -08001009 c.tools = append(c.tools, path)
Colin Crossba9e4032020-11-24 16:32:22 -08001010 return c.Text(c.PathForTool(path))
1011}
1012
1013// Tool adds the specified tool path to the dependencies returned by RuleBuilder.Tools.
1014func (c *RuleBuilderCommand) ImplicitTool(path Path) *RuleBuilderCommand {
Paul Duffin3866b892021-10-04 11:24:48 +01001015 checkPathNotNil(path)
Colin Crossba9e4032020-11-24 16:32:22 -08001016 c.tools = append(c.tools, path)
1017 return c
1018}
1019
1020// Tool adds the specified tool path to the dependencies returned by RuleBuilder.Tools.
1021func (c *RuleBuilderCommand) ImplicitTools(paths Paths) *RuleBuilderCommand {
Paul Duffin3866b892021-10-04 11:24:48 +01001022 for _, path := range paths {
1023 c.ImplicitTool(path)
1024 }
Colin Crossba9e4032020-11-24 16:32:22 -08001025 return c
Colin Crossfeec25b2019-01-30 17:32:39 -08001026}
1027
Colin Crossee94d6a2019-07-08 17:08:34 -07001028// BuiltTool adds the specified tool path that was built using a host Soong module to the command line. The path will
1029// be also added to the dependencies returned by RuleBuilder.Tools.
1030//
1031// It is equivalent to:
Colin Crossd079e0b2022-08-16 10:27:33 -07001032//
1033// cmd.Tool(ctx.Config().HostToolPath(ctx, tool))
Colin Crossf1a035e2020-11-16 17:32:30 -08001034func (c *RuleBuilderCommand) BuiltTool(tool string) *RuleBuilderCommand {
Colin Cross9b698b62021-12-22 09:55:32 -08001035 if c.rule.ctx.Config().UseHostMusl() {
1036 // If the host is using musl, assume that the tool was built against musl libc and include
1037 // libc_musl.so in the sandbox.
1038 // TODO(ccross): if we supported adding new dependencies during GenerateAndroidBuildActions
1039 // this could be a dependency + TransitivePackagingSpecs.
1040 c.ImplicitTool(c.rule.ctx.Config().HostJNIToolPath(c.rule.ctx, "libc_musl"))
1041 }
1042 return c.builtToolWithoutDeps(tool)
1043}
1044
1045// builtToolWithoutDeps is similar to BuiltTool, but doesn't add any dependencies. It is used
1046// internally by RuleBuilder for helper tools that are known to be compiled statically.
1047func (c *RuleBuilderCommand) builtToolWithoutDeps(tool string) *RuleBuilderCommand {
Colin Crossf1a035e2020-11-16 17:32:30 -08001048 return c.Tool(c.rule.ctx.Config().HostToolPath(c.rule.ctx, tool))
Colin Crossee94d6a2019-07-08 17:08:34 -07001049}
1050
1051// PrebuiltBuildTool adds the specified tool path from prebuils/build-tools. The path will be also added to the
1052// dependencies returned by RuleBuilder.Tools.
1053//
1054// It is equivalent to:
Colin Crossd079e0b2022-08-16 10:27:33 -07001055//
1056// cmd.Tool(ctx.Config().PrebuiltBuildTool(ctx, tool))
Colin Crossee94d6a2019-07-08 17:08:34 -07001057func (c *RuleBuilderCommand) PrebuiltBuildTool(ctx PathContext, tool string) *RuleBuilderCommand {
1058 return c.Tool(ctx.Config().PrebuiltBuildTool(ctx, tool))
1059}
1060
Colin Cross758290d2019-02-01 16:42:32 -08001061// Input adds the specified input path to the command line. The path will also be added to the dependencies returned by
1062// RuleBuilder.Inputs.
Colin Cross69f59a32019-02-15 10:39:37 -08001063func (c *RuleBuilderCommand) Input(path Path) *RuleBuilderCommand {
Dan Willemsen633c5022019-04-12 11:11:38 -07001064 return c.Text(c.addInput(path))
Colin Crossfeec25b2019-01-30 17:32:39 -08001065}
1066
Colin Cross758290d2019-02-01 16:42:32 -08001067// Inputs adds the specified input paths to the command line, separated by spaces. The paths will also be added to the
1068// dependencies returned by RuleBuilder.Inputs.
Colin Cross69f59a32019-02-15 10:39:37 -08001069func (c *RuleBuilderCommand) Inputs(paths Paths) *RuleBuilderCommand {
Colin Cross758290d2019-02-01 16:42:32 -08001070 for _, path := range paths {
1071 c.Input(path)
1072 }
1073 return c
1074}
1075
1076// Implicit adds the specified input path to the dependencies returned by RuleBuilder.Inputs without modifying the
1077// command line.
Colin Cross69f59a32019-02-15 10:39:37 -08001078func (c *RuleBuilderCommand) Implicit(path Path) *RuleBuilderCommand {
Ramy Medhat2f99eec2020-06-13 17:38:27 -04001079 c.addImplicit(path)
Colin Crossfeec25b2019-01-30 17:32:39 -08001080 return c
1081}
1082
Colin Cross758290d2019-02-01 16:42:32 -08001083// Implicits adds the specified input paths to the dependencies returned by RuleBuilder.Inputs without modifying the
1084// command line.
Colin Cross69f59a32019-02-15 10:39:37 -08001085func (c *RuleBuilderCommand) Implicits(paths Paths) *RuleBuilderCommand {
Dan Willemsen633c5022019-04-12 11:11:38 -07001086 for _, path := range paths {
Ramy Medhat2f99eec2020-06-13 17:38:27 -04001087 c.addImplicit(path)
Dan Willemsen633c5022019-04-12 11:11:38 -07001088 }
Colin Crossfeec25b2019-01-30 17:32:39 -08001089 return c
1090}
1091
Ramy Medhat2f99eec2020-06-13 17:38:27 -04001092// GetImplicits returns the command's implicit inputs.
1093func (c *RuleBuilderCommand) GetImplicits() Paths {
1094 return c.implicits
1095}
1096
Colin Crossda71eda2020-02-21 16:55:19 -08001097// OrderOnly adds the specified input path to the dependencies returned by RuleBuilder.OrderOnlys
1098// without modifying the command line.
1099func (c *RuleBuilderCommand) OrderOnly(path Path) *RuleBuilderCommand {
1100 c.addOrderOnly(path)
1101 return c
1102}
1103
1104// OrderOnlys adds the specified input paths to the dependencies returned by RuleBuilder.OrderOnlys
1105// without modifying the command line.
1106func (c *RuleBuilderCommand) OrderOnlys(paths Paths) *RuleBuilderCommand {
1107 for _, path := range paths {
1108 c.addOrderOnly(path)
1109 }
1110 return c
1111}
1112
Colin Crossae89abe2021-04-21 11:45:23 -07001113// Validation adds the specified input path to the validation dependencies by
1114// RuleBuilder.Validations without modifying the command line.
1115func (c *RuleBuilderCommand) Validation(path Path) *RuleBuilderCommand {
Paul Duffin3866b892021-10-04 11:24:48 +01001116 checkPathNotNil(path)
Colin Crossae89abe2021-04-21 11:45:23 -07001117 c.validations = append(c.validations, path)
1118 return c
1119}
1120
1121// Validations adds the specified input paths to the validation dependencies by
1122// RuleBuilder.Validations without modifying the command line.
1123func (c *RuleBuilderCommand) Validations(paths Paths) *RuleBuilderCommand {
Paul Duffin3866b892021-10-04 11:24:48 +01001124 for _, path := range paths {
1125 c.Validation(path)
1126 }
Colin Crossae89abe2021-04-21 11:45:23 -07001127 return c
1128}
1129
Colin Cross758290d2019-02-01 16:42:32 -08001130// Output adds the specified output path to the command line. The path will also be added to the outputs returned by
1131// RuleBuilder.Outputs.
Colin Cross69f59a32019-02-15 10:39:37 -08001132func (c *RuleBuilderCommand) Output(path WritablePath) *RuleBuilderCommand {
Paul Duffin3866b892021-10-04 11:24:48 +01001133 checkPathNotNil(path)
Colin Crossfeec25b2019-01-30 17:32:39 -08001134 c.outputs = append(c.outputs, path)
Colin Crossf1a035e2020-11-16 17:32:30 -08001135 return c.Text(c.PathForOutput(path))
Colin Crossfeec25b2019-01-30 17:32:39 -08001136}
1137
Colin Cross758290d2019-02-01 16:42:32 -08001138// Outputs adds the specified output paths to the command line, separated by spaces. The paths will also be added to
1139// the outputs returned by RuleBuilder.Outputs.
Colin Cross69f59a32019-02-15 10:39:37 -08001140func (c *RuleBuilderCommand) Outputs(paths WritablePaths) *RuleBuilderCommand {
Colin Cross758290d2019-02-01 16:42:32 -08001141 for _, path := range paths {
1142 c.Output(path)
1143 }
1144 return c
1145}
1146
Dan Willemsen1945a4b2019-06-04 17:10:41 -07001147// OutputDir adds the output directory to the command line. This is only available when used with RuleBuilder.Sbox,
1148// and will be the temporary output directory managed by sbox, not the final one.
1149func (c *RuleBuilderCommand) OutputDir() *RuleBuilderCommand {
Colin Crossf1a035e2020-11-16 17:32:30 -08001150 if !c.rule.sbox {
Dan Willemsen1945a4b2019-06-04 17:10:41 -07001151 panic("OutputDir only valid with Sbox")
1152 }
Colin Cross3d680512020-11-13 16:23:53 -08001153 return c.Text(sboxOutDir)
Dan Willemsen1945a4b2019-06-04 17:10:41 -07001154}
1155
Colin Cross1d2cf042019-03-29 15:33:06 -07001156// DepFile adds the specified depfile path to the paths returned by RuleBuilder.DepFiles and adds it to the command
1157// line, and causes RuleBuilder.Build file to set the depfile flag for ninja. If multiple depfiles are added to
1158// commands in a single RuleBuilder then RuleBuilder.Build will add an extra command to merge the depfiles together.
1159func (c *RuleBuilderCommand) DepFile(path WritablePath) *RuleBuilderCommand {
Paul Duffin3866b892021-10-04 11:24:48 +01001160 checkPathNotNil(path)
Colin Cross1d2cf042019-03-29 15:33:06 -07001161 c.depFiles = append(c.depFiles, path)
Colin Crossf1a035e2020-11-16 17:32:30 -08001162 return c.Text(c.PathForOutput(path))
Colin Cross1d2cf042019-03-29 15:33:06 -07001163}
1164
Colin Cross758290d2019-02-01 16:42:32 -08001165// ImplicitOutput adds the specified output path to the dependencies returned by RuleBuilder.Outputs without modifying
1166// the command line.
Colin Cross69f59a32019-02-15 10:39:37 -08001167func (c *RuleBuilderCommand) ImplicitOutput(path WritablePath) *RuleBuilderCommand {
Colin Crossfeec25b2019-01-30 17:32:39 -08001168 c.outputs = append(c.outputs, path)
1169 return c
1170}
1171
Colin Cross758290d2019-02-01 16:42:32 -08001172// ImplicitOutputs adds the specified output paths to the dependencies returned by RuleBuilder.Outputs without modifying
1173// the command line.
Colin Cross69f59a32019-02-15 10:39:37 -08001174func (c *RuleBuilderCommand) ImplicitOutputs(paths WritablePaths) *RuleBuilderCommand {
Colin Cross758290d2019-02-01 16:42:32 -08001175 c.outputs = append(c.outputs, paths...)
1176 return c
1177}
1178
Jingwen Chence679d22020-09-23 04:30:02 +00001179// ImplicitSymlinkOutput declares the specified path as an implicit output that
1180// will be a symlink instead of a regular file. Does not modify the command
1181// line.
1182func (c *RuleBuilderCommand) ImplicitSymlinkOutput(path WritablePath) *RuleBuilderCommand {
Paul Duffin3866b892021-10-04 11:24:48 +01001183 checkPathNotNil(path)
Jingwen Chence679d22020-09-23 04:30:02 +00001184 c.symlinkOutputs = append(c.symlinkOutputs, path)
1185 return c.ImplicitOutput(path)
1186}
1187
1188// ImplicitSymlinkOutputs declares the specified paths as implicit outputs that
1189// will be a symlinks instead of regular files. Does not modify the command
1190// line.
1191func (c *RuleBuilderCommand) ImplicitSymlinkOutputs(paths WritablePaths) *RuleBuilderCommand {
1192 for _, path := range paths {
1193 c.ImplicitSymlinkOutput(path)
1194 }
1195 return c
1196}
1197
1198// SymlinkOutput declares the specified path as an output that will be a symlink
1199// instead of a regular file. Modifies the command line.
1200func (c *RuleBuilderCommand) SymlinkOutput(path WritablePath) *RuleBuilderCommand {
Paul Duffin3866b892021-10-04 11:24:48 +01001201 checkPathNotNil(path)
Jingwen Chence679d22020-09-23 04:30:02 +00001202 c.symlinkOutputs = append(c.symlinkOutputs, path)
1203 return c.Output(path)
1204}
1205
1206// SymlinkOutputsl declares the specified paths as outputs that will be symlinks
1207// instead of regular files. Modifies the command line.
1208func (c *RuleBuilderCommand) SymlinkOutputs(paths WritablePaths) *RuleBuilderCommand {
1209 for _, path := range paths {
1210 c.SymlinkOutput(path)
1211 }
1212 return c
1213}
1214
Colin Cross1d2cf042019-03-29 15:33:06 -07001215// ImplicitDepFile adds the specified depfile path to the paths returned by RuleBuilder.DepFiles without modifying
1216// the command line, and causes RuleBuilder.Build file to set the depfile flag for ninja. If multiple depfiles
1217// are added to commands in a single RuleBuilder then RuleBuilder.Build will add an extra command to merge the
1218// depfiles together.
1219func (c *RuleBuilderCommand) ImplicitDepFile(path WritablePath) *RuleBuilderCommand {
1220 c.depFiles = append(c.depFiles, path)
1221 return c
1222}
1223
Colin Cross758290d2019-02-01 16:42:32 -08001224// FlagWithInput adds the specified flag and input path to the command line, with no separator between them. The path
1225// will also be added to the dependencies returned by RuleBuilder.Inputs.
Colin Cross69f59a32019-02-15 10:39:37 -08001226func (c *RuleBuilderCommand) FlagWithInput(flag string, path Path) *RuleBuilderCommand {
Dan Willemsen633c5022019-04-12 11:11:38 -07001227 return c.Text(flag + c.addInput(path))
Colin Crossfeec25b2019-01-30 17:32:39 -08001228}
1229
Colin Cross758290d2019-02-01 16:42:32 -08001230// FlagWithInputList adds the specified flag and input paths to the command line, with the inputs joined by sep
1231// and no separator between the flag and inputs. The input paths will also be added to the dependencies returned by
1232// RuleBuilder.Inputs.
Colin Cross69f59a32019-02-15 10:39:37 -08001233func (c *RuleBuilderCommand) FlagWithInputList(flag string, paths Paths, sep string) *RuleBuilderCommand {
Dan Willemsen633c5022019-04-12 11:11:38 -07001234 strs := make([]string, len(paths))
1235 for i, path := range paths {
1236 strs[i] = c.addInput(path)
1237 }
1238 return c.FlagWithList(flag, strs, sep)
Colin Crossfeec25b2019-01-30 17:32:39 -08001239}
1240
Colin Cross758290d2019-02-01 16:42:32 -08001241// FlagForEachInput adds the specified flag joined with each input path to the command line. The input paths will also
1242// be added to the dependencies returned by RuleBuilder.Inputs. The result is identical to calling FlagWithInput for
1243// each input path.
Colin Cross69f59a32019-02-15 10:39:37 -08001244func (c *RuleBuilderCommand) FlagForEachInput(flag string, paths Paths) *RuleBuilderCommand {
Colin Cross758290d2019-02-01 16:42:32 -08001245 for _, path := range paths {
1246 c.FlagWithInput(flag, path)
1247 }
1248 return c
1249}
1250
1251// FlagWithOutput adds the specified flag and output path to the command line, with no separator between them. The path
1252// will also be added to the outputs returned by RuleBuilder.Outputs.
Colin Cross69f59a32019-02-15 10:39:37 -08001253func (c *RuleBuilderCommand) FlagWithOutput(flag string, path WritablePath) *RuleBuilderCommand {
Colin Crossfeec25b2019-01-30 17:32:39 -08001254 c.outputs = append(c.outputs, path)
Colin Crossf1a035e2020-11-16 17:32:30 -08001255 return c.Text(flag + c.PathForOutput(path))
Colin Crossfeec25b2019-01-30 17:32:39 -08001256}
1257
Colin Cross1d2cf042019-03-29 15:33:06 -07001258// FlagWithDepFile adds the specified flag and depfile path to the command line, with no separator between them. The path
1259// will also be added to the outputs returned by RuleBuilder.Outputs.
1260func (c *RuleBuilderCommand) FlagWithDepFile(flag string, path WritablePath) *RuleBuilderCommand {
1261 c.depFiles = append(c.depFiles, path)
Colin Crossf1a035e2020-11-16 17:32:30 -08001262 return c.Text(flag + c.PathForOutput(path))
Colin Cross1d2cf042019-03-29 15:33:06 -07001263}
1264
Colin Crossce3a51d2021-03-19 16:22:12 -07001265// FlagWithRspFileInputList adds the specified flag and path to an rspfile to the command line, with
1266// no separator between them. The paths will be written to the rspfile. If sbox is enabled, the
1267// rspfile must be outside the sbox directory. The first use of FlagWithRspFileInputList in any
1268// RuleBuilderCommand of a RuleBuilder will use Ninja's rsp file support for the rule, additional
1269// uses will result in an auxiliary rules to write the rspFile contents.
Colin Cross70c47412021-03-12 17:48:14 -08001270func (c *RuleBuilderCommand) FlagWithRspFileInputList(flag string, rspFile WritablePath, paths Paths) *RuleBuilderCommand {
Colin Cross0cb0d7b2019-07-11 10:59:15 -07001271 // Use an empty slice if paths is nil, the non-nil slice is used as an indicator that the rsp file must be
1272 // generated.
1273 if paths == nil {
1274 paths = Paths{}
1275 }
1276
Colin Crossce3a51d2021-03-19 16:22:12 -07001277 c.rspFiles = append(c.rspFiles, rspFileAndPaths{rspFile, paths})
Colin Cross0cb0d7b2019-07-11 10:59:15 -07001278
Colin Cross70c47412021-03-12 17:48:14 -08001279 if c.rule.sbox {
1280 if _, isRel, _ := maybeRelErr(c.rule.outDir.String(), rspFile.String()); isRel {
1281 panic(fmt.Errorf("FlagWithRspFileInputList rspfile %q must not be inside out dir %q",
1282 rspFile.String(), c.rule.outDir.String()))
1283 }
1284 }
1285
Colin Crossab020a72021-03-12 17:52:23 -08001286 c.FlagWithArg(flag, c.PathForInput(rspFile))
Colin Cross0cb0d7b2019-07-11 10:59:15 -07001287 return c
1288}
1289
Colin Cross758290d2019-02-01 16:42:32 -08001290// String returns the command line.
1291func (c *RuleBuilderCommand) String() string {
Colin Crosscfec40c2019-07-08 17:07:18 -07001292 return c.buf.String()
Colin Cross758290d2019-02-01 16:42:32 -08001293}
Colin Cross1d2cf042019-03-29 15:33:06 -07001294
Colin Crosse16ce362020-11-12 08:29:30 -08001295// RuleBuilderSboxProtoForTests takes the BuildParams for the manifest passed to RuleBuilder.Sbox()
1296// and returns sbox testproto generated by the RuleBuilder.
1297func RuleBuilderSboxProtoForTests(t *testing.T, params TestingBuildParams) *sbox_proto.Manifest {
1298 t.Helper()
1299 content := ContentFromFileRuleForTests(t, params)
1300 manifest := sbox_proto.Manifest{}
Dan Willemsen4591b642021-05-24 14:24:12 -07001301 err := prototext.Unmarshal([]byte(content), &manifest)
Colin Crosse16ce362020-11-12 08:29:30 -08001302 if err != nil {
1303 t.Fatalf("failed to unmarshal manifest: %s", err.Error())
1304 }
1305 return &manifest
1306}
1307
Colin Cross1d2cf042019-03-29 15:33:06 -07001308func ninjaNameEscape(s string) string {
1309 b := []byte(s)
1310 escaped := false
1311 for i, c := range b {
1312 valid := (c >= 'a' && c <= 'z') ||
1313 (c >= 'A' && c <= 'Z') ||
1314 (c >= '0' && c <= '9') ||
1315 (c == '_') ||
1316 (c == '-') ||
1317 (c == '.')
1318 if !valid {
1319 b[i] = '_'
1320 escaped = true
1321 }
1322 }
1323 if escaped {
1324 s = string(b)
1325 }
1326 return s
1327}
Colin Cross3d680512020-11-13 16:23:53 -08001328
1329// hashSrcFiles returns a hash of the list of source files. It is used to ensure the command line
1330// or the sbox textproto manifest change even if the input files are not listed on the command line.
1331func hashSrcFiles(srcFiles Paths) string {
1332 h := sha256.New()
1333 srcFileList := strings.Join(srcFiles.Strings(), "\n")
1334 h.Write([]byte(srcFileList))
1335 return fmt.Sprintf("%x", h.Sum(nil))
1336}
Colin Crossf1a035e2020-11-16 17:32:30 -08001337
1338// BuilderContextForTesting returns a BuilderContext for the given config that can be used for tests
1339// that need to call methods that take a BuilderContext.
1340func BuilderContextForTesting(config Config) BuilderContext {
1341 pathCtx := PathContextForTesting(config)
1342 return builderContextForTests{
1343 PathContext: pathCtx,
1344 }
1345}
1346
1347type builderContextForTests struct {
1348 PathContext
1349}
1350
1351func (builderContextForTests) Rule(PackageContext, string, blueprint.RuleParams, ...string) blueprint.Rule {
1352 return nil
1353}
1354func (builderContextForTests) Build(PackageContext, BuildParams) {}
Colin Crossef972742021-03-12 17:24:45 -08001355
Colin Crosse55bd422021-03-23 13:44:30 -07001356func writeRspFileRule(ctx BuilderContext, rspFile WritablePath, paths Paths) {
1357 buf := &strings.Builder{}
1358 err := response.WriteRspFile(buf, paths.Strings())
1359 if err != nil {
1360 // There should never be I/O errors writing to a bytes.Buffer.
1361 panic(err)
Colin Crossef972742021-03-12 17:24:45 -08001362 }
Colin Crosse55bd422021-03-23 13:44:30 -07001363 WriteFileRule(ctx, rspFile, buf.String())
Colin Crossef972742021-03-12 17:24:45 -08001364}