• 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	"slices"
26	"strconv"
27	"strings"
28
29	"github.com/google/blueprint"
30	"github.com/google/blueprint/pathtools"
31
32	"android/soong/android"
33	"android/soong/cc/config"
34	"android/soong/remoteexec"
35)
36
37const (
38	objectExtension        = ".o"
39	staticLibraryExtension = ".a"
40)
41
42var (
43	pctx = android.NewPackageContext("android/soong/cc")
44
45	// Rule to invoke gcc with given command, flags, and dependencies. Outputs a .d depfile.
46	cc = pctx.AndroidRemoteStaticRule("cc", android.RemoteRuleSupports{Goma: true, RBE: true},
47		blueprint.RuleParams{
48			Depfile:     "${out}.d",
49			Deps:        blueprint.DepsGCC,
50			Command:     "$relPwd ${config.CcWrapper}$ccCmd -c $cFlags -MD -MF ${out}.d -o $out $in$postCmd",
51			CommandDeps: []string{"$ccCmd"},
52		},
53		"ccCmd", "cFlags", "postCmd")
54
55	// Rule to invoke gcc with given command and flags, but no dependencies.
56	ccNoDeps = pctx.AndroidStaticRule("ccNoDeps",
57		blueprint.RuleParams{
58			Command:     "$relPwd $ccCmd -c $cFlags -o $out $in$postCmd",
59			CommandDeps: []string{"$ccCmd"},
60		},
61		"ccCmd", "cFlags", "postCmd")
62
63	// Rules to invoke ld to link binaries. Uses a .rsp file to list dependencies, as there may
64	// be many.
65	ld, ldRE = pctx.RemoteStaticRules("ld",
66		blueprint.RuleParams{
67			Command: "$reTemplate$ldCmd ${crtBegin} @${out}.rsp " +
68				"${crtEnd} -o ${out} ${ldFlags} ${extraLibFlags}",
69			CommandDeps:    []string{"$ldCmd"},
70			Rspfile:        "${out}.rsp",
71			RspfileContent: "${in} ${libFlags}",
72			// clang -Wl,--out-implib doesn't update its output file if it hasn't changed.
73			Restat: true,
74		},
75		&remoteexec.REParams{
76			Labels:          map[string]string{"type": "link", "tool": "clang"},
77			ExecStrategy:    "${config.RECXXLinksExecStrategy}",
78			Inputs:          []string{"${out}.rsp", "$implicitInputs"},
79			RSPFiles:        []string{"${out}.rsp"},
80			OutputFiles:     []string{"${out}", "$implicitOutputs"},
81			ToolchainInputs: []string{"$ldCmd"},
82			Platform:        map[string]string{remoteexec.PoolKey: "${config.RECXXLinksPool}"},
83		}, []string{"ldCmd", "crtBegin", "libFlags", "crtEnd", "ldFlags", "extraLibFlags"}, []string{"implicitInputs", "implicitOutputs"})
84
85	// Rules for .o files to combine to other .o files, using ld partial linking.
86	partialLd, partialLdRE = pctx.RemoteStaticRules("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	// Rule to invoke `ar` with given cmd and flags, but no static library depenencies.
102	ar = pctx.AndroidStaticRule("ar",
103		blueprint.RuleParams{
104			Command:        "rm -f ${out} && $arCmd $arFlags $out @${out}.rsp",
105			CommandDeps:    []string{"$arCmd"},
106			Rspfile:        "${out}.rsp",
107			RspfileContent: "${in}",
108		},
109		"arCmd", "arFlags")
110
111	// Rule to invoke `ar` with given cmd, flags, and library dependencies. Generates a .a
112	// (archive) file from .o files.
113	arWithLibs = pctx.AndroidStaticRule("arWithLibs",
114		blueprint.RuleParams{
115			Command:        "rm -f ${out} && $arCmd $arObjFlags $out @${out}.rsp && $arCmd $arLibFlags $out $arLibs",
116			CommandDeps:    []string{"$arCmd"},
117			Rspfile:        "${out}.rsp",
118			RspfileContent: "${arObjs}",
119		},
120		"arCmd", "arObjFlags", "arObjs", "arLibFlags", "arLibs")
121
122	// Rule to run objcopy --prefix-symbols (to prefix all symbols in a file with a given string).
123	prefixSymbols = pctx.AndroidStaticRule("prefixSymbols",
124		blueprint.RuleParams{
125			Command:     "$objcopyCmd --prefix-symbols=${prefix} ${in} ${out}",
126			CommandDeps: []string{"$objcopyCmd"},
127		},
128		"objcopyCmd", "prefix")
129
130	// Rule to run objcopy --remove-section=.llvm_addrsig on a partially linked object
131	noAddrSig = pctx.AndroidStaticRule("noAddrSig",
132		blueprint.RuleParams{
133			Command:     "rm -f ${out} && $objcopyCmd --remove-section=.llvm_addrsig ${in} ${out}",
134			CommandDeps: []string{"$objcopyCmd"},
135		},
136		"objcopyCmd")
137
138	_ = pctx.SourcePathVariable("stripPath", "build/soong/scripts/strip.sh")
139	_ = pctx.SourcePathVariable("xzCmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/xz")
140	_ = pctx.SourcePathVariable("createMiniDebugInfo", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/create_minidebuginfo")
141
142	// Rule to invoke `strip` (to discard symbols and data from object files).
143	strip = pctx.AndroidStaticRule("strip",
144		blueprint.RuleParams{
145			Depfile: "${out}.d",
146			Deps:    blueprint.DepsGCC,
147			Command: "XZ=$xzCmd CREATE_MINIDEBUGINFO=$createMiniDebugInfo CLANG_BIN=${config.ClangBin} $stripPath ${args} -i ${in} -o ${out} -d ${out}.d",
148			CommandDeps: func() []string {
149				if runtime.GOOS != "darwin" {
150					return []string{"$stripPath", "$xzCmd", "$createMiniDebugInfo"}
151				} else {
152					return []string{"$stripPath", "$xzCmd"}
153				}
154			}(),
155			Pool: darwinStripPool,
156		},
157		"args")
158
159	// Rule to invoke `strip` (to discard symbols and data from object files) on darwin architecture.
160	darwinStrip = func() blueprint.Rule {
161		if runtime.GOOS == "darwin" {
162			return pctx.AndroidStaticRule("darwinStrip",
163				blueprint.RuleParams{
164					Command:     "${config.MacStripPath} -u -r -o $out $in",
165					CommandDeps: []string{"${config.MacStripPath}"},
166				})
167		} else {
168			return nil
169		}
170	}()
171
172	// b/132822437: objcopy uses a file descriptor per .o file when called on .a files, which runs the system out of
173	// file descriptors on darwin.  Limit concurrent calls to 5 on darwin.
174	darwinStripPool = func() blueprint.Pool {
175		if runtime.GOOS == "darwin" {
176			return pctx.StaticPool("darwinStripPool", blueprint.PoolParams{
177				Depth: 5,
178			})
179		} else {
180			return nil
181		}
182	}()
183
184	darwinLipo = func() blueprint.Rule {
185		if runtime.GOOS == "darwin" {
186			return pctx.AndroidStaticRule("darwinLipo",
187				blueprint.RuleParams{
188					Command:     "${config.MacLipoPath} -create -output $out $in",
189					CommandDeps: []string{"${config.MacLipoPath}"},
190				})
191		} else {
192			return nil
193		}
194	}()
195
196	_ = pctx.SourcePathVariable("archiveRepackPath", "build/soong/scripts/archive_repack.sh")
197
198	// Rule to repack an archive (.a) file with a subset of object files.
199	archiveRepack = pctx.AndroidStaticRule("archiveRepack",
200		blueprint.RuleParams{
201			Depfile:     "${out}.d",
202			Deps:        blueprint.DepsGCC,
203			Command:     "CLANG_BIN=${config.ClangBin} $archiveRepackPath -i ${in} -o ${out} -d ${out}.d ${objects}",
204			CommandDeps: []string{"$archiveRepackPath"},
205		},
206		"objects")
207
208	// Rule to create an empty file at a given path.
209	emptyFile = pctx.AndroidStaticRule("emptyFile",
210		blueprint.RuleParams{
211			Command: "rm -f $out && touch $out",
212		})
213
214	_ = pctx.SourcePathVariable("tocPath", "build/soong/scripts/toc.sh")
215
216	// A rule for extracting a table of contents from a shared library (.so).
217	toc = pctx.AndroidStaticRule("toc",
218		blueprint.RuleParams{
219			Depfile:     "${out}.d",
220			Deps:        blueprint.DepsGCC,
221			Command:     "CLANG_BIN=$clangBin $tocPath $format -i ${in} -o ${out} -d ${out}.d",
222			CommandDeps: []string{"$tocPath"},
223			Restat:      true,
224		},
225		"clangBin", "format")
226
227	// Rules for invoking clang-tidy (a clang-based linter).
228	clangTidy, clangTidyRE = pctx.RemoteStaticRules("clangTidy",
229		blueprint.RuleParams{
230			Depfile: "${out}.d",
231			Deps:    blueprint.DepsGCC,
232			Command: "CLANG_CMD=$clangCmd TIDY_FILE=$out " +
233				"$tidyVars$reTemplate${config.ClangBin}/clang-tidy.sh $in $tidyFlags -- $cFlags",
234			CommandDeps: []string{"${config.ClangBin}/clang-tidy.sh", "$ccCmd", "$tidyCmd"},
235		},
236		&remoteexec.REParams{
237			Labels:               map[string]string{"type": "lint", "tool": "clang-tidy", "lang": "cpp"},
238			ExecStrategy:         "${config.REClangTidyExecStrategy}",
239			Inputs:               []string{"$in"},
240			OutputFiles:          []string{"${out}", "${out}.d"},
241			ToolchainInputs:      []string{"$ccCmd", "$tidyCmd"},
242			EnvironmentVariables: []string{"CLANG_CMD", "TIDY_FILE", "TIDY_TIMEOUT"},
243			// Although clang-tidy has an option to "fix" source files, that feature is hardly useable
244			// under parallel compilation and RBE. So we assume no OutputFiles here.
245			// The clang-tidy fix option is best run locally in single thread.
246			// Copying source file back to local caused two problems:
247			// (1) New timestamps trigger clang and clang-tidy compilations again.
248			// (2) Changing source files caused concurrent clang or clang-tidy jobs to crash.
249			Platform: map[string]string{remoteexec.PoolKey: "${config.REClangTidyPool}"},
250		}, []string{"cFlags", "ccCmd", "clangCmd", "tidyCmd", "tidyFlags", "tidyVars"}, []string{})
251
252	_ = pctx.SourcePathVariable("yasmCmd", "prebuilts/misc/${config.HostPrebuiltTag}/yasm/yasm")
253
254	// Rule for invoking yasm to compile .asm assembly files.
255	yasm = pctx.AndroidStaticRule("yasm",
256		blueprint.RuleParams{
257			Command:     "$yasmCmd $asFlags -o $out $in && $yasmCmd $asFlags -M $in >$out.d",
258			CommandDeps: []string{"$yasmCmd"},
259			Depfile:     "$out.d",
260			Deps:        blueprint.DepsGCC,
261		},
262		"asFlags")
263
264	_ = pctx.SourcePathVariable("sAbiDumper", "prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/header-abi-dumper")
265
266	// -w has been added since header-abi-dumper does not need to produce any sort of diagnostic information.
267	sAbiDump, sAbiDumpRE = pctx.RemoteStaticRules("sAbiDump",
268		blueprint.RuleParams{
269			Command:     "rm -f $out && $reTemplate$sAbiDumper --root-dir . --root-dir $$OUT_DIR:out -o ${out} $in $exportDirs -- $cFlags -w -isystem prebuilts/clang-tools/${config.HostPrebuiltTag}/clang-headers",
270			CommandDeps: []string{"$sAbiDumper"},
271		}, &remoteexec.REParams{
272			Labels:       map[string]string{"type": "abi-dump", "tool": "header-abi-dumper"},
273			ExecStrategy: "${config.REAbiDumperExecStrategy}",
274			Inputs:       []string{"$sAbiLinkerLibs"},
275			Platform: map[string]string{
276				remoteexec.PoolKey: "${config.RECXXPool}",
277			},
278		}, []string{"cFlags", "exportDirs"}, nil)
279
280	_ = pctx.SourcePathVariable("sAbiLinker", "prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/header-abi-linker")
281	_ = pctx.SourcePathVariable("sAbiLinkerLibs", "prebuilts/clang-tools/${config.HostPrebuiltTag}/lib64")
282
283	// Rule to combine .dump sAbi dump files from multiple source files into a single .ldump
284	// sAbi dump file.
285	sAbiLink, sAbiLinkRE = pctx.RemoteStaticRules("sAbiLink",
286		blueprint.RuleParams{
287			Command:        "$reTemplate$sAbiLinker --root-dir . --root-dir $$OUT_DIR:out -o ${out} $symbolFilter -arch $arch $exportedHeaderFlags @${out}.rsp",
288			CommandDeps:    []string{"$sAbiLinker"},
289			Rspfile:        "${out}.rsp",
290			RspfileContent: "${in}",
291		}, &remoteexec.REParams{
292			Labels:          map[string]string{"type": "tool", "name": "abi-linker"},
293			ExecStrategy:    "${config.REAbiLinkerExecStrategy}",
294			Inputs:          []string{"$sAbiLinkerLibs", "${out}.rsp", "$implicitInputs"},
295			RSPFiles:        []string{"${out}.rsp"},
296			OutputFiles:     []string{"$out"},
297			ToolchainInputs: []string{"$sAbiLinker"},
298			Platform:        map[string]string{remoteexec.PoolKey: "${config.RECXXPool}"},
299		}, []string{"symbolFilter", "arch", "exportedHeaderFlags"}, []string{"implicitInputs"})
300
301	_ = pctx.SourcePathVariable("sAbiDiffer", "prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/header-abi-diff")
302
303	// Rule to compare linked sAbi dump files (.ldump).
304	sAbiDiff = pctx.RuleFunc("sAbiDiff",
305		func(ctx android.PackageRuleContext) blueprint.RuleParams {
306			commandStr := "($sAbiDiffer ${extraFlags} -lib ${libName} -arch ${arch} -o ${out} -new ${in} -old ${referenceDump})"
307			commandStr += "|| (echo '${errorMessage}'"
308			commandStr += " && (mkdir -p $$DIST_DIR/abidiffs && cp ${out} $$DIST_DIR/abidiffs/)"
309			commandStr += " && exit 1)"
310			return blueprint.RuleParams{
311				Command:     commandStr,
312				CommandDeps: []string{"$sAbiDiffer"},
313			}
314		},
315		"extraFlags", "referenceDump", "libName", "arch", "errorMessage")
316
317	// Rule to zip files.
318	zip = pctx.AndroidStaticRule("zip",
319		blueprint.RuleParams{
320			Command:        "${SoongZipCmd} -o ${out} -C $$OUT_DIR -r ${out}.rsp",
321			CommandDeps:    []string{"${SoongZipCmd}"},
322			Rspfile:        "${out}.rsp",
323			RspfileContent: "$in",
324		})
325
326	_ = pctx.SourcePathVariable("cxxExtractor",
327		"prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/cxx_extractor")
328	_ = pctx.SourcePathVariable("kytheVnames", "build/soong/vnames.json")
329	_ = pctx.VariableFunc("kytheCorpus",
330		func(ctx android.PackageVarContext) string { return ctx.Config().XrefCorpusName() })
331	_ = pctx.VariableFunc("kytheCuEncoding",
332		func(ctx android.PackageVarContext) string { return ctx.Config().XrefCuEncoding() })
333
334	// Rule to use kythe extractors to generate .kzip files, used to build code cross references.
335	kytheExtract = pctx.StaticRule("kythe",
336		blueprint.RuleParams{
337			Command: `rm -f $out && ` +
338				`KYTHE_CORPUS=${kytheCorpus} ` +
339				`KYTHE_OUTPUT_FILE=$out ` +
340				`KYTHE_VNAMES=$kytheVnames ` +
341				`KYTHE_KZIP_ENCODING=${kytheCuEncoding} ` +
342				`KYTHE_CANONICALIZE_VNAME_PATHS=prefer-relative ` +
343				`$cxxExtractor $cFlags $in `,
344			CommandDeps: []string{"$cxxExtractor", "$kytheVnames"},
345		},
346		"cFlags")
347
348	// Function pointer for producting staticlibs from rlibs. Corresponds to
349	// rust.TransformRlibstoStaticlib(), initialized in soong-rust (rust/builder.go init())
350	//
351	// This is required since soong-rust depends on soong-cc, so soong-cc cannot depend on soong-rust
352	// without resulting in a circular dependency. Setting this function pointer in soong-rust allows
353	// soong-cc to call into this particular function.
354	TransformRlibstoStaticlib (func(ctx android.ModuleContext, mainSrc android.Path, deps []RustRlibDep,
355		outputFile android.WritablePath) android.Path) = nil
356)
357
358func PwdPrefix() string {
359	// Darwin doesn't have /proc
360	if runtime.GOOS != "darwin" {
361		return "PWD=/proc/self/cwd"
362	}
363	return ""
364}
365
366func init() {
367	// We run gcc/clang with PWD=/proc/self/cwd to remove $TOP from the
368	// debug output. That way two builds in two different directories will
369	// create the same output.
370	pctx.StaticVariable("relPwd", PwdPrefix())
371
372	pctx.HostBinToolVariable("SoongZipCmd", "soong_zip")
373}
374
375// builderFlags contains various types of command line flags (and settings) for use in building
376// build statements related to C++.
377type builderFlags struct {
378	// Global flags (which build system or toolchain is responsible for). These are separate from
379	// local flags because they should appear first (so that they may be overridden by local flags).
380	globalCommonFlags     string
381	globalAsFlags         string
382	globalYasmFlags       string
383	globalCFlags          string
384	globalToolingCFlags   string // A separate set of cFlags for clang LibTooling tools
385	globalToolingCppFlags string // A separate set of cppFlags for clang LibTooling tools
386	globalConlyFlags      string
387	globalCppFlags        string
388	globalLdFlags         string
389
390	// Local flags (which individual modules are responsible for). These may override global flags.
391	localCommonFlags     string
392	localAsFlags         string
393	localYasmFlags       string
394	localCFlags          string
395	localToolingCFlags   string // A separate set of cFlags for clang LibTooling tools
396	localToolingCppFlags string // A separate set of cppFlags for clang LibTooling tools
397	localConlyFlags      string
398	localCppFlags        string
399	localLdFlags         string
400
401	noOverrideFlags string // Flags appended at the end so they are not overridden.
402	libFlags        string // Flags to add to the linker directly after specifying libraries to link.
403	extraLibFlags   string // Flags to add to the linker last.
404	tidyFlags       string // Flags that apply to clang-tidy
405	sAbiFlags       string // Flags that apply to header-abi-dumps
406	aidlFlags       string // Flags that apply to aidl source files
407	rsFlags         string // Flags that apply to renderscript source files
408	toolchain       config.Toolchain
409
410	// True if these extra features are enabled.
411	tidy          bool
412	needTidyFiles bool
413	gcovCoverage  bool
414	sAbiDump      bool
415	emitXrefs     bool
416	clangVerify   bool
417
418	assemblerWithCpp bool // True if .s files should be processed with the c preprocessor.
419
420	systemIncludeFlags string
421
422	proto            android.ProtoFlags
423	protoC           bool // If true, compile protos as `.c` files. Otherwise, output as `.cc`.
424	protoOptionsFile bool // If true, output a proto options file.
425
426	yacc *YaccProperties
427	lex  *LexProperties
428}
429
430// StripFlags represents flags related to stripping. This is separate from builderFlags, as these
431// flags are useful outside of this package (such as for Rust).
432type StripFlags struct {
433	Toolchain                     config.Toolchain
434	StripKeepSymbols              bool
435	StripKeepSymbolsList          string
436	StripKeepSymbolsAndDebugFrame bool
437	StripKeepMiniDebugInfo        bool
438	StripAddGnuDebuglink          bool
439	StripUseGnuStrip              bool
440}
441
442// Objects is a collection of file paths corresponding to outputs for C++ related build statements.
443type Objects struct {
444	objFiles      android.Paths
445	tidyFiles     android.Paths
446	tidyDepFiles  android.Paths // link dependent .tidy files
447	coverageFiles android.Paths
448	sAbiDumpFiles android.Paths
449	kytheFiles    android.Paths
450}
451
452func (a Objects) Copy() Objects {
453	return Objects{
454		objFiles:      append(android.Paths{}, a.objFiles...),
455		tidyFiles:     append(android.Paths{}, a.tidyFiles...),
456		tidyDepFiles:  append(android.Paths{}, a.tidyDepFiles...),
457		coverageFiles: append(android.Paths{}, a.coverageFiles...),
458		sAbiDumpFiles: append(android.Paths{}, a.sAbiDumpFiles...),
459		kytheFiles:    append(android.Paths{}, a.kytheFiles...),
460	}
461}
462
463func (a Objects) Append(b Objects) Objects {
464	return Objects{
465		objFiles:      append(a.objFiles, b.objFiles...),
466		tidyFiles:     append(a.tidyFiles, b.tidyFiles...),
467		tidyDepFiles:  append(a.tidyDepFiles, b.tidyDepFiles...),
468		coverageFiles: append(a.coverageFiles, b.coverageFiles...),
469		sAbiDumpFiles: append(a.sAbiDumpFiles, b.sAbiDumpFiles...),
470		kytheFiles:    append(a.kytheFiles, b.kytheFiles...),
471	}
472}
473
474// Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files
475func transformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles, noTidySrcs, timeoutTidySrcs android.Paths,
476	flags builderFlags, pathDeps android.Paths, cFlagsDeps android.Paths, sharedFlags *SharedFlags) Objects {
477
478	// Not all source files produce a .o; a Rust source provider
479	// may provide both a .c and a .rs file (e.g. rust_bindgen).
480	srcObjFiles := android.Paths{}
481	for _, src := range srcFiles {
482		if src.Ext() != ".rs" {
483			srcObjFiles = append(srcObjFiles, src)
484		}
485	}
486
487	// Source files are one-to-one with tidy, coverage, or kythe files, if enabled.
488	objFiles := make(android.Paths, len(srcObjFiles))
489	var tidyFiles android.Paths
490	noTidySrcsMap := make(map[string]bool)
491	var tidyVars string
492	if flags.tidy {
493		tidyFiles = make(android.Paths, 0, len(srcObjFiles))
494		for _, path := range noTidySrcs {
495			noTidySrcsMap[path.String()] = true
496		}
497		tidyTimeout := ctx.Config().Getenv("TIDY_TIMEOUT")
498		if len(tidyTimeout) > 0 {
499			tidyVars += "TIDY_TIMEOUT=" + tidyTimeout + " "
500			// add timeoutTidySrcs into noTidySrcsMap if TIDY_TIMEOUT is set
501			for _, path := range timeoutTidySrcs {
502				noTidySrcsMap[path.String()] = true
503			}
504		}
505	}
506	var coverageFiles android.Paths
507	if flags.gcovCoverage {
508		coverageFiles = make(android.Paths, 0, len(srcObjFiles))
509	}
510	var kytheFiles android.Paths
511	if flags.emitXrefs && ctx.Module() == ctx.PrimaryModule() {
512		kytheFiles = make(android.Paths, 0, len(srcObjFiles))
513	}
514
515	// Produce fully expanded flags for use by C tools, C compiles, C++ tools, C++ compiles, and asm compiles
516	// respectively.
517	toolingCflags := flags.globalCommonFlags + " " +
518		flags.globalToolingCFlags + " " +
519		flags.globalConlyFlags + " " +
520		flags.localCommonFlags + " " +
521		flags.localToolingCFlags + " " +
522		flags.localConlyFlags + " " +
523		flags.systemIncludeFlags + " " +
524		flags.noOverrideFlags
525
526	cflags := flags.globalCommonFlags + " " +
527		flags.globalCFlags + " " +
528		flags.globalConlyFlags + " " +
529		flags.localCommonFlags + " " +
530		flags.localCFlags + " " +
531		flags.localConlyFlags + " " +
532		flags.systemIncludeFlags + " " +
533		flags.noOverrideFlags
534
535	toolingCppflags := flags.globalCommonFlags + " " +
536		flags.globalToolingCFlags + " " +
537		flags.globalToolingCppFlags + " " +
538		flags.localCommonFlags + " " +
539		flags.localToolingCFlags + " " +
540		flags.localToolingCppFlags + " " +
541		flags.systemIncludeFlags + " " +
542		flags.noOverrideFlags
543
544	cppflags := flags.globalCommonFlags + " " +
545		flags.globalCFlags + " " +
546		flags.globalCppFlags + " " +
547		flags.localCommonFlags + " " +
548		flags.localCFlags + " " +
549		flags.localCppFlags + " " +
550		flags.systemIncludeFlags + " " +
551		flags.noOverrideFlags
552
553	asflags := flags.globalCommonFlags + " " +
554		flags.globalAsFlags + " " +
555		flags.localCommonFlags + " " +
556		flags.localAsFlags + " " +
557		flags.systemIncludeFlags
558
559	var sAbiDumpFiles android.Paths
560	if flags.sAbiDump {
561		sAbiDumpFiles = make(android.Paths, 0, len(srcObjFiles))
562	}
563
564	// Multiple source files have build rules usually share the same cFlags or tidyFlags.
565	// SharedFlags provides one version for this module and shares it in multiple build rules.
566	// To simplify the code, the SharedFlags variables are all named as $flags<nnn>.
567	// Share flags only when there are multiple files or tidy rules.
568	var hasMultipleRules = len(srcObjFiles) > 1 || flags.tidy
569
570	var shareFlags = func(kind string, flags string) string {
571		if !hasMultipleRules || len(flags) < 60 {
572			// Modules have long names and so do the module variables.
573			// It does not save space by replacing a short name with a long one.
574			return flags
575		}
576		mapKey := kind + flags
577		n, ok := sharedFlags.FlagsMap[mapKey]
578		if !ok {
579			sharedFlags.NumSharedFlags += 1
580			n = strconv.Itoa(sharedFlags.NumSharedFlags)
581			sharedFlags.FlagsMap[mapKey] = n
582			ctx.Variable(pctx, kind+n, flags)
583		}
584		return "$" + kind + n
585	}
586
587	for i, srcFile := range srcObjFiles {
588		objFile := android.ObjPathWithExt(ctx, subdir, srcFile, "o")
589
590		objFiles[i] = objFile
591
592		// Register compilation build statements. The actual rule used depends on the source file type.
593		switch srcFile.Ext() {
594		case ".asm":
595			ctx.Build(pctx, android.BuildParams{
596				Rule:        yasm,
597				Description: "yasm " + srcFile.Rel(),
598				Output:      objFile,
599				Input:       srcFile,
600				Implicits:   cFlagsDeps,
601				OrderOnly:   pathDeps,
602				Args: map[string]string{
603					"asFlags": shareFlags("asFlags", flags.globalYasmFlags+" "+flags.localYasmFlags),
604				},
605			})
606			continue
607		case ".o":
608			objFiles[i] = srcFile
609			continue
610		}
611
612		var moduleFlags string
613		var moduleToolingFlags string
614
615		var ccCmd string
616		var postCmd string
617		tidy := flags.tidy
618		coverage := flags.gcovCoverage
619		dump := flags.sAbiDump
620		rule := cc
621		emitXref := flags.emitXrefs
622
623		switch srcFile.Ext() {
624		case ".s":
625			if !flags.assemblerWithCpp {
626				rule = ccNoDeps
627			}
628			fallthrough
629		case ".S":
630			ccCmd = "clang"
631			moduleFlags = asflags
632			tidy = false
633			coverage = false
634			dump = false
635			emitXref = false
636		case ".c":
637			ccCmd = "clang"
638			moduleFlags = cflags
639			moduleToolingFlags = toolingCflags
640		case ".cpp", ".cc", ".cxx", ".mm":
641			ccCmd = "clang++"
642			moduleFlags = cppflags
643			moduleToolingFlags = toolingCppflags
644		case ".rs":
645			// A source provider (e.g. rust_bindgen) may provide both rs and c files.
646			// Ignore the rs files.
647			continue
648		case ".h", ".hpp":
649			ctx.PropertyErrorf("srcs", "Header file %s is not supported, instead use export_include_dirs or local_include_dirs.", srcFile)
650			continue
651		default:
652			ctx.PropertyErrorf("srcs", "File %s has unknown extension. Supported extensions: .s, .S, .c, .cpp, .cc, .cxx, .mm", srcFile)
653			continue
654		}
655
656		// ccCmd is "clang" or "clang++"
657		ccDesc := ccCmd
658
659		ccCmd = "${config.ClangBin}/" + ccCmd
660
661		if flags.clangVerify {
662			postCmd = " && touch " + objFile.String()
663		}
664
665		var implicitOutputs android.WritablePaths
666		if coverage {
667			gcnoFile := android.ObjPathWithExt(ctx, subdir, srcFile, "gcno")
668			implicitOutputs = append(implicitOutputs, gcnoFile)
669			coverageFiles = append(coverageFiles, gcnoFile)
670		}
671
672		ctx.Build(pctx, android.BuildParams{
673			Rule:            rule,
674			Description:     ccDesc + " " + srcFile.Rel(),
675			Output:          objFile,
676			ImplicitOutputs: implicitOutputs,
677			Input:           srcFile,
678			Implicits:       cFlagsDeps,
679			OrderOnly:       pathDeps,
680			Args: map[string]string{
681				"cFlags":  shareFlags("cFlags", moduleFlags),
682				"ccCmd":   ccCmd, // short and not shared
683				"postCmd": postCmd,
684			},
685		})
686
687		// Register post-process build statements (such as for tidy or kythe).
688		if emitXref && ctx.Module() == ctx.PrimaryModule() {
689			kytheFile := android.ObjPathWithExt(ctx, subdir, srcFile, "kzip")
690			ctx.Build(pctx, android.BuildParams{
691				Rule:        kytheExtract,
692				Description: "Xref C++ extractor " + srcFile.Rel(),
693				Output:      kytheFile,
694				Input:       srcFile,
695				Implicits:   cFlagsDeps,
696				OrderOnly:   pathDeps,
697				Args: map[string]string{
698					"cFlags": shareFlags("cFlags", moduleFlags),
699				},
700			})
701			kytheFiles = append(kytheFiles, kytheFile)
702		}
703
704		//  Even with tidy, some src file could be skipped by noTidySrcsMap.
705		if tidy && !noTidySrcsMap[srcFile.String()] {
706			tidyFile := android.ObjPathWithExt(ctx, subdir, srcFile, "tidy")
707			tidyFiles = append(tidyFiles, tidyFile)
708			tidyCmd := "${config.ClangBin}/clang-tidy"
709
710			rule := clangTidy
711			if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CLANG_TIDY") {
712				rule = clangTidyRE
713			}
714
715			sharedCFlags := shareFlags("cFlags", moduleFlags)
716			srcRelPath := srcFile.Rel()
717
718			// Add the .tidy rule
719			ctx.Build(pctx, android.BuildParams{
720				Rule:        rule,
721				Description: "clang-tidy " + srcRelPath,
722				Output:      tidyFile,
723				Input:       srcFile,
724				Implicits:   cFlagsDeps,
725				OrderOnly:   pathDeps,
726				Args: map[string]string{
727					"cFlags":    sharedCFlags,
728					"ccCmd":     ccCmd,
729					"clangCmd":  ccDesc,
730					"tidyCmd":   tidyCmd,
731					"tidyFlags": shareFlags("tidyFlags", config.TidyFlagsForSrcFile(srcFile, flags.tidyFlags)),
732					"tidyVars":  tidyVars, // short and not shared
733				},
734			})
735		}
736
737		if dump {
738			sAbiDumpFile := android.ObjPathWithExt(ctx, subdir, srcFile, "sdump")
739			sAbiDumpFiles = append(sAbiDumpFiles, sAbiDumpFile)
740
741			dumpRule := sAbiDump
742			if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_ABI_DUMPER") {
743				dumpRule = sAbiDumpRE
744			}
745			ctx.Build(pctx, android.BuildParams{
746				Rule:        dumpRule,
747				Description: "header-abi-dumper " + srcFile.Rel(),
748				Output:      sAbiDumpFile,
749				Input:       srcFile,
750				Implicit:    objFile,
751				Implicits:   cFlagsDeps,
752				OrderOnly:   pathDeps,
753				Args: map[string]string{
754					"cFlags":     shareFlags("cFlags", moduleToolingFlags),
755					"exportDirs": shareFlags("exportDirs", flags.sAbiFlags),
756				},
757			})
758		}
759
760	}
761
762	var tidyDepFiles android.Paths
763	if flags.needTidyFiles {
764		tidyDepFiles = tidyFiles
765	}
766	return Objects{
767		objFiles:      objFiles,
768		tidyFiles:     tidyFiles,
769		tidyDepFiles:  tidyDepFiles,
770		coverageFiles: coverageFiles,
771		sAbiDumpFiles: sAbiDumpFiles,
772		kytheFiles:    kytheFiles,
773	}
774}
775
776// Generate a rule for compiling multiple .o files to a static library (.a)
777func transformObjToStaticLib(ctx android.ModuleContext,
778	objFiles android.Paths, wholeStaticLibs android.Paths,
779	flags builderFlags, outputFile android.ModuleOutPath, deps android.Paths, validations android.Paths) {
780
781	arCmd := "${config.ClangBin}/llvm-ar"
782	arFlags := ""
783	if !ctx.Darwin() {
784		arFlags += " --format=gnu"
785	}
786
787	if len(wholeStaticLibs) == 0 {
788		ctx.Build(pctx, android.BuildParams{
789			Rule:        ar,
790			Description: "static link " + outputFile.Base(),
791			Output:      outputFile,
792			Inputs:      objFiles,
793			Implicits:   deps,
794			Validations: validations,
795			Args: map[string]string{
796				"arFlags": "crsPD" + arFlags,
797				"arCmd":   arCmd,
798			},
799		})
800
801	} else {
802		ctx.Build(pctx, android.BuildParams{
803			Rule:        arWithLibs,
804			Description: "static link " + outputFile.Base(),
805			Output:      outputFile,
806			Inputs:      append(objFiles, wholeStaticLibs...),
807			Implicits:   deps,
808			Args: map[string]string{
809				"arCmd":      arCmd,
810				"arObjFlags": "crsPD" + arFlags,
811				"arObjs":     strings.Join(objFiles.Strings(), " "),
812				"arLibFlags": "cqsL" + arFlags,
813				"arLibs":     strings.Join(wholeStaticLibs.Strings(), " "),
814			},
815		})
816	}
817}
818
819// Generate a Rust staticlib from a list of rlibDeps. Returns nil if TransformRlibstoStaticlib is nil or rlibDeps is empty.
820func GenerateRustStaticlib(ctx android.ModuleContext, rlibDeps []RustRlibDep) android.Path {
821	if TransformRlibstoStaticlib == nil && len(rlibDeps) > 0 {
822		// This should only be reachable if a module defines Rust deps in static_libs and
823		// soong-rust hasn't been loaded alongside soong-cc (e.g. in soong-cc tests).
824		panic(fmt.Errorf(
825			"TransformRlibstoStaticlib is not set and rust deps are defined in static_libs for %s",
826			ctx.ModuleName()))
827
828	} else if len(rlibDeps) == 0 {
829		return nil
830	}
831
832	output := android.PathForModuleOut(ctx, "generated_rust_staticlib", "librustlibs.a")
833	stemFile := output.ReplaceExtension(ctx, "rs")
834	crateNames := []string{}
835
836	// Collect crate names
837	for _, lib := range rlibDeps {
838		// Exclude libstd so this can support no_std builds.
839		if lib.CrateName != "libstd" {
840			crateNames = append(crateNames, lib.CrateName)
841		}
842	}
843
844	// Deduplicate any crateNames just to be safe
845	crateNames = android.FirstUniqueStrings(crateNames)
846
847	// Write the source file
848	android.WriteFileRule(ctx, stemFile, genRustStaticlibSrcFile(crateNames))
849
850	return TransformRlibstoStaticlib(ctx, stemFile, rlibDeps, output)
851}
852
853func genRustStaticlibSrcFile(crateNames []string) string {
854	lines := []string{
855		"// @Soong generated Source",
856		"#![no_std]", // pre-emptively set no_std to support both std and no_std.
857	}
858	for _, crate := range crateNames {
859		lines = append(lines, fmt.Sprintf("extern crate %s;", crate))
860	}
861	return strings.Join(lines, "\n")
862}
863
864func BuildRustStubs(ctx android.ModuleContext, outputFile android.ModuleOutPath,
865	stubObjs Objects, ccFlags Flags) {
866
867	// Instantiate paths
868	sharedLibs := android.Paths{}
869	staticLibs := android.Paths{}
870	lateStaticLibs := android.Paths{}
871	wholeStaticLibs := android.Paths{}
872	deps := android.Paths{}
873	implicitOutputs := android.WritablePaths{}
874	validations := android.Paths{}
875	crtBegin := android.Paths{}
876	crtEnd := android.Paths{}
877	groupLate := false
878
879	builderFlags := flagsToBuilderFlags(ccFlags)
880	transformObjToDynamicBinary(ctx, stubObjs.objFiles, sharedLibs, staticLibs,
881		lateStaticLibs, wholeStaticLibs, deps, crtBegin, crtEnd,
882		groupLate, builderFlags, outputFile, implicitOutputs, validations)
883}
884
885// Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries,
886// and shared libraries, to a shared library (.so) or dynamic executable
887func transformObjToDynamicBinary(ctx android.ModuleContext,
888	objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps, crtBegin, crtEnd android.Paths,
889	groupLate bool, flags builderFlags, outputFile android.WritablePath,
890	implicitOutputs android.WritablePaths, validations android.Paths) {
891
892	ldCmd := "${config.ClangBin}/clang++"
893
894	var libFlagsList []string
895
896	if len(flags.libFlags) > 0 {
897		libFlagsList = append(libFlagsList, flags.libFlags)
898	}
899
900	if len(wholeStaticLibs) > 0 {
901		if ctx.Host() && ctx.Darwin() {
902			libFlagsList = append(libFlagsList, android.JoinWithPrefix(wholeStaticLibs.Strings(), "-force_load "))
903		} else {
904			libFlagsList = append(libFlagsList, "-Wl,--whole-archive ")
905			libFlagsList = append(libFlagsList, wholeStaticLibs.Strings()...)
906			libFlagsList = append(libFlagsList, "-Wl,--no-whole-archive ")
907		}
908	}
909
910	libFlagsList = append(libFlagsList, staticLibs.Strings()...)
911
912	if groupLate && !ctx.Darwin() && len(lateStaticLibs) > 0 {
913		libFlagsList = append(libFlagsList, "-Wl,--start-group")
914	}
915	libFlagsList = append(libFlagsList, lateStaticLibs.Strings()...)
916	if groupLate && !ctx.Darwin() && len(lateStaticLibs) > 0 {
917		libFlagsList = append(libFlagsList, "-Wl,--end-group")
918	}
919
920	for _, lib := range sharedLibs {
921		libFile := lib.String()
922		if ctx.Windows() {
923			libFile = pathtools.ReplaceExtension(libFile, "lib")
924		}
925		libFlagsList = append(libFlagsList, libFile)
926	}
927
928	deps = append(deps, staticLibs...)
929	deps = append(deps, lateStaticLibs...)
930	deps = append(deps, wholeStaticLibs...)
931	deps = append(deps, crtBegin...)
932	deps = append(deps, crtEnd...)
933
934	rule := ld
935	args := map[string]string{
936		"ldCmd":         ldCmd,
937		"crtBegin":      strings.Join(crtBegin.Strings(), " "),
938		"libFlags":      strings.Join(libFlagsList, " "),
939		"extraLibFlags": flags.extraLibFlags,
940		"ldFlags":       flags.globalLdFlags + " " + flags.localLdFlags,
941		"crtEnd":        strings.Join(crtEnd.Strings(), " "),
942	}
943
944	// On Windows, we always generate a PDB file
945	// --strip-debug is needed to also keep COFF symbols which are needed when
946	// we patch binaries with symbol_inject.
947	if ctx.Windows() {
948		pdb := outputFile.ReplaceExtension(ctx, "pdb")
949		args["ldFlags"] = args["ldFlags"] + " -Wl,--strip-debug -Wl,--pdb=" + pdb.String() + " "
950		implicitOutputs = append(slices.Clone(implicitOutputs), pdb)
951	}
952
953	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CXX_LINKS") {
954		rule = ldRE
955		args["implicitOutputs"] = strings.Join(implicitOutputs.Strings(), ",")
956		args["implicitInputs"] = strings.Join(deps.Strings(), ",")
957	}
958
959	ctx.Build(pctx, android.BuildParams{
960		Rule:            rule,
961		Description:     "link " + outputFile.Base(),
962		Output:          outputFile,
963		ImplicitOutputs: implicitOutputs,
964		Inputs:          objFiles,
965		Implicits:       deps,
966		OrderOnly:       sharedLibs,
967		Validations:     validations,
968		Args:            args,
969	})
970}
971
972// Generate a rule to combine .dump sAbi dump files from multiple source files
973// into a single .ldump sAbi dump file
974func transformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Paths, soFile android.Path,
975	baseName string, exportedIncludeDirs []string, symbolFile android.OptionalPath,
976	excludedSymbolVersions, excludedSymbolTags, includedSymbolTags []string,
977	api string, commonGlobalIncludes bool) android.Path {
978
979	outputFile := android.PathForModuleOut(ctx, baseName+".lsdump")
980
981	implicits := android.Paths{soFile}
982	symbolFilterStr := "-so " + soFile.String()
983	exportedHeaderFlags := android.JoinWithPrefix(exportedIncludeDirs, "-I")
984	// If this library does not export any include directory, do not append the flags
985	// so that the ABI tool dumps everything without filtering by the include directories.
986	if commonGlobalIncludes && len(exportedIncludeDirs) > 0 {
987		exportedHeaderFlags += " ${config.CommonGlobalIncludes}"
988	}
989
990	if symbolFile.Valid() {
991		implicits = append(implicits, symbolFile.Path())
992		symbolFilterStr += " -v " + symbolFile.String()
993	}
994	for _, ver := range excludedSymbolVersions {
995		symbolFilterStr += " --exclude-symbol-version " + ver
996	}
997	for _, tag := range excludedSymbolTags {
998		symbolFilterStr += " --exclude-symbol-tag " + tag
999	}
1000	for _, tag := range includedSymbolTags {
1001		symbolFilterStr += " --include-symbol-tag " + tag
1002	}
1003	apiLevelsJson := android.GetApiLevelsJson(ctx)
1004	implicits = append(implicits, apiLevelsJson)
1005	symbolFilterStr += " --api-map " + apiLevelsJson.String()
1006	symbolFilterStr += " --api " + api
1007
1008	rule := sAbiLink
1009	args := map[string]string{
1010		"symbolFilter":        symbolFilterStr,
1011		"arch":                ctx.Arch().ArchType.Name,
1012		"exportedHeaderFlags": exportedHeaderFlags,
1013	}
1014	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_ABI_LINKER") {
1015		rule = sAbiLinkRE
1016		rbeImplicits := append(implicits.Strings(), exportedIncludeDirs...)
1017		args["implicitInputs"] = strings.Join(rbeImplicits, ",")
1018	}
1019	ctx.Build(pctx, android.BuildParams{
1020		Rule:        rule,
1021		Description: "header-abi-linker " + outputFile.Base(),
1022		Output:      outputFile,
1023		Inputs:      sAbiDumps,
1024		Implicits:   implicits,
1025		Args:        args,
1026	})
1027	return outputFile
1028}
1029
1030func transformAbiDumpToAbiDiff(ctx android.ModuleContext, inputDump, referenceDump android.Path,
1031	baseName, nameExt string, extraFlags []string, errorMessage string) android.Path {
1032
1033	var outputFile android.ModuleOutPath
1034	if nameExt != "" {
1035		outputFile = android.PathForModuleOut(ctx, baseName+"."+nameExt+".abidiff")
1036	} else {
1037		outputFile = android.PathForModuleOut(ctx, baseName+".abidiff")
1038	}
1039	libName := strings.TrimSuffix(baseName, filepath.Ext(baseName))
1040
1041	ctx.Build(pctx, android.BuildParams{
1042		Rule:        sAbiDiff,
1043		Description: "header-abi-diff " + outputFile.Base(),
1044		Output:      outputFile,
1045		Input:       inputDump,
1046		Implicit:    referenceDump,
1047		Args: map[string]string{
1048			"referenceDump": referenceDump.String(),
1049			"libName":       libName,
1050			"arch":          ctx.Arch().ArchType.Name,
1051			"extraFlags":    strings.Join(extraFlags, " "),
1052			"errorMessage":  errorMessage,
1053		},
1054	})
1055	return outputFile
1056}
1057
1058// Generate a rule for extracting a table of contents from a shared library (.so)
1059func TransformSharedObjectToToc(ctx android.ModuleContext, inputFile android.Path, outputFile android.WritablePath) {
1060
1061	var format string
1062	if ctx.Darwin() {
1063		format = "--macho"
1064	} else if ctx.Windows() {
1065		format = "--pe"
1066	} else {
1067		format = "--elf"
1068	}
1069
1070	ctx.Build(pctx, android.BuildParams{
1071		Rule:        toc,
1072		Description: "generate toc " + inputFile.Base(),
1073		Output:      outputFile,
1074		Input:       inputFile,
1075		Args: map[string]string{
1076			"clangBin": "${config.ClangBin}",
1077			"format":   format,
1078		},
1079	})
1080}
1081
1082// Generate a rule for compiling multiple .o files to a .o using ld partial linking
1083func transformObjsToObj(ctx android.ModuleContext, objFiles android.Paths,
1084	flags builderFlags, outputFile android.WritablePath, deps android.Paths) {
1085
1086	ldCmd := "${config.ClangBin}/clang++"
1087
1088	rule := partialLd
1089	args := map[string]string{
1090		"ldCmd":   ldCmd,
1091		"ldFlags": flags.globalLdFlags + " " + flags.localLdFlags,
1092	}
1093	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CXX_LINKS") {
1094		rule = partialLdRE
1095		args["inCommaList"] = strings.Join(objFiles.Strings(), ",")
1096		args["implicitInputs"] = strings.Join(deps.Strings(), ",")
1097	}
1098	ctx.Build(pctx, android.BuildParams{
1099		Rule:        rule,
1100		Description: "link " + outputFile.Base(),
1101		Output:      outputFile,
1102		Inputs:      objFiles,
1103		Implicits:   deps,
1104		Args:        args,
1105	})
1106}
1107
1108// Generate a rule for running objcopy --prefix-symbols on a binary
1109func transformBinaryPrefixSymbols(ctx android.ModuleContext, prefix string, inputFile android.Path,
1110	flags builderFlags, outputFile android.WritablePath) {
1111
1112	objcopyCmd := "${config.ClangBin}/llvm-objcopy"
1113
1114	ctx.Build(pctx, android.BuildParams{
1115		Rule:        prefixSymbols,
1116		Description: "prefix symbols " + outputFile.Base(),
1117		Output:      outputFile,
1118		Input:       inputFile,
1119		Args: map[string]string{
1120			"objcopyCmd": objcopyCmd,
1121			"prefix":     prefix,
1122		},
1123	})
1124}
1125
1126// Generate a rule for running objcopy --remove-section=.llvm_addrsig on a partially linked object
1127func transformObjectNoAddrSig(ctx android.ModuleContext, inputFile android.Path, outputFile android.WritablePath) {
1128	objcopyCmd := "${config.ClangBin}/llvm-objcopy"
1129
1130	ctx.Build(pctx, android.BuildParams{
1131		Rule:        noAddrSig,
1132		Description: "remove addrsig " + outputFile.Base(),
1133		Output:      outputFile,
1134		Input:       inputFile,
1135		Args: map[string]string{
1136			"objcopyCmd": objcopyCmd,
1137		},
1138	})
1139}
1140
1141// Registers a build statement to invoke `strip` (to discard symbols and data from object files).
1142func transformStrip(ctx android.ModuleContext, inputFile android.Path,
1143	outputFile android.WritablePath, flags StripFlags) {
1144
1145	args := ""
1146	if flags.StripAddGnuDebuglink {
1147		args += " --add-gnu-debuglink"
1148	}
1149	if flags.StripKeepMiniDebugInfo {
1150		args += " --keep-mini-debug-info"
1151	}
1152	if flags.StripKeepSymbols {
1153		args += " --keep-symbols"
1154	}
1155	if flags.StripKeepSymbolsList != "" {
1156		args += " -k" + flags.StripKeepSymbolsList
1157	}
1158	if flags.StripKeepSymbolsAndDebugFrame {
1159		args += " --keep-symbols-and-debug-frame"
1160	}
1161	if ctx.Windows() {
1162		args += " --windows"
1163	}
1164
1165	ctx.Build(pctx, android.BuildParams{
1166		Rule:        strip,
1167		Description: "strip " + outputFile.Base(),
1168		Output:      outputFile,
1169		Input:       inputFile,
1170		Args: map[string]string{
1171			"args": args,
1172		},
1173	})
1174}
1175
1176// Registers build statement to invoke `strip` on darwin architecture.
1177func transformDarwinStrip(ctx android.ModuleContext, inputFile android.Path,
1178	outputFile android.WritablePath) {
1179
1180	ctx.Build(pctx, android.BuildParams{
1181		Rule:        darwinStrip,
1182		Description: "strip " + outputFile.Base(),
1183		Output:      outputFile,
1184		Input:       inputFile,
1185	})
1186}
1187
1188func transformDarwinUniversalBinary(ctx android.ModuleContext, outputFile android.WritablePath, inputFiles ...android.Path) {
1189	ctx.Build(pctx, android.BuildParams{
1190		Rule:        darwinLipo,
1191		Description: "lipo " + outputFile.Base(),
1192		Output:      outputFile,
1193		Inputs:      inputFiles,
1194	})
1195}
1196
1197// Registers build statement to zip one or more coverage files.
1198func transformCoverageFilesToZip(ctx android.ModuleContext,
1199	inputs Objects, baseName string) android.OptionalPath {
1200
1201	if len(inputs.coverageFiles) > 0 {
1202		outputFile := android.PathForModuleOut(ctx, baseName+".zip")
1203
1204		ctx.Build(pctx, android.BuildParams{
1205			Rule:        zip,
1206			Description: "zip " + outputFile.Base(),
1207			Inputs:      inputs.coverageFiles,
1208			Output:      outputFile,
1209		})
1210
1211		return android.OptionalPathForPath(outputFile)
1212	}
1213
1214	return android.OptionalPath{}
1215}
1216
1217// Rule to repack an archive (.a) file with a subset of object files.
1218func transformArchiveRepack(ctx android.ModuleContext, inputFile android.Path,
1219	outputFile android.WritablePath, objects []string) {
1220
1221	ctx.Build(pctx, android.BuildParams{
1222		Rule:        archiveRepack,
1223		Description: "Repack archive " + outputFile.Base(),
1224		Output:      outputFile,
1225		Input:       inputFile,
1226		Args: map[string]string{
1227			"objects": strings.Join(objects, " "),
1228		},
1229	})
1230}
1231