blob: 98f66d9f18cbc279f9a5fe5ca9e2c8716095fb04 [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"
Colin Cross3f40fa42015-01-30 17:27:36 -080031)
32
33const (
Dan Albertc3144b12015-04-28 18:17:56 -070034 objectExtension = ".o"
Colin Cross3f40fa42015-01-30 17:27:36 -080035 staticLibraryExtension = ".a"
36)
37
38var (
Dan Willemsen34cc69e2015-09-23 15:26:20 -070039 pctx = common.NewPackageContext("android/soong/cc")
Colin Cross3f40fa42015-01-30 17:27:36 -080040
41 cc = pctx.StaticRule("cc",
42 blueprint.RuleParams{
43 Depfile: "${out}.d",
44 Deps: blueprint.DepsGCC,
Dan Willemsene6540452015-10-20 15:21:33 -070045 Command: "$relPwd $ccCmd -c $cFlags -MD -MF ${out}.d -o $out $in",
Dan Willemsenc94a7682015-11-17 15:27:28 -080046 CommandDeps: []string{"$ccCmd"},
Colin Cross3f40fa42015-01-30 17:27:36 -080047 Description: "cc $out",
48 },
Dan Willemsen322a0a62015-11-17 15:19:46 -080049 "ccCmd", "cFlags")
Colin Cross3f40fa42015-01-30 17:27:36 -080050
51 ld = pctx.StaticRule("ld",
52 blueprint.RuleParams{
Colin Cross7d21c442015-03-30 17:47:53 -070053 Command: "$ldCmd ${ldDirFlags} ${crtBegin} @${out}.rsp " +
Colin Cross28344522015-04-22 13:07:53 -070054 "${libFlags} ${crtEnd} -o ${out} ${ldFlags}",
Dan Willemsenc94a7682015-11-17 15:27:28 -080055 CommandDeps: []string{"$ldCmd"},
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{
Colin Cross41280a42015-11-23 14:01:42 -080064 Command: "$ldCmd -nostdlib -Wl,-r ${in} -o ${out} ${ldFlags}",
Dan Willemsenc94a7682015-11-17 15:27:28 -080065 CommandDeps: []string{"$ldCmd"},
Colin Cross3f40fa42015-01-30 17:27:36 -080066 Description: "partialLd $out",
67 },
Colin Cross41280a42015-11-23 14:01:42 -080068 "ldCmd", "ldFlags")
Colin Cross3f40fa42015-01-30 17:27:36 -080069
70 ar = pctx.StaticRule("ar",
71 blueprint.RuleParams{
Colin Cross7d21c442015-03-30 17:47:53 -070072 Command: "rm -f ${out} && $arCmd $arFlags $out @${out}.rsp",
Dan Willemsenc94a7682015-11-17 15:27:28 -080073 CommandDeps: []string{"$arCmd"},
Colin Cross7d21c442015-03-30 17:47:53 -070074 Description: "ar $out",
75 Rspfile: "${out}.rsp",
76 RspfileContent: "${in}",
Colin Cross3f40fa42015-01-30 17:27:36 -080077 },
78 "arCmd", "arFlags")
79
Colin Cross0af4b842015-04-30 16:36:18 -070080 darwinAr = pctx.StaticRule("darwinAr",
81 blueprint.RuleParams{
82 Command: "rm -f ${out} && $arCmd $arFlags $out $in",
Dan Willemsenc94a7682015-11-17 15:27:28 -080083 CommandDeps: []string{"$arCmd"},
Colin Cross0af4b842015-04-30 16:36:18 -070084 Description: "ar $out",
85 },
86 "arCmd", "arFlags")
87
88 darwinAppendAr = pctx.StaticRule("darwinAppendAr",
89 blueprint.RuleParams{
90 Command: "cp -f ${inAr} ${out}.tmp && $arCmd $arFlags ${out}.tmp $in && mv ${out}.tmp ${out}",
Dan Willemsenc94a7682015-11-17 15:27:28 -080091 CommandDeps: []string{"$arCmd"},
Colin Cross0af4b842015-04-30 16:36:18 -070092 Description: "ar $out",
93 },
94 "arCmd", "arFlags", "inAr")
95
Colin Crossbfae8852015-03-26 14:44:11 -070096 prefixSymbols = pctx.StaticRule("prefixSymbols",
97 blueprint.RuleParams{
98 Command: "$objcopyCmd --prefix-symbols=${prefix} ${in} ${out}",
Dan Willemsenc94a7682015-11-17 15:27:28 -080099 CommandDeps: []string{"$objcopyCmd"},
Colin Crossbfae8852015-03-26 14:44:11 -0700100 Description: "prefixSymbols $out",
101 },
102 "objcopyCmd", "prefix")
103
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700104 copyGccLibPath = pctx.SourcePathVariable("copyGccLibPath", "build/soong/copygcclib.sh")
Colin Cross3f40fa42015-01-30 17:27:36 -0800105
106 copyGccLib = pctx.StaticRule("copyGccLib",
107 blueprint.RuleParams{
108 Depfile: "${out}.d",
109 Deps: blueprint.DepsGCC,
110 Command: "$copyGccLibPath $out $ccCmd $cFlags -print-file-name=${libName}",
Dan Willemsenc94a7682015-11-17 15:27:28 -0800111 CommandDeps: []string{"$copyGccLibPath", "$ccCmd"},
Colin Cross3f40fa42015-01-30 17:27:36 -0800112 Description: "copy gcc $out",
113 },
114 "ccCmd", "cFlags", "libName")
115)
116
Dan Willemsen322a0a62015-11-17 15:19:46 -0800117func init() {
118 // We run gcc/clang with PWD=/proc/self/cwd to remove $TOP from the
119 // debug output. That way two builds in two different directories will
120 // create the same output.
121 if runtime.GOOS != "darwin" {
122 pctx.StaticVariable("relPwd", "PWD=/proc/self/cwd")
123 } else {
124 // Darwin doesn't have /proc
125 pctx.StaticVariable("relPwd", "")
126 }
127}
128
Colin Cross3f40fa42015-01-30 17:27:36 -0800129type builderFlags struct {
130 globalFlags string
131 asFlags string
132 cFlags string
133 conlyFlags string
134 cppFlags string
135 ldFlags string
Colin Cross581c1892015-04-07 16:50:10 -0700136 yaccFlags string
Colin Cross3f40fa42015-01-30 17:27:36 -0800137 nocrt bool
Colin Cross97ba0732015-03-23 17:50:24 -0700138 toolchain Toolchain
Colin Cross3f40fa42015-01-30 17:27:36 -0800139 clang bool
140}
141
142// Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700143func TransformSourceToObj(ctx common.AndroidModuleContext, subdir string, srcFiles common.Paths,
144 flags builderFlags, deps common.Paths) (objFiles common.Paths) {
Colin Cross581c1892015-04-07 16:50:10 -0700145
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700146 objFiles = make(common.Paths, len(srcFiles))
Colin Cross3f40fa42015-01-30 17:27:36 -0800147
148 cflags := flags.globalFlags + " " + flags.cFlags + " " + flags.conlyFlags
149 cppflags := flags.globalFlags + " " + flags.cFlags + " " + flags.cppFlags
150 asflags := flags.globalFlags + " " + flags.asFlags
151
152 for i, srcFile := range srcFiles {
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700153 objFile := common.ObjPathWithExt(ctx, srcFile, subdir, "o")
Colin Cross3f40fa42015-01-30 17:27:36 -0800154
155 objFiles[i] = objFile
156
157 var moduleCflags string
158 var ccCmd string
159
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700160 switch srcFile.Ext() {
Colin Cross3f40fa42015-01-30 17:27:36 -0800161 case ".S", ".s":
162 ccCmd = "gcc"
163 moduleCflags = asflags
164 case ".c":
165 ccCmd = "gcc"
166 moduleCflags = cflags
167 case ".cpp", ".cc":
168 ccCmd = "g++"
169 moduleCflags = cppflags
170 default:
171 ctx.ModuleErrorf("File %s has unknown extension", srcFile)
172 continue
173 }
174
175 if flags.clang {
176 switch ccCmd {
177 case "gcc":
178 ccCmd = "clang"
179 case "g++":
180 ccCmd = "clang++"
181 default:
182 panic("unrecoginzied ccCmd")
183 }
184
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700185 ccCmd = "${clangPath}/" + ccCmd
Colin Cross3f40fa42015-01-30 17:27:36 -0800186 } else {
187 ccCmd = gccCmd(flags.toolchain, ccCmd)
188 }
189
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700190 ctx.ModuleBuild(pctx, common.ModuleBuildParams{
Colin Cross3f40fa42015-01-30 17:27:36 -0800191 Rule: cc,
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700192 Output: objFile,
193 Input: srcFile,
Dan Willemsenc94a7682015-11-17 15:27:28 -0800194 Implicits: deps,
Colin Cross3f40fa42015-01-30 17:27:36 -0800195 Args: map[string]string{
Colin Cross28344522015-04-22 13:07:53 -0700196 "cFlags": moduleCflags,
197 "ccCmd": ccCmd,
Colin Cross3f40fa42015-01-30 17:27:36 -0800198 },
199 })
200 }
201
202 return objFiles
203}
204
205// Generate a rule for compiling multiple .o files to a static library (.a)
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700206func TransformObjToStaticLib(ctx common.AndroidModuleContext, objFiles common.Paths,
207 flags builderFlags, outputFile common.ModuleOutPath) {
Colin Cross3f40fa42015-01-30 17:27:36 -0800208
209 arCmd := gccCmd(flags.toolchain, "ar")
210 arFlags := "crsPD"
211
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700212 ctx.ModuleBuild(pctx, common.ModuleBuildParams{
213 Rule: ar,
214 Output: outputFile,
215 Inputs: objFiles,
Colin Cross3f40fa42015-01-30 17:27:36 -0800216 Args: map[string]string{
217 "arFlags": arFlags,
218 "arCmd": arCmd,
219 },
220 })
221}
222
Colin Cross0af4b842015-04-30 16:36:18 -0700223// Generate a rule for compiling multiple .o files to a static library (.a) on
224// darwin. The darwin ar tool doesn't support @file for list files, and has a
225// very small command line length limit, so we have to split the ar into multiple
226// steps, each appending to the previous one.
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700227func TransformDarwinObjToStaticLib(ctx common.AndroidModuleContext, objFiles common.Paths,
228 flags builderFlags, outputPath common.ModuleOutPath) {
Colin Cross0af4b842015-04-30 16:36:18 -0700229
Dan Willemsencf7c71b2015-12-14 20:02:44 -0800230 arCmd := "${macArPath}"
Colin Cross0af4b842015-04-30 16:36:18 -0700231 arFlags := "cqs"
232
233 // ARG_MAX on darwin is 262144, use half that to be safe
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700234 objFilesLists, err := splitListForSize(objFiles.Strings(), 131072)
Colin Cross0af4b842015-04-30 16:36:18 -0700235 if err != nil {
236 ctx.ModuleErrorf("%s", err.Error())
237 }
238
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700239 outputFile := outputPath.String()
240
Colin Cross0af4b842015-04-30 16:36:18 -0700241 var in, out string
242 for i, l := range objFilesLists {
243 in = out
244 out = outputFile
245 if i != len(objFilesLists)-1 {
246 out += "." + strconv.Itoa(i)
247 }
248
249 if in == "" {
250 ctx.Build(pctx, blueprint.BuildParams{
251 Rule: darwinAr,
252 Outputs: []string{out},
253 Inputs: l,
254 Args: map[string]string{
255 "arFlags": arFlags,
256 "arCmd": arCmd,
257 },
258 })
259 } else {
260 ctx.Build(pctx, blueprint.BuildParams{
261 Rule: darwinAppendAr,
262 Outputs: []string{out},
263 Inputs: l,
264 Implicits: []string{in},
265 Args: map[string]string{
266 "arFlags": arFlags,
267 "arCmd": arCmd,
268 "inAr": in,
269 },
270 })
271 }
272 }
273}
274
Colin Cross3f40fa42015-01-30 17:27:36 -0800275// Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries,
276// and shared libraires, to a shared library (.so) or dynamic executable
277func TransformObjToDynamicBinary(ctx common.AndroidModuleContext,
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700278 objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps common.Paths,
279 crtBegin, crtEnd common.OptionalPath, groupLate bool, flags builderFlags, outputFile common.WritablePath) {
Colin Cross3f40fa42015-01-30 17:27:36 -0800280
281 var ldCmd string
282 if flags.clang {
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700283 ldCmd = "${clangPath}/clang++"
Colin Cross3f40fa42015-01-30 17:27:36 -0800284 } else {
285 ldCmd = gccCmd(flags.toolchain, "g++")
286 }
287
288 var ldDirs []string
289 var libFlagsList []string
290
291 if len(wholeStaticLibs) > 0 {
Dan Willemsen490fd492015-11-24 17:53:15 -0800292 if ctx.Host() && ctx.Darwin() {
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700293 libFlagsList = append(libFlagsList, common.JoinWithPrefix(wholeStaticLibs.Strings(), "-force_load "))
Colin Cross0af4b842015-04-30 16:36:18 -0700294 } else {
295 libFlagsList = append(libFlagsList, "-Wl,--whole-archive ")
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700296 libFlagsList = append(libFlagsList, wholeStaticLibs.Strings()...)
Colin Cross0af4b842015-04-30 16:36:18 -0700297 libFlagsList = append(libFlagsList, "-Wl,--no-whole-archive ")
298 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800299 }
300
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700301 libFlagsList = append(libFlagsList, staticLibs.Strings()...)
Colin Cross3f40fa42015-01-30 17:27:36 -0800302
Dan Willemsenedc385f2015-07-08 13:02:23 -0700303 if groupLate && len(lateStaticLibs) > 0 {
304 libFlagsList = append(libFlagsList, "-Wl,--start-group")
305 }
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700306 libFlagsList = append(libFlagsList, lateStaticLibs.Strings()...)
Dan Willemsenedc385f2015-07-08 13:02:23 -0700307 if groupLate && len(lateStaticLibs) > 0 {
308 libFlagsList = append(libFlagsList, "-Wl,--end-group")
309 }
310
Colin Cross3f40fa42015-01-30 17:27:36 -0800311 for _, lib := range sharedLibs {
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700312 dir, file := filepath.Split(lib.String())
Colin Cross3f40fa42015-01-30 17:27:36 -0800313 if !strings.HasPrefix(file, "lib") {
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700314 panic("shared library " + lib.String() + " does not start with lib")
Colin Cross3f40fa42015-01-30 17:27:36 -0800315 }
Dan Willemsen490fd492015-11-24 17:53:15 -0800316 if !strings.HasSuffix(file, flags.toolchain.ShlibSuffix()) {
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700317 panic("shared library " + lib.String() + " does not end with " + flags.toolchain.ShlibSuffix())
Colin Cross3f40fa42015-01-30 17:27:36 -0800318 }
319 libFlagsList = append(libFlagsList,
Dan Willemsen490fd492015-11-24 17:53:15 -0800320 "-l"+strings.TrimSuffix(strings.TrimPrefix(file, "lib"), flags.toolchain.ShlibSuffix()))
Colin Cross3f40fa42015-01-30 17:27:36 -0800321 ldDirs = append(ldDirs, dir)
322 }
323
Colin Cross3f40fa42015-01-30 17:27:36 -0800324 deps = append(deps, sharedLibs...)
325 deps = append(deps, staticLibs...)
Colin Cross3075ad02015-03-17 10:47:08 -0700326 deps = append(deps, lateStaticLibs...)
Colin Cross3f40fa42015-01-30 17:27:36 -0800327 deps = append(deps, wholeStaticLibs...)
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700328 if crtBegin.Valid() {
329 deps = append(deps, crtBegin.Path(), crtEnd.Path())
Colin Cross3f40fa42015-01-30 17:27:36 -0800330 }
331
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700332 ctx.ModuleBuild(pctx, common.ModuleBuildParams{
Colin Cross3f40fa42015-01-30 17:27:36 -0800333 Rule: ld,
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700334 Output: outputFile,
Colin Cross3f40fa42015-01-30 17:27:36 -0800335 Inputs: objFiles,
336 Implicits: deps,
337 Args: map[string]string{
338 "ldCmd": ldCmd,
339 "ldDirFlags": ldDirsToFlags(ldDirs),
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700340 "crtBegin": crtBegin.String(),
Colin Cross3f40fa42015-01-30 17:27:36 -0800341 "libFlags": strings.Join(libFlagsList, " "),
342 "ldFlags": flags.ldFlags,
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700343 "crtEnd": crtEnd.String(),
Colin Cross3f40fa42015-01-30 17:27:36 -0800344 },
345 })
346}
347
348// Generate a rule for compiling multiple .o files to a .o using ld partial linking
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700349func TransformObjsToObj(ctx common.AndroidModuleContext, objFiles common.Paths,
350 flags builderFlags, outputFile common.WritablePath) {
Colin Cross3f40fa42015-01-30 17:27:36 -0800351
Colin Cross41280a42015-11-23 14:01:42 -0800352 var ldCmd string
353 if flags.clang {
354 ldCmd = "${clangPath}clang++"
355 } else {
356 ldCmd = gccCmd(flags.toolchain, "g++")
357 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800358
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700359 ctx.ModuleBuild(pctx, common.ModuleBuildParams{
360 Rule: partialLd,
361 Output: outputFile,
362 Inputs: objFiles,
Colin Cross3f40fa42015-01-30 17:27:36 -0800363 Args: map[string]string{
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700364 "ldCmd": ldCmd,
Colin Cross41280a42015-11-23 14:01:42 -0800365 "ldFlags": flags.ldFlags,
Colin Cross3f40fa42015-01-30 17:27:36 -0800366 },
367 })
368}
369
Colin Crossbfae8852015-03-26 14:44:11 -0700370// Generate a rule for runing objcopy --prefix-symbols on a binary
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700371func TransformBinaryPrefixSymbols(ctx common.AndroidModuleContext, prefix string, inputFile common.Path,
372 flags builderFlags, outputFile common.WritablePath) {
Colin Crossbfae8852015-03-26 14:44:11 -0700373
374 objcopyCmd := gccCmd(flags.toolchain, "objcopy")
375
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700376 ctx.ModuleBuild(pctx, common.ModuleBuildParams{
377 Rule: prefixSymbols,
378 Output: outputFile,
379 Input: inputFile,
Colin Crossbfae8852015-03-26 14:44:11 -0700380 Args: map[string]string{
381 "objcopyCmd": objcopyCmd,
382 "prefix": prefix,
383 },
384 })
385}
386
Colin Cross3f40fa42015-01-30 17:27:36 -0800387func CopyGccLib(ctx common.AndroidModuleContext, libName string,
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700388 flags builderFlags, outputFile common.WritablePath) {
Colin Cross3f40fa42015-01-30 17:27:36 -0800389
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700390 ctx.ModuleBuild(pctx, common.ModuleBuildParams{
391 Rule: copyGccLib,
392 Output: outputFile,
Colin Cross3f40fa42015-01-30 17:27:36 -0800393 Args: map[string]string{
394 "ccCmd": gccCmd(flags.toolchain, "gcc"),
395 "cFlags": flags.globalFlags,
396 "libName": libName,
397 },
398 })
399}
400
Colin Cross97ba0732015-03-23 17:50:24 -0700401func gccCmd(toolchain Toolchain, cmd string) string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800402 return filepath.Join(toolchain.GccRoot(), "bin", toolchain.GccTriple()+"-"+cmd)
403}
Colin Cross0af4b842015-04-30 16:36:18 -0700404
405func splitListForSize(list []string, limit int) (lists [][]string, err error) {
406 var i int
407
408 start := 0
409 bytes := 0
410 for i = range list {
411 l := len(list[i])
412 if l > limit {
413 return nil, fmt.Errorf("list element greater than size limit (%d)", limit)
414 }
415 if bytes+l > limit {
416 lists = append(lists, list[start:i])
417 start = i
418 bytes = 0
419 }
420 bytes += l + 1 // count a space between each list element
421 }
422
423 lists = append(lists, list[start:])
424
425 totalLen := 0
426 for _, l := range lists {
427 totalLen += len(l)
428 }
429 if totalLen != len(list) {
430 panic(fmt.Errorf("Failed breaking up list, %d != %d", len(list), totalLen))
431 }
432 return lists, nil
433}