blob: 218c73b2423d4dd425aa44cbb6ece47e123cced5 [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,
Colin Cross28344522015-04-22 13:07:53 -070047 Command: "$ccCmd -c $cFlags -MD -MF ${out}.d -o $out $in",
Colin Cross3f40fa42015-01-30 17:27:36 -080048 Description: "cc $out",
49 },
Colin Cross28344522015-04-22 13:07:53 -070050 "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
131 objFiles = make([]string, len(srcFiles))
132 objDir := common.ModuleObjDir(ctx)
133 if subdir != "" {
134 objDir = filepath.Join(objDir, subdir)
135 }
136
137 cflags := flags.globalFlags + " " + flags.cFlags + " " + flags.conlyFlags
138 cppflags := flags.globalFlags + " " + flags.cFlags + " " + flags.cppFlags
139 asflags := flags.globalFlags + " " + flags.asFlags
140
141 for i, srcFile := range srcFiles {
Colin Cross581c1892015-04-07 16:50:10 -0700142 var objFile string
143 if strings.HasPrefix(srcFile, srcRoot) {
144 objFile = strings.TrimPrefix(srcFile, srcRoot)
145 objFile = filepath.Join(objDir, objFile)
146 } else if strings.HasPrefix(srcFile, intermediatesRoot) {
147 objFile = strings.TrimPrefix(srcFile, intermediatesRoot)
148 objFile = filepath.Join(objDir, "gen", objFile)
149 } else {
150 ctx.ModuleErrorf("source file %q is not in source directory %q", srcFile, srcRoot)
151 continue
152 }
153
Colin Cross3f40fa42015-01-30 17:27:36 -0800154 objFile = pathtools.ReplaceExtension(objFile, "o")
155
156 objFiles[i] = objFile
157
158 var moduleCflags string
159 var ccCmd string
160
161 switch filepath.Ext(srcFile) {
162 case ".S", ".s":
163 ccCmd = "gcc"
164 moduleCflags = asflags
165 case ".c":
166 ccCmd = "gcc"
167 moduleCflags = cflags
168 case ".cpp", ".cc":
169 ccCmd = "g++"
170 moduleCflags = cppflags
171 default:
172 ctx.ModuleErrorf("File %s has unknown extension", srcFile)
173 continue
174 }
175
176 if flags.clang {
177 switch ccCmd {
178 case "gcc":
179 ccCmd = "clang"
180 case "g++":
181 ccCmd = "clang++"
182 default:
183 panic("unrecoginzied ccCmd")
184 }
185
186 ccCmd = "${clangPath}" + ccCmd
187 } else {
188 ccCmd = gccCmd(flags.toolchain, ccCmd)
189 }
190
Colin Cross581c1892015-04-07 16:50:10 -0700191 deps = append([]string{ccCmd}, deps...)
192
Colin Cross3f40fa42015-01-30 17:27:36 -0800193 ctx.Build(pctx, blueprint.BuildParams{
194 Rule: cc,
195 Outputs: []string{objFile},
196 Inputs: []string{srcFile},
Colin Cross581c1892015-04-07 16:50:10 -0700197 Implicits: deps,
Colin Cross3f40fa42015-01-30 17:27:36 -0800198 Args: map[string]string{
Colin Cross28344522015-04-22 13:07:53 -0700199 "cFlags": moduleCflags,
200 "ccCmd": ccCmd,
Colin Cross3f40fa42015-01-30 17:27:36 -0800201 },
202 })
203 }
204
205 return objFiles
206}
207
208// Generate a rule for compiling multiple .o files to a static library (.a)
209func TransformObjToStaticLib(ctx common.AndroidModuleContext, objFiles []string,
210 flags builderFlags, outputFile string) {
211
212 arCmd := gccCmd(flags.toolchain, "ar")
213 arFlags := "crsPD"
214
215 ctx.Build(pctx, blueprint.BuildParams{
216 Rule: ar,
217 Outputs: []string{outputFile},
218 Inputs: objFiles,
219 Implicits: []string{arCmd},
220 Args: map[string]string{
221 "arFlags": arFlags,
222 "arCmd": arCmd,
223 },
224 })
225}
226
Colin Cross0af4b842015-04-30 16:36:18 -0700227// Generate a rule for compiling multiple .o files to a static library (.a) on
228// darwin. The darwin ar tool doesn't support @file for list files, and has a
229// very small command line length limit, so we have to split the ar into multiple
230// steps, each appending to the previous one.
231func TransformDarwinObjToStaticLib(ctx common.AndroidModuleContext, objFiles []string,
232 flags builderFlags, outputFile string) {
233
234 arCmd := "ar"
235 arFlags := "cqs"
236
237 // ARG_MAX on darwin is 262144, use half that to be safe
238 objFilesLists, err := splitListForSize(objFiles, 131072)
239 if err != nil {
240 ctx.ModuleErrorf("%s", err.Error())
241 }
242
243 var in, out string
244 for i, l := range objFilesLists {
245 in = out
246 out = outputFile
247 if i != len(objFilesLists)-1 {
248 out += "." + strconv.Itoa(i)
249 }
250
251 if in == "" {
252 ctx.Build(pctx, blueprint.BuildParams{
253 Rule: darwinAr,
254 Outputs: []string{out},
255 Inputs: l,
256 Args: map[string]string{
257 "arFlags": arFlags,
258 "arCmd": arCmd,
259 },
260 })
261 } else {
262 ctx.Build(pctx, blueprint.BuildParams{
263 Rule: darwinAppendAr,
264 Outputs: []string{out},
265 Inputs: l,
266 Implicits: []string{in},
267 Args: map[string]string{
268 "arFlags": arFlags,
269 "arCmd": arCmd,
270 "inAr": in,
271 },
272 })
273 }
274 }
275}
276
Colin Cross3f40fa42015-01-30 17:27:36 -0800277// Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries,
278// and shared libraires, to a shared library (.so) or dynamic executable
279func TransformObjToDynamicBinary(ctx common.AndroidModuleContext,
Colin Cross77b00fa2015-03-16 16:15:49 -0700280 objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs []string,
Colin Crossed4cf0b2015-03-26 14:43:45 -0700281 crtBegin, crtEnd string, groupLate bool, flags builderFlags, outputFile string) {
Colin Cross3f40fa42015-01-30 17:27:36 -0800282
283 var ldCmd string
284 if flags.clang {
285 ldCmd = "${clangPath}clang++"
286 } else {
287 ldCmd = gccCmd(flags.toolchain, "g++")
288 }
289
290 var ldDirs []string
291 var libFlagsList []string
292
293 if len(wholeStaticLibs) > 0 {
Colin Cross0af4b842015-04-30 16:36:18 -0700294 if ctx.Host() && runtime.GOOS == "darwin" {
295 libFlagsList = append(libFlagsList, common.JoinWithPrefix(wholeStaticLibs, "-force_load "))
296 } else {
297 libFlagsList = append(libFlagsList, "-Wl,--whole-archive ")
298 libFlagsList = append(libFlagsList, wholeStaticLibs...)
299 libFlagsList = append(libFlagsList, "-Wl,--no-whole-archive ")
300 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800301 }
302
303 libFlagsList = append(libFlagsList, staticLibs...)
304
305 for _, lib := range sharedLibs {
306 dir, file := filepath.Split(lib)
307 if !strings.HasPrefix(file, "lib") {
308 panic("shared library " + lib + " does not start with lib")
309 }
310 if !strings.HasSuffix(file, sharedLibraryExtension) {
311 panic("shared library " + lib + " does not end with " + sharedLibraryExtension)
312 }
313 libFlagsList = append(libFlagsList,
314 "-l"+strings.TrimSuffix(strings.TrimPrefix(file, "lib"), sharedLibraryExtension))
315 ldDirs = append(ldDirs, dir)
316 }
317
Colin Cross0af4b842015-04-30 16:36:18 -0700318 if groupLate && len(lateStaticLibs) > 0 {
Colin Crossed4cf0b2015-03-26 14:43:45 -0700319 libFlagsList = append(libFlagsList, "-Wl,--start-group")
320 }
Colin Cross77b00fa2015-03-16 16:15:49 -0700321 libFlagsList = append(libFlagsList, lateStaticLibs...)
Colin Cross0af4b842015-04-30 16:36:18 -0700322 if groupLate && len(lateStaticLibs) > 0 {
Colin Crossed4cf0b2015-03-26 14:43:45 -0700323 libFlagsList = append(libFlagsList, "-Wl,--end-group")
324 }
Colin Cross77b00fa2015-03-16 16:15:49 -0700325
Colin Cross3f40fa42015-01-30 17:27:36 -0800326 deps := []string{ldCmd}
327 deps = append(deps, sharedLibs...)
328 deps = append(deps, staticLibs...)
Colin Cross3075ad02015-03-17 10:47:08 -0700329 deps = append(deps, lateStaticLibs...)
Colin Cross3f40fa42015-01-30 17:27:36 -0800330 deps = append(deps, wholeStaticLibs...)
331 if crtBegin != "" {
332 deps = append(deps, crtBegin, crtEnd)
333 }
334
335 ctx.Build(pctx, blueprint.BuildParams{
336 Rule: ld,
337 Outputs: []string{outputFile},
338 Inputs: objFiles,
339 Implicits: deps,
340 Args: map[string]string{
341 "ldCmd": ldCmd,
342 "ldDirFlags": ldDirsToFlags(ldDirs),
343 "crtBegin": crtBegin,
344 "libFlags": strings.Join(libFlagsList, " "),
345 "ldFlags": flags.ldFlags,
346 "crtEnd": crtEnd,
Colin Cross3f40fa42015-01-30 17:27:36 -0800347 },
348 })
349}
350
351// Generate a rule for compiling multiple .o files to a .o using ld partial linking
352func TransformObjsToObj(ctx common.AndroidModuleContext, objFiles []string,
353 flags builderFlags, outputFile string) {
354
355 ldCmd := gccCmd(flags.toolchain, "ld")
356
357 deps := []string{ldCmd}
358
359 ctx.Build(pctx, blueprint.BuildParams{
360 Rule: partialLd,
361 Outputs: []string{outputFile},
362 Inputs: objFiles,
363 Implicits: deps,
364 Args: map[string]string{
365 "ldCmd": ldCmd,
366 },
367 })
368}
369
Colin Crossbfae8852015-03-26 14:44:11 -0700370// Generate a rule for runing objcopy --prefix-symbols on a binary
371func TransformBinaryPrefixSymbols(ctx common.AndroidModuleContext, prefix string, inputFile string,
372 flags builderFlags, outputFile string) {
373
374 objcopyCmd := gccCmd(flags.toolchain, "objcopy")
375
376 ctx.Build(pctx, blueprint.BuildParams{
377 Rule: prefixSymbols,
378 Outputs: []string{outputFile},
379 Inputs: []string{inputFile},
380 Implicits: []string{objcopyCmd},
381 Args: map[string]string{
382 "objcopyCmd": objcopyCmd,
383 "prefix": prefix,
384 },
385 })
386}
387
Colin Cross3f40fa42015-01-30 17:27:36 -0800388func CopyGccLib(ctx common.AndroidModuleContext, libName string,
389 flags builderFlags, outputFile string) {
390
391 ctx.Build(pctx, blueprint.BuildParams{
392 Rule: copyGccLib,
393 Outputs: []string{outputFile},
394 Implicits: []string{
395 "$copyGccLibPath",
396 gccCmd(flags.toolchain, "gcc"),
397 },
398 Args: map[string]string{
399 "ccCmd": gccCmd(flags.toolchain, "gcc"),
400 "cFlags": flags.globalFlags,
401 "libName": libName,
402 },
403 })
404}
405
Colin Cross97ba0732015-03-23 17:50:24 -0700406func gccCmd(toolchain Toolchain, cmd string) string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800407 return filepath.Join(toolchain.GccRoot(), "bin", toolchain.GccTriple()+"-"+cmd)
408}
Colin Cross0af4b842015-04-30 16:36:18 -0700409
410func splitListForSize(list []string, limit int) (lists [][]string, err error) {
411 var i int
412
413 start := 0
414 bytes := 0
415 for i = range list {
416 l := len(list[i])
417 if l > limit {
418 return nil, fmt.Errorf("list element greater than size limit (%d)", limit)
419 }
420 if bytes+l > limit {
421 lists = append(lists, list[start:i])
422 start = i
423 bytes = 0
424 }
425 bytes += l + 1 // count a space between each list element
426 }
427
428 lists = append(lists, list[start:])
429
430 totalLen := 0
431 for _, l := range lists {
432 totalLen += len(l)
433 }
434 if totalLen != len(list) {
435 panic(fmt.Errorf("Failed breaking up list, %d != %d", len(list), totalLen))
436 }
437 return lists, nil
438}