blob: 3d5bb7796445593ab920719b8c9aff21ee2d637e [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 Willemsen322a0a62015-11-17 15:19:46 -080050 "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
Dan Willemsen322a0a62015-11-17 15:19:46 -0800111func init() {
112 // We run gcc/clang with PWD=/proc/self/cwd to remove $TOP from the
113 // debug output. That way two builds in two different directories will
114 // create the same output.
115 if runtime.GOOS != "darwin" {
116 pctx.StaticVariable("relPwd", "PWD=/proc/self/cwd")
117 } else {
118 // Darwin doesn't have /proc
119 pctx.StaticVariable("relPwd", "")
120 }
121}
122
Colin Cross3f40fa42015-01-30 17:27:36 -0800123type builderFlags struct {
124 globalFlags string
125 asFlags string
126 cFlags string
127 conlyFlags string
128 cppFlags string
129 ldFlags string
Colin Cross581c1892015-04-07 16:50:10 -0700130 yaccFlags string
Colin Cross3f40fa42015-01-30 17:27:36 -0800131 nocrt bool
Colin Cross97ba0732015-03-23 17:50:24 -0700132 toolchain Toolchain
Colin Cross3f40fa42015-01-30 17:27:36 -0800133 clang bool
134}
135
136// Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files
137func TransformSourceToObj(ctx common.AndroidModuleContext, subdir string, srcFiles []string,
Colin Cross581c1892015-04-07 16:50:10 -0700138 flags builderFlags, deps []string) (objFiles []string) {
139
Colin Cross1332b002015-04-07 17:11:30 -0700140 srcRoot := ctx.AConfig().SrcDir()
141 intermediatesRoot := ctx.AConfig().IntermediatesDir()
Colin Cross3f40fa42015-01-30 17:27:36 -0800142
143 objFiles = make([]string, len(srcFiles))
144 objDir := common.ModuleObjDir(ctx)
145 if subdir != "" {
146 objDir = filepath.Join(objDir, subdir)
147 }
148
149 cflags := flags.globalFlags + " " + flags.cFlags + " " + flags.conlyFlags
150 cppflags := flags.globalFlags + " " + flags.cFlags + " " + flags.cppFlags
151 asflags := flags.globalFlags + " " + flags.asFlags
152
153 for i, srcFile := range srcFiles {
Colin Cross581c1892015-04-07 16:50:10 -0700154 var objFile string
Dan Willemsen87b17d12015-07-14 00:39:06 -0700155 if strings.HasPrefix(srcFile, intermediatesRoot) {
Colin Cross581c1892015-04-07 16:50:10 -0700156 objFile = strings.TrimPrefix(srcFile, intermediatesRoot)
157 objFile = filepath.Join(objDir, "gen", objFile)
Dan Willemsen87b17d12015-07-14 00:39:06 -0700158 } else if strings.HasPrefix(srcFile, srcRoot) {
159 srcFile, _ = filepath.Rel(srcRoot, srcFile)
160 objFile = filepath.Join(objDir, srcFile)
161 } else if srcRoot == "." && srcFile[0] != '/' {
162 objFile = filepath.Join(objDir, srcFile)
Colin Cross581c1892015-04-07 16:50:10 -0700163 } else {
164 ctx.ModuleErrorf("source file %q is not in source directory %q", srcFile, srcRoot)
165 continue
166 }
167
Colin Cross3f40fa42015-01-30 17:27:36 -0800168 objFile = pathtools.ReplaceExtension(objFile, "o")
169
170 objFiles[i] = objFile
171
172 var moduleCflags string
173 var ccCmd string
174
175 switch filepath.Ext(srcFile) {
176 case ".S", ".s":
177 ccCmd = "gcc"
178 moduleCflags = asflags
179 case ".c":
180 ccCmd = "gcc"
181 moduleCflags = cflags
182 case ".cpp", ".cc":
183 ccCmd = "g++"
184 moduleCflags = cppflags
185 default:
186 ctx.ModuleErrorf("File %s has unknown extension", srcFile)
187 continue
188 }
189
190 if flags.clang {
191 switch ccCmd {
192 case "gcc":
193 ccCmd = "clang"
194 case "g++":
195 ccCmd = "clang++"
196 default:
197 panic("unrecoginzied ccCmd")
198 }
199
200 ccCmd = "${clangPath}" + ccCmd
201 } else {
202 ccCmd = gccCmd(flags.toolchain, ccCmd)
203 }
204
Colin Crossd8149602015-05-12 17:14:57 -0700205 objDeps := append([]string{ccCmd}, deps...)
Colin Cross581c1892015-04-07 16:50:10 -0700206
Colin Cross3f40fa42015-01-30 17:27:36 -0800207 ctx.Build(pctx, blueprint.BuildParams{
208 Rule: cc,
209 Outputs: []string{objFile},
210 Inputs: []string{srcFile},
Colin Crossd8149602015-05-12 17:14:57 -0700211 Implicits: objDeps,
Colin Cross3f40fa42015-01-30 17:27:36 -0800212 Args: map[string]string{
Colin Cross28344522015-04-22 13:07:53 -0700213 "cFlags": moduleCflags,
214 "ccCmd": ccCmd,
Colin Cross3f40fa42015-01-30 17:27:36 -0800215 },
216 })
217 }
218
219 return objFiles
220}
221
222// Generate a rule for compiling multiple .o files to a static library (.a)
223func TransformObjToStaticLib(ctx common.AndroidModuleContext, objFiles []string,
224 flags builderFlags, outputFile string) {
225
226 arCmd := gccCmd(flags.toolchain, "ar")
227 arFlags := "crsPD"
228
229 ctx.Build(pctx, blueprint.BuildParams{
230 Rule: ar,
231 Outputs: []string{outputFile},
232 Inputs: objFiles,
233 Implicits: []string{arCmd},
234 Args: map[string]string{
235 "arFlags": arFlags,
236 "arCmd": arCmd,
237 },
238 })
239}
240
Colin Cross0af4b842015-04-30 16:36:18 -0700241// Generate a rule for compiling multiple .o files to a static library (.a) on
242// darwin. The darwin ar tool doesn't support @file for list files, and has a
243// very small command line length limit, so we have to split the ar into multiple
244// steps, each appending to the previous one.
245func TransformDarwinObjToStaticLib(ctx common.AndroidModuleContext, objFiles []string,
246 flags builderFlags, outputFile string) {
247
248 arCmd := "ar"
249 arFlags := "cqs"
250
251 // ARG_MAX on darwin is 262144, use half that to be safe
252 objFilesLists, err := splitListForSize(objFiles, 131072)
253 if err != nil {
254 ctx.ModuleErrorf("%s", err.Error())
255 }
256
257 var in, out string
258 for i, l := range objFilesLists {
259 in = out
260 out = outputFile
261 if i != len(objFilesLists)-1 {
262 out += "." + strconv.Itoa(i)
263 }
264
265 if in == "" {
266 ctx.Build(pctx, blueprint.BuildParams{
267 Rule: darwinAr,
268 Outputs: []string{out},
269 Inputs: l,
270 Args: map[string]string{
271 "arFlags": arFlags,
272 "arCmd": arCmd,
273 },
274 })
275 } else {
276 ctx.Build(pctx, blueprint.BuildParams{
277 Rule: darwinAppendAr,
278 Outputs: []string{out},
279 Inputs: l,
280 Implicits: []string{in},
281 Args: map[string]string{
282 "arFlags": arFlags,
283 "arCmd": arCmd,
284 "inAr": in,
285 },
286 })
287 }
288 }
289}
290
Colin Cross3f40fa42015-01-30 17:27:36 -0800291// Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries,
292// and shared libraires, to a shared library (.so) or dynamic executable
293func TransformObjToDynamicBinary(ctx common.AndroidModuleContext,
Colin Crossaee540a2015-07-06 17:48:31 -0700294 objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps []string,
Colin Crossed4cf0b2015-03-26 14:43:45 -0700295 crtBegin, crtEnd string, groupLate bool, flags builderFlags, outputFile string) {
Colin Cross3f40fa42015-01-30 17:27:36 -0800296
297 var ldCmd string
298 if flags.clang {
299 ldCmd = "${clangPath}clang++"
300 } else {
301 ldCmd = gccCmd(flags.toolchain, "g++")
302 }
303
304 var ldDirs []string
305 var libFlagsList []string
306
307 if len(wholeStaticLibs) > 0 {
Colin Cross0af4b842015-04-30 16:36:18 -0700308 if ctx.Host() && runtime.GOOS == "darwin" {
309 libFlagsList = append(libFlagsList, common.JoinWithPrefix(wholeStaticLibs, "-force_load "))
310 } else {
311 libFlagsList = append(libFlagsList, "-Wl,--whole-archive ")
312 libFlagsList = append(libFlagsList, wholeStaticLibs...)
313 libFlagsList = append(libFlagsList, "-Wl,--no-whole-archive ")
314 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800315 }
316
317 libFlagsList = append(libFlagsList, staticLibs...)
318
Dan Willemsenedc385f2015-07-08 13:02:23 -0700319 if groupLate && len(lateStaticLibs) > 0 {
320 libFlagsList = append(libFlagsList, "-Wl,--start-group")
321 }
322 libFlagsList = append(libFlagsList, lateStaticLibs...)
323 if groupLate && len(lateStaticLibs) > 0 {
324 libFlagsList = append(libFlagsList, "-Wl,--end-group")
325 }
326
Colin Cross3f40fa42015-01-30 17:27:36 -0800327 for _, lib := range sharedLibs {
328 dir, file := filepath.Split(lib)
329 if !strings.HasPrefix(file, "lib") {
330 panic("shared library " + lib + " does not start with lib")
331 }
332 if !strings.HasSuffix(file, sharedLibraryExtension) {
333 panic("shared library " + lib + " does not end with " + sharedLibraryExtension)
334 }
335 libFlagsList = append(libFlagsList,
336 "-l"+strings.TrimSuffix(strings.TrimPrefix(file, "lib"), sharedLibraryExtension))
337 ldDirs = append(ldDirs, dir)
338 }
339
Colin Crossaee540a2015-07-06 17:48:31 -0700340 deps = append(deps, ldCmd)
Colin Cross3f40fa42015-01-30 17:27:36 -0800341 deps = append(deps, sharedLibs...)
342 deps = append(deps, staticLibs...)
Colin Cross3075ad02015-03-17 10:47:08 -0700343 deps = append(deps, lateStaticLibs...)
Colin Cross3f40fa42015-01-30 17:27:36 -0800344 deps = append(deps, wholeStaticLibs...)
345 if crtBegin != "" {
346 deps = append(deps, crtBegin, crtEnd)
347 }
348
349 ctx.Build(pctx, blueprint.BuildParams{
350 Rule: ld,
351 Outputs: []string{outputFile},
352 Inputs: objFiles,
353 Implicits: deps,
354 Args: map[string]string{
355 "ldCmd": ldCmd,
356 "ldDirFlags": ldDirsToFlags(ldDirs),
357 "crtBegin": crtBegin,
358 "libFlags": strings.Join(libFlagsList, " "),
359 "ldFlags": flags.ldFlags,
360 "crtEnd": crtEnd,
Colin Cross3f40fa42015-01-30 17:27:36 -0800361 },
362 })
363}
364
365// Generate a rule for compiling multiple .o files to a .o using ld partial linking
366func TransformObjsToObj(ctx common.AndroidModuleContext, objFiles []string,
367 flags builderFlags, outputFile string) {
368
369 ldCmd := gccCmd(flags.toolchain, "ld")
370
371 deps := []string{ldCmd}
372
373 ctx.Build(pctx, blueprint.BuildParams{
374 Rule: partialLd,
375 Outputs: []string{outputFile},
376 Inputs: objFiles,
377 Implicits: deps,
378 Args: map[string]string{
379 "ldCmd": ldCmd,
380 },
381 })
382}
383
Colin Crossbfae8852015-03-26 14:44:11 -0700384// Generate a rule for runing objcopy --prefix-symbols on a binary
385func TransformBinaryPrefixSymbols(ctx common.AndroidModuleContext, prefix string, inputFile string,
386 flags builderFlags, outputFile string) {
387
388 objcopyCmd := gccCmd(flags.toolchain, "objcopy")
389
390 ctx.Build(pctx, blueprint.BuildParams{
391 Rule: prefixSymbols,
392 Outputs: []string{outputFile},
393 Inputs: []string{inputFile},
394 Implicits: []string{objcopyCmd},
395 Args: map[string]string{
396 "objcopyCmd": objcopyCmd,
397 "prefix": prefix,
398 },
399 })
400}
401
Colin Cross3f40fa42015-01-30 17:27:36 -0800402func CopyGccLib(ctx common.AndroidModuleContext, libName string,
403 flags builderFlags, outputFile string) {
404
405 ctx.Build(pctx, blueprint.BuildParams{
406 Rule: copyGccLib,
407 Outputs: []string{outputFile},
408 Implicits: []string{
409 "$copyGccLibPath",
410 gccCmd(flags.toolchain, "gcc"),
411 },
412 Args: map[string]string{
413 "ccCmd": gccCmd(flags.toolchain, "gcc"),
414 "cFlags": flags.globalFlags,
415 "libName": libName,
416 },
417 })
418}
419
Colin Cross97ba0732015-03-23 17:50:24 -0700420func gccCmd(toolchain Toolchain, cmd string) string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800421 return filepath.Join(toolchain.GccRoot(), "bin", toolchain.GccTriple()+"-"+cmd)
422}
Colin Cross0af4b842015-04-30 16:36:18 -0700423
424func splitListForSize(list []string, limit int) (lists [][]string, err error) {
425 var i int
426
427 start := 0
428 bytes := 0
429 for i = range list {
430 l := len(list[i])
431 if l > limit {
432 return nil, fmt.Errorf("list element greater than size limit (%d)", limit)
433 }
434 if bytes+l > limit {
435 lists = append(lists, list[start:i])
436 start = i
437 bytes = 0
438 }
439 bytes += l + 1 // count a space between each list element
440 }
441
442 lists = append(lists, list[start:])
443
444 totalLen := 0
445 for _, l := range lists {
446 totalLen += len(l)
447 }
448 if totalLen != len(list) {
449 panic(fmt.Errorf("Failed breaking up list, %d != %d", len(list), totalLen))
450 }
451 return lists, nil
452}