blob: 18eed2dae26f67d03d602780091fa6613b00813a [file] [log] [blame]
Colin Cross3f40fa42015-01-30 17:27:36 -08001// Copyright 2015 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Colin Cross635c3b02016-05-18 15:37:25 -070015package android
Colin Cross3f40fa42015-01-30 17:27:36 -080016
17import (
Hans Månssond3f2bd72020-11-27 12:37:28 +010018 "fmt"
Colin Crosscf371cc2020-11-13 11:48:42 -080019 "strings"
20 "testing"
21
Colin Cross70b40592015-03-23 12:57:34 -070022 "github.com/google/blueprint"
Colin Crossc20dc852020-11-10 12:27:45 -080023 "github.com/google/blueprint/bootstrap"
Colin Crosscf371cc2020-11-13 11:48:42 -080024 "github.com/google/blueprint/proptools"
Colin Cross3f40fa42015-01-30 17:27:36 -080025)
26
27var (
Sam Delmerico46d08b42022-11-15 15:51:04 -050028 pctx = NewPackageContext("android/soong/android")
29 exportedVars = NewExportedVariables(pctx)
Colin Cross3f40fa42015-01-30 17:27:36 -080030
31 cpPreserveSymlinks = pctx.VariableConfigMethod("cpPreserveSymlinks",
32 Config.CpPreserveSymlinksFlags)
33
Colin Cross3f40fa42015-01-30 17:27:36 -080034 // A phony rule that is not the built-in Ninja phony rule. The built-in
35 // phony rule has special behavior that is sometimes not desired. See the
36 // Ninja docs for more details.
Colin Cross9d45bb72016-08-29 16:14:13 -070037 Phony = pctx.AndroidStaticRule("Phony",
Colin Cross3f40fa42015-01-30 17:27:36 -080038 blueprint.RuleParams{
39 Command: "# phony $out",
40 Description: "phony $out",
41 })
42
43 // GeneratedFile is a rule for indicating that a given file was generated
44 // while running soong. This allows the file to be cleaned up if it ever
45 // stops being generated by soong.
Colin Cross9d45bb72016-08-29 16:14:13 -070046 GeneratedFile = pctx.AndroidStaticRule("GeneratedFile",
Colin Cross3f40fa42015-01-30 17:27:36 -080047 blueprint.RuleParams{
48 Command: "# generated $out",
49 Description: "generated $out",
50 Generator: true,
51 })
52
53 // A copy rule.
Colin Cross9d45bb72016-08-29 16:14:13 -070054 Cp = pctx.AndroidStaticRule("Cp",
Colin Cross3f40fa42015-01-30 17:27:36 -080055 blueprint.RuleParams{
Colin Cross50ed1f92021-11-12 17:41:02 -080056 Command: "rm -f $out && cp $cpPreserveSymlinks $cpFlags $in $out$extraCmds",
Colin Cross3f40fa42015-01-30 17:27:36 -080057 Description: "cp $out",
58 },
Colin Cross50ed1f92021-11-12 17:41:02 -080059 "cpFlags", "extraCmds")
Colin Cross3f40fa42015-01-30 17:27:36 -080060
Sam Delmerico4ed95e22023-02-03 18:12:15 -050061 // A copy rule that doesn't preserve symlinks.
62 CpNoPreserveSymlink = pctx.AndroidStaticRule("CpNoPreserveSymlink",
63 blueprint.RuleParams{
64 Command: "rm -f $out && cp $cpFlags $in $out$extraCmds",
65 Description: "cp $out",
66 },
67 "cpFlags", "extraCmds")
68
Colin Cross00d93b12021-03-04 10:00:09 -080069 // A copy rule that only updates the output if it changed.
70 CpIfChanged = pctx.AndroidStaticRule("CpIfChanged",
71 blueprint.RuleParams{
72 Command: "if ! cmp -s $in $out; then cp $in $out; fi",
73 Description: "cp if changed $out",
74 Restat: true,
75 },
76 "cpFlags")
77
Colin Cross5c517922017-08-31 12:29:17 -070078 CpExecutable = pctx.AndroidStaticRule("CpExecutable",
79 blueprint.RuleParams{
Chih-Hung Hsieh1048a732022-08-10 20:51:37 -070080 Command: "rm -f $out && cp $cpFlags $in $out && chmod +x $out$extraCmds",
Colin Cross5c517922017-08-31 12:29:17 -070081 Description: "cp $out",
82 },
Colin Cross50ed1f92021-11-12 17:41:02 -080083 "cpFlags", "extraCmds")
Colin Cross5c517922017-08-31 12:29:17 -070084
Dan Albert5d723ab2016-07-18 22:29:52 -070085 // A timestamp touch rule.
Colin Cross9d45bb72016-08-29 16:14:13 -070086 Touch = pctx.AndroidStaticRule("Touch",
Dan Albert5d723ab2016-07-18 22:29:52 -070087 blueprint.RuleParams{
88 Command: "touch $out",
89 Description: "touch $out",
90 })
91
Colin Cross3f40fa42015-01-30 17:27:36 -080092 // A symlink rule.
Colin Cross9d45bb72016-08-29 16:14:13 -070093 Symlink = pctx.AndroidStaticRule("Symlink",
Colin Cross3f40fa42015-01-30 17:27:36 -080094 blueprint.RuleParams{
Jingwen Chence679d22020-09-23 04:30:02 +000095 Command: "rm -f $out && ln -f -s $fromPath $out",
96 Description: "symlink $out",
97 SymlinkOutputs: []string{"$out"},
Colin Cross3f40fa42015-01-30 17:27:36 -080098 },
99 "fromPath")
Colin Cross6ff51382015-12-17 16:39:19 -0800100
Colin Cross9d45bb72016-08-29 16:14:13 -0700101 ErrorRule = pctx.AndroidStaticRule("Error",
Colin Cross6ff51382015-12-17 16:39:19 -0800102 blueprint.RuleParams{
103 Command: `echo "$error" && false`,
104 Description: "error building $out",
105 },
106 "error")
Colin Cross9d45bb72016-08-29 16:14:13 -0700107
Dan Albertc6345fb2016-10-20 01:36:11 -0700108 Cat = pctx.AndroidStaticRule("Cat",
109 blueprint.RuleParams{
110 Command: "cat $in > $out",
111 Description: "concatenate licenses $out",
112 })
113
Nan Zhang27005112017-05-12 14:02:13 -0700114 // ubuntu 14.04 offcially use dash for /bin/sh, and its builtin echo command
115 // doesn't support -e option. Therefore we force to use /bin/bash when writing out
116 // content to file.
Colin Crosscf371cc2020-11-13 11:48:42 -0800117 writeFile = pctx.AndroidStaticRule("writeFile",
Dan Albert30c9d6e2017-03-28 14:54:55 -0700118 blueprint.RuleParams{
Hans Månssond3f2bd72020-11-27 12:37:28 +0100119 Command: `/bin/bash -c 'echo -e -n "$$0" > $out' $content`,
Dan Albert30c9d6e2017-03-28 14:54:55 -0700120 Description: "writing file $out",
121 },
122 "content")
123
Colin Cross9d45bb72016-08-29 16:14:13 -0700124 // Used only when USE_GOMA=true is set, to restrict non-goma jobs to the local parallelism value
125 localPool = blueprint.NewBuiltinPool("local_pool")
Colin Cross8b8bec32019-11-15 13:18:43 -0800126
Ramy Medhat944839a2020-03-31 22:14:52 -0400127 // Used only by RuleBuilder to identify remoteable rules. Does not actually get created in ninja.
128 remotePool = blueprint.NewBuiltinPool("remote_pool")
129
Colin Cross8b8bec32019-11-15 13:18:43 -0800130 // Used for processes that need significant RAM to ensure there are not too many running in parallel.
131 highmemPool = blueprint.NewBuiltinPool("highmem_pool")
Colin Cross3f40fa42015-01-30 17:27:36 -0800132)
Dan Willemsen24f2f8d2015-07-15 14:34:02 -0700133
134func init() {
135 pctx.Import("github.com/google/blueprint/bootstrap")
Colin Cross77cdcfd2021-03-12 11:28:25 -0800136
137 pctx.VariableFunc("RBEWrapper", func(ctx PackageVarContext) string {
138 return ctx.Config().RBEWrapper()
139 })
Sam Delmerico46d08b42022-11-15 15:51:04 -0500140
141 exportedVars.ExportStringList("NeverAllowNotInIncludeDir", neverallowNotInIncludeDir)
142 exportedVars.ExportStringList("NeverAllowNoUseIncludeDir", neverallowNoUseIncludeDir)
143}
144
145func BazelCcToolchainVars(config Config) string {
146 return BazelToolchainVars(config, exportedVars)
Dan Willemsen24f2f8d2015-07-15 14:34:02 -0700147}
Colin Crosscf371cc2020-11-13 11:48:42 -0800148
149var (
150 // echoEscaper escapes a string such that passing it to "echo -e" will produce the input value.
151 echoEscaper = strings.NewReplacer(
152 `\`, `\\`, // First escape existing backslashes so they aren't interpreted by `echo -e`.
153 "\n", `\n`, // Then replace newlines with \n
154 )
155
156 // echoEscaper reverses echoEscaper.
157 echoUnescaper = strings.NewReplacer(
158 `\n`, "\n",
159 `\\`, `\`,
160 )
161
162 // shellUnescaper reverses the replacer in proptools.ShellEscape
163 shellUnescaper = strings.NewReplacer(`'\''`, `'`)
164)
165
Hans Månssond3f2bd72020-11-27 12:37:28 +0100166func buildWriteFileRule(ctx BuilderContext, outputFile WritablePath, content string) {
Colin Crosscf371cc2020-11-13 11:48:42 -0800167 content = echoEscaper.Replace(content)
Colin Cross1c217fd2021-03-12 17:24:18 -0800168 content = proptools.NinjaEscape(proptools.ShellEscapeIncludingSpaces(content))
Colin Crosscf371cc2020-11-13 11:48:42 -0800169 if content == "" {
170 content = "''"
171 }
172 ctx.Build(pctx, BuildParams{
173 Rule: writeFile,
174 Output: outputFile,
175 Description: "write " + outputFile.Base(),
176 Args: map[string]string{
177 "content": content,
178 },
179 })
180}
181
Hans Månssond3f2bd72020-11-27 12:37:28 +0100182// WriteFileRule creates a ninja rule to write contents to a file. The contents will be escaped
183// so that the file contains exactly the contents passed to the function, plus a trailing newline.
184func WriteFileRule(ctx BuilderContext, outputFile WritablePath, content string) {
Cole Fausta7347492022-12-16 10:56:24 -0800185 WriteFileRuleVerbatim(ctx, outputFile, content+"\n")
186}
187
188// WriteFileRuleVerbatim creates a ninja rule to write contents to a file. The contents will be
189// escaped so that the file contains exactly the contents passed to the function.
190func WriteFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string) {
Hans Månssond3f2bd72020-11-27 12:37:28 +0100191 // This is MAX_ARG_STRLEN subtracted with some safety to account for shell escapes
192 const SHARD_SIZE = 131072 - 10000
193
Hans Månssond3f2bd72020-11-27 12:37:28 +0100194 if len(content) > SHARD_SIZE {
195 var chunks WritablePaths
196 for i, c := range ShardString(content, SHARD_SIZE) {
197 tempPath := outputFile.ReplaceExtension(ctx, fmt.Sprintf("%s.%d", outputFile.Ext(), i))
198 buildWriteFileRule(ctx, tempPath, c)
199 chunks = append(chunks, tempPath)
200 }
201 ctx.Build(pctx, BuildParams{
202 Rule: Cat,
203 Inputs: chunks.Paths(),
204 Output: outputFile,
205 Description: "Merging to " + outputFile.Base(),
206 })
207 return
208 }
209 buildWriteFileRule(ctx, outputFile, content)
210}
211
Rob Seymour925aa092021-08-10 20:42:03 +0000212func CatFileRule(ctx BuilderContext, paths Paths, outputFile WritablePath) {
213 ctx.Build(pctx, BuildParams{
214 Rule: Cat,
215 Inputs: paths,
216 Output: outputFile,
217 Description: "combine files to " + outputFile.Base(),
218 })
219}
220
Colin Crosscf371cc2020-11-13 11:48:42 -0800221// shellUnescape reverses proptools.ShellEscape
222func shellUnescape(s string) string {
223 // Remove leading and trailing quotes if present
224 if len(s) >= 2 && s[0] == '\'' {
225 s = s[1 : len(s)-1]
226 }
227 s = shellUnescaper.Replace(s)
228 return s
229}
230
231// ContentFromFileRuleForTests returns the content that was passed to a WriteFileRule for use
232// in tests.
233func ContentFromFileRuleForTests(t *testing.T, params TestingBuildParams) string {
234 t.Helper()
235 if g, w := params.Rule, writeFile; g != w {
236 t.Errorf("expected params.Rule to be %q, was %q", w, g)
237 return ""
238 }
239
240 content := params.Args["content"]
241 content = shellUnescape(content)
242 content = echoUnescaper.Replace(content)
243
244 return content
245}
Colin Crossc20dc852020-11-10 12:27:45 -0800246
247// GlobToListFileRule creates a rule that writes a list of files matching a pattern to a file.
248func GlobToListFileRule(ctx ModuleContext, pattern string, excludes []string, file WritablePath) {
249 bootstrap.GlobFile(ctx.blueprintModuleContext(), pattern, excludes, file.String())
250}