blob: f21708232f57ce11d2a3047e4bf649a8df8584ab [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
15package cc
16
17// This file generates the final rules for compiling all C/C++. All properties related to
18// compiling should have been translated into builderFlags or another argument to the Transform*
19// functions.
20
21import (
22 "android/soong/common"
Colin Cross0af4b842015-04-30 16:36:18 -070023 "fmt"
24 "runtime"
25 "strconv"
Colin Cross3f40fa42015-01-30 17:27:36 -080026
Colin Cross3f40fa42015-01-30 17:27:36 -080027 "path/filepath"
28 "strings"
Colin Crossed4cf0b2015-03-26 14:43:45 -070029
30 "github.com/google/blueprint"
31 "github.com/google/blueprint/pathtools"
Colin Cross3f40fa42015-01-30 17:27:36 -080032)
33
34const (
Dan Albertc3144b12015-04-28 18:17:56 -070035 objectExtension = ".o"
Colin Cross3f40fa42015-01-30 17:27:36 -080036 sharedLibraryExtension = ".so"
37 staticLibraryExtension = ".a"
38)
39
40var (
41 pctx = blueprint.NewPackageContext("android/soong/cc")
42
43 cc = pctx.StaticRule("cc",
44 blueprint.RuleParams{
45 Depfile: "${out}.d",
46 Deps: blueprint.DepsGCC,
Dan Willemsene6540452015-10-20 15:21:33 -070047 Command: "$relPwd $ccCmd -c $cFlags -MD -MF ${out}.d -o $out $in",
Colin Cross3f40fa42015-01-30 17:27:36 -080048 Description: "cc $out",
49 },
Dan Willemsene6540452015-10-20 15:21:33 -070050 "relPwd", "ccCmd", "cFlags")
Colin Cross3f40fa42015-01-30 17:27:36 -080051
52 ld = pctx.StaticRule("ld",
53 blueprint.RuleParams{
Colin Cross7d21c442015-03-30 17:47:53 -070054 Command: "$ldCmd ${ldDirFlags} ${crtBegin} @${out}.rsp " +
Colin Cross28344522015-04-22 13:07:53 -070055 "${libFlags} ${crtEnd} -o ${out} ${ldFlags}",
Colin Cross7d21c442015-03-30 17:47:53 -070056 Description: "ld $out",
57 Rspfile: "${out}.rsp",
58 RspfileContent: "${in}",
Colin Cross3f40fa42015-01-30 17:27:36 -080059 },
Colin Cross28344522015-04-22 13:07:53 -070060 "ldCmd", "ldDirFlags", "crtBegin", "libFlags", "crtEnd", "ldFlags")
Colin Cross3f40fa42015-01-30 17:27:36 -080061
62 partialLd = pctx.StaticRule("partialLd",
63 blueprint.RuleParams{
64 Command: "$ldCmd -r ${in} -o ${out}",
65 Description: "partialLd $out",
66 },
67 "ldCmd")
68
69 ar = pctx.StaticRule("ar",
70 blueprint.RuleParams{
Colin Cross7d21c442015-03-30 17:47:53 -070071 Command: "rm -f ${out} && $arCmd $arFlags $out @${out}.rsp",
72 Description: "ar $out",
73 Rspfile: "${out}.rsp",
74 RspfileContent: "${in}",
Colin Cross3f40fa42015-01-30 17:27:36 -080075 },
76 "arCmd", "arFlags")
77
Colin Cross0af4b842015-04-30 16:36:18 -070078 darwinAr = pctx.StaticRule("darwinAr",
79 blueprint.RuleParams{
80 Command: "rm -f ${out} && $arCmd $arFlags $out $in",
81 Description: "ar $out",
82 },
83 "arCmd", "arFlags")
84
85 darwinAppendAr = pctx.StaticRule("darwinAppendAr",
86 blueprint.RuleParams{
87 Command: "cp -f ${inAr} ${out}.tmp && $arCmd $arFlags ${out}.tmp $in && mv ${out}.tmp ${out}",
88 Description: "ar $out",
89 },
90 "arCmd", "arFlags", "inAr")
91
Colin Crossbfae8852015-03-26 14:44:11 -070092 prefixSymbols = pctx.StaticRule("prefixSymbols",
93 blueprint.RuleParams{
94 Command: "$objcopyCmd --prefix-symbols=${prefix} ${in} ${out}",
95 Description: "prefixSymbols $out",
96 },
97 "objcopyCmd", "prefix")
98
Colin Cross3f40fa42015-01-30 17:27:36 -080099 copyGccLibPath = pctx.StaticVariable("copyGccLibPath", "${SrcDir}/build/soong/copygcclib.sh")
100
101 copyGccLib = pctx.StaticRule("copyGccLib",
102 blueprint.RuleParams{
103 Depfile: "${out}.d",
104 Deps: blueprint.DepsGCC,
105 Command: "$copyGccLibPath $out $ccCmd $cFlags -print-file-name=${libName}",
106 Description: "copy gcc $out",
107 },
108 "ccCmd", "cFlags", "libName")
109)
110
111type builderFlags struct {
112 globalFlags string
113 asFlags string
114 cFlags string
115 conlyFlags string
116 cppFlags string
117 ldFlags string
Colin Cross581c1892015-04-07 16:50:10 -0700118 yaccFlags string
Colin Cross3f40fa42015-01-30 17:27:36 -0800119 nocrt bool
Colin Cross97ba0732015-03-23 17:50:24 -0700120 toolchain Toolchain
Colin Cross3f40fa42015-01-30 17:27:36 -0800121 clang bool
122}
123
124// Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files
125func TransformSourceToObj(ctx common.AndroidModuleContext, subdir string, srcFiles []string,
Colin Cross581c1892015-04-07 16:50:10 -0700126 flags builderFlags, deps []string) (objFiles []string) {
127
Colin Cross1332b002015-04-07 17:11:30 -0700128 srcRoot := ctx.AConfig().SrcDir()
129 intermediatesRoot := ctx.AConfig().IntermediatesDir()
Colin Cross3f40fa42015-01-30 17:27:36 -0800130
Dan Willemsene6540452015-10-20 15:21:33 -0700131 // We run gcc/clang with PWD=/proc/self/cwd to remove $TOP from the
132 // debug output. That way two builds in two different directories will
133 // create the same output.
134 relPwd := "PWD=/proc/self/cwd"
135 if ctx.Darwin() {
136 // /proc doesn't exist on Darwin
137 relPwd = ""
138 }
139
Colin Cross3f40fa42015-01-30 17:27:36 -0800140 objFiles = make([]string, len(srcFiles))
141 objDir := common.ModuleObjDir(ctx)
142 if subdir != "" {
143 objDir = filepath.Join(objDir, subdir)
144 }
145
146 cflags := flags.globalFlags + " " + flags.cFlags + " " + flags.conlyFlags
147 cppflags := flags.globalFlags + " " + flags.cFlags + " " + flags.cppFlags
148 asflags := flags.globalFlags + " " + flags.asFlags
149
150 for i, srcFile := range srcFiles {
Colin Cross581c1892015-04-07 16:50:10 -0700151 var objFile string
Dan Willemsen87b17d12015-07-14 00:39:06 -0700152 if strings.HasPrefix(srcFile, intermediatesRoot) {
Colin Cross581c1892015-04-07 16:50:10 -0700153 objFile = strings.TrimPrefix(srcFile, intermediatesRoot)
154 objFile = filepath.Join(objDir, "gen", objFile)
Dan Willemsen87b17d12015-07-14 00:39:06 -0700155 } else if strings.HasPrefix(srcFile, srcRoot) {
156 srcFile, _ = filepath.Rel(srcRoot, srcFile)
157 objFile = filepath.Join(objDir, srcFile)
158 } else if srcRoot == "." && srcFile[0] != '/' {
159 objFile = filepath.Join(objDir, srcFile)
Colin Cross581c1892015-04-07 16:50:10 -0700160 } else {
161 ctx.ModuleErrorf("source file %q is not in source directory %q", srcFile, srcRoot)
162 continue
163 }
164
Colin Cross3f40fa42015-01-30 17:27:36 -0800165 objFile = pathtools.ReplaceExtension(objFile, "o")
166
167 objFiles[i] = objFile
168
169 var moduleCflags string
170 var ccCmd string
171
172 switch filepath.Ext(srcFile) {
173 case ".S", ".s":
174 ccCmd = "gcc"
175 moduleCflags = asflags
176 case ".c":
177 ccCmd = "gcc"
178 moduleCflags = cflags
179 case ".cpp", ".cc":
180 ccCmd = "g++"
181 moduleCflags = cppflags
182 default:
183 ctx.ModuleErrorf("File %s has unknown extension", srcFile)
184 continue
185 }
186
187 if flags.clang {
188 switch ccCmd {
189 case "gcc":
190 ccCmd = "clang"
191 case "g++":
192 ccCmd = "clang++"
193 default:
194 panic("unrecoginzied ccCmd")
195 }
196
197 ccCmd = "${clangPath}" + ccCmd
198 } else {
199 ccCmd = gccCmd(flags.toolchain, ccCmd)
200 }
201
Colin Crossd8149602015-05-12 17:14:57 -0700202 objDeps := append([]string{ccCmd}, deps...)
Colin Cross581c1892015-04-07 16:50:10 -0700203
Colin Cross3f40fa42015-01-30 17:27:36 -0800204 ctx.Build(pctx, blueprint.BuildParams{
205 Rule: cc,
206 Outputs: []string{objFile},
207 Inputs: []string{srcFile},
Colin Crossd8149602015-05-12 17:14:57 -0700208 Implicits: objDeps,
Colin Cross3f40fa42015-01-30 17:27:36 -0800209 Args: map[string]string{
Colin Cross28344522015-04-22 13:07:53 -0700210 "cFlags": moduleCflags,
211 "ccCmd": ccCmd,
Dan Willemsene6540452015-10-20 15:21:33 -0700212 "relPwd": relPwd,
Colin Cross3f40fa42015-01-30 17:27:36 -0800213 },
214 })
215 }
216
217 return objFiles
218}
219
220// Generate a rule for compiling multiple .o files to a static library (.a)
221func TransformObjToStaticLib(ctx common.AndroidModuleContext, objFiles []string,
222 flags builderFlags, outputFile string) {
223
224 arCmd := gccCmd(flags.toolchain, "ar")
225 arFlags := "crsPD"
226
227 ctx.Build(pctx, blueprint.BuildParams{
228 Rule: ar,
229 Outputs: []string{outputFile},
230 Inputs: objFiles,
231 Implicits: []string{arCmd},
232 Args: map[string]string{
233 "arFlags": arFlags,
234 "arCmd": arCmd,
235 },
236 })
237}
238
Colin Cross0af4b842015-04-30 16:36:18 -0700239// Generate a rule for compiling multiple .o files to a static library (.a) on
240// darwin. The darwin ar tool doesn't support @file for list files, and has a
241// very small command line length limit, so we have to split the ar into multiple
242// steps, each appending to the previous one.
243func TransformDarwinObjToStaticLib(ctx common.AndroidModuleContext, objFiles []string,
244 flags builderFlags, outputFile string) {
245
246 arCmd := "ar"
247 arFlags := "cqs"
248
249 // ARG_MAX on darwin is 262144, use half that to be safe
250 objFilesLists, err := splitListForSize(objFiles, 131072)
251 if err != nil {
252 ctx.ModuleErrorf("%s", err.Error())
253 }
254
255 var in, out string
256 for i, l := range objFilesLists {
257 in = out
258 out = outputFile
259 if i != len(objFilesLists)-1 {
260 out += "." + strconv.Itoa(i)
261 }
262
263 if in == "" {
264 ctx.Build(pctx, blueprint.BuildParams{
265 Rule: darwinAr,
266 Outputs: []string{out},
267 Inputs: l,
268 Args: map[string]string{
269 "arFlags": arFlags,
270 "arCmd": arCmd,
271 },
272 })
273 } else {
274 ctx.Build(pctx, blueprint.BuildParams{
275 Rule: darwinAppendAr,
276 Outputs: []string{out},
277 Inputs: l,
278 Implicits: []string{in},
279 Args: map[string]string{
280 "arFlags": arFlags,
281 "arCmd": arCmd,
282 "inAr": in,
283 },
284 })
285 }
286 }
287}
288
Colin Cross3f40fa42015-01-30 17:27:36 -0800289// Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries,
290// and shared libraires, to a shared library (.so) or dynamic executable
291func TransformObjToDynamicBinary(ctx common.AndroidModuleContext,
Colin Crossaee540a2015-07-06 17:48:31 -0700292 objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps []string,
Colin Crossed4cf0b2015-03-26 14:43:45 -0700293 crtBegin, crtEnd string, groupLate bool, flags builderFlags, outputFile string) {
Colin Cross3f40fa42015-01-30 17:27:36 -0800294
295 var ldCmd string
296 if flags.clang {
297 ldCmd = "${clangPath}clang++"
298 } else {
299 ldCmd = gccCmd(flags.toolchain, "g++")
300 }
301
302 var ldDirs []string
303 var libFlagsList []string
304
305 if len(wholeStaticLibs) > 0 {
Colin Cross0af4b842015-04-30 16:36:18 -0700306 if ctx.Host() && runtime.GOOS == "darwin" {
307 libFlagsList = append(libFlagsList, common.JoinWithPrefix(wholeStaticLibs, "-force_load "))
308 } else {
309 libFlagsList = append(libFlagsList, "-Wl,--whole-archive ")
310 libFlagsList = append(libFlagsList, wholeStaticLibs...)
311 libFlagsList = append(libFlagsList, "-Wl,--no-whole-archive ")
312 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800313 }
314
315 libFlagsList = append(libFlagsList, staticLibs...)
316
Dan Willemsenedc385f2015-07-08 13:02:23 -0700317 if groupLate && len(lateStaticLibs) > 0 {
318 libFlagsList = append(libFlagsList, "-Wl,--start-group")
319 }
320 libFlagsList = append(libFlagsList, lateStaticLibs...)
321 if groupLate && len(lateStaticLibs) > 0 {
322 libFlagsList = append(libFlagsList, "-Wl,--end-group")
323 }
324
Colin Cross3f40fa42015-01-30 17:27:36 -0800325 for _, lib := range sharedLibs {
326 dir, file := filepath.Split(lib)
327 if !strings.HasPrefix(file, "lib") {
328 panic("shared library " + lib + " does not start with lib")
329 }
330 if !strings.HasSuffix(file, sharedLibraryExtension) {
331 panic("shared library " + lib + " does not end with " + sharedLibraryExtension)
332 }
333 libFlagsList = append(libFlagsList,
334 "-l"+strings.TrimSuffix(strings.TrimPrefix(file, "lib"), sharedLibraryExtension))
335 ldDirs = append(ldDirs, dir)
336 }
337
Colin Crossaee540a2015-07-06 17:48:31 -0700338 deps = append(deps, ldCmd)
Colin Cross3f40fa42015-01-30 17:27:36 -0800339 deps = append(deps, sharedLibs...)
340 deps = append(deps, staticLibs...)
Colin Cross3075ad02015-03-17 10:47:08 -0700341 deps = append(deps, lateStaticLibs...)
Colin Cross3f40fa42015-01-30 17:27:36 -0800342 deps = append(deps, wholeStaticLibs...)
343 if crtBegin != "" {
344 deps = append(deps, crtBegin, crtEnd)
345 }
346
347 ctx.Build(pctx, blueprint.BuildParams{
348 Rule: ld,
349 Outputs: []string{outputFile},
350 Inputs: objFiles,
351 Implicits: deps,
352 Args: map[string]string{
353 "ldCmd": ldCmd,
354 "ldDirFlags": ldDirsToFlags(ldDirs),
355 "crtBegin": crtBegin,
356 "libFlags": strings.Join(libFlagsList, " "),
357 "ldFlags": flags.ldFlags,
358 "crtEnd": crtEnd,
Colin Cross3f40fa42015-01-30 17:27:36 -0800359 },
360 })
361}
362
363// Generate a rule for compiling multiple .o files to a .o using ld partial linking
364func TransformObjsToObj(ctx common.AndroidModuleContext, objFiles []string,
365 flags builderFlags, outputFile string) {
366
367 ldCmd := gccCmd(flags.toolchain, "ld")
368
369 deps := []string{ldCmd}
370
371 ctx.Build(pctx, blueprint.BuildParams{
372 Rule: partialLd,
373 Outputs: []string{outputFile},
374 Inputs: objFiles,
375 Implicits: deps,
376 Args: map[string]string{
377 "ldCmd": ldCmd,
378 },
379 })
380}
381
Colin Crossbfae8852015-03-26 14:44:11 -0700382// Generate a rule for runing objcopy --prefix-symbols on a binary
383func TransformBinaryPrefixSymbols(ctx common.AndroidModuleContext, prefix string, inputFile string,
384 flags builderFlags, outputFile string) {
385
386 objcopyCmd := gccCmd(flags.toolchain, "objcopy")
387
388 ctx.Build(pctx, blueprint.BuildParams{
389 Rule: prefixSymbols,
390 Outputs: []string{outputFile},
391 Inputs: []string{inputFile},
392 Implicits: []string{objcopyCmd},
393 Args: map[string]string{
394 "objcopyCmd": objcopyCmd,
395 "prefix": prefix,
396 },
397 })
398}
399
Colin Cross3f40fa42015-01-30 17:27:36 -0800400func CopyGccLib(ctx common.AndroidModuleContext, libName string,
401 flags builderFlags, outputFile string) {
402
403 ctx.Build(pctx, blueprint.BuildParams{
404 Rule: copyGccLib,
405 Outputs: []string{outputFile},
406 Implicits: []string{
407 "$copyGccLibPath",
408 gccCmd(flags.toolchain, "gcc"),
409 },
410 Args: map[string]string{
411 "ccCmd": gccCmd(flags.toolchain, "gcc"),
412 "cFlags": flags.globalFlags,
413 "libName": libName,
414 },
415 })
416}
417
Colin Cross97ba0732015-03-23 17:50:24 -0700418func gccCmd(toolchain Toolchain, cmd string) string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800419 return filepath.Join(toolchain.GccRoot(), "bin", toolchain.GccTriple()+"-"+cmd)
420}
Colin Cross0af4b842015-04-30 16:36:18 -0700421
422func splitListForSize(list []string, limit int) (lists [][]string, err error) {
423 var i int
424
425 start := 0
426 bytes := 0
427 for i = range list {
428 l := len(list[i])
429 if l > limit {
430 return nil, fmt.Errorf("list element greater than size limit (%d)", limit)
431 }
432 if bytes+l > limit {
433 lists = append(lists, list[start:i])
434 start = i
435 bytes = 0
436 }
437 bytes += l + 1 // count a space between each list element
438 }
439
440 lists = append(lists, list[start:])
441
442 totalLen := 0
443 for _, l := range lists {
444 totalLen += len(l)
445 }
446 if totalLen != len(list) {
447 panic(fmt.Errorf("Failed breaking up list, %d != %d", len(list), totalLen))
448 }
449 return lists, nil
450}