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 "fmt" 23 "path/filepath" 24 "runtime" 25 "strconv" 26 "strings" 27 28 "github.com/google/blueprint" 29 30 "android/soong/android" 31 "android/soong/cc/config" 32) 33 34const ( 35 objectExtension = ".o" 36 staticLibraryExtension = ".a" 37) 38 39var ( 40 abiCheckAllowFlags = []string{ 41 "-allow-unreferenced-changes", 42 "-allow-unreferenced-elf-symbol-changes", 43 } 44) 45 46var ( 47 pctx = android.NewPackageContext("android/soong/cc") 48 49 cc = pctx.AndroidGomaStaticRule("cc", 50 blueprint.RuleParams{ 51 Depfile: "${out}.d", 52 Deps: blueprint.DepsGCC, 53 Command: "$relPwd ${config.CcWrapper}$ccCmd -c $cFlags -MD -MF ${out}.d -o $out $in", 54 CommandDeps: []string{"$ccCmd"}, 55 }, 56 "ccCmd", "cFlags") 57 58 ccNoDeps = pctx.AndroidGomaStaticRule("ccNoDeps", 59 blueprint.RuleParams{ 60 Command: "$relPwd ${config.CcWrapper}$ccCmd -c $cFlags -o $out $in", 61 CommandDeps: []string{"$ccCmd"}, 62 }, 63 "ccCmd", "cFlags") 64 65 ld = pctx.AndroidStaticRule("ld", 66 blueprint.RuleParams{ 67 Command: "$ldCmd ${crtBegin} @${out}.rsp " + 68 "${libFlags} ${crtEnd} -o ${out} ${ldFlags}", 69 CommandDeps: []string{"$ldCmd"}, 70 Rspfile: "${out}.rsp", 71 RspfileContent: "${in}", 72 // clang -Wl,--out-implib doesn't update its output file if it hasn't changed. 73 Restat: true, 74 }, 75 "ldCmd", "crtBegin", "libFlags", "crtEnd", "ldFlags") 76 77 partialLd = pctx.AndroidStaticRule("partialLd", 78 blueprint.RuleParams{ 79 // Without -no-pie, clang 7.0 adds -pie to link Android files, 80 // but -r and -pie cannot be used together. 81 Command: "$ldCmd -nostdlib -no-pie -Wl,-r ${in} -o ${out} ${ldFlags}", 82 CommandDeps: []string{"$ldCmd"}, 83 }, 84 "ldCmd", "ldFlags") 85 86 ar = pctx.AndroidStaticRule("ar", 87 blueprint.RuleParams{ 88 Command: "rm -f ${out} && $arCmd $arFlags $out @${out}.rsp", 89 CommandDeps: []string{"$arCmd"}, 90 Rspfile: "${out}.rsp", 91 RspfileContent: "${in}", 92 }, 93 "arCmd", "arFlags") 94 95 darwinAr = pctx.AndroidStaticRule("darwinAr", 96 blueprint.RuleParams{ 97 Command: "rm -f ${out} && ${config.MacArPath} $arFlags $out $in", 98 CommandDeps: []string{"${config.MacArPath}"}, 99 }, 100 "arFlags") 101 102 darwinAppendAr = pctx.AndroidStaticRule("darwinAppendAr", 103 blueprint.RuleParams{ 104 Command: "cp -f ${inAr} ${out}.tmp && ${config.MacArPath} $arFlags ${out}.tmp $in && mv ${out}.tmp ${out}", 105 CommandDeps: []string{"${config.MacArPath}", "${inAr}"}, 106 }, 107 "arFlags", "inAr") 108 109 darwinStrip = pctx.AndroidStaticRule("darwinStrip", 110 blueprint.RuleParams{ 111 Command: "${config.MacStripPath} -u -r -o $out $in", 112 CommandDeps: []string{"${config.MacStripPath}"}, 113 }) 114 115 prefixSymbols = pctx.AndroidStaticRule("prefixSymbols", 116 blueprint.RuleParams{ 117 Command: "$objcopyCmd --prefix-symbols=${prefix} ${in} ${out}", 118 CommandDeps: []string{"$objcopyCmd"}, 119 }, 120 "objcopyCmd", "prefix") 121 122 _ = pctx.SourcePathVariable("stripPath", "build/soong/scripts/strip.sh") 123 _ = pctx.SourcePathVariable("xzCmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/xz") 124 125 // b/132822437: objcopy uses a file descriptor per .o file when called on .a files, which runs the system out of 126 // file descriptors on darwin. Limit concurrent calls to 5 on darwin. 127 darwinStripPool = func() blueprint.Pool { 128 if runtime.GOOS == "darwin" { 129 return pctx.StaticPool("darwinStripPool", blueprint.PoolParams{ 130 Depth: 5, 131 }) 132 } else { 133 return nil 134 } 135 }() 136 137 strip = pctx.AndroidStaticRule("strip", 138 blueprint.RuleParams{ 139 Depfile: "${out}.d", 140 Deps: blueprint.DepsGCC, 141 Command: "CROSS_COMPILE=$crossCompile XZ=$xzCmd CLANG_BIN=${config.ClangBin} $stripPath ${args} -i ${in} -o ${out} -d ${out}.d", 142 CommandDeps: []string{"$stripPath", "$xzCmd"}, 143 Pool: darwinStripPool, 144 }, 145 "args", "crossCompile") 146 147 emptyFile = pctx.AndroidStaticRule("emptyFile", 148 blueprint.RuleParams{ 149 Command: "rm -f $out && touch $out", 150 }) 151 152 _ = pctx.SourcePathVariable("tocPath", "build/soong/scripts/toc.sh") 153 154 toc = pctx.AndroidStaticRule("toc", 155 blueprint.RuleParams{ 156 Depfile: "${out}.d", 157 Deps: blueprint.DepsGCC, 158 Command: "CROSS_COMPILE=$crossCompile $tocPath $format -i ${in} -o ${out} -d ${out}.d", 159 CommandDeps: []string{"$tocPath"}, 160 Restat: true, 161 }, 162 "crossCompile", "format") 163 164 clangTidy = pctx.AndroidStaticRule("clangTidy", 165 blueprint.RuleParams{ 166 Command: "rm -f $out && CLANG_TIDY=${config.ClangBin}/clang-tidy ${config.ClangTidyShellPath} $tidyFlags $in -- $cFlags && touch $out", 167 CommandDeps: []string{"${config.ClangBin}/clang-tidy", "${config.ClangTidyShellPath}"}, 168 }, 169 "cFlags", "tidyFlags") 170 171 _ = pctx.SourcePathVariable("yasmCmd", "prebuilts/misc/${config.HostPrebuiltTag}/yasm/yasm") 172 173 yasm = pctx.AndroidStaticRule("yasm", 174 blueprint.RuleParams{ 175 Command: "$yasmCmd $asFlags -o $out $in && $yasmCmd $asFlags -M $in >$out.d", 176 CommandDeps: []string{"$yasmCmd"}, 177 Depfile: "$out.d", 178 Deps: blueprint.DepsGCC, 179 }, 180 "asFlags") 181 182 windres = pctx.AndroidStaticRule("windres", 183 blueprint.RuleParams{ 184 Command: "$windresCmd $flags -I$$(dirname $in) -i $in -o $out", 185 CommandDeps: []string{"$windresCmd"}, 186 }, 187 "windresCmd", "flags") 188 189 _ = pctx.SourcePathVariable("sAbiDumper", "prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/header-abi-dumper") 190 191 // -w has been added since header-abi-dumper does not need to produce any sort of diagnostic information. 192 sAbiDump = pctx.AndroidStaticRule("sAbiDump", 193 blueprint.RuleParams{ 194 Command: "rm -f $out && $sAbiDumper -o ${out} $in $exportDirs -- $cFlags -w -isystem prebuilts/clang-tools/${config.HostPrebuiltTag}/clang-headers", 195 CommandDeps: []string{"$sAbiDumper"}, 196 }, 197 "cFlags", "exportDirs") 198 199 _ = pctx.SourcePathVariable("sAbiLinker", "prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/header-abi-linker") 200 201 sAbiLink = pctx.AndroidStaticRule("sAbiLink", 202 blueprint.RuleParams{ 203 Command: "$sAbiLinker -o ${out} $symbolFilter -arch $arch $exportedHeaderFlags @${out}.rsp ", 204 CommandDeps: []string{"$sAbiLinker"}, 205 Rspfile: "${out}.rsp", 206 RspfileContent: "${in}", 207 }, 208 "symbolFilter", "arch", "exportedHeaderFlags") 209 210 _ = pctx.SourcePathVariable("sAbiDiffer", "prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/header-abi-diff") 211 212 sAbiDiff = pctx.AndroidRuleFunc("sAbiDiff", 213 func(ctx android.PackageRuleContext) blueprint.RuleParams { 214 // TODO(b/78139997): Add -check-all-apis back 215 commandStr := "($sAbiDiffer ${allowFlags} -lib ${libName} -arch ${arch} -o ${out} -new ${in} -old ${referenceDump})" 216 commandStr += "|| (echo 'error: Please update ABI references with: $$ANDROID_BUILD_TOP/development/vndk/tools/header-checker/utils/create_reference_dumps.py ${createReferenceDumpFlags} -l ${libName}'" 217 commandStr += " && (mkdir -p $$DIST_DIR/abidiffs && cp ${out} $$DIST_DIR/abidiffs/)" 218 commandStr += " && exit 1)" 219 return blueprint.RuleParams{ 220 Command: commandStr, 221 CommandDeps: []string{"$sAbiDiffer"}, 222 } 223 }, 224 "allowFlags", "referenceDump", "libName", "arch", "createReferenceDumpFlags") 225 226 unzipRefSAbiDump = pctx.AndroidStaticRule("unzipRefSAbiDump", 227 blueprint.RuleParams{ 228 Command: "gunzip -c $in > $out", 229 }) 230) 231 232func init() { 233 // We run gcc/clang with PWD=/proc/self/cwd to remove $TOP from the 234 // debug output. That way two builds in two different directories will 235 // create the same output. 236 if runtime.GOOS != "darwin" { 237 pctx.StaticVariable("relPwd", "PWD=/proc/self/cwd") 238 } else { 239 // Darwin doesn't have /proc 240 pctx.StaticVariable("relPwd", "") 241 } 242} 243 244type builderFlags struct { 245 globalFlags string 246 arFlags string 247 asFlags string 248 cFlags string 249 toolingCFlags string // A separate set of cFlags for clang LibTooling tools 250 toolingCppFlags string // A separate set of cppFlags for clang LibTooling tools 251 conlyFlags string 252 cppFlags string 253 ldFlags string 254 libFlags string 255 yaccFlags string 256 tidyFlags string 257 sAbiFlags string 258 yasmFlags string 259 aidlFlags string 260 rsFlags string 261 toolchain config.Toolchain 262 tidy bool 263 coverage bool 264 sAbiDump bool 265 266 systemIncludeFlags string 267 268 groupStaticLibs bool 269 270 stripKeepSymbols bool 271 stripKeepSymbolsList string 272 stripKeepMiniDebugInfo bool 273 stripAddGnuDebuglink bool 274 stripUseGnuStrip bool 275 276 proto android.ProtoFlags 277 protoC bool 278 protoOptionsFile bool 279} 280 281type Objects struct { 282 objFiles android.Paths 283 tidyFiles android.Paths 284 coverageFiles android.Paths 285 sAbiDumpFiles android.Paths 286} 287 288func (a Objects) Copy() Objects { 289 return Objects{ 290 objFiles: append(android.Paths{}, a.objFiles...), 291 tidyFiles: append(android.Paths{}, a.tidyFiles...), 292 coverageFiles: append(android.Paths{}, a.coverageFiles...), 293 sAbiDumpFiles: append(android.Paths{}, a.sAbiDumpFiles...), 294 } 295} 296 297func (a Objects) Append(b Objects) Objects { 298 return Objects{ 299 objFiles: append(a.objFiles, b.objFiles...), 300 tidyFiles: append(a.tidyFiles, b.tidyFiles...), 301 coverageFiles: append(a.coverageFiles, b.coverageFiles...), 302 sAbiDumpFiles: append(a.sAbiDumpFiles, b.sAbiDumpFiles...), 303 } 304} 305 306// Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files 307func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles android.Paths, 308 flags builderFlags, pathDeps android.Paths, cFlagsDeps android.Paths) Objects { 309 310 objFiles := make(android.Paths, len(srcFiles)) 311 var tidyFiles android.Paths 312 if flags.tidy { 313 tidyFiles = make(android.Paths, 0, len(srcFiles)) 314 } 315 var coverageFiles android.Paths 316 if flags.coverage { 317 coverageFiles = make(android.Paths, 0, len(srcFiles)) 318 } 319 320 commonFlags := strings.Join([]string{ 321 flags.globalFlags, 322 flags.systemIncludeFlags, 323 }, " ") 324 325 toolingCflags := strings.Join([]string{ 326 commonFlags, 327 flags.toolingCFlags, 328 flags.conlyFlags, 329 }, " ") 330 331 cflags := strings.Join([]string{ 332 commonFlags, 333 flags.cFlags, 334 flags.conlyFlags, 335 }, " ") 336 337 toolingCppflags := strings.Join([]string{ 338 commonFlags, 339 flags.toolingCFlags, 340 flags.toolingCppFlags, 341 }, " ") 342 343 cppflags := strings.Join([]string{ 344 commonFlags, 345 flags.cFlags, 346 flags.cppFlags, 347 }, " ") 348 349 asflags := strings.Join([]string{ 350 commonFlags, 351 flags.asFlags, 352 }, " ") 353 354 var sAbiDumpFiles android.Paths 355 if flags.sAbiDump { 356 sAbiDumpFiles = make(android.Paths, 0, len(srcFiles)) 357 } 358 359 cflags += " ${config.NoOverrideClangGlobalCflags}" 360 toolingCflags += " ${config.NoOverrideClangGlobalCflags}" 361 cppflags += " ${config.NoOverrideClangGlobalCflags}" 362 toolingCppflags += " ${config.NoOverrideClangGlobalCflags}" 363 364 for i, srcFile := range srcFiles { 365 objFile := android.ObjPathWithExt(ctx, subdir, srcFile, "o") 366 367 objFiles[i] = objFile 368 369 switch srcFile.Ext() { 370 case ".asm": 371 ctx.Build(pctx, android.BuildParams{ 372 Rule: yasm, 373 Description: "yasm " + srcFile.Rel(), 374 Output: objFile, 375 Input: srcFile, 376 Implicits: cFlagsDeps, 377 OrderOnly: pathDeps, 378 Args: map[string]string{ 379 "asFlags": flags.yasmFlags, 380 }, 381 }) 382 continue 383 case ".rc": 384 ctx.Build(pctx, android.BuildParams{ 385 Rule: windres, 386 Description: "windres " + srcFile.Rel(), 387 Output: objFile, 388 Input: srcFile, 389 Implicits: cFlagsDeps, 390 OrderOnly: pathDeps, 391 Args: map[string]string{ 392 "windresCmd": gccCmd(flags.toolchain, "windres"), 393 "flags": flags.toolchain.WindresFlags(), 394 }, 395 }) 396 continue 397 } 398 399 var moduleCflags string 400 var moduleToolingCflags string 401 var ccCmd string 402 tidy := flags.tidy 403 coverage := flags.coverage 404 dump := flags.sAbiDump 405 rule := cc 406 407 switch srcFile.Ext() { 408 case ".s": 409 rule = ccNoDeps 410 fallthrough 411 case ".S": 412 ccCmd = "clang" 413 moduleCflags = asflags 414 tidy = false 415 coverage = false 416 dump = false 417 case ".c": 418 ccCmd = "clang" 419 moduleCflags = cflags 420 moduleToolingCflags = toolingCflags 421 case ".cpp", ".cc", ".mm": 422 ccCmd = "clang++" 423 moduleCflags = cppflags 424 moduleToolingCflags = toolingCppflags 425 default: 426 ctx.ModuleErrorf("File %s has unknown extension", srcFile) 427 continue 428 } 429 430 ccDesc := ccCmd 431 432 ccCmd = "${config.ClangBin}/" + ccCmd 433 434 var implicitOutputs android.WritablePaths 435 if coverage { 436 gcnoFile := android.ObjPathWithExt(ctx, subdir, srcFile, "gcno") 437 implicitOutputs = append(implicitOutputs, gcnoFile) 438 coverageFiles = append(coverageFiles, gcnoFile) 439 } 440 441 ctx.Build(pctx, android.BuildParams{ 442 Rule: rule, 443 Description: ccDesc + " " + srcFile.Rel(), 444 Output: objFile, 445 ImplicitOutputs: implicitOutputs, 446 Input: srcFile, 447 Implicits: cFlagsDeps, 448 OrderOnly: pathDeps, 449 Args: map[string]string{ 450 "cFlags": moduleCflags, 451 "ccCmd": ccCmd, 452 }, 453 }) 454 455 if tidy { 456 tidyFile := android.ObjPathWithExt(ctx, subdir, srcFile, "tidy") 457 tidyFiles = append(tidyFiles, tidyFile) 458 459 ctx.Build(pctx, android.BuildParams{ 460 Rule: clangTidy, 461 Description: "clang-tidy " + srcFile.Rel(), 462 Output: tidyFile, 463 Input: srcFile, 464 // We must depend on objFile, since clang-tidy doesn't 465 // support exporting dependencies. 466 Implicit: objFile, 467 Args: map[string]string{ 468 "cFlags": moduleToolingCflags, 469 "tidyFlags": flags.tidyFlags, 470 }, 471 }) 472 } 473 474 if dump { 475 sAbiDumpFile := android.ObjPathWithExt(ctx, subdir, srcFile, "sdump") 476 sAbiDumpFiles = append(sAbiDumpFiles, sAbiDumpFile) 477 478 ctx.Build(pctx, android.BuildParams{ 479 Rule: sAbiDump, 480 Description: "header-abi-dumper " + srcFile.Rel(), 481 Output: sAbiDumpFile, 482 Input: srcFile, 483 Implicit: objFile, 484 Args: map[string]string{ 485 "cFlags": moduleToolingCflags, 486 "exportDirs": flags.sAbiFlags, 487 }, 488 }) 489 } 490 491 } 492 493 return Objects{ 494 objFiles: objFiles, 495 tidyFiles: tidyFiles, 496 coverageFiles: coverageFiles, 497 sAbiDumpFiles: sAbiDumpFiles, 498 } 499} 500 501// Generate a rule for compiling multiple .o files to a static library (.a) 502func TransformObjToStaticLib(ctx android.ModuleContext, objFiles android.Paths, 503 flags builderFlags, outputFile android.ModuleOutPath, deps android.Paths) { 504 505 if ctx.Darwin() { 506 transformDarwinObjToStaticLib(ctx, objFiles, flags, outputFile, deps) 507 return 508 } 509 510 arCmd := "${config.ClangBin}/llvm-ar" 511 arFlags := "crsD" 512 if !ctx.Darwin() { 513 arFlags += " -format=gnu" 514 } 515 if flags.arFlags != "" { 516 arFlags += " " + flags.arFlags 517 } 518 519 ctx.Build(pctx, android.BuildParams{ 520 Rule: ar, 521 Description: "static link " + outputFile.Base(), 522 Output: outputFile, 523 Inputs: objFiles, 524 Implicits: deps, 525 Args: map[string]string{ 526 "arFlags": arFlags, 527 "arCmd": arCmd, 528 }, 529 }) 530} 531 532// Generate a rule for compiling multiple .o files to a static library (.a) on 533// darwin. The darwin ar tool doesn't support @file for list files, and has a 534// very small command line length limit, so we have to split the ar into multiple 535// steps, each appending to the previous one. 536func transformDarwinObjToStaticLib(ctx android.ModuleContext, objFiles android.Paths, 537 flags builderFlags, outputFile android.ModuleOutPath, deps android.Paths) { 538 539 arFlags := "cqs" 540 541 if len(objFiles) == 0 { 542 dummy := android.PathForModuleOut(ctx, "dummy"+objectExtension) 543 dummyAr := android.PathForModuleOut(ctx, "dummy"+staticLibraryExtension) 544 545 ctx.Build(pctx, android.BuildParams{ 546 Rule: emptyFile, 547 Description: "empty object file", 548 Output: dummy, 549 Implicits: deps, 550 }) 551 552 ctx.Build(pctx, android.BuildParams{ 553 Rule: darwinAr, 554 Description: "empty static archive", 555 Output: dummyAr, 556 Input: dummy, 557 Args: map[string]string{ 558 "arFlags": arFlags, 559 }, 560 }) 561 562 ctx.Build(pctx, android.BuildParams{ 563 Rule: darwinAppendAr, 564 Description: "static link " + outputFile.Base(), 565 Output: outputFile, 566 Input: dummy, 567 Args: map[string]string{ 568 "arFlags": "d", 569 "inAr": dummyAr.String(), 570 }, 571 }) 572 573 return 574 } 575 576 // ARG_MAX on darwin is 262144, use half that to be safe 577 objFilesLists, err := splitListForSize(objFiles, 131072) 578 if err != nil { 579 ctx.ModuleErrorf("%s", err.Error()) 580 } 581 582 var in, out android.WritablePath 583 for i, l := range objFilesLists { 584 in = out 585 out = outputFile 586 if i != len(objFilesLists)-1 { 587 out = android.PathForModuleOut(ctx, outputFile.Base()+strconv.Itoa(i)) 588 } 589 590 build := android.BuildParams{ 591 Rule: darwinAr, 592 Description: "static link " + out.Base(), 593 Output: out, 594 Inputs: l, 595 Implicits: deps, 596 Args: map[string]string{ 597 "arFlags": arFlags, 598 }, 599 } 600 if i != 0 { 601 build.Rule = darwinAppendAr 602 build.Args["inAr"] = in.String() 603 } 604 ctx.Build(pctx, build) 605 } 606} 607 608// Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries, 609// and shared libraries, to a shared library (.so) or dynamic executable 610func TransformObjToDynamicBinary(ctx android.ModuleContext, 611 objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps android.Paths, 612 crtBegin, crtEnd android.OptionalPath, groupLate bool, flags builderFlags, outputFile android.WritablePath) { 613 614 ldCmd := "${config.ClangBin}/clang++" 615 616 var libFlagsList []string 617 618 if len(flags.libFlags) > 0 { 619 libFlagsList = append(libFlagsList, flags.libFlags) 620 } 621 622 if len(wholeStaticLibs) > 0 { 623 if ctx.Host() && ctx.Darwin() { 624 libFlagsList = append(libFlagsList, android.JoinWithPrefix(wholeStaticLibs.Strings(), "-force_load ")) 625 } else { 626 libFlagsList = append(libFlagsList, "-Wl,--whole-archive ") 627 libFlagsList = append(libFlagsList, wholeStaticLibs.Strings()...) 628 libFlagsList = append(libFlagsList, "-Wl,--no-whole-archive ") 629 } 630 } 631 632 if flags.groupStaticLibs && !ctx.Darwin() && len(staticLibs) > 0 { 633 libFlagsList = append(libFlagsList, "-Wl,--start-group") 634 } 635 libFlagsList = append(libFlagsList, staticLibs.Strings()...) 636 if flags.groupStaticLibs && !ctx.Darwin() && len(staticLibs) > 0 { 637 libFlagsList = append(libFlagsList, "-Wl,--end-group") 638 } 639 640 if groupLate && !ctx.Darwin() && len(lateStaticLibs) > 0 { 641 libFlagsList = append(libFlagsList, "-Wl,--start-group") 642 } 643 libFlagsList = append(libFlagsList, lateStaticLibs.Strings()...) 644 if groupLate && !ctx.Darwin() && len(lateStaticLibs) > 0 { 645 libFlagsList = append(libFlagsList, "-Wl,--end-group") 646 } 647 648 for _, lib := range sharedLibs { 649 libFlagsList = append(libFlagsList, lib.String()) 650 } 651 652 deps = append(deps, staticLibs...) 653 deps = append(deps, lateStaticLibs...) 654 deps = append(deps, wholeStaticLibs...) 655 if crtBegin.Valid() { 656 deps = append(deps, crtBegin.Path(), crtEnd.Path()) 657 } 658 659 ctx.Build(pctx, android.BuildParams{ 660 Rule: ld, 661 Description: "link " + outputFile.Base(), 662 Output: outputFile, 663 Inputs: objFiles, 664 Implicits: deps, 665 Args: map[string]string{ 666 "ldCmd": ldCmd, 667 "crtBegin": crtBegin.String(), 668 "libFlags": strings.Join(libFlagsList, " "), 669 "ldFlags": flags.ldFlags, 670 "crtEnd": crtEnd.String(), 671 }, 672 }) 673} 674 675// Generate a rule to combine .dump sAbi dump files from multiple source files 676// into a single .ldump sAbi dump file 677func TransformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Paths, soFile android.Path, 678 baseName, exportedHeaderFlags string, symbolFile android.OptionalPath, 679 excludedSymbolVersions, excludedSymbolTags []string) android.OptionalPath { 680 681 outputFile := android.PathForModuleOut(ctx, baseName+".lsdump") 682 sabiLock.Lock() 683 lsdumpPaths = append(lsdumpPaths, outputFile.String()) 684 sabiLock.Unlock() 685 686 implicits := android.Paths{soFile} 687 symbolFilterStr := "-so " + soFile.String() 688 689 if symbolFile.Valid() { 690 implicits = append(implicits, symbolFile.Path()) 691 symbolFilterStr += " -v " + symbolFile.String() 692 } 693 for _, ver := range excludedSymbolVersions { 694 symbolFilterStr += " --exclude-symbol-version " + ver 695 } 696 for _, tag := range excludedSymbolTags { 697 symbolFilterStr += " --exclude-symbol-tag " + tag 698 } 699 ctx.Build(pctx, android.BuildParams{ 700 Rule: sAbiLink, 701 Description: "header-abi-linker " + outputFile.Base(), 702 Output: outputFile, 703 Inputs: sAbiDumps, 704 Implicits: implicits, 705 Args: map[string]string{ 706 "symbolFilter": symbolFilterStr, 707 "arch": ctx.Arch().ArchType.Name, 708 "exportedHeaderFlags": exportedHeaderFlags, 709 }, 710 }) 711 return android.OptionalPathForPath(outputFile) 712} 713 714func UnzipRefDump(ctx android.ModuleContext, zippedRefDump android.Path, baseName string) android.Path { 715 outputFile := android.PathForModuleOut(ctx, baseName+"_ref.lsdump") 716 ctx.Build(pctx, android.BuildParams{ 717 Rule: unzipRefSAbiDump, 718 Description: "gunzip" + outputFile.Base(), 719 Output: outputFile, 720 Input: zippedRefDump, 721 }) 722 return outputFile 723} 724 725func SourceAbiDiff(ctx android.ModuleContext, inputDump android.Path, referenceDump android.Path, 726 baseName, exportedHeaderFlags string, isLlndk, isVndkExt bool) android.OptionalPath { 727 728 outputFile := android.PathForModuleOut(ctx, baseName+".abidiff") 729 libName := strings.TrimSuffix(baseName, filepath.Ext(baseName)) 730 createReferenceDumpFlags := "" 731 732 localAbiCheckAllowFlags := append([]string(nil), abiCheckAllowFlags...) 733 if exportedHeaderFlags == "" { 734 localAbiCheckAllowFlags = append(localAbiCheckAllowFlags, "-advice-only") 735 } 736 if isLlndk { 737 localAbiCheckAllowFlags = append(localAbiCheckAllowFlags, "-consider-opaque-types-different") 738 createReferenceDumpFlags = "--llndk" 739 } 740 if isVndkExt { 741 localAbiCheckAllowFlags = append(localAbiCheckAllowFlags, "-allow-extensions") 742 } 743 744 ctx.Build(pctx, android.BuildParams{ 745 Rule: sAbiDiff, 746 Description: "header-abi-diff " + outputFile.Base(), 747 Output: outputFile, 748 Input: inputDump, 749 Implicit: referenceDump, 750 Args: map[string]string{ 751 "referenceDump": referenceDump.String(), 752 "libName": libName, 753 "arch": ctx.Arch().ArchType.Name, 754 "allowFlags": strings.Join(localAbiCheckAllowFlags, " "), 755 "createReferenceDumpFlags": createReferenceDumpFlags, 756 }, 757 }) 758 return android.OptionalPathForPath(outputFile) 759} 760 761// Generate a rule for extracting a table of contents from a shared library (.so) 762func TransformSharedObjectToToc(ctx android.ModuleContext, inputFile android.Path, 763 outputFile android.WritablePath, flags builderFlags) { 764 765 var format string 766 var crossCompile string 767 if ctx.Darwin() { 768 format = "--macho" 769 crossCompile = "${config.MacToolPath}" 770 } else if ctx.Windows() { 771 format = "--pe" 772 crossCompile = gccCmd(flags.toolchain, "") 773 } else { 774 format = "--elf" 775 crossCompile = gccCmd(flags.toolchain, "") 776 } 777 778 ctx.Build(pctx, android.BuildParams{ 779 Rule: toc, 780 Description: "generate toc " + inputFile.Base(), 781 Output: outputFile, 782 Input: inputFile, 783 Args: map[string]string{ 784 "crossCompile": crossCompile, 785 "format": format, 786 }, 787 }) 788} 789 790// Generate a rule for compiling multiple .o files to a .o using ld partial linking 791func TransformObjsToObj(ctx android.ModuleContext, objFiles android.Paths, 792 flags builderFlags, outputFile android.WritablePath) { 793 794 ldCmd := "${config.ClangBin}/clang++" 795 796 ctx.Build(pctx, android.BuildParams{ 797 Rule: partialLd, 798 Description: "link " + outputFile.Base(), 799 Output: outputFile, 800 Inputs: objFiles, 801 Args: map[string]string{ 802 "ldCmd": ldCmd, 803 "ldFlags": flags.ldFlags, 804 }, 805 }) 806} 807 808// Generate a rule for runing objcopy --prefix-symbols on a binary 809func TransformBinaryPrefixSymbols(ctx android.ModuleContext, prefix string, inputFile android.Path, 810 flags builderFlags, outputFile android.WritablePath) { 811 812 objcopyCmd := gccCmd(flags.toolchain, "objcopy") 813 814 ctx.Build(pctx, android.BuildParams{ 815 Rule: prefixSymbols, 816 Description: "prefix symbols " + outputFile.Base(), 817 Output: outputFile, 818 Input: inputFile, 819 Args: map[string]string{ 820 "objcopyCmd": objcopyCmd, 821 "prefix": prefix, 822 }, 823 }) 824} 825 826func TransformStrip(ctx android.ModuleContext, inputFile android.Path, 827 outputFile android.WritablePath, flags builderFlags) { 828 829 crossCompile := gccCmd(flags.toolchain, "") 830 args := "" 831 if flags.stripAddGnuDebuglink { 832 args += " --add-gnu-debuglink" 833 } 834 if flags.stripKeepMiniDebugInfo { 835 args += " --keep-mini-debug-info" 836 } 837 if flags.stripKeepSymbols { 838 args += " --keep-symbols" 839 } 840 if flags.stripKeepSymbolsList != "" { 841 args += " -k" + flags.stripKeepSymbolsList 842 } 843 if flags.stripUseGnuStrip { 844 args += " --use-gnu-strip" 845 } 846 847 ctx.Build(pctx, android.BuildParams{ 848 Rule: strip, 849 Description: "strip " + outputFile.Base(), 850 Output: outputFile, 851 Input: inputFile, 852 Args: map[string]string{ 853 "crossCompile": crossCompile, 854 "args": args, 855 }, 856 }) 857} 858 859func TransformDarwinStrip(ctx android.ModuleContext, inputFile android.Path, 860 outputFile android.WritablePath) { 861 862 ctx.Build(pctx, android.BuildParams{ 863 Rule: darwinStrip, 864 Description: "strip " + outputFile.Base(), 865 Output: outputFile, 866 Input: inputFile, 867 }) 868} 869 870func TransformCoverageFilesToLib(ctx android.ModuleContext, 871 inputs Objects, flags builderFlags, baseName string) android.OptionalPath { 872 873 if len(inputs.coverageFiles) > 0 { 874 outputFile := android.PathForModuleOut(ctx, baseName+".gcnodir") 875 876 TransformObjToStaticLib(ctx, inputs.coverageFiles, flags, outputFile, nil) 877 878 return android.OptionalPathForPath(outputFile) 879 } 880 881 return android.OptionalPath{} 882} 883 884func gccCmd(toolchain config.Toolchain, cmd string) string { 885 return filepath.Join(toolchain.GccRoot(), "bin", toolchain.GccTriple()+"-"+cmd) 886} 887 888func splitListForSize(list android.Paths, limit int) (lists []android.Paths, err error) { 889 var i int 890 891 start := 0 892 bytes := 0 893 for i = range list { 894 l := len(list[i].String()) 895 if l > limit { 896 return nil, fmt.Errorf("list element greater than size limit (%d)", limit) 897 } 898 if bytes+l > limit { 899 lists = append(lists, list[start:i]) 900 start = i 901 bytes = 0 902 } 903 bytes += l + 1 // count a space between each list element 904 } 905 906 lists = append(lists, list[start:]) 907 908 totalLen := 0 909 for _, l := range lists { 910 totalLen += len(l) 911 } 912 if totalLen != len(list) { 913 panic(fmt.Errorf("Failed breaking up list, %d != %d", len(list), totalLen)) 914 } 915 return lists, nil 916} 917