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