Home | History | Annotate | Download | only in cc
      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 
     15 package 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 
     21 import (
     22 	"android/soong/common"
     23 	"fmt"
     24 	"runtime"
     25 	"strconv"
     26 
     27 	"path/filepath"
     28 	"strings"
     29 
     30 	"github.com/google/blueprint"
     31 )
     32 
     33 const (
     34 	objectExtension        = ".o"
     35 	staticLibraryExtension = ".a"
     36 )
     37 
     38 var (
     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 
    117 func 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 
    129 type 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
    143 func 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)
    214 func 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.
    235 func 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
    285 func 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
    357 func 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
    379 func 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 
    395 func 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 
    409 func gccCmd(toolchain Toolchain, cmd string) string {
    410 	return filepath.Join(toolchain.GccRoot(), "bin", toolchain.GccTriple()+"-"+cmd)
    411 }
    412 
    413 func 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