blob: 64437d2821ad5ffad8d4fbbf90de7e5c3a31883f [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 staticLibraryExtension = ".a"
37)
38
39var (
40 pctx = blueprint.NewPackageContext("android/soong/cc")
41
42 cc = pctx.StaticRule("cc",
43 blueprint.RuleParams{
44 Depfile: "${out}.d",
45 Deps: blueprint.DepsGCC,
Dan Willemsene6540452015-10-20 15:21:33 -070046 Command: "$relPwd $ccCmd -c $cFlags -MD -MF ${out}.d -o $out $in",
Dan Willemsenc94a7682015-11-17 15:27:28 -080047 CommandDeps: []string{"$ccCmd"},
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}",
Dan Willemsenc94a7682015-11-17 15:27:28 -080056 CommandDeps: []string{"$ldCmd"},
Colin Cross7d21c442015-03-30 17:47:53 -070057 Description: "ld $out",
58 Rspfile: "${out}.rsp",
59 RspfileContent: "${in}",
Colin Cross3f40fa42015-01-30 17:27:36 -080060 },
Colin Cross28344522015-04-22 13:07:53 -070061 "ldCmd", "ldDirFlags", "crtBegin", "libFlags", "crtEnd", "ldFlags")
Colin Cross3f40fa42015-01-30 17:27:36 -080062
63 partialLd = pctx.StaticRule("partialLd",
64 blueprint.RuleParams{
Colin Cross41280a42015-11-23 14:01:42 -080065 Command: "$ldCmd -nostdlib -Wl,-r ${in} -o ${out} ${ldFlags}",
Dan Willemsenc94a7682015-11-17 15:27:28 -080066 CommandDeps: []string{"$ldCmd"},
Colin Cross3f40fa42015-01-30 17:27:36 -080067 Description: "partialLd $out",
68 },
Colin Cross41280a42015-11-23 14:01:42 -080069 "ldCmd", "ldFlags")
Colin Cross3f40fa42015-01-30 17:27:36 -080070
71 ar = pctx.StaticRule("ar",
72 blueprint.RuleParams{
Colin Cross7d21c442015-03-30 17:47:53 -070073 Command: "rm -f ${out} && $arCmd $arFlags $out @${out}.rsp",
Dan Willemsenc94a7682015-11-17 15:27:28 -080074 CommandDeps: []string{"$arCmd"},
Colin Cross7d21c442015-03-30 17:47:53 -070075 Description: "ar $out",
76 Rspfile: "${out}.rsp",
77 RspfileContent: "${in}",
Colin Cross3f40fa42015-01-30 17:27:36 -080078 },
79 "arCmd", "arFlags")
80
Colin Cross0af4b842015-04-30 16:36:18 -070081 darwinAr = pctx.StaticRule("darwinAr",
82 blueprint.RuleParams{
83 Command: "rm -f ${out} && $arCmd $arFlags $out $in",
Dan Willemsenc94a7682015-11-17 15:27:28 -080084 CommandDeps: []string{"$arCmd"},
Colin Cross0af4b842015-04-30 16:36:18 -070085 Description: "ar $out",
86 },
87 "arCmd", "arFlags")
88
89 darwinAppendAr = pctx.StaticRule("darwinAppendAr",
90 blueprint.RuleParams{
91 Command: "cp -f ${inAr} ${out}.tmp && $arCmd $arFlags ${out}.tmp $in && mv ${out}.tmp ${out}",
Dan Willemsenc94a7682015-11-17 15:27:28 -080092 CommandDeps: []string{"$arCmd"},
Colin Cross0af4b842015-04-30 16:36:18 -070093 Description: "ar $out",
94 },
95 "arCmd", "arFlags", "inAr")
96
Colin Crossbfae8852015-03-26 14:44:11 -070097 prefixSymbols = pctx.StaticRule("prefixSymbols",
98 blueprint.RuleParams{
99 Command: "$objcopyCmd --prefix-symbols=${prefix} ${in} ${out}",
Dan Willemsenc94a7682015-11-17 15:27:28 -0800100 CommandDeps: []string{"$objcopyCmd"},
Colin Crossbfae8852015-03-26 14:44:11 -0700101 Description: "prefixSymbols $out",
102 },
103 "objcopyCmd", "prefix")
104
Colin Cross3f40fa42015-01-30 17:27:36 -0800105 copyGccLibPath = pctx.StaticVariable("copyGccLibPath", "${SrcDir}/build/soong/copygcclib.sh")
106
107 copyGccLib = pctx.StaticRule("copyGccLib",
108 blueprint.RuleParams{
109 Depfile: "${out}.d",
110 Deps: blueprint.DepsGCC,
111 Command: "$copyGccLibPath $out $ccCmd $cFlags -print-file-name=${libName}",
Dan Willemsenc94a7682015-11-17 15:27:28 -0800112 CommandDeps: []string{"$copyGccLibPath", "$ccCmd"},
Colin Cross3f40fa42015-01-30 17:27:36 -0800113 Description: "copy gcc $out",
114 },
115 "ccCmd", "cFlags", "libName")
116)
117
Dan Willemsen322a0a62015-11-17 15:19:46 -0800118func init() {
119 // We run gcc/clang with PWD=/proc/self/cwd to remove $TOP from the
120 // debug output. That way two builds in two different directories will
121 // create the same output.
122 if runtime.GOOS != "darwin" {
123 pctx.StaticVariable("relPwd", "PWD=/proc/self/cwd")
124 } else {
125 // Darwin doesn't have /proc
126 pctx.StaticVariable("relPwd", "")
127 }
128}
129
Colin Cross3f40fa42015-01-30 17:27:36 -0800130type builderFlags struct {
131 globalFlags string
132 asFlags string
133 cFlags string
134 conlyFlags string
135 cppFlags string
136 ldFlags string
Colin Cross581c1892015-04-07 16:50:10 -0700137 yaccFlags string
Colin Cross3f40fa42015-01-30 17:27:36 -0800138 nocrt bool
Colin Cross97ba0732015-03-23 17:50:24 -0700139 toolchain Toolchain
Colin Cross3f40fa42015-01-30 17:27:36 -0800140 clang bool
141}
142
143// Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files
144func TransformSourceToObj(ctx common.AndroidModuleContext, subdir string, srcFiles []string,
Colin Cross581c1892015-04-07 16:50:10 -0700145 flags builderFlags, deps []string) (objFiles []string) {
146
Colin Cross1332b002015-04-07 17:11:30 -0700147 srcRoot := ctx.AConfig().SrcDir()
148 intermediatesRoot := ctx.AConfig().IntermediatesDir()
Colin Cross3f40fa42015-01-30 17:27:36 -0800149
150 objFiles = make([]string, len(srcFiles))
151 objDir := common.ModuleObjDir(ctx)
152 if subdir != "" {
153 objDir = filepath.Join(objDir, subdir)
154 }
155
156 cflags := flags.globalFlags + " " + flags.cFlags + " " + flags.conlyFlags
157 cppflags := flags.globalFlags + " " + flags.cFlags + " " + flags.cppFlags
158 asflags := flags.globalFlags + " " + flags.asFlags
159
160 for i, srcFile := range srcFiles {
Colin Cross581c1892015-04-07 16:50:10 -0700161 var objFile string
Dan Willemsen87b17d12015-07-14 00:39:06 -0700162 if strings.HasPrefix(srcFile, intermediatesRoot) {
Colin Cross581c1892015-04-07 16:50:10 -0700163 objFile = strings.TrimPrefix(srcFile, intermediatesRoot)
164 objFile = filepath.Join(objDir, "gen", objFile)
Dan Willemsen87b17d12015-07-14 00:39:06 -0700165 } else if strings.HasPrefix(srcFile, srcRoot) {
166 srcFile, _ = filepath.Rel(srcRoot, srcFile)
167 objFile = filepath.Join(objDir, srcFile)
168 } else if srcRoot == "." && srcFile[0] != '/' {
169 objFile = filepath.Join(objDir, srcFile)
Colin Cross581c1892015-04-07 16:50:10 -0700170 } else {
171 ctx.ModuleErrorf("source file %q is not in source directory %q", srcFile, srcRoot)
172 continue
173 }
174
Colin Cross3f40fa42015-01-30 17:27:36 -0800175 objFile = pathtools.ReplaceExtension(objFile, "o")
176
177 objFiles[i] = objFile
178
179 var moduleCflags string
180 var ccCmd string
181
182 switch filepath.Ext(srcFile) {
183 case ".S", ".s":
184 ccCmd = "gcc"
185 moduleCflags = asflags
186 case ".c":
187 ccCmd = "gcc"
188 moduleCflags = cflags
189 case ".cpp", ".cc":
190 ccCmd = "g++"
191 moduleCflags = cppflags
192 default:
193 ctx.ModuleErrorf("File %s has unknown extension", srcFile)
194 continue
195 }
196
197 if flags.clang {
198 switch ccCmd {
199 case "gcc":
200 ccCmd = "clang"
201 case "g++":
202 ccCmd = "clang++"
203 default:
204 panic("unrecoginzied ccCmd")
205 }
206
207 ccCmd = "${clangPath}" + ccCmd
208 } else {
209 ccCmd = gccCmd(flags.toolchain, ccCmd)
210 }
211
212 ctx.Build(pctx, blueprint.BuildParams{
213 Rule: cc,
214 Outputs: []string{objFile},
215 Inputs: []string{srcFile},
Dan Willemsenc94a7682015-11-17 15:27:28 -0800216 Implicits: deps,
Colin Cross3f40fa42015-01-30 17:27:36 -0800217 Args: map[string]string{
Colin Cross28344522015-04-22 13:07:53 -0700218 "cFlags": moduleCflags,
219 "ccCmd": ccCmd,
Colin Cross3f40fa42015-01-30 17:27:36 -0800220 },
221 })
222 }
223
224 return objFiles
225}
226
227// Generate a rule for compiling multiple .o files to a static library (.a)
228func TransformObjToStaticLib(ctx common.AndroidModuleContext, objFiles []string,
229 flags builderFlags, outputFile string) {
230
231 arCmd := gccCmd(flags.toolchain, "ar")
232 arFlags := "crsPD"
233
234 ctx.Build(pctx, blueprint.BuildParams{
Dan Willemsenc94a7682015-11-17 15:27:28 -0800235 Rule: ar,
236 Outputs: []string{outputFile},
237 Inputs: objFiles,
Colin Cross3f40fa42015-01-30 17:27:36 -0800238 Args: map[string]string{
239 "arFlags": arFlags,
240 "arCmd": arCmd,
241 },
242 })
243}
244
Colin Cross0af4b842015-04-30 16:36:18 -0700245// Generate a rule for compiling multiple .o files to a static library (.a) on
246// darwin. The darwin ar tool doesn't support @file for list files, and has a
247// very small command line length limit, so we have to split the ar into multiple
248// steps, each appending to the previous one.
249func TransformDarwinObjToStaticLib(ctx common.AndroidModuleContext, objFiles []string,
250 flags builderFlags, outputFile string) {
251
252 arCmd := "ar"
253 arFlags := "cqs"
254
255 // ARG_MAX on darwin is 262144, use half that to be safe
256 objFilesLists, err := splitListForSize(objFiles, 131072)
257 if err != nil {
258 ctx.ModuleErrorf("%s", err.Error())
259 }
260
261 var in, out string
262 for i, l := range objFilesLists {
263 in = out
264 out = outputFile
265 if i != len(objFilesLists)-1 {
266 out += "." + strconv.Itoa(i)
267 }
268
269 if in == "" {
270 ctx.Build(pctx, blueprint.BuildParams{
271 Rule: darwinAr,
272 Outputs: []string{out},
273 Inputs: l,
274 Args: map[string]string{
275 "arFlags": arFlags,
276 "arCmd": arCmd,
277 },
278 })
279 } else {
280 ctx.Build(pctx, blueprint.BuildParams{
281 Rule: darwinAppendAr,
282 Outputs: []string{out},
283 Inputs: l,
284 Implicits: []string{in},
285 Args: map[string]string{
286 "arFlags": arFlags,
287 "arCmd": arCmd,
288 "inAr": in,
289 },
290 })
291 }
292 }
293}
294
Colin Cross3f40fa42015-01-30 17:27:36 -0800295// Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries,
296// and shared libraires, to a shared library (.so) or dynamic executable
297func TransformObjToDynamicBinary(ctx common.AndroidModuleContext,
Colin Crossaee540a2015-07-06 17:48:31 -0700298 objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps []string,
Colin Crossed4cf0b2015-03-26 14:43:45 -0700299 crtBegin, crtEnd string, groupLate bool, flags builderFlags, outputFile string) {
Colin Cross3f40fa42015-01-30 17:27:36 -0800300
301 var ldCmd string
302 if flags.clang {
303 ldCmd = "${clangPath}clang++"
304 } else {
305 ldCmd = gccCmd(flags.toolchain, "g++")
306 }
307
308 var ldDirs []string
309 var libFlagsList []string
310
311 if len(wholeStaticLibs) > 0 {
Dan Willemsen490fd492015-11-24 17:53:15 -0800312 if ctx.Host() && ctx.Darwin() {
Colin Cross0af4b842015-04-30 16:36:18 -0700313 libFlagsList = append(libFlagsList, common.JoinWithPrefix(wholeStaticLibs, "-force_load "))
314 } else {
315 libFlagsList = append(libFlagsList, "-Wl,--whole-archive ")
316 libFlagsList = append(libFlagsList, wholeStaticLibs...)
317 libFlagsList = append(libFlagsList, "-Wl,--no-whole-archive ")
318 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800319 }
320
321 libFlagsList = append(libFlagsList, staticLibs...)
322
Dan Willemsenedc385f2015-07-08 13:02:23 -0700323 if groupLate && len(lateStaticLibs) > 0 {
324 libFlagsList = append(libFlagsList, "-Wl,--start-group")
325 }
326 libFlagsList = append(libFlagsList, lateStaticLibs...)
327 if groupLate && len(lateStaticLibs) > 0 {
328 libFlagsList = append(libFlagsList, "-Wl,--end-group")
329 }
330
Colin Cross3f40fa42015-01-30 17:27:36 -0800331 for _, lib := range sharedLibs {
332 dir, file := filepath.Split(lib)
333 if !strings.HasPrefix(file, "lib") {
334 panic("shared library " + lib + " does not start with lib")
335 }
Dan Willemsen490fd492015-11-24 17:53:15 -0800336 if !strings.HasSuffix(file, flags.toolchain.ShlibSuffix()) {
337 panic("shared library " + lib + " does not end with " + flags.toolchain.ShlibSuffix())
Colin Cross3f40fa42015-01-30 17:27:36 -0800338 }
339 libFlagsList = append(libFlagsList,
Dan Willemsen490fd492015-11-24 17:53:15 -0800340 "-l"+strings.TrimSuffix(strings.TrimPrefix(file, "lib"), flags.toolchain.ShlibSuffix()))
Colin Cross3f40fa42015-01-30 17:27:36 -0800341 ldDirs = append(ldDirs, dir)
342 }
343
Colin Cross3f40fa42015-01-30 17:27:36 -0800344 deps = append(deps, sharedLibs...)
345 deps = append(deps, staticLibs...)
Colin Cross3075ad02015-03-17 10:47:08 -0700346 deps = append(deps, lateStaticLibs...)
Colin Cross3f40fa42015-01-30 17:27:36 -0800347 deps = append(deps, wholeStaticLibs...)
348 if crtBegin != "" {
349 deps = append(deps, crtBegin, crtEnd)
350 }
351
352 ctx.Build(pctx, blueprint.BuildParams{
353 Rule: ld,
354 Outputs: []string{outputFile},
355 Inputs: objFiles,
356 Implicits: deps,
357 Args: map[string]string{
358 "ldCmd": ldCmd,
359 "ldDirFlags": ldDirsToFlags(ldDirs),
360 "crtBegin": crtBegin,
361 "libFlags": strings.Join(libFlagsList, " "),
362 "ldFlags": flags.ldFlags,
363 "crtEnd": crtEnd,
Colin Cross3f40fa42015-01-30 17:27:36 -0800364 },
365 })
366}
367
368// Generate a rule for compiling multiple .o files to a .o using ld partial linking
369func TransformObjsToObj(ctx common.AndroidModuleContext, objFiles []string,
370 flags builderFlags, outputFile string) {
371
Colin Cross41280a42015-11-23 14:01:42 -0800372 var ldCmd string
373 if flags.clang {
374 ldCmd = "${clangPath}clang++"
375 } else {
376 ldCmd = gccCmd(flags.toolchain, "g++")
377 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800378
Colin Cross3f40fa42015-01-30 17:27:36 -0800379 ctx.Build(pctx, blueprint.BuildParams{
Dan Willemsenc94a7682015-11-17 15:27:28 -0800380 Rule: partialLd,
381 Outputs: []string{outputFile},
382 Inputs: objFiles,
Colin Cross3f40fa42015-01-30 17:27:36 -0800383 Args: map[string]string{
384 "ldCmd": ldCmd,
Colin Cross41280a42015-11-23 14:01:42 -0800385 "ldFlags": flags.ldFlags,
Colin Cross3f40fa42015-01-30 17:27:36 -0800386 },
387 })
388}
389
Colin Crossbfae8852015-03-26 14:44:11 -0700390// Generate a rule for runing objcopy --prefix-symbols on a binary
391func TransformBinaryPrefixSymbols(ctx common.AndroidModuleContext, prefix string, inputFile string,
392 flags builderFlags, outputFile string) {
393
394 objcopyCmd := gccCmd(flags.toolchain, "objcopy")
395
396 ctx.Build(pctx, blueprint.BuildParams{
Dan Willemsenc94a7682015-11-17 15:27:28 -0800397 Rule: prefixSymbols,
398 Outputs: []string{outputFile},
399 Inputs: []string{inputFile},
Colin Crossbfae8852015-03-26 14:44:11 -0700400 Args: map[string]string{
401 "objcopyCmd": objcopyCmd,
402 "prefix": prefix,
403 },
404 })
405}
406
Colin Cross3f40fa42015-01-30 17:27:36 -0800407func CopyGccLib(ctx common.AndroidModuleContext, libName string,
408 flags builderFlags, outputFile string) {
409
410 ctx.Build(pctx, blueprint.BuildParams{
411 Rule: copyGccLib,
412 Outputs: []string{outputFile},
Colin Cross3f40fa42015-01-30 17:27:36 -0800413 Args: map[string]string{
414 "ccCmd": gccCmd(flags.toolchain, "gcc"),
415 "cFlags": flags.globalFlags,
416 "libName": libName,
417 },
418 })
419}
420
Colin Cross97ba0732015-03-23 17:50:24 -0700421func gccCmd(toolchain Toolchain, cmd string) string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800422 return filepath.Join(toolchain.GccRoot(), "bin", toolchain.GccTriple()+"-"+cmd)
423}
Colin Cross0af4b842015-04-30 16:36:18 -0700424
425func splitListForSize(list []string, limit int) (lists [][]string, err error) {
426 var i int
427
428 start := 0
429 bytes := 0
430 for i = range list {
431 l := len(list[i])
432 if l > limit {
433 return nil, fmt.Errorf("list element greater than size limit (%d)", limit)
434 }
435 if bytes+l > limit {
436 lists = append(lists, list[start:i])
437 start = i
438 bytes = 0
439 }
440 bytes += l + 1 // count a space between each list element
441 }
442
443 lists = append(lists, list[start:])
444
445 totalLen := 0
446 for _, l := range lists {
447 totalLen += len(l)
448 }
449 if totalLen != len(list) {
450 panic(fmt.Errorf("Failed breaking up list, %d != %d", len(list), totalLen))
451 }
452 return lists, nil
453}