defs.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. // Copyright 2015 Google Inc. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package android
  15. import (
  16. "fmt"
  17. "strings"
  18. "testing"
  19. "github.com/google/blueprint"
  20. "github.com/google/blueprint/bootstrap"
  21. "github.com/google/blueprint/proptools"
  22. )
  23. var (
  24. pctx = NewPackageContext("android/soong/android")
  25. exportedVars = NewExportedVariables(pctx)
  26. cpPreserveSymlinks = pctx.VariableConfigMethod("cpPreserveSymlinks",
  27. Config.CpPreserveSymlinksFlags)
  28. // A phony rule that is not the built-in Ninja phony rule. The built-in
  29. // phony rule has special behavior that is sometimes not desired. See the
  30. // Ninja docs for more details.
  31. Phony = pctx.AndroidStaticRule("Phony",
  32. blueprint.RuleParams{
  33. Command: "# phony $out",
  34. Description: "phony $out",
  35. })
  36. // GeneratedFile is a rule for indicating that a given file was generated
  37. // while running soong. This allows the file to be cleaned up if it ever
  38. // stops being generated by soong.
  39. GeneratedFile = pctx.AndroidStaticRule("GeneratedFile",
  40. blueprint.RuleParams{
  41. Command: "# generated $out",
  42. Description: "generated $out",
  43. Generator: true,
  44. })
  45. // A copy rule.
  46. Cp = pctx.AndroidStaticRule("Cp",
  47. blueprint.RuleParams{
  48. Command: "rm -f $out && cp $cpPreserveSymlinks $cpFlags $in $out$extraCmds",
  49. Description: "cp $out",
  50. },
  51. "cpFlags", "extraCmds")
  52. // A copy rule that doesn't preserve symlinks.
  53. CpNoPreserveSymlink = pctx.AndroidStaticRule("CpNoPreserveSymlink",
  54. blueprint.RuleParams{
  55. Command: "rm -f $out && cp $cpFlags $in $out$extraCmds",
  56. Description: "cp $out",
  57. },
  58. "cpFlags", "extraCmds")
  59. // A copy rule that only updates the output if it changed.
  60. CpIfChanged = pctx.AndroidStaticRule("CpIfChanged",
  61. blueprint.RuleParams{
  62. Command: "if ! cmp -s $in $out; then cp $in $out; fi",
  63. Description: "cp if changed $out",
  64. Restat: true,
  65. },
  66. "cpFlags")
  67. CpExecutable = pctx.AndroidStaticRule("CpExecutable",
  68. blueprint.RuleParams{
  69. Command: "rm -f $out && cp $cpFlags $in $out && chmod +x $out$extraCmds",
  70. Description: "cp $out",
  71. },
  72. "cpFlags", "extraCmds")
  73. // A timestamp touch rule.
  74. Touch = pctx.AndroidStaticRule("Touch",
  75. blueprint.RuleParams{
  76. Command: "touch $out",
  77. Description: "touch $out",
  78. })
  79. // A symlink rule.
  80. Symlink = pctx.AndroidStaticRule("Symlink",
  81. blueprint.RuleParams{
  82. Command: "rm -f $out && ln -f -s $fromPath $out",
  83. Description: "symlink $out",
  84. SymlinkOutputs: []string{"$out"},
  85. },
  86. "fromPath")
  87. ErrorRule = pctx.AndroidStaticRule("Error",
  88. blueprint.RuleParams{
  89. Command: `echo "$error" && false`,
  90. Description: "error building $out",
  91. },
  92. "error")
  93. Cat = pctx.AndroidStaticRule("Cat",
  94. blueprint.RuleParams{
  95. Command: "cat $in > $out",
  96. Description: "concatenate licenses $out",
  97. })
  98. // ubuntu 14.04 offcially use dash for /bin/sh, and its builtin echo command
  99. // doesn't support -e option. Therefore we force to use /bin/bash when writing out
  100. // content to file.
  101. writeFile = pctx.AndroidStaticRule("writeFile",
  102. blueprint.RuleParams{
  103. Command: `/bin/bash -c 'echo -e -n "$$0" > $out' $content`,
  104. Description: "writing file $out",
  105. },
  106. "content")
  107. // Used only when USE_GOMA=true is set, to restrict non-goma jobs to the local parallelism value
  108. localPool = blueprint.NewBuiltinPool("local_pool")
  109. // Used only by RuleBuilder to identify remoteable rules. Does not actually get created in ninja.
  110. remotePool = blueprint.NewBuiltinPool("remote_pool")
  111. // Used for processes that need significant RAM to ensure there are not too many running in parallel.
  112. highmemPool = blueprint.NewBuiltinPool("highmem_pool")
  113. )
  114. func init() {
  115. pctx.Import("github.com/google/blueprint/bootstrap")
  116. pctx.VariableFunc("RBEWrapper", func(ctx PackageVarContext) string {
  117. return ctx.Config().RBEWrapper()
  118. })
  119. exportedVars.ExportStringList("NeverAllowNotInIncludeDir", neverallowNotInIncludeDir)
  120. exportedVars.ExportStringList("NeverAllowNoUseIncludeDir", neverallowNoUseIncludeDir)
  121. }
  122. func BazelCcToolchainVars(config Config) string {
  123. return BazelToolchainVars(config, exportedVars)
  124. }
  125. var (
  126. // echoEscaper escapes a string such that passing it to "echo -e" will produce the input value.
  127. echoEscaper = strings.NewReplacer(
  128. `\`, `\\`, // First escape existing backslashes so they aren't interpreted by `echo -e`.
  129. "\n", `\n`, // Then replace newlines with \n
  130. )
  131. // echoEscaper reverses echoEscaper.
  132. echoUnescaper = strings.NewReplacer(
  133. `\n`, "\n",
  134. `\\`, `\`,
  135. )
  136. // shellUnescaper reverses the replacer in proptools.ShellEscape
  137. shellUnescaper = strings.NewReplacer(`'\''`, `'`)
  138. )
  139. func buildWriteFileRule(ctx BuilderContext, outputFile WritablePath, content string) {
  140. content = echoEscaper.Replace(content)
  141. content = proptools.NinjaEscape(proptools.ShellEscapeIncludingSpaces(content))
  142. if content == "" {
  143. content = "''"
  144. }
  145. ctx.Build(pctx, BuildParams{
  146. Rule: writeFile,
  147. Output: outputFile,
  148. Description: "write " + outputFile.Base(),
  149. Args: map[string]string{
  150. "content": content,
  151. },
  152. })
  153. }
  154. // WriteFileRule creates a ninja rule to write contents to a file. The contents will be escaped
  155. // so that the file contains exactly the contents passed to the function, plus a trailing newline.
  156. func WriteFileRule(ctx BuilderContext, outputFile WritablePath, content string) {
  157. WriteFileRuleVerbatim(ctx, outputFile, content+"\n")
  158. }
  159. // WriteFileRuleVerbatim creates a ninja rule to write contents to a file. The contents will be
  160. // escaped so that the file contains exactly the contents passed to the function.
  161. func WriteFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string) {
  162. // This is MAX_ARG_STRLEN subtracted with some safety to account for shell escapes
  163. const SHARD_SIZE = 131072 - 10000
  164. if len(content) > SHARD_SIZE {
  165. var chunks WritablePaths
  166. for i, c := range ShardString(content, SHARD_SIZE) {
  167. tempPath := outputFile.ReplaceExtension(ctx, fmt.Sprintf("%s.%d", outputFile.Ext(), i))
  168. buildWriteFileRule(ctx, tempPath, c)
  169. chunks = append(chunks, tempPath)
  170. }
  171. ctx.Build(pctx, BuildParams{
  172. Rule: Cat,
  173. Inputs: chunks.Paths(),
  174. Output: outputFile,
  175. Description: "Merging to " + outputFile.Base(),
  176. })
  177. return
  178. }
  179. buildWriteFileRule(ctx, outputFile, content)
  180. }
  181. func CatFileRule(ctx BuilderContext, paths Paths, outputFile WritablePath) {
  182. ctx.Build(pctx, BuildParams{
  183. Rule: Cat,
  184. Inputs: paths,
  185. Output: outputFile,
  186. Description: "combine files to " + outputFile.Base(),
  187. })
  188. }
  189. // shellUnescape reverses proptools.ShellEscape
  190. func shellUnescape(s string) string {
  191. // Remove leading and trailing quotes if present
  192. if len(s) >= 2 && s[0] == '\'' {
  193. s = s[1 : len(s)-1]
  194. }
  195. s = shellUnescaper.Replace(s)
  196. return s
  197. }
  198. // ContentFromFileRuleForTests returns the content that was passed to a WriteFileRule for use
  199. // in tests.
  200. func ContentFromFileRuleForTests(t *testing.T, params TestingBuildParams) string {
  201. t.Helper()
  202. if g, w := params.Rule, writeFile; g != w {
  203. t.Errorf("expected params.Rule to be %q, was %q", w, g)
  204. return ""
  205. }
  206. content := params.Args["content"]
  207. content = shellUnescape(content)
  208. content = echoUnescaper.Replace(content)
  209. return content
  210. }
  211. // GlobToListFileRule creates a rule that writes a list of files matching a pattern to a file.
  212. func GlobToListFileRule(ctx ModuleContext, pattern string, excludes []string, file WritablePath) {
  213. bootstrap.GlobFile(ctx.blueprintModuleContext(), pattern, excludes, file.String())
  214. }