1// 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" 23 "fmt" 24 "runtime" 25 "strconv" 26 27 "path/filepath" 28 "strings" 29 30 "github.com/google/blueprint" 31) 32 33const ( 34 objectExtension = ".o" 35 staticLibraryExtension = ".a" 36) 37 38var ( 39 pctx = common.NewPackageContext("android/soong/cc") 40 41 cc = pctx.StaticRule("cc", 42 blueprint.RuleParams{ 43 Depfile: "${out}.d", 44 Deps: blueprint.DepsGCC, 45 Command: "$relPwd $ccCmd -c $cFlags -MD -MF ${out}.d -o $out $in", 46 CommandDeps: []string{"$ccCmd"}, 47 Description: "cc $out", 48 }, 49 "ccCmd", "cFlags") 50 51 ld = pctx.StaticRule("ld", 52 blueprint.RuleParams{ 53 Command: "$ldCmd ${ldDirFlags} ${crtBegin} @${out}.rsp " + 54 "${libFlags} ${crtEnd} -o ${out} ${ldFlags}", 55 CommandDeps: []string{"$ldCmd"}, 56 Description: "ld $out", 57 Rspfile: "${out}.rsp", 58 RspfileContent: "${in}", 59 }, 60 "ldCmd", "ldDirFlags", "crtBegin", "libFlags", "crtEnd", "ldFlags") 61 62 partialLd = pctx.StaticRule("partialLd", 63 blueprint.RuleParams{ 64 Command: "$ldCmd -nostdlib -Wl,-r ${in} -o ${out} ${ldFlags}", 65 CommandDeps: []string{"$ldCmd"}, 66 Description: "partialLd $out", 67 }, 68 "ldCmd", "ldFlags") 69 70 ar = pctx.StaticRule("ar", 71 blueprint.RuleParams{ 72 Command: "rm -f ${out} && $arCmd $arFlags $out @${out}.rsp", 73 CommandDeps: []string{"$arCmd"}, 74 Description: "ar $out", 75 Rspfile: "${out}.rsp", 76 RspfileContent: "${in}", 77 }, 78 "arCmd", "arFlags") 79 80 darwinAr = pctx.StaticRule("darwinAr", 81 blueprint.RuleParams{ 82 Command: "rm -f ${out} && $arCmd $arFlags $out $in", 83 CommandDeps: []string{"$arCmd"}, 84 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}", 91 CommandDeps: []string{"$arCmd"}, 92 Description: "ar $out", 93 }, 94 "arCmd", "arFlags", "inAr") 95 96 prefixSymbols = pctx.StaticRule("prefixSymbols", 97 blueprint.RuleParams{ 98 Command: "$objcopyCmd --prefix-symbols=${prefix} ${in} ${out}", 99 CommandDeps: []string{"$objcopyCmd"}, 100 Description: "prefixSymbols $out", 101 }, 102 "objcopyCmd", "prefix") 103 104 copyGccLibPath = pctx.SourcePathVariable("copyGccLibPath", "build/soong/copygcclib.sh") 105 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}", 111 CommandDeps: []string{"$copyGccLibPath", "$ccCmd"}, 112 Description: "copy gcc $out", 113 }, 114 "ccCmd", "cFlags", "libName") 115) 116 117func 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 129type builderFlags struct { 130 globalFlags string 131 asFlags string 132 cFlags string 133 conlyFlags string 134 cppFlags string 135 ldFlags string 136 yaccFlags string 137 nocrt bool 138 toolchain Toolchain 139 clang bool 140} 141 142// Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files 143func TransformSourceToObj(ctx common.AndroidModuleContext, subdir string, srcFiles common.Paths, 144 flags builderFlags, deps common.Paths) (objFiles common.Paths) { 145 146 objFiles = make(common.Paths, len(srcFiles)) 147 148 cflags := flags.globalFlags + " " + flags.cFlags + " " + flags.conlyFlags 149 cppflags := flags.globalFlags + " " + flags.cFlags + " " + flags.cppFlags 150 asflags := flags.globalFlags + " " + flags.asFlags 151 152 if flags.clang { 153 cflags += " ${noOverrideClangGlobalCflags}" 154 cppflags += " ${noOverrideClangGlobalCflags}" 155 } else { 156 cflags += " ${noOverrideGlobalCflags}" 157 cppflags += " ${noOverrideGlobalCflags}" 158 } 159 160 for i, srcFile := range srcFiles { 161 objFile := common.ObjPathWithExt(ctx, srcFile, subdir, "o") 162 163 objFiles[i] = objFile 164 165 var moduleCflags string 166 var ccCmd string 167 168 switch srcFile.Ext() { 169 case ".S", ".s": 170 ccCmd = "gcc" 171 moduleCflags = asflags 172 case ".c": 173 ccCmd = "gcc" 174 moduleCflags = cflags 175 case ".cpp", ".cc": 176 ccCmd = "g++" 177 moduleCflags = cppflags 178 default: 179 ctx.ModuleErrorf("File %s has unknown extension", srcFile) 180 continue 181 } 182 183 if flags.clang { 184 switch ccCmd { 185 case "gcc": 186 ccCmd = "clang" 187 case "g++": 188 ccCmd = "clang++" 189 default: 190 panic("unrecoginzied ccCmd") 191 } 192 193 ccCmd = "${clangPath}/" + ccCmd 194 } else { 195 ccCmd = gccCmd(flags.toolchain, ccCmd) 196 } 197 198 ctx.ModuleBuild(pctx, common.ModuleBuildParams{ 199 Rule: cc, 200 Output: objFile, 201 Input: srcFile, 202 Implicits: deps, 203 Args: map[string]string{ 204 "cFlags": moduleCflags, 205 "ccCmd": ccCmd, 206 }, 207 }) 208 } 209 210 return objFiles 211} 212 213// Generate a rule for compiling multiple .o files to a static library (.a) 214func TransformObjToStaticLib(ctx common.AndroidModuleContext, objFiles common.Paths, 215 flags builderFlags, outputFile common.ModuleOutPath) { 216 217 arCmd := gccCmd(flags.toolchain, "ar") 218 arFlags := "crsPD" 219 220 ctx.ModuleBuild(pctx, common.ModuleBuildParams{ 221 Rule: ar, 222 Output: outputFile, 223 Inputs: objFiles, 224 Args: map[string]string{ 225 "arFlags": arFlags, 226 "arCmd": arCmd, 227 }, 228 }) 229} 230 231// Generate a rule for compiling multiple .o files to a static library (.a) on 232// darwin. The darwin ar tool doesn't support @file for list files, and has a 233// very small command line length limit, so we have to split the ar into multiple 234// steps, each appending to the previous one. 235func TransformDarwinObjToStaticLib(ctx common.AndroidModuleContext, objFiles common.Paths, 236 flags builderFlags, outputPath common.ModuleOutPath) { 237 238 arCmd := "${macArPath}" 239 arFlags := "cqs" 240 241 // ARG_MAX on darwin is 262144, use half that to be safe 242 objFilesLists, err := splitListForSize(objFiles.Strings(), 131072) 243 if err != nil { 244 ctx.ModuleErrorf("%s", err.Error()) 245 } 246 247 outputFile := outputPath.String() 248 249 var in, out string 250 for i, l := range objFilesLists { 251 in = out 252 out = outputFile 253 if i != len(objFilesLists)-1 { 254 out += "." + strconv.Itoa(i) 255 } 256 257 if in == "" { 258 ctx.Build(pctx, blueprint.BuildParams{ 259 Rule: darwinAr, 260 Outputs: []string{out}, 261 Inputs: l, 262 Args: map[string]string{ 263 "arFlags": arFlags, 264 "arCmd": arCmd, 265 }, 266 }) 267 } else { 268 ctx.Build(pctx, blueprint.BuildParams{ 269 Rule: darwinAppendAr, 270 Outputs: []string{out}, 271 Inputs: l, 272 Implicits: []string{in}, 273 Args: map[string]string{ 274 "arFlags": arFlags, 275 "arCmd": arCmd, 276 "inAr": in, 277 }, 278 }) 279 } 280 } 281} 282 283// Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries, 284// and shared libraires, to a shared library (.so) or dynamic executable 285func TransformObjToDynamicBinary(ctx common.AndroidModuleContext, 286 objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps common.Paths, 287 crtBegin, crtEnd common.OptionalPath, groupLate bool, flags builderFlags, outputFile common.WritablePath) { 288 289 var ldCmd string 290 if flags.clang { 291 ldCmd = "${clangPath}/clang++" 292 } else { 293 ldCmd = gccCmd(flags.toolchain, "g++") 294 } 295 296 var ldDirs []string 297 var libFlagsList []string 298 299 if len(wholeStaticLibs) > 0 { 300 if ctx.Host() && ctx.Darwin() { 301 libFlagsList = append(libFlagsList, common.JoinWithPrefix(wholeStaticLibs.Strings(), "-force_load ")) 302 } else { 303 libFlagsList = append(libFlagsList, "-Wl,--whole-archive ") 304 libFlagsList = append(libFlagsList, wholeStaticLibs.Strings()...) 305 libFlagsList = append(libFlagsList, "-Wl,--no-whole-archive ") 306 } 307 } 308 309 libFlagsList = append(libFlagsList, staticLibs.Strings()...) 310 311 if groupLate && len(lateStaticLibs) > 0 { 312 libFlagsList = append(libFlagsList, "-Wl,--start-group") 313 } 314 libFlagsList = append(libFlagsList, lateStaticLibs.Strings()...) 315 if groupLate && len(lateStaticLibs) > 0 { 316 libFlagsList = append(libFlagsList, "-Wl,--end-group") 317 } 318 319 for _, lib := range sharedLibs { 320 dir, file := filepath.Split(lib.String()) 321 if !strings.HasPrefix(file, "lib") { 322 panic("shared library " + lib.String() + " does not start with lib") 323 } 324 if !strings.HasSuffix(file, flags.toolchain.ShlibSuffix()) { 325 panic("shared library " + lib.String() + " does not end with " + flags.toolchain.ShlibSuffix()) 326 } 327 libFlagsList = append(libFlagsList, 328 "-l"+strings.TrimSuffix(strings.TrimPrefix(file, "lib"), flags.toolchain.ShlibSuffix())) 329 ldDirs = append(ldDirs, dir) 330 } 331 332 deps = append(deps, sharedLibs...) 333 deps = append(deps, staticLibs...) 334 deps = append(deps, lateStaticLibs...) 335 deps = append(deps, wholeStaticLibs...) 336 if crtBegin.Valid() { 337 deps = append(deps, crtBegin.Path(), crtEnd.Path()) 338 } 339 340 ctx.ModuleBuild(pctx, common.ModuleBuildParams{ 341 Rule: ld, 342 Output: outputFile, 343 Inputs: objFiles, 344 Implicits: deps, 345 Args: map[string]string{ 346 "ldCmd": ldCmd, 347 "ldDirFlags": ldDirsToFlags(ldDirs), 348 "crtBegin": crtBegin.String(), 349 "libFlags": strings.Join(libFlagsList, " "), 350 "ldFlags": flags.ldFlags, 351 "crtEnd": crtEnd.String(), 352 }, 353 }) 354} 355 356// Generate a rule for compiling multiple .o files to a .o using ld partial linking 357func TransformObjsToObj(ctx common.AndroidModuleContext, objFiles common.Paths, 358 flags builderFlags, outputFile common.WritablePath) { 359 360 var ldCmd string 361 if flags.clang { 362 ldCmd = "${clangPath}clang++" 363 } else { 364 ldCmd = gccCmd(flags.toolchain, "g++") 365 } 366 367 ctx.ModuleBuild(pctx, common.ModuleBuildParams{ 368 Rule: partialLd, 369 Output: outputFile, 370 Inputs: objFiles, 371 Args: map[string]string{ 372 "ldCmd": ldCmd, 373 "ldFlags": flags.ldFlags, 374 }, 375 }) 376} 377 378// Generate a rule for runing objcopy --prefix-symbols on a binary 379func TransformBinaryPrefixSymbols(ctx common.AndroidModuleContext, prefix string, inputFile common.Path, 380 flags builderFlags, outputFile common.WritablePath) { 381 382 objcopyCmd := gccCmd(flags.toolchain, "objcopy") 383 384 ctx.ModuleBuild(pctx, common.ModuleBuildParams{ 385 Rule: prefixSymbols, 386 Output: outputFile, 387 Input: inputFile, 388 Args: map[string]string{ 389 "objcopyCmd": objcopyCmd, 390 "prefix": prefix, 391 }, 392 }) 393} 394 395func CopyGccLib(ctx common.AndroidModuleContext, libName string, 396 flags builderFlags, outputFile common.WritablePath) { 397 398 ctx.ModuleBuild(pctx, common.ModuleBuildParams{ 399 Rule: copyGccLib, 400 Output: outputFile, 401 Args: map[string]string{ 402 "ccCmd": gccCmd(flags.toolchain, "gcc"), 403 "cFlags": flags.globalFlags, 404 "libName": libName, 405 }, 406 }) 407} 408 409func gccCmd(toolchain Toolchain, cmd string) string { 410 return filepath.Join(toolchain.GccRoot(), "bin", toolchain.GccTriple()+"-"+cmd) 411} 412 413func splitListForSize(list []string, limit int) (lists [][]string, err error) { 414 var i int 415 416 start := 0 417 bytes := 0 418 for i = range list { 419 l := len(list[i]) 420 if l > limit { 421 return nil, fmt.Errorf("list element greater than size limit (%d)", limit) 422 } 423 if bytes+l > limit { 424 lists = append(lists, list[start:i]) 425 start = i 426 bytes = 0 427 } 428 bytes += l + 1 // count a space between each list element 429 } 430 431 lists = append(lists, list[start:]) 432 433 totalLen := 0 434 for _, l := range lists { 435 totalLen += len(l) 436 } 437 if totalLen != len(list) { 438 panic(fmt.Errorf("Failed breaking up list, %d != %d", len(list), totalLen)) 439 } 440 return lists, nil 441} 442