123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440 |
- // Copyright 2015 Google Inc. All rights reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package cc
- // This file generates the final rules for compiling all C/C++. All properties related to
- // compiling should have been translated into builderFlags or another argument to the Transform*
- // functions.
- import (
- "android/soong/common"
- "fmt"
- "runtime"
- "strconv"
- "path/filepath"
- "strings"
- "github.com/google/blueprint"
- "github.com/google/blueprint/pathtools"
- )
- const (
- objectExtension = ".o"
- sharedLibraryExtension = ".so"
- staticLibraryExtension = ".a"
- )
- var (
- pctx = blueprint.NewPackageContext("android/soong/cc")
- cc = pctx.StaticRule("cc",
- blueprint.RuleParams{
- Depfile: "${out}.d",
- Deps: blueprint.DepsGCC,
- Command: "$ccCmd -c $cFlags -MD -MF ${out}.d -o $out $in",
- Description: "cc $out",
- },
- "ccCmd", "cFlags")
- ld = pctx.StaticRule("ld",
- blueprint.RuleParams{
- Command: "$ldCmd ${ldDirFlags} ${crtBegin} @${out}.rsp " +
- "${libFlags} ${crtEnd} -o ${out} ${ldFlags}",
- Description: "ld $out",
- Rspfile: "${out}.rsp",
- RspfileContent: "${in}",
- },
- "ldCmd", "ldDirFlags", "crtBegin", "libFlags", "crtEnd", "ldFlags")
- partialLd = pctx.StaticRule("partialLd",
- blueprint.RuleParams{
- Command: "$ldCmd -r ${in} -o ${out}",
- Description: "partialLd $out",
- },
- "ldCmd")
- ar = pctx.StaticRule("ar",
- blueprint.RuleParams{
- Command: "rm -f ${out} && $arCmd $arFlags $out @${out}.rsp",
- Description: "ar $out",
- Rspfile: "${out}.rsp",
- RspfileContent: "${in}",
- },
- "arCmd", "arFlags")
- darwinAr = pctx.StaticRule("darwinAr",
- blueprint.RuleParams{
- Command: "rm -f ${out} && $arCmd $arFlags $out $in",
- Description: "ar $out",
- },
- "arCmd", "arFlags")
- darwinAppendAr = pctx.StaticRule("darwinAppendAr",
- blueprint.RuleParams{
- Command: "cp -f ${inAr} ${out}.tmp && $arCmd $arFlags ${out}.tmp $in && mv ${out}.tmp ${out}",
- Description: "ar $out",
- },
- "arCmd", "arFlags", "inAr")
- prefixSymbols = pctx.StaticRule("prefixSymbols",
- blueprint.RuleParams{
- Command: "$objcopyCmd --prefix-symbols=${prefix} ${in} ${out}",
- Description: "prefixSymbols $out",
- },
- "objcopyCmd", "prefix")
- copyGccLibPath = pctx.StaticVariable("copyGccLibPath", "${SrcDir}/build/soong/copygcclib.sh")
- copyGccLib = pctx.StaticRule("copyGccLib",
- blueprint.RuleParams{
- Depfile: "${out}.d",
- Deps: blueprint.DepsGCC,
- Command: "$copyGccLibPath $out $ccCmd $cFlags -print-file-name=${libName}",
- Description: "copy gcc $out",
- },
- "ccCmd", "cFlags", "libName")
- )
- type builderFlags struct {
- globalFlags string
- asFlags string
- cFlags string
- conlyFlags string
- cppFlags string
- ldFlags string
- yaccFlags string
- nocrt bool
- toolchain Toolchain
- clang bool
- }
- // Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files
- func TransformSourceToObj(ctx common.AndroidModuleContext, subdir string, srcFiles []string,
- flags builderFlags, deps []string) (objFiles []string) {
- srcRoot := ctx.AConfig().SrcDir()
- intermediatesRoot := ctx.AConfig().IntermediatesDir()
- objFiles = make([]string, len(srcFiles))
- objDir := common.ModuleObjDir(ctx)
- if subdir != "" {
- objDir = filepath.Join(objDir, subdir)
- }
- cflags := flags.globalFlags + " " + flags.cFlags + " " + flags.conlyFlags
- cppflags := flags.globalFlags + " " + flags.cFlags + " " + flags.cppFlags
- asflags := flags.globalFlags + " " + flags.asFlags
- for i, srcFile := range srcFiles {
- var objFile string
- if strings.HasPrefix(srcFile, intermediatesRoot) {
- objFile = strings.TrimPrefix(srcFile, intermediatesRoot)
- objFile = filepath.Join(objDir, "gen", objFile)
- } else if strings.HasPrefix(srcFile, srcRoot) {
- srcFile, _ = filepath.Rel(srcRoot, srcFile)
- objFile = filepath.Join(objDir, srcFile)
- } else if srcRoot == "." && srcFile[0] != '/' {
- objFile = filepath.Join(objDir, srcFile)
- } else {
- ctx.ModuleErrorf("source file %q is not in source directory %q", srcFile, srcRoot)
- continue
- }
- objFile = pathtools.ReplaceExtension(objFile, "o")
- objFiles[i] = objFile
- var moduleCflags string
- var ccCmd string
- switch filepath.Ext(srcFile) {
- case ".S", ".s":
- ccCmd = "gcc"
- moduleCflags = asflags
- case ".c":
- ccCmd = "gcc"
- moduleCflags = cflags
- case ".cpp", ".cc":
- ccCmd = "g++"
- moduleCflags = cppflags
- default:
- ctx.ModuleErrorf("File %s has unknown extension", srcFile)
- continue
- }
- if flags.clang {
- switch ccCmd {
- case "gcc":
- ccCmd = "clang"
- case "g++":
- ccCmd = "clang++"
- default:
- panic("unrecoginzied ccCmd")
- }
- ccCmd = "${clangPath}" + ccCmd
- } else {
- ccCmd = gccCmd(flags.toolchain, ccCmd)
- }
- objDeps := append([]string{ccCmd}, deps...)
- ctx.Build(pctx, blueprint.BuildParams{
- Rule: cc,
- Outputs: []string{objFile},
- Inputs: []string{srcFile},
- Implicits: objDeps,
- Args: map[string]string{
- "cFlags": moduleCflags,
- "ccCmd": ccCmd,
- },
- })
- }
- return objFiles
- }
- // Generate a rule for compiling multiple .o files to a static library (.a)
- func TransformObjToStaticLib(ctx common.AndroidModuleContext, objFiles []string,
- flags builderFlags, outputFile string) {
- arCmd := gccCmd(flags.toolchain, "ar")
- arFlags := "crsPD"
- ctx.Build(pctx, blueprint.BuildParams{
- Rule: ar,
- Outputs: []string{outputFile},
- Inputs: objFiles,
- Implicits: []string{arCmd},
- Args: map[string]string{
- "arFlags": arFlags,
- "arCmd": arCmd,
- },
- })
- }
- // Generate a rule for compiling multiple .o files to a static library (.a) on
- // darwin. The darwin ar tool doesn't support @file for list files, and has a
- // very small command line length limit, so we have to split the ar into multiple
- // steps, each appending to the previous one.
- func TransformDarwinObjToStaticLib(ctx common.AndroidModuleContext, objFiles []string,
- flags builderFlags, outputFile string) {
- arCmd := "ar"
- arFlags := "cqs"
- // ARG_MAX on darwin is 262144, use half that to be safe
- objFilesLists, err := splitListForSize(objFiles, 131072)
- if err != nil {
- ctx.ModuleErrorf("%s", err.Error())
- }
- var in, out string
- for i, l := range objFilesLists {
- in = out
- out = outputFile
- if i != len(objFilesLists)-1 {
- out += "." + strconv.Itoa(i)
- }
- if in == "" {
- ctx.Build(pctx, blueprint.BuildParams{
- Rule: darwinAr,
- Outputs: []string{out},
- Inputs: l,
- Args: map[string]string{
- "arFlags": arFlags,
- "arCmd": arCmd,
- },
- })
- } else {
- ctx.Build(pctx, blueprint.BuildParams{
- Rule: darwinAppendAr,
- Outputs: []string{out},
- Inputs: l,
- Implicits: []string{in},
- Args: map[string]string{
- "arFlags": arFlags,
- "arCmd": arCmd,
- "inAr": in,
- },
- })
- }
- }
- }
- // Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries,
- // and shared libraires, to a shared library (.so) or dynamic executable
- func TransformObjToDynamicBinary(ctx common.AndroidModuleContext,
- objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps []string,
- crtBegin, crtEnd string, groupLate bool, flags builderFlags, outputFile string) {
- var ldCmd string
- if flags.clang {
- ldCmd = "${clangPath}clang++"
- } else {
- ldCmd = gccCmd(flags.toolchain, "g++")
- }
- var ldDirs []string
- var libFlagsList []string
- if len(wholeStaticLibs) > 0 {
- if ctx.Host() && runtime.GOOS == "darwin" {
- libFlagsList = append(libFlagsList, common.JoinWithPrefix(wholeStaticLibs, "-force_load "))
- } else {
- libFlagsList = append(libFlagsList, "-Wl,--whole-archive ")
- libFlagsList = append(libFlagsList, wholeStaticLibs...)
- libFlagsList = append(libFlagsList, "-Wl,--no-whole-archive ")
- }
- }
- libFlagsList = append(libFlagsList, staticLibs...)
- if groupLate && len(lateStaticLibs) > 0 {
- libFlagsList = append(libFlagsList, "-Wl,--start-group")
- }
- libFlagsList = append(libFlagsList, lateStaticLibs...)
- if groupLate && len(lateStaticLibs) > 0 {
- libFlagsList = append(libFlagsList, "-Wl,--end-group")
- }
- for _, lib := range sharedLibs {
- dir, file := filepath.Split(lib)
- if !strings.HasPrefix(file, "lib") {
- panic("shared library " + lib + " does not start with lib")
- }
- if !strings.HasSuffix(file, sharedLibraryExtension) {
- panic("shared library " + lib + " does not end with " + sharedLibraryExtension)
- }
- libFlagsList = append(libFlagsList,
- "-l"+strings.TrimSuffix(strings.TrimPrefix(file, "lib"), sharedLibraryExtension))
- ldDirs = append(ldDirs, dir)
- }
- deps = append(deps, ldCmd)
- deps = append(deps, sharedLibs...)
- deps = append(deps, staticLibs...)
- deps = append(deps, lateStaticLibs...)
- deps = append(deps, wholeStaticLibs...)
- if crtBegin != "" {
- deps = append(deps, crtBegin, crtEnd)
- }
- ctx.Build(pctx, blueprint.BuildParams{
- Rule: ld,
- Outputs: []string{outputFile},
- Inputs: objFiles,
- Implicits: deps,
- Args: map[string]string{
- "ldCmd": ldCmd,
- "ldDirFlags": ldDirsToFlags(ldDirs),
- "crtBegin": crtBegin,
- "libFlags": strings.Join(libFlagsList, " "),
- "ldFlags": flags.ldFlags,
- "crtEnd": crtEnd,
- },
- })
- }
- // Generate a rule for compiling multiple .o files to a .o using ld partial linking
- func TransformObjsToObj(ctx common.AndroidModuleContext, objFiles []string,
- flags builderFlags, outputFile string) {
- ldCmd := gccCmd(flags.toolchain, "ld")
- deps := []string{ldCmd}
- ctx.Build(pctx, blueprint.BuildParams{
- Rule: partialLd,
- Outputs: []string{outputFile},
- Inputs: objFiles,
- Implicits: deps,
- Args: map[string]string{
- "ldCmd": ldCmd,
- },
- })
- }
- // Generate a rule for runing objcopy --prefix-symbols on a binary
- func TransformBinaryPrefixSymbols(ctx common.AndroidModuleContext, prefix string, inputFile string,
- flags builderFlags, outputFile string) {
- objcopyCmd := gccCmd(flags.toolchain, "objcopy")
- ctx.Build(pctx, blueprint.BuildParams{
- Rule: prefixSymbols,
- Outputs: []string{outputFile},
- Inputs: []string{inputFile},
- Implicits: []string{objcopyCmd},
- Args: map[string]string{
- "objcopyCmd": objcopyCmd,
- "prefix": prefix,
- },
- })
- }
- func CopyGccLib(ctx common.AndroidModuleContext, libName string,
- flags builderFlags, outputFile string) {
- ctx.Build(pctx, blueprint.BuildParams{
- Rule: copyGccLib,
- Outputs: []string{outputFile},
- Implicits: []string{
- "$copyGccLibPath",
- gccCmd(flags.toolchain, "gcc"),
- },
- Args: map[string]string{
- "ccCmd": gccCmd(flags.toolchain, "gcc"),
- "cFlags": flags.globalFlags,
- "libName": libName,
- },
- })
- }
- func gccCmd(toolchain Toolchain, cmd string) string {
- return filepath.Join(toolchain.GccRoot(), "bin", toolchain.GccTriple()+"-"+cmd)
- }
- func splitListForSize(list []string, limit int) (lists [][]string, err error) {
- var i int
- start := 0
- bytes := 0
- for i = range list {
- l := len(list[i])
- if l > limit {
- return nil, fmt.Errorf("list element greater than size limit (%d)", limit)
- }
- if bytes+l > limit {
- lists = append(lists, list[start:i])
- start = i
- bytes = 0
- }
- bytes += l + 1 // count a space between each list element
- }
- lists = append(lists, list[start:])
- totalLen := 0
- for _, l := range lists {
- totalLen += len(l)
- }
- if totalLen != len(list) {
- panic(fmt.Errorf("Failed breaking up list, %d != %d", len(list), totalLen))
- }
- return lists, nil
- }
|