blob: a1d7f2c4dde238109114634630bfeffccf9b3837 [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",
Dan Willemsenc94a7682015-11-17 15:27:28 -080048 CommandDeps: []string{"$ccCmd"},
Colin Cross3f40fa42015-01-30 17:27:36 -080049 Description: "cc $out",
50 },
Dan Willemsen322a0a62015-11-17 15:19:46 -080051 "ccCmd", "cFlags")
Colin Cross3f40fa42015-01-30 17:27:36 -080052
53 ld = pctx.StaticRule("ld",
54 blueprint.RuleParams{
Colin Cross7d21c442015-03-30 17:47:53 -070055 Command: "$ldCmd ${ldDirFlags} ${crtBegin} @${out}.rsp " +
Colin Cross28344522015-04-22 13:07:53 -070056 "${libFlags} ${crtEnd} -o ${out} ${ldFlags}",
Dan Willemsenc94a7682015-11-17 15:27:28 -080057 CommandDeps: []string{"$ldCmd"},
Colin Cross7d21c442015-03-30 17:47:53 -070058 Description: "ld $out",
59 Rspfile: "${out}.rsp",
60 RspfileContent: "${in}",
Colin Cross3f40fa42015-01-30 17:27:36 -080061 },
Colin Cross28344522015-04-22 13:07:53 -070062 "ldCmd", "ldDirFlags", "crtBegin", "libFlags", "crtEnd", "ldFlags")
Colin Cross3f40fa42015-01-30 17:27:36 -080063
64 partialLd = pctx.StaticRule("partialLd",
65 blueprint.RuleParams{
66 Command: "$ldCmd -r ${in} -o ${out}",
Dan Willemsenc94a7682015-11-17 15:27:28 -080067 CommandDeps: []string{"$ldCmd"},
Colin Cross3f40fa42015-01-30 17:27:36 -080068 Description: "partialLd $out",
69 },
70 "ldCmd")
71
72 ar = pctx.StaticRule("ar",
73 blueprint.RuleParams{
Colin Cross7d21c442015-03-30 17:47:53 -070074 Command: "rm -f ${out} && $arCmd $arFlags $out @${out}.rsp",
Dan Willemsenc94a7682015-11-17 15:27:28 -080075 CommandDeps: []string{"$arCmd"},
Colin Cross7d21c442015-03-30 17:47:53 -070076 Description: "ar $out",
77 Rspfile: "${out}.rsp",
78 RspfileContent: "${in}",
Colin Cross3f40fa42015-01-30 17:27:36 -080079 },
80 "arCmd", "arFlags")
81
Colin Cross0af4b842015-04-30 16:36:18 -070082 darwinAr = pctx.StaticRule("darwinAr",
83 blueprint.RuleParams{
84 Command: "rm -f ${out} && $arCmd $arFlags $out $in",
Dan Willemsenc94a7682015-11-17 15:27:28 -080085 CommandDeps: []string{"$arCmd"},
Colin Cross0af4b842015-04-30 16:36:18 -070086 Description: "ar $out",
87 },
88 "arCmd", "arFlags")
89
90 darwinAppendAr = pctx.StaticRule("darwinAppendAr",
91 blueprint.RuleParams{
92 Command: "cp -f ${inAr} ${out}.tmp && $arCmd $arFlags ${out}.tmp $in && mv ${out}.tmp ${out}",
Dan Willemsenc94a7682015-11-17 15:27:28 -080093 CommandDeps: []string{"$arCmd"},
Colin Cross0af4b842015-04-30 16:36:18 -070094 Description: "ar $out",
95 },
96 "arCmd", "arFlags", "inAr")
97
Colin Crossbfae8852015-03-26 14:44:11 -070098 prefixSymbols = pctx.StaticRule("prefixSymbols",
99 blueprint.RuleParams{
100 Command: "$objcopyCmd --prefix-symbols=${prefix} ${in} ${out}",
Dan Willemsenc94a7682015-11-17 15:27:28 -0800101 CommandDeps: []string{"$objcopyCmd"},
Colin Crossbfae8852015-03-26 14:44:11 -0700102 Description: "prefixSymbols $out",
103 },
104 "objcopyCmd", "prefix")
105
Colin Cross3f40fa42015-01-30 17:27:36 -0800106 copyGccLibPath = pctx.StaticVariable("copyGccLibPath", "${SrcDir}/build/soong/copygcclib.sh")
107
108 copyGccLib = pctx.StaticRule("copyGccLib",
109 blueprint.RuleParams{
110 Depfile: "${out}.d",
111 Deps: blueprint.DepsGCC,
112 Command: "$copyGccLibPath $out $ccCmd $cFlags -print-file-name=${libName}",
Dan Willemsenc94a7682015-11-17 15:27:28 -0800113 CommandDeps: []string{"$copyGccLibPath", "$ccCmd"},
Colin Cross3f40fa42015-01-30 17:27:36 -0800114 Description: "copy gcc $out",
115 },
116 "ccCmd", "cFlags", "libName")
117)
118
Dan Willemsen322a0a62015-11-17 15:19:46 -0800119func init() {
120 // We run gcc/clang with PWD=/proc/self/cwd to remove $TOP from the
121 // debug output. That way two builds in two different directories will
122 // create the same output.
123 if runtime.GOOS != "darwin" {
124 pctx.StaticVariable("relPwd", "PWD=/proc/self/cwd")
125 } else {
126 // Darwin doesn't have /proc
127 pctx.StaticVariable("relPwd", "")
128 }
129}
130
Colin Cross3f40fa42015-01-30 17:27:36 -0800131type builderFlags struct {
132 globalFlags string
133 asFlags string
134 cFlags string
135 conlyFlags string
136 cppFlags string
137 ldFlags string
Colin Cross581c1892015-04-07 16:50:10 -0700138 yaccFlags string
Colin Cross3f40fa42015-01-30 17:27:36 -0800139 nocrt bool
Colin Cross97ba0732015-03-23 17:50:24 -0700140 toolchain Toolchain
Colin Cross3f40fa42015-01-30 17:27:36 -0800141 clang bool
142}
143
144// Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files
145func TransformSourceToObj(ctx common.AndroidModuleContext, subdir string, srcFiles []string,
Colin Cross581c1892015-04-07 16:50:10 -0700146 flags builderFlags, deps []string) (objFiles []string) {
147
Colin Cross1332b002015-04-07 17:11:30 -0700148 srcRoot := ctx.AConfig().SrcDir()
149 intermediatesRoot := ctx.AConfig().IntermediatesDir()
Colin Cross3f40fa42015-01-30 17:27:36 -0800150
151 objFiles = make([]string, len(srcFiles))
152 objDir := common.ModuleObjDir(ctx)
153 if subdir != "" {
154 objDir = filepath.Join(objDir, subdir)
155 }
156
157 cflags := flags.globalFlags + " " + flags.cFlags + " " + flags.conlyFlags
158 cppflags := flags.globalFlags + " " + flags.cFlags + " " + flags.cppFlags
159 asflags := flags.globalFlags + " " + flags.asFlags
160
161 for i, srcFile := range srcFiles {
Colin Cross581c1892015-04-07 16:50:10 -0700162 var objFile string
Dan Willemsen87b17d12015-07-14 00:39:06 -0700163 if strings.HasPrefix(srcFile, intermediatesRoot) {
Colin Cross581c1892015-04-07 16:50:10 -0700164 objFile = strings.TrimPrefix(srcFile, intermediatesRoot)
165 objFile = filepath.Join(objDir, "gen", objFile)
Dan Willemsen87b17d12015-07-14 00:39:06 -0700166 } else if strings.HasPrefix(srcFile, srcRoot) {
167 srcFile, _ = filepath.Rel(srcRoot, srcFile)
168 objFile = filepath.Join(objDir, srcFile)
169 } else if srcRoot == "." && srcFile[0] != '/' {
170 objFile = filepath.Join(objDir, srcFile)
Colin Cross581c1892015-04-07 16:50:10 -0700171 } else {
172 ctx.ModuleErrorf("source file %q is not in source directory %q", srcFile, srcRoot)
173 continue
174 }
175
Colin Cross3f40fa42015-01-30 17:27:36 -0800176 objFile = pathtools.ReplaceExtension(objFile, "o")
177
178 objFiles[i] = objFile
179
180 var moduleCflags string
181 var ccCmd string
182
183 switch filepath.Ext(srcFile) {
184 case ".S", ".s":
185 ccCmd = "gcc"
186 moduleCflags = asflags
187 case ".c":
188 ccCmd = "gcc"
189 moduleCflags = cflags
190 case ".cpp", ".cc":
191 ccCmd = "g++"
192 moduleCflags = cppflags
193 default:
194 ctx.ModuleErrorf("File %s has unknown extension", srcFile)
195 continue
196 }
197
198 if flags.clang {
199 switch ccCmd {
200 case "gcc":
201 ccCmd = "clang"
202 case "g++":
203 ccCmd = "clang++"
204 default:
205 panic("unrecoginzied ccCmd")
206 }
207
208 ccCmd = "${clangPath}" + ccCmd
209 } else {
210 ccCmd = gccCmd(flags.toolchain, ccCmd)
211 }
212
213 ctx.Build(pctx, blueprint.BuildParams{
214 Rule: cc,
215 Outputs: []string{objFile},
216 Inputs: []string{srcFile},
Dan Willemsenc94a7682015-11-17 15:27:28 -0800217 Implicits: deps,
Colin Cross3f40fa42015-01-30 17:27:36 -0800218 Args: map[string]string{
Colin Cross28344522015-04-22 13:07:53 -0700219 "cFlags": moduleCflags,
220 "ccCmd": ccCmd,
Colin Cross3f40fa42015-01-30 17:27:36 -0800221 },
222 })
223 }
224
225 return objFiles
226}
227
228// Generate a rule for compiling multiple .o files to a static library (.a)
229func TransformObjToStaticLib(ctx common.AndroidModuleContext, objFiles []string,
230 flags builderFlags, outputFile string) {
231
232 arCmd := gccCmd(flags.toolchain, "ar")
233 arFlags := "crsPD"
234
235 ctx.Build(pctx, blueprint.BuildParams{
Dan Willemsenc94a7682015-11-17 15:27:28 -0800236 Rule: ar,
237 Outputs: []string{outputFile},
238 Inputs: objFiles,
Colin Cross3f40fa42015-01-30 17:27:36 -0800239 Args: map[string]string{
240 "arFlags": arFlags,
241 "arCmd": arCmd,
242 },
243 })
244}
245
Colin Cross0af4b842015-04-30 16:36:18 -0700246// Generate a rule for compiling multiple .o files to a static library (.a) on
247// darwin. The darwin ar tool doesn't support @file for list files, and has a
248// very small command line length limit, so we have to split the ar into multiple
249// steps, each appending to the previous one.
250func TransformDarwinObjToStaticLib(ctx common.AndroidModuleContext, objFiles []string,
251 flags builderFlags, outputFile string) {
252
253 arCmd := "ar"
254 arFlags := "cqs"
255
256 // ARG_MAX on darwin is 262144, use half that to be safe
257 objFilesLists, err := splitListForSize(objFiles, 131072)
258 if err != nil {
259 ctx.ModuleErrorf("%s", err.Error())
260 }
261
262 var in, out string
263 for i, l := range objFilesLists {
264 in = out
265 out = outputFile
266 if i != len(objFilesLists)-1 {
267 out += "." + strconv.Itoa(i)
268 }
269
270 if in == "" {
271 ctx.Build(pctx, blueprint.BuildParams{
272 Rule: darwinAr,
273 Outputs: []string{out},
274 Inputs: l,
275 Args: map[string]string{
276 "arFlags": arFlags,
277 "arCmd": arCmd,
278 },
279 })
280 } else {
281 ctx.Build(pctx, blueprint.BuildParams{
282 Rule: darwinAppendAr,
283 Outputs: []string{out},
284 Inputs: l,
285 Implicits: []string{in},
286 Args: map[string]string{
287 "arFlags": arFlags,
288 "arCmd": arCmd,
289 "inAr": in,
290 },
291 })
292 }
293 }
294}
295
Colin Cross3f40fa42015-01-30 17:27:36 -0800296// Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries,
297// and shared libraires, to a shared library (.so) or dynamic executable
298func TransformObjToDynamicBinary(ctx common.AndroidModuleContext,
Colin Crossaee540a2015-07-06 17:48:31 -0700299 objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps []string,
Colin Crossed4cf0b2015-03-26 14:43:45 -0700300 crtBegin, crtEnd string, groupLate bool, flags builderFlags, outputFile string) {
Colin Cross3f40fa42015-01-30 17:27:36 -0800301
302 var ldCmd string
303 if flags.clang {
304 ldCmd = "${clangPath}clang++"
305 } else {
306 ldCmd = gccCmd(flags.toolchain, "g++")
307 }
308
309 var ldDirs []string
310 var libFlagsList []string
311
312 if len(wholeStaticLibs) > 0 {
Colin Cross0af4b842015-04-30 16:36:18 -0700313 if ctx.Host() && runtime.GOOS == "darwin" {
314 libFlagsList = append(libFlagsList, common.JoinWithPrefix(wholeStaticLibs, "-force_load "))
315 } else {
316 libFlagsList = append(libFlagsList, "-Wl,--whole-archive ")
317 libFlagsList = append(libFlagsList, wholeStaticLibs...)
318 libFlagsList = append(libFlagsList, "-Wl,--no-whole-archive ")
319 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800320 }
321
322 libFlagsList = append(libFlagsList, staticLibs...)
323
Dan Willemsenedc385f2015-07-08 13:02:23 -0700324 if groupLate && len(lateStaticLibs) > 0 {
325 libFlagsList = append(libFlagsList, "-Wl,--start-group")
326 }
327 libFlagsList = append(libFlagsList, lateStaticLibs...)
328 if groupLate && len(lateStaticLibs) > 0 {
329 libFlagsList = append(libFlagsList, "-Wl,--end-group")
330 }
331
Colin Cross3f40fa42015-01-30 17:27:36 -0800332 for _, lib := range sharedLibs {
333 dir, file := filepath.Split(lib)
334 if !strings.HasPrefix(file, "lib") {
335 panic("shared library " + lib + " does not start with lib")
336 }
337 if !strings.HasSuffix(file, sharedLibraryExtension) {
338 panic("shared library " + lib + " does not end with " + sharedLibraryExtension)
339 }
340 libFlagsList = append(libFlagsList,
341 "-l"+strings.TrimSuffix(strings.TrimPrefix(file, "lib"), sharedLibraryExtension))
342 ldDirs = append(ldDirs, dir)
343 }
344
Colin Cross3f40fa42015-01-30 17:27:36 -0800345 deps = append(deps, sharedLibs...)
346 deps = append(deps, staticLibs...)
Colin Cross3075ad02015-03-17 10:47:08 -0700347 deps = append(deps, lateStaticLibs...)
Colin Cross3f40fa42015-01-30 17:27:36 -0800348 deps = append(deps, wholeStaticLibs...)
349 if crtBegin != "" {
350 deps = append(deps, crtBegin, crtEnd)
351 }
352
353 ctx.Build(pctx, blueprint.BuildParams{
354 Rule: ld,
355 Outputs: []string{outputFile},
356 Inputs: objFiles,
357 Implicits: deps,
358 Args: map[string]string{
359 "ldCmd": ldCmd,
360 "ldDirFlags": ldDirsToFlags(ldDirs),
361 "crtBegin": crtBegin,
362 "libFlags": strings.Join(libFlagsList, " "),
363 "ldFlags": flags.ldFlags,
364 "crtEnd": crtEnd,
Colin Cross3f40fa42015-01-30 17:27:36 -0800365 },
366 })
367}
368
369// Generate a rule for compiling multiple .o files to a .o using ld partial linking
370func TransformObjsToObj(ctx common.AndroidModuleContext, objFiles []string,
371 flags builderFlags, outputFile string) {
372
373 ldCmd := gccCmd(flags.toolchain, "ld")
374
Colin Cross3f40fa42015-01-30 17:27:36 -0800375 ctx.Build(pctx, blueprint.BuildParams{
Dan Willemsenc94a7682015-11-17 15:27:28 -0800376 Rule: partialLd,
377 Outputs: []string{outputFile},
378 Inputs: objFiles,
Colin Cross3f40fa42015-01-30 17:27:36 -0800379 Args: map[string]string{
380 "ldCmd": ldCmd,
381 },
382 })
383}
384
Colin Crossbfae8852015-03-26 14:44:11 -0700385// Generate a rule for runing objcopy --prefix-symbols on a binary
386func TransformBinaryPrefixSymbols(ctx common.AndroidModuleContext, prefix string, inputFile string,
387 flags builderFlags, outputFile string) {
388
389 objcopyCmd := gccCmd(flags.toolchain, "objcopy")
390
391 ctx.Build(pctx, blueprint.BuildParams{
Dan Willemsenc94a7682015-11-17 15:27:28 -0800392 Rule: prefixSymbols,
393 Outputs: []string{outputFile},
394 Inputs: []string{inputFile},
Colin Crossbfae8852015-03-26 14:44:11 -0700395 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},
Colin Cross3f40fa42015-01-30 17:27:36 -0800408 Args: map[string]string{
409 "ccCmd": gccCmd(flags.toolchain, "gcc"),
410 "cFlags": flags.globalFlags,
411 "libName": libName,
412 },
413 })
414}
415
Colin Cross97ba0732015-03-23 17:50:24 -0700416func gccCmd(toolchain Toolchain, cmd string) string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800417 return filepath.Join(toolchain.GccRoot(), "bin", toolchain.GccTriple()+"-"+cmd)
418}
Colin Cross0af4b842015-04-30 16:36:18 -0700419
420func splitListForSize(list []string, limit int) (lists [][]string, err error) {
421 var i int
422
423 start := 0
424 bytes := 0
425 for i = range list {
426 l := len(list[i])
427 if l > limit {
428 return nil, fmt.Errorf("list element greater than size limit (%d)", limit)
429 }
430 if bytes+l > limit {
431 lists = append(lists, list[start:i])
432 start = i
433 bytes = 0
434 }
435 bytes += l + 1 // count a space between each list element
436 }
437
438 lists = append(lists, list[start:])
439
440 totalLen := 0
441 for _, l := range lists {
442 totalLen += len(l)
443 }
444 if totalLen != len(list) {
445 panic(fmt.Errorf("Failed breaking up list, %d != %d", len(list), totalLen))
446 }
447 return lists, nil
448}