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