builder.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  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 cc
  15. // This file generates the final rules for compiling all C/C++. All properties related to
  16. // compiling should have been translated into builderFlags or another argument to the Transform*
  17. // functions.
  18. import (
  19. "android/soong/common"
  20. "fmt"
  21. "runtime"
  22. "strconv"
  23. "path/filepath"
  24. "strings"
  25. "github.com/google/blueprint"
  26. "github.com/google/blueprint/pathtools"
  27. )
  28. const (
  29. objectExtension = ".o"
  30. sharedLibraryExtension = ".so"
  31. staticLibraryExtension = ".a"
  32. )
  33. var (
  34. pctx = blueprint.NewPackageContext("android/soong/cc")
  35. cc = pctx.StaticRule("cc",
  36. blueprint.RuleParams{
  37. Depfile: "${out}.d",
  38. Deps: blueprint.DepsGCC,
  39. Command: "$ccCmd -c $cFlags -MD -MF ${out}.d -o $out $in",
  40. Description: "cc $out",
  41. },
  42. "ccCmd", "cFlags")
  43. ld = pctx.StaticRule("ld",
  44. blueprint.RuleParams{
  45. Command: "$ldCmd ${ldDirFlags} ${crtBegin} @${out}.rsp " +
  46. "${libFlags} ${crtEnd} -o ${out} ${ldFlags}",
  47. Description: "ld $out",
  48. Rspfile: "${out}.rsp",
  49. RspfileContent: "${in}",
  50. },
  51. "ldCmd", "ldDirFlags", "crtBegin", "libFlags", "crtEnd", "ldFlags")
  52. partialLd = pctx.StaticRule("partialLd",
  53. blueprint.RuleParams{
  54. Command: "$ldCmd -r ${in} -o ${out}",
  55. Description: "partialLd $out",
  56. },
  57. "ldCmd")
  58. ar = pctx.StaticRule("ar",
  59. blueprint.RuleParams{
  60. Command: "rm -f ${out} && $arCmd $arFlags $out @${out}.rsp",
  61. Description: "ar $out",
  62. Rspfile: "${out}.rsp",
  63. RspfileContent: "${in}",
  64. },
  65. "arCmd", "arFlags")
  66. darwinAr = pctx.StaticRule("darwinAr",
  67. blueprint.RuleParams{
  68. Command: "rm -f ${out} && $arCmd $arFlags $out $in",
  69. Description: "ar $out",
  70. },
  71. "arCmd", "arFlags")
  72. darwinAppendAr = pctx.StaticRule("darwinAppendAr",
  73. blueprint.RuleParams{
  74. Command: "cp -f ${inAr} ${out}.tmp && $arCmd $arFlags ${out}.tmp $in && mv ${out}.tmp ${out}",
  75. Description: "ar $out",
  76. },
  77. "arCmd", "arFlags", "inAr")
  78. prefixSymbols = pctx.StaticRule("prefixSymbols",
  79. blueprint.RuleParams{
  80. Command: "$objcopyCmd --prefix-symbols=${prefix} ${in} ${out}",
  81. Description: "prefixSymbols $out",
  82. },
  83. "objcopyCmd", "prefix")
  84. copyGccLibPath = pctx.StaticVariable("copyGccLibPath", "${SrcDir}/build/soong/copygcclib.sh")
  85. copyGccLib = pctx.StaticRule("copyGccLib",
  86. blueprint.RuleParams{
  87. Depfile: "${out}.d",
  88. Deps: blueprint.DepsGCC,
  89. Command: "$copyGccLibPath $out $ccCmd $cFlags -print-file-name=${libName}",
  90. Description: "copy gcc $out",
  91. },
  92. "ccCmd", "cFlags", "libName")
  93. )
  94. type builderFlags struct {
  95. globalFlags string
  96. asFlags string
  97. cFlags string
  98. conlyFlags string
  99. cppFlags string
  100. ldFlags string
  101. yaccFlags string
  102. nocrt bool
  103. toolchain Toolchain
  104. clang bool
  105. }
  106. // Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files
  107. func TransformSourceToObj(ctx common.AndroidModuleContext, subdir string, srcFiles []string,
  108. flags builderFlags, deps []string) (objFiles []string) {
  109. srcRoot := ctx.AConfig().SrcDir()
  110. intermediatesRoot := ctx.AConfig().IntermediatesDir()
  111. objFiles = make([]string, len(srcFiles))
  112. objDir := common.ModuleObjDir(ctx)
  113. if subdir != "" {
  114. objDir = filepath.Join(objDir, subdir)
  115. }
  116. cflags := flags.globalFlags + " " + flags.cFlags + " " + flags.conlyFlags
  117. cppflags := flags.globalFlags + " " + flags.cFlags + " " + flags.cppFlags
  118. asflags := flags.globalFlags + " " + flags.asFlags
  119. for i, srcFile := range srcFiles {
  120. var objFile string
  121. if strings.HasPrefix(srcFile, intermediatesRoot) {
  122. objFile = strings.TrimPrefix(srcFile, intermediatesRoot)
  123. objFile = filepath.Join(objDir, "gen", objFile)
  124. } else if strings.HasPrefix(srcFile, srcRoot) {
  125. srcFile, _ = filepath.Rel(srcRoot, srcFile)
  126. objFile = filepath.Join(objDir, srcFile)
  127. } else if srcRoot == "." && srcFile[0] != '/' {
  128. objFile = filepath.Join(objDir, srcFile)
  129. } else {
  130. ctx.ModuleErrorf("source file %q is not in source directory %q", srcFile, srcRoot)
  131. continue
  132. }
  133. objFile = pathtools.ReplaceExtension(objFile, "o")
  134. objFiles[i] = objFile
  135. var moduleCflags string
  136. var ccCmd string
  137. switch filepath.Ext(srcFile) {
  138. case ".S", ".s":
  139. ccCmd = "gcc"
  140. moduleCflags = asflags
  141. case ".c":
  142. ccCmd = "gcc"
  143. moduleCflags = cflags
  144. case ".cpp", ".cc":
  145. ccCmd = "g++"
  146. moduleCflags = cppflags
  147. default:
  148. ctx.ModuleErrorf("File %s has unknown extension", srcFile)
  149. continue
  150. }
  151. if flags.clang {
  152. switch ccCmd {
  153. case "gcc":
  154. ccCmd = "clang"
  155. case "g++":
  156. ccCmd = "clang++"
  157. default:
  158. panic("unrecoginzied ccCmd")
  159. }
  160. ccCmd = "${clangPath}" + ccCmd
  161. } else {
  162. ccCmd = gccCmd(flags.toolchain, ccCmd)
  163. }
  164. objDeps := append([]string{ccCmd}, deps...)
  165. ctx.Build(pctx, blueprint.BuildParams{
  166. Rule: cc,
  167. Outputs: []string{objFile},
  168. Inputs: []string{srcFile},
  169. Implicits: objDeps,
  170. Args: map[string]string{
  171. "cFlags": moduleCflags,
  172. "ccCmd": ccCmd,
  173. },
  174. })
  175. }
  176. return objFiles
  177. }
  178. // Generate a rule for compiling multiple .o files to a static library (.a)
  179. func TransformObjToStaticLib(ctx common.AndroidModuleContext, objFiles []string,
  180. flags builderFlags, outputFile string) {
  181. arCmd := gccCmd(flags.toolchain, "ar")
  182. arFlags := "crsPD"
  183. ctx.Build(pctx, blueprint.BuildParams{
  184. Rule: ar,
  185. Outputs: []string{outputFile},
  186. Inputs: objFiles,
  187. Implicits: []string{arCmd},
  188. Args: map[string]string{
  189. "arFlags": arFlags,
  190. "arCmd": arCmd,
  191. },
  192. })
  193. }
  194. // Generate a rule for compiling multiple .o files to a static library (.a) on
  195. // darwin. The darwin ar tool doesn't support @file for list files, and has a
  196. // very small command line length limit, so we have to split the ar into multiple
  197. // steps, each appending to the previous one.
  198. func TransformDarwinObjToStaticLib(ctx common.AndroidModuleContext, objFiles []string,
  199. flags builderFlags, outputFile string) {
  200. arCmd := "ar"
  201. arFlags := "cqs"
  202. // ARG_MAX on darwin is 262144, use half that to be safe
  203. objFilesLists, err := splitListForSize(objFiles, 131072)
  204. if err != nil {
  205. ctx.ModuleErrorf("%s", err.Error())
  206. }
  207. var in, out string
  208. for i, l := range objFilesLists {
  209. in = out
  210. out = outputFile
  211. if i != len(objFilesLists)-1 {
  212. out += "." + strconv.Itoa(i)
  213. }
  214. if in == "" {
  215. ctx.Build(pctx, blueprint.BuildParams{
  216. Rule: darwinAr,
  217. Outputs: []string{out},
  218. Inputs: l,
  219. Args: map[string]string{
  220. "arFlags": arFlags,
  221. "arCmd": arCmd,
  222. },
  223. })
  224. } else {
  225. ctx.Build(pctx, blueprint.BuildParams{
  226. Rule: darwinAppendAr,
  227. Outputs: []string{out},
  228. Inputs: l,
  229. Implicits: []string{in},
  230. Args: map[string]string{
  231. "arFlags": arFlags,
  232. "arCmd": arCmd,
  233. "inAr": in,
  234. },
  235. })
  236. }
  237. }
  238. }
  239. // Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries,
  240. // and shared libraires, to a shared library (.so) or dynamic executable
  241. func TransformObjToDynamicBinary(ctx common.AndroidModuleContext,
  242. objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps []string,
  243. crtBegin, crtEnd string, groupLate bool, flags builderFlags, outputFile string) {
  244. var ldCmd string
  245. if flags.clang {
  246. ldCmd = "${clangPath}clang++"
  247. } else {
  248. ldCmd = gccCmd(flags.toolchain, "g++")
  249. }
  250. var ldDirs []string
  251. var libFlagsList []string
  252. if len(wholeStaticLibs) > 0 {
  253. if ctx.Host() && runtime.GOOS == "darwin" {
  254. libFlagsList = append(libFlagsList, common.JoinWithPrefix(wholeStaticLibs, "-force_load "))
  255. } else {
  256. libFlagsList = append(libFlagsList, "-Wl,--whole-archive ")
  257. libFlagsList = append(libFlagsList, wholeStaticLibs...)
  258. libFlagsList = append(libFlagsList, "-Wl,--no-whole-archive ")
  259. }
  260. }
  261. libFlagsList = append(libFlagsList, staticLibs...)
  262. if groupLate && len(lateStaticLibs) > 0 {
  263. libFlagsList = append(libFlagsList, "-Wl,--start-group")
  264. }
  265. libFlagsList = append(libFlagsList, lateStaticLibs...)
  266. if groupLate && len(lateStaticLibs) > 0 {
  267. libFlagsList = append(libFlagsList, "-Wl,--end-group")
  268. }
  269. for _, lib := range sharedLibs {
  270. dir, file := filepath.Split(lib)
  271. if !strings.HasPrefix(file, "lib") {
  272. panic("shared library " + lib + " does not start with lib")
  273. }
  274. if !strings.HasSuffix(file, sharedLibraryExtension) {
  275. panic("shared library " + lib + " does not end with " + sharedLibraryExtension)
  276. }
  277. libFlagsList = append(libFlagsList,
  278. "-l"+strings.TrimSuffix(strings.TrimPrefix(file, "lib"), sharedLibraryExtension))
  279. ldDirs = append(ldDirs, dir)
  280. }
  281. deps = append(deps, ldCmd)
  282. deps = append(deps, sharedLibs...)
  283. deps = append(deps, staticLibs...)
  284. deps = append(deps, lateStaticLibs...)
  285. deps = append(deps, wholeStaticLibs...)
  286. if crtBegin != "" {
  287. deps = append(deps, crtBegin, crtEnd)
  288. }
  289. ctx.Build(pctx, blueprint.BuildParams{
  290. Rule: ld,
  291. Outputs: []string{outputFile},
  292. Inputs: objFiles,
  293. Implicits: deps,
  294. Args: map[string]string{
  295. "ldCmd": ldCmd,
  296. "ldDirFlags": ldDirsToFlags(ldDirs),
  297. "crtBegin": crtBegin,
  298. "libFlags": strings.Join(libFlagsList, " "),
  299. "ldFlags": flags.ldFlags,
  300. "crtEnd": crtEnd,
  301. },
  302. })
  303. }
  304. // Generate a rule for compiling multiple .o files to a .o using ld partial linking
  305. func TransformObjsToObj(ctx common.AndroidModuleContext, objFiles []string,
  306. flags builderFlags, outputFile string) {
  307. ldCmd := gccCmd(flags.toolchain, "ld")
  308. deps := []string{ldCmd}
  309. ctx.Build(pctx, blueprint.BuildParams{
  310. Rule: partialLd,
  311. Outputs: []string{outputFile},
  312. Inputs: objFiles,
  313. Implicits: deps,
  314. Args: map[string]string{
  315. "ldCmd": ldCmd,
  316. },
  317. })
  318. }
  319. // Generate a rule for runing objcopy --prefix-symbols on a binary
  320. func TransformBinaryPrefixSymbols(ctx common.AndroidModuleContext, prefix string, inputFile string,
  321. flags builderFlags, outputFile string) {
  322. objcopyCmd := gccCmd(flags.toolchain, "objcopy")
  323. ctx.Build(pctx, blueprint.BuildParams{
  324. Rule: prefixSymbols,
  325. Outputs: []string{outputFile},
  326. Inputs: []string{inputFile},
  327. Implicits: []string{objcopyCmd},
  328. Args: map[string]string{
  329. "objcopyCmd": objcopyCmd,
  330. "prefix": prefix,
  331. },
  332. })
  333. }
  334. func CopyGccLib(ctx common.AndroidModuleContext, libName string,
  335. flags builderFlags, outputFile string) {
  336. ctx.Build(pctx, blueprint.BuildParams{
  337. Rule: copyGccLib,
  338. Outputs: []string{outputFile},
  339. Implicits: []string{
  340. "$copyGccLibPath",
  341. gccCmd(flags.toolchain, "gcc"),
  342. },
  343. Args: map[string]string{
  344. "ccCmd": gccCmd(flags.toolchain, "gcc"),
  345. "cFlags": flags.globalFlags,
  346. "libName": libName,
  347. },
  348. })
  349. }
  350. func gccCmd(toolchain Toolchain, cmd string) string {
  351. return filepath.Join(toolchain.GccRoot(), "bin", toolchain.GccTriple()+"-"+cmd)
  352. }
  353. func splitListForSize(list []string, limit int) (lists [][]string, err error) {
  354. var i int
  355. start := 0
  356. bytes := 0
  357. for i = range list {
  358. l := len(list[i])
  359. if l > limit {
  360. return nil, fmt.Errorf("list element greater than size limit (%d)", limit)
  361. }
  362. if bytes+l > limit {
  363. lists = append(lists, list[start:i])
  364. start = i
  365. bytes = 0
  366. }
  367. bytes += l + 1 // count a space between each list element
  368. }
  369. lists = append(lists, list[start:])
  370. totalLen := 0
  371. for _, l := range lists {
  372. totalLen += len(l)
  373. }
  374. if totalLen != len(list) {
  375. panic(fmt.Errorf("Failed breaking up list, %d != %d", len(list), totalLen))
  376. }
  377. return lists, nil
  378. }