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