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