blob: 9c9bddd82c81540ca519a9765de92374467a49c3 [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
Dan Willemsen87b17d12015-07-14 00:39:06 -0700143 if strings.HasPrefix(srcFile, intermediatesRoot) {
Colin Cross581c1892015-04-07 16:50:10 -0700144 objFile = strings.TrimPrefix(srcFile, intermediatesRoot)
145 objFile = filepath.Join(objDir, "gen", objFile)
Dan Willemsen87b17d12015-07-14 00:39:06 -0700146 } else if strings.HasPrefix(srcFile, srcRoot) {
147 srcFile, _ = filepath.Rel(srcRoot, srcFile)
148 objFile = filepath.Join(objDir, srcFile)
149 } else if srcRoot == "." && srcFile[0] != '/' {
150 objFile = filepath.Join(objDir, srcFile)
Colin Cross581c1892015-04-07 16:50:10 -0700151 } else {
152 ctx.ModuleErrorf("source file %q is not in source directory %q", srcFile, srcRoot)
153 continue
154 }
155
Colin Cross3f40fa42015-01-30 17:27:36 -0800156 objFile = pathtools.ReplaceExtension(objFile, "o")
157
158 objFiles[i] = objFile
159
160 var moduleCflags string
161 var ccCmd string
162
163 switch filepath.Ext(srcFile) {
164 case ".S", ".s":
165 ccCmd = "gcc"
166 moduleCflags = asflags
167 case ".c":
168 ccCmd = "gcc"
169 moduleCflags = cflags
170 case ".cpp", ".cc":
171 ccCmd = "g++"
172 moduleCflags = cppflags
173 default:
174 ctx.ModuleErrorf("File %s has unknown extension", srcFile)
175 continue
176 }
177
178 if flags.clang {
179 switch ccCmd {
180 case "gcc":
181 ccCmd = "clang"
182 case "g++":
183 ccCmd = "clang++"
184 default:
185 panic("unrecoginzied ccCmd")
186 }
187
188 ccCmd = "${clangPath}" + ccCmd
189 } else {
190 ccCmd = gccCmd(flags.toolchain, ccCmd)
191 }
192
Colin Crossd8149602015-05-12 17:14:57 -0700193 objDeps := append([]string{ccCmd}, deps...)
Colin Cross581c1892015-04-07 16:50:10 -0700194
Colin Cross3f40fa42015-01-30 17:27:36 -0800195 ctx.Build(pctx, blueprint.BuildParams{
196 Rule: cc,
197 Outputs: []string{objFile},
198 Inputs: []string{srcFile},
Colin Crossd8149602015-05-12 17:14:57 -0700199 Implicits: objDeps,
Colin Cross3f40fa42015-01-30 17:27:36 -0800200 Args: map[string]string{
Colin Cross28344522015-04-22 13:07:53 -0700201 "cFlags": moduleCflags,
202 "ccCmd": ccCmd,
Colin Cross3f40fa42015-01-30 17:27:36 -0800203 },
204 })
205 }
206
207 return objFiles
208}
209
210// Generate a rule for compiling multiple .o files to a static library (.a)
211func TransformObjToStaticLib(ctx common.AndroidModuleContext, objFiles []string,
212 flags builderFlags, outputFile string) {
213
214 arCmd := gccCmd(flags.toolchain, "ar")
215 arFlags := "crsPD"
216
217 ctx.Build(pctx, blueprint.BuildParams{
218 Rule: ar,
219 Outputs: []string{outputFile},
220 Inputs: objFiles,
221 Implicits: []string{arCmd},
222 Args: map[string]string{
223 "arFlags": arFlags,
224 "arCmd": arCmd,
225 },
226 })
227}
228
Colin Cross0af4b842015-04-30 16:36:18 -0700229// Generate a rule for compiling multiple .o files to a static library (.a) on
230// darwin. The darwin ar tool doesn't support @file for list files, and has a
231// very small command line length limit, so we have to split the ar into multiple
232// steps, each appending to the previous one.
233func TransformDarwinObjToStaticLib(ctx common.AndroidModuleContext, objFiles []string,
234 flags builderFlags, outputFile string) {
235
236 arCmd := "ar"
237 arFlags := "cqs"
238
239 // ARG_MAX on darwin is 262144, use half that to be safe
240 objFilesLists, err := splitListForSize(objFiles, 131072)
241 if err != nil {
242 ctx.ModuleErrorf("%s", err.Error())
243 }
244
245 var in, out string
246 for i, l := range objFilesLists {
247 in = out
248 out = outputFile
249 if i != len(objFilesLists)-1 {
250 out += "." + strconv.Itoa(i)
251 }
252
253 if in == "" {
254 ctx.Build(pctx, blueprint.BuildParams{
255 Rule: darwinAr,
256 Outputs: []string{out},
257 Inputs: l,
258 Args: map[string]string{
259 "arFlags": arFlags,
260 "arCmd": arCmd,
261 },
262 })
263 } else {
264 ctx.Build(pctx, blueprint.BuildParams{
265 Rule: darwinAppendAr,
266 Outputs: []string{out},
267 Inputs: l,
268 Implicits: []string{in},
269 Args: map[string]string{
270 "arFlags": arFlags,
271 "arCmd": arCmd,
272 "inAr": in,
273 },
274 })
275 }
276 }
277}
278
Colin Cross3f40fa42015-01-30 17:27:36 -0800279// Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries,
280// and shared libraires, to a shared library (.so) or dynamic executable
281func TransformObjToDynamicBinary(ctx common.AndroidModuleContext,
Colin Crossaee540a2015-07-06 17:48:31 -0700282 objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps []string,
Colin Crossed4cf0b2015-03-26 14:43:45 -0700283 crtBegin, crtEnd string, groupLate bool, flags builderFlags, outputFile string) {
Colin Cross3f40fa42015-01-30 17:27:36 -0800284
285 var ldCmd string
286 if flags.clang {
287 ldCmd = "${clangPath}clang++"
288 } else {
289 ldCmd = gccCmd(flags.toolchain, "g++")
290 }
291
292 var ldDirs []string
293 var libFlagsList []string
294
295 if len(wholeStaticLibs) > 0 {
Colin Cross0af4b842015-04-30 16:36:18 -0700296 if ctx.Host() && runtime.GOOS == "darwin" {
297 libFlagsList = append(libFlagsList, common.JoinWithPrefix(wholeStaticLibs, "-force_load "))
298 } else {
299 libFlagsList = append(libFlagsList, "-Wl,--whole-archive ")
300 libFlagsList = append(libFlagsList, wholeStaticLibs...)
301 libFlagsList = append(libFlagsList, "-Wl,--no-whole-archive ")
302 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800303 }
304
305 libFlagsList = append(libFlagsList, staticLibs...)
306
Dan Willemsenedc385f2015-07-08 13:02:23 -0700307 if groupLate && len(lateStaticLibs) > 0 {
308 libFlagsList = append(libFlagsList, "-Wl,--start-group")
309 }
310 libFlagsList = append(libFlagsList, lateStaticLibs...)
311 if groupLate && len(lateStaticLibs) > 0 {
312 libFlagsList = append(libFlagsList, "-Wl,--end-group")
313 }
314
Colin Cross3f40fa42015-01-30 17:27:36 -0800315 for _, lib := range sharedLibs {
316 dir, file := filepath.Split(lib)
317 if !strings.HasPrefix(file, "lib") {
318 panic("shared library " + lib + " does not start with lib")
319 }
320 if !strings.HasSuffix(file, sharedLibraryExtension) {
321 panic("shared library " + lib + " does not end with " + sharedLibraryExtension)
322 }
323 libFlagsList = append(libFlagsList,
324 "-l"+strings.TrimSuffix(strings.TrimPrefix(file, "lib"), sharedLibraryExtension))
325 ldDirs = append(ldDirs, dir)
326 }
327
Colin Crossaee540a2015-07-06 17:48:31 -0700328 deps = append(deps, ldCmd)
Colin Cross3f40fa42015-01-30 17:27:36 -0800329 deps = append(deps, sharedLibs...)
330 deps = append(deps, staticLibs...)
Colin Cross3075ad02015-03-17 10:47:08 -0700331 deps = append(deps, lateStaticLibs...)
Colin Cross3f40fa42015-01-30 17:27:36 -0800332 deps = append(deps, wholeStaticLibs...)
333 if crtBegin != "" {
334 deps = append(deps, crtBegin, crtEnd)
335 }
336
337 ctx.Build(pctx, blueprint.BuildParams{
338 Rule: ld,
339 Outputs: []string{outputFile},
340 Inputs: objFiles,
341 Implicits: deps,
342 Args: map[string]string{
343 "ldCmd": ldCmd,
344 "ldDirFlags": ldDirsToFlags(ldDirs),
345 "crtBegin": crtBegin,
346 "libFlags": strings.Join(libFlagsList, " "),
347 "ldFlags": flags.ldFlags,
348 "crtEnd": crtEnd,
Colin Cross3f40fa42015-01-30 17:27:36 -0800349 },
350 })
351}
352
353// Generate a rule for compiling multiple .o files to a .o using ld partial linking
354func TransformObjsToObj(ctx common.AndroidModuleContext, objFiles []string,
355 flags builderFlags, outputFile string) {
356
357 ldCmd := gccCmd(flags.toolchain, "ld")
358
359 deps := []string{ldCmd}
360
361 ctx.Build(pctx, blueprint.BuildParams{
362 Rule: partialLd,
363 Outputs: []string{outputFile},
364 Inputs: objFiles,
365 Implicits: deps,
366 Args: map[string]string{
367 "ldCmd": ldCmd,
368 },
369 })
370}
371
Colin Crossbfae8852015-03-26 14:44:11 -0700372// Generate a rule for runing objcopy --prefix-symbols on a binary
373func TransformBinaryPrefixSymbols(ctx common.AndroidModuleContext, prefix string, inputFile string,
374 flags builderFlags, outputFile string) {
375
376 objcopyCmd := gccCmd(flags.toolchain, "objcopy")
377
378 ctx.Build(pctx, blueprint.BuildParams{
379 Rule: prefixSymbols,
380 Outputs: []string{outputFile},
381 Inputs: []string{inputFile},
382 Implicits: []string{objcopyCmd},
383 Args: map[string]string{
384 "objcopyCmd": objcopyCmd,
385 "prefix": prefix,
386 },
387 })
388}
389
Colin Cross3f40fa42015-01-30 17:27:36 -0800390func CopyGccLib(ctx common.AndroidModuleContext, libName string,
391 flags builderFlags, outputFile string) {
392
393 ctx.Build(pctx, blueprint.BuildParams{
394 Rule: copyGccLib,
395 Outputs: []string{outputFile},
396 Implicits: []string{
397 "$copyGccLibPath",
398 gccCmd(flags.toolchain, "gcc"),
399 },
400 Args: map[string]string{
401 "ccCmd": gccCmd(flags.toolchain, "gcc"),
402 "cFlags": flags.globalFlags,
403 "libName": libName,
404 },
405 })
406}
407
Colin Cross97ba0732015-03-23 17:50:24 -0700408func gccCmd(toolchain Toolchain, cmd string) string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800409 return filepath.Join(toolchain.GccRoot(), "bin", toolchain.GccTriple()+"-"+cmd)
410}
Colin Cross0af4b842015-04-30 16:36:18 -0700411
412func splitListForSize(list []string, limit int) (lists [][]string, err error) {
413 var i int
414
415 start := 0
416 bytes := 0
417 for i = range list {
418 l := len(list[i])
419 if l > limit {
420 return nil, fmt.Errorf("list element greater than size limit (%d)", limit)
421 }
422 if bytes+l > limit {
423 lists = append(lists, list[start:i])
424 start = i
425 bytes = 0
426 }
427 bytes += l + 1 // count a space between each list element
428 }
429
430 lists = append(lists, list[start:])
431
432 totalLen := 0
433 for _, l := range lists {
434 totalLen += len(l)
435 }
436 if totalLen != len(list) {
437 panic(fmt.Errorf("Failed breaking up list, %d != %d", len(list), totalLen))
438 }
439 return lists, nil
440}