• 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 java
16
17// This file generates the final rules for compiling all Java.  All properties related to
18// compiling should have been translated into javaBuilderFlags or another argument to the Transform*
19// functions.
20
21import (
22	"path/filepath"
23	"strconv"
24	"strings"
25
26	"github.com/google/blueprint"
27	"github.com/google/blueprint/proptools"
28
29	"android/soong/android"
30	"android/soong/remoteexec"
31)
32
33var (
34	pctx = android.NewPackageContext("android/soong/java")
35
36	// Compiling java is not conducive to proper dependency tracking.  The path-matches-class-name
37	// requirement leads to unpredictable generated source file names, and a single .java file
38	// will get compiled into multiple .class files if it contains inner classes.  To work around
39	// this, all java rules write into separate directories and then are combined into a .jar file
40	// (if the rule produces .class files) or a .srcjar file (if the rule produces .java files).
41	// .srcjar files are unzipped into a temporary directory when compiled with javac.
42	// TODO(b/143658984): goma can't handle the --system argument to javac.
43	javac, javacRE = pctx.MultiCommandRemoteStaticRules("javac",
44		blueprint.RuleParams{
45			Command: `rm -rf "$outDir" "$annoDir" "$srcJarDir" "$out" && mkdir -p "$outDir" "$annoDir" "$srcJarDir" && ` +
46				`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
47				`(if [ -s $srcJarDir/list ] || [ -s $out.rsp ] ; then ` +
48				`${config.SoongJavacWrapper} $javaTemplate${config.JavacCmd} ` +
49				`${config.JavacHeapFlags} ${config.JavacVmFlags} ${config.CommonJdkFlags} ` +
50				`$processorpath $processor $javacFlags $bootClasspath $classpath ` +
51				`-source $javaVersion -target $javaVersion ` +
52				`-d $outDir -s $annoDir @$out.rsp @$srcJarDir/list ; fi ) && ` +
53				`$zipTemplate${config.SoongZipCmd} -jar -o $out -C $outDir -D $outDir && ` +
54				`rm -rf "$srcJarDir"`,
55			CommandDeps: []string{
56				"${config.JavacCmd}",
57				"${config.SoongZipCmd}",
58				"${config.ZipSyncCmd}",
59			},
60			CommandOrderOnly: []string{"${config.SoongJavacWrapper}"},
61			Rspfile:          "$out.rsp",
62			RspfileContent:   "$in",
63		}, map[string]*remoteexec.REParams{
64			"$javaTemplate": &remoteexec.REParams{
65				Labels:       map[string]string{"type": "compile", "lang": "java", "compiler": "javac"},
66				ExecStrategy: "${config.REJavacExecStrategy}",
67				Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
68			},
69			"$zipTemplate": &remoteexec.REParams{
70				Labels:       map[string]string{"type": "tool", "name": "soong_zip"},
71				Inputs:       []string{"${config.SoongZipCmd}", "$outDir"},
72				OutputFiles:  []string{"$out"},
73				ExecStrategy: "${config.REJavacExecStrategy}",
74				Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
75			},
76		}, []string{"javacFlags", "bootClasspath", "classpath", "processorpath", "processor", "srcJars", "srcJarDir",
77			"outDir", "annoDir", "javaVersion"}, nil)
78
79	_ = pctx.VariableFunc("kytheCorpus",
80		func(ctx android.PackageVarContext) string { return ctx.Config().XrefCorpusName() })
81	_ = pctx.VariableFunc("kytheCuEncoding",
82		func(ctx android.PackageVarContext) string { return ctx.Config().XrefCuEncoding() })
83	_ = pctx.VariableFunc("kytheCuJavaSourceMax",
84		func(ctx android.PackageVarContext) string { return ctx.Config().XrefCuJavaSourceMax() })
85	_ = pctx.SourcePathVariable("kytheVnames", "build/soong/vnames.json")
86	// Run it with -add-opens=java.base/java.nio=ALL-UNNAMED to avoid JDK9's warning about
87	// "Illegal reflective access by com.google.protobuf.Utf8$UnsafeProcessor ...
88	// to field java.nio.Buffer.address"
89	kytheExtract = pctx.AndroidStaticRule("kythe",
90		blueprint.RuleParams{
91			Command: `${config.ZipSyncCmd} -d $srcJarDir ` +
92				`-l $srcJarDir/list -f "*.java" $srcJars && ` +
93				`( [ ! -s $srcJarDir/list -a ! -s $out.rsp ] || ` +
94				`KYTHE_ROOT_DIRECTORY=. KYTHE_OUTPUT_FILE=$out ` +
95				`KYTHE_CORPUS=${kytheCorpus} ` +
96				`KYTHE_VNAMES=${kytheVnames} ` +
97				`KYTHE_KZIP_ENCODING=${kytheCuEncoding} ` +
98				`KYTHE_JAVA_SOURCE_BATCH_SIZE=${kytheCuJavaSourceMax} ` +
99				`${config.SoongJavacWrapper} ${config.JavaCmd} ` +
100				`--add-opens=java.base/java.nio=ALL-UNNAMED ` +
101				`-jar ${config.JavaKytheExtractorJar} ` +
102				`${config.JavacHeapFlags} ${config.CommonJdkFlags} ` +
103				`$processorpath $processor $javacFlags $bootClasspath $classpath ` +
104				`-source $javaVersion -target $javaVersion ` +
105				`-d $outDir -s $annoDir @$out.rsp @$srcJarDir/list)`,
106			CommandDeps: []string{
107				"${config.JavaCmd}",
108				"${config.JavaKytheExtractorJar}",
109				"${kytheVnames}",
110				"${config.ZipSyncCmd}",
111			},
112			CommandOrderOnly: []string{"${config.SoongJavacWrapper}"},
113			Rspfile:          "$out.rsp",
114			RspfileContent:   "$in",
115		},
116		"javacFlags", "bootClasspath", "classpath", "processorpath", "processor", "srcJars", "srcJarDir",
117		"outDir", "annoDir", "javaVersion")
118
119	extractMatchingApks = pctx.StaticRule(
120		"extractMatchingApks",
121		blueprint.RuleParams{
122			Command: `rm -rf "$out" && ` +
123				`${config.ExtractApksCmd} -o "${out}" -zip "${zip}" -allow-prereleased=${allow-prereleased} ` +
124				`-sdk-version=${sdk-version} -abis=${abis} ` +
125				`--screen-densities=${screen-densities} --stem=${stem} ` +
126				`-apkcerts=${apkcerts} -partition=${partition} ` +
127				`${in}`,
128			CommandDeps: []string{"${config.ExtractApksCmd}"},
129		},
130		"abis", "allow-prereleased", "screen-densities", "sdk-version", "stem", "apkcerts", "partition", "zip")
131
132	turbine, turbineRE = pctx.RemoteStaticRules("turbine",
133		blueprint.RuleParams{
134			Command: `$reTemplate${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.TurbineJar} $outputFlags ` +
135				`--sources @$out.rsp  --source_jars $srcJars ` +
136				`--javacopts ${config.CommonJdkFlags} ` +
137				`$javacFlags -source $javaVersion -target $javaVersion -- $turbineFlags && ` +
138				`(for o in $outputs; do if cmp -s $${o}.tmp $${o} ; then rm $${o}.tmp ; else mv $${o}.tmp $${o} ; fi; done )`,
139			CommandDeps: []string{
140				"${config.TurbineJar}",
141				"${config.JavaCmd}",
142			},
143			Rspfile:        "$out.rsp",
144			RspfileContent: "$in",
145			Restat:         true,
146		},
147		&remoteexec.REParams{Labels: map[string]string{"type": "tool", "name": "turbine"},
148			ExecStrategy:    "${config.RETurbineExecStrategy}",
149			Inputs:          []string{"${config.TurbineJar}", "${out}.rsp", "$implicits"},
150			RSPFiles:        []string{"${out}.rsp"},
151			OutputFiles:     []string{"$rbeOutputs"},
152			ToolchainInputs: []string{"${config.JavaCmd}"},
153			Platform:        map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
154		},
155		[]string{"javacFlags", "turbineFlags", "outputFlags", "javaVersion", "outputs", "rbeOutputs", "srcJars"}, []string{"implicits"})
156
157	jar, jarRE = pctx.RemoteStaticRules("jar",
158		blueprint.RuleParams{
159			Command:        `$reTemplate${config.SoongZipCmd} -jar -o $out @$out.rsp`,
160			CommandDeps:    []string{"${config.SoongZipCmd}"},
161			Rspfile:        "$out.rsp",
162			RspfileContent: "$jarArgs",
163		},
164		&remoteexec.REParams{
165			ExecStrategy: "${config.REJarExecStrategy}",
166			Inputs:       []string{"${config.SoongZipCmd}", "${out}.rsp"},
167			RSPFiles:     []string{"${out}.rsp"},
168			OutputFiles:  []string{"$out"},
169			Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
170		}, []string{"jarArgs"}, nil)
171
172	zip, zipRE = pctx.RemoteStaticRules("zip",
173		blueprint.RuleParams{
174			Command:        `${config.SoongZipCmd} -o $out @$out.rsp`,
175			CommandDeps:    []string{"${config.SoongZipCmd}"},
176			Rspfile:        "$out.rsp",
177			RspfileContent: "$jarArgs",
178		},
179		&remoteexec.REParams{
180			ExecStrategy: "${config.REZipExecStrategy}",
181			Inputs:       []string{"${config.SoongZipCmd}", "${out}.rsp", "$implicits"},
182			RSPFiles:     []string{"${out}.rsp"},
183			OutputFiles:  []string{"$out"},
184			Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
185		}, []string{"jarArgs"}, []string{"implicits"})
186
187	combineJar = pctx.AndroidStaticRule("combineJar",
188		blueprint.RuleParams{
189			Command:     `${config.MergeZipsCmd} --ignore-duplicates -j $jarArgs $out $in`,
190			CommandDeps: []string{"${config.MergeZipsCmd}"},
191		},
192		"jarArgs")
193
194	jarjar = pctx.AndroidStaticRule("jarjar",
195		blueprint.RuleParams{
196			Command: "" +
197				// Jarjar doesn't exit with an error when the rules file contains a syntax error,
198				// leading to stale or missing files later in the build.  Remove the output file
199				// before running jarjar.
200				"rm -f ${out} && " +
201				"${config.JavaCmd} ${config.JavaVmFlags}" +
202				// b/146418363 Enable Android specific jarjar transformer to drop compat annotations
203				// for newly repackaged classes. Dropping @UnsupportedAppUsage on repackaged classes
204				// avoids adding new hiddenapis after jarjar'ing.
205				" -DremoveAndroidCompatAnnotations=true" +
206				" -jar ${config.JarjarCmd} process $rulesFile $in $out && " +
207				// Turn a missing output file into a ninja error
208				`[ -e ${out} ] || (echo "Missing output file"; exit 1)`,
209			CommandDeps: []string{"${config.JavaCmd}", "${config.JarjarCmd}", "$rulesFile"},
210		},
211		"rulesFile")
212
213	packageCheck = pctx.AndroidStaticRule("packageCheck",
214		blueprint.RuleParams{
215			Command: "rm -f $out && " +
216				"${config.PackageCheckCmd} $in $packages && " +
217				"touch $out",
218			CommandDeps: []string{"${config.PackageCheckCmd}"},
219		},
220		"packages")
221
222	jetifier = pctx.AndroidStaticRule("jetifier",
223		blueprint.RuleParams{
224			Command:     "${config.JavaCmd}  ${config.JavaVmFlags} -jar ${config.JetifierJar} -l error -o $out -i $in",
225			CommandDeps: []string{"${config.JavaCmd}", "${config.JetifierJar}"},
226		},
227	)
228
229	zipalign = pctx.AndroidStaticRule("zipalign",
230		blueprint.RuleParams{
231			Command: "if ! ${config.ZipAlign} -c -p 4 $in > /dev/null; then " +
232				"${config.ZipAlign} -f -p 4 $in $out; " +
233				"else " +
234				"cp -f $in $out; " +
235				"fi",
236			CommandDeps: []string{"${config.ZipAlign}"},
237		},
238	)
239)
240
241func init() {
242	pctx.Import("android/soong/android")
243	pctx.Import("android/soong/java/config")
244}
245
246type javaBuilderFlags struct {
247	javacFlags string
248
249	// bootClasspath is the list of jars that form the boot classpath (generally the java.* and
250	// android.* classes) for tools that still use it.  javac targeting 1.9 or higher uses
251	// systemModules and java9Classpath instead.
252	bootClasspath classpath
253
254	// classpath is the list of jars that form the classpath for javac and kotlinc rules.  It
255	// contains header jars for all static and non-static dependencies.
256	classpath classpath
257
258	// dexClasspath is the list of jars that form the classpath for d8 and r8 rules.  It contains
259	// header jars for all non-static dependencies.  Static dependencies have already been
260	// combined into the program jar.
261	dexClasspath classpath
262
263	// java9Classpath is the list of jars that will be added to the classpath when targeting
264	// 1.9 or higher.  It generally contains the android.* classes, while the java.* classes
265	// are provided by systemModules.
266	java9Classpath classpath
267
268	processorPath classpath
269	processors    []string
270	systemModules *systemModules
271	aidlFlags     string
272	aidlDeps      android.Paths
273	javaVersion   javaVersion
274
275	errorProneExtraJavacFlags string
276	errorProneProcessorPath   classpath
277
278	kotlincFlags     string
279	kotlincClasspath classpath
280	kotlincDeps      android.Paths
281
282	proto android.ProtoFlags
283}
284
285func TransformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath, shardIdx int,
286	srcFiles, srcJars android.Paths, flags javaBuilderFlags, deps android.Paths) {
287
288	// Compile java sources into .class files
289	desc := "javac"
290	if shardIdx >= 0 {
291		desc += strconv.Itoa(shardIdx)
292	}
293
294	transformJavaToClasses(ctx, outputFile, shardIdx, srcFiles, srcJars, flags, deps, "javac", desc)
295}
296
297// Emits the rule to generate Xref input file (.kzip file) for the given set of source files and source jars
298// to compile with given set of builder flags, etc.
299func emitXrefRule(ctx android.ModuleContext, xrefFile android.WritablePath, idx int,
300	srcFiles, srcJars android.Paths,
301	flags javaBuilderFlags, deps android.Paths) {
302
303	deps = append(deps, srcJars...)
304	classpath := flags.classpath
305
306	var bootClasspath string
307	if flags.javaVersion.usesJavaModules() {
308		var systemModuleDeps android.Paths
309		bootClasspath, systemModuleDeps = flags.systemModules.FormJavaSystemModulesPath(ctx.Device())
310		deps = append(deps, systemModuleDeps...)
311		classpath = append(flags.java9Classpath, classpath...)
312	} else {
313		deps = append(deps, flags.bootClasspath...)
314		if len(flags.bootClasspath) == 0 && ctx.Device() {
315			// explicitly specify -bootclasspath "" if the bootclasspath is empty to
316			// ensure java does not fall back to the default bootclasspath.
317			bootClasspath = `-bootclasspath ""`
318		} else {
319			bootClasspath = flags.bootClasspath.FormJavaClassPath("-bootclasspath")
320		}
321	}
322
323	deps = append(deps, classpath...)
324	deps = append(deps, flags.processorPath...)
325
326	processor := "-proc:none"
327	if len(flags.processors) > 0 {
328		processor = "-processor " + strings.Join(flags.processors, ",")
329	}
330
331	intermediatesDir := "xref"
332	if idx >= 0 {
333		intermediatesDir += strconv.Itoa(idx)
334	}
335
336	ctx.Build(pctx,
337		android.BuildParams{
338			Rule:        kytheExtract,
339			Description: "Xref Java extractor",
340			Output:      xrefFile,
341			Inputs:      srcFiles,
342			Implicits:   deps,
343			Args: map[string]string{
344				"annoDir":       android.PathForModuleOut(ctx, intermediatesDir, "anno").String(),
345				"bootClasspath": bootClasspath,
346				"classpath":     classpath.FormJavaClassPath("-classpath"),
347				"javacFlags":    flags.javacFlags,
348				"javaVersion":   flags.javaVersion.String(),
349				"outDir":        android.PathForModuleOut(ctx, "javac", "classes.xref").String(),
350				"processorpath": flags.processorPath.FormJavaClassPath("-processorpath"),
351				"processor":     processor,
352				"srcJarDir":     android.PathForModuleOut(ctx, intermediatesDir, "srcjars.xref").String(),
353				"srcJars":       strings.Join(srcJars.Strings(), " "),
354			},
355		})
356}
357
358func turbineFlags(ctx android.ModuleContext, flags javaBuilderFlags) (string, android.Paths) {
359	var deps android.Paths
360
361	classpath := flags.classpath
362
363	var bootClasspath string
364	if flags.javaVersion.usesJavaModules() {
365		var systemModuleDeps android.Paths
366		bootClasspath, systemModuleDeps = flags.systemModules.FormTurbineSystemModulesPath(ctx.Device())
367		deps = append(deps, systemModuleDeps...)
368		classpath = append(flags.java9Classpath, classpath...)
369	} else {
370		deps = append(deps, flags.bootClasspath...)
371		if len(flags.bootClasspath) == 0 && ctx.Device() {
372			// explicitly specify -bootclasspath "" if the bootclasspath is empty to
373			// ensure turbine does not fall back to the default bootclasspath.
374			bootClasspath = `--bootclasspath ""`
375		} else {
376			bootClasspath = flags.bootClasspath.FormTurbineClassPath("--bootclasspath ")
377		}
378	}
379
380	deps = append(deps, classpath...)
381	turbineFlags := bootClasspath + " " + classpath.FormTurbineClassPath("--classpath ")
382
383	return turbineFlags, deps
384}
385
386func TransformJavaToHeaderClasses(ctx android.ModuleContext, outputFile android.WritablePath,
387	srcFiles, srcJars android.Paths, flags javaBuilderFlags) {
388
389	turbineFlags, deps := turbineFlags(ctx, flags)
390
391	deps = append(deps, srcJars...)
392
393	rule := turbine
394	args := map[string]string{
395		"javacFlags":   flags.javacFlags,
396		"srcJars":      strings.Join(srcJars.Strings(), " "),
397		"javaVersion":  flags.javaVersion.String(),
398		"turbineFlags": turbineFlags,
399		"outputFlags":  "--output " + outputFile.String() + ".tmp",
400		"outputs":      outputFile.String(),
401	}
402	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_TURBINE") {
403		rule = turbineRE
404		args["implicits"] = strings.Join(deps.Strings(), ",")
405		args["rbeOutputs"] = outputFile.String() + ".tmp"
406	}
407	ctx.Build(pctx, android.BuildParams{
408		Rule:        rule,
409		Description: "turbine",
410		Output:      outputFile,
411		Inputs:      srcFiles,
412		Implicits:   deps,
413		Args:        args,
414	})
415}
416
417// TurbineApt produces a rule to run annotation processors using turbine.
418func TurbineApt(ctx android.ModuleContext, outputSrcJar, outputResJar android.WritablePath,
419	srcFiles, srcJars android.Paths, flags javaBuilderFlags) {
420
421	turbineFlags, deps := turbineFlags(ctx, flags)
422
423	deps = append(deps, srcJars...)
424
425	deps = append(deps, flags.processorPath...)
426	turbineFlags += " " + flags.processorPath.FormTurbineClassPath("--processorpath ")
427	turbineFlags += " --processors " + strings.Join(flags.processors, " ")
428
429	outputs := android.WritablePaths{outputSrcJar, outputResJar}
430	outputFlags := "--gensrc_output " + outputSrcJar.String() + ".tmp " +
431		"--resource_output " + outputResJar.String() + ".tmp"
432
433	rule := turbine
434	args := map[string]string{
435		"javacFlags":   flags.javacFlags,
436		"srcJars":      strings.Join(srcJars.Strings(), " "),
437		"javaVersion":  flags.javaVersion.String(),
438		"turbineFlags": turbineFlags,
439		"outputFlags":  outputFlags,
440		"outputs":      strings.Join(outputs.Strings(), " "),
441	}
442	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_TURBINE") {
443		rule = turbineRE
444		args["implicits"] = strings.Join(deps.Strings(), ",")
445		args["rbeOutputs"] = outputSrcJar.String() + ".tmp," + outputResJar.String() + ".tmp"
446	}
447	ctx.Build(pctx, android.BuildParams{
448		Rule:            rule,
449		Description:     "turbine apt",
450		Output:          outputs[0],
451		ImplicitOutputs: outputs[1:],
452		Inputs:          srcFiles,
453		Implicits:       deps,
454		Args:            args,
455	})
456}
457
458// transformJavaToClasses takes source files and converts them to a jar containing .class files.
459// srcFiles is a list of paths to sources, srcJars is a list of paths to jar files that contain
460// sources.  flags contains various command line flags to be passed to the compiler.
461//
462// This method may be used for different compilers, including javac and Error Prone.  The rule
463// argument specifies which command line to use and desc sets the description of the rule that will
464// be printed at build time.  The stem argument provides the file name of the output jar, and
465// suffix will be appended to various intermediate files and directories to avoid collisions when
466// this function is called twice in the same module directory.
467func transformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath,
468	shardIdx int, srcFiles, srcJars android.Paths,
469	flags javaBuilderFlags, deps android.Paths,
470	intermediatesDir, desc string) {
471
472	deps = append(deps, srcJars...)
473
474	classpath := flags.classpath
475
476	var bootClasspath string
477	if flags.javaVersion.usesJavaModules() {
478		var systemModuleDeps android.Paths
479		bootClasspath, systemModuleDeps = flags.systemModules.FormJavaSystemModulesPath(ctx.Device())
480		deps = append(deps, systemModuleDeps...)
481		classpath = append(flags.java9Classpath, classpath...)
482	} else {
483		deps = append(deps, flags.bootClasspath...)
484		if len(flags.bootClasspath) == 0 && ctx.Device() {
485			// explicitly specify -bootclasspath "" if the bootclasspath is empty to
486			// ensure java does not fall back to the default bootclasspath.
487			bootClasspath = `-bootclasspath ""`
488		} else {
489			bootClasspath = flags.bootClasspath.FormJavaClassPath("-bootclasspath")
490		}
491	}
492
493	deps = append(deps, classpath...)
494	deps = append(deps, flags.processorPath...)
495
496	processor := "-proc:none"
497	if len(flags.processors) > 0 {
498		processor = "-processor " + strings.Join(flags.processors, ",")
499	}
500
501	srcJarDir := "srcjars"
502	outDir := "classes"
503	annoDir := "anno"
504	if shardIdx >= 0 {
505		shardDir := "shard" + strconv.Itoa(shardIdx)
506		srcJarDir = filepath.Join(shardDir, srcJarDir)
507		outDir = filepath.Join(shardDir, outDir)
508		annoDir = filepath.Join(shardDir, annoDir)
509	}
510	rule := javac
511	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_JAVAC") {
512		rule = javacRE
513	}
514	ctx.Build(pctx, android.BuildParams{
515		Rule:        rule,
516		Description: desc,
517		Output:      outputFile,
518		Inputs:      srcFiles,
519		Implicits:   deps,
520		Args: map[string]string{
521			"javacFlags":    flags.javacFlags,
522			"bootClasspath": bootClasspath,
523			"classpath":     classpath.FormJavaClassPath("-classpath"),
524			"processorpath": flags.processorPath.FormJavaClassPath("-processorpath"),
525			"processor":     processor,
526			"srcJars":       strings.Join(srcJars.Strings(), " "),
527			"srcJarDir":     android.PathForModuleOut(ctx, intermediatesDir, srcJarDir).String(),
528			"outDir":        android.PathForModuleOut(ctx, intermediatesDir, outDir).String(),
529			"annoDir":       android.PathForModuleOut(ctx, intermediatesDir, annoDir).String(),
530			"javaVersion":   flags.javaVersion.String(),
531		},
532	})
533}
534
535func TransformResourcesToJar(ctx android.ModuleContext, outputFile android.WritablePath,
536	jarArgs []string, deps android.Paths) {
537
538	rule := jar
539	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_JAR") {
540		rule = jarRE
541	}
542	ctx.Build(pctx, android.BuildParams{
543		Rule:        rule,
544		Description: "jar",
545		Output:      outputFile,
546		Implicits:   deps,
547		Args: map[string]string{
548			"jarArgs": strings.Join(proptools.NinjaAndShellEscapeList(jarArgs), " "),
549		},
550	})
551}
552
553func TransformJarsToJar(ctx android.ModuleContext, outputFile android.WritablePath, desc string,
554	jars android.Paths, manifest android.OptionalPath, stripDirEntries bool, filesToStrip []string,
555	dirsToStrip []string) {
556
557	var deps android.Paths
558
559	var jarArgs []string
560	if manifest.Valid() {
561		jarArgs = append(jarArgs, "-m ", manifest.String())
562		deps = append(deps, manifest.Path())
563	}
564
565	for _, dir := range dirsToStrip {
566		jarArgs = append(jarArgs, "-stripDir ", dir)
567	}
568
569	for _, file := range filesToStrip {
570		jarArgs = append(jarArgs, "-stripFile ", file)
571	}
572
573	// Remove any module-info.class files that may have come from prebuilt jars, they cause problems
574	// for downstream tools like desugar.
575	jarArgs = append(jarArgs, "-stripFile module-info.class")
576
577	if stripDirEntries {
578		jarArgs = append(jarArgs, "-D")
579	}
580
581	ctx.Build(pctx, android.BuildParams{
582		Rule:        combineJar,
583		Description: desc,
584		Output:      outputFile,
585		Inputs:      jars,
586		Implicits:   deps,
587		Args: map[string]string{
588			"jarArgs": strings.Join(jarArgs, " "),
589		},
590	})
591}
592
593func TransformJarJar(ctx android.ModuleContext, outputFile android.WritablePath,
594	classesJar android.Path, rulesFile android.Path) {
595	ctx.Build(pctx, android.BuildParams{
596		Rule:        jarjar,
597		Description: "jarjar",
598		Output:      outputFile,
599		Input:       classesJar,
600		Implicit:    rulesFile,
601		Args: map[string]string{
602			"rulesFile": rulesFile.String(),
603		},
604	})
605}
606
607func CheckJarPackages(ctx android.ModuleContext, outputFile android.WritablePath,
608	classesJar android.Path, permittedPackages []string) {
609	ctx.Build(pctx, android.BuildParams{
610		Rule:        packageCheck,
611		Description: "packageCheck",
612		Output:      outputFile,
613		Input:       classesJar,
614		Args: map[string]string{
615			"packages": strings.Join(permittedPackages, " "),
616		},
617	})
618}
619
620func TransformJetifier(ctx android.ModuleContext, outputFile android.WritablePath,
621	inputFile android.Path) {
622	ctx.Build(pctx, android.BuildParams{
623		Rule:        jetifier,
624		Description: "jetifier",
625		Output:      outputFile,
626		Input:       inputFile,
627	})
628}
629
630func GenerateMainClassManifest(ctx android.ModuleContext, outputFile android.WritablePath, mainClass string) {
631	android.WriteFileRule(ctx, outputFile, "Main-Class: "+mainClass+"\n")
632}
633
634func TransformZipAlign(ctx android.ModuleContext, outputFile android.WritablePath, inputFile android.Path) {
635	ctx.Build(pctx, android.BuildParams{
636		Rule:        zipalign,
637		Description: "align",
638		Input:       inputFile,
639		Output:      outputFile,
640	})
641}
642
643type classpath android.Paths
644
645func (x *classpath) formJoinedClassPath(optName string, sep string) string {
646	if optName != "" && !strings.HasSuffix(optName, "=") && !strings.HasSuffix(optName, " ") {
647		optName += " "
648	}
649	if len(*x) > 0 {
650		return optName + strings.Join(x.Strings(), sep)
651	} else {
652		return ""
653	}
654}
655func (x *classpath) FormJavaClassPath(optName string) string {
656	return x.formJoinedClassPath(optName, ":")
657}
658
659func (x *classpath) FormTurbineClassPath(optName string) string {
660	return x.formJoinedClassPath(optName, " ")
661}
662
663// FormRepeatedClassPath returns a list of arguments with the given optName prefixed to each element of the classpath.
664func (x *classpath) FormRepeatedClassPath(optName string) []string {
665	if x == nil || *x == nil {
666		return nil
667	}
668	flags := make([]string, len(*x))
669	for i, v := range *x {
670		flags[i] = optName + v.String()
671	}
672
673	return flags
674}
675
676// Convert a classpath to an android.Paths
677func (x *classpath) Paths() android.Paths {
678	return append(android.Paths(nil), (*x)...)
679}
680
681func (x *classpath) Strings() []string {
682	if x == nil {
683		return nil
684	}
685	ret := make([]string, len(*x))
686	for i, path := range *x {
687		ret[i] = path.String()
688	}
689	return ret
690}
691
692type systemModules struct {
693	dir  android.Path
694	deps android.Paths
695}
696
697// Returns a --system argument in the form javac expects with -source 1.9 and the list of files to
698// depend on.  If forceEmpty is true, returns --system=none if the list is empty to ensure javac
699// does not fall back to the default system modules.
700func (x *systemModules) FormJavaSystemModulesPath(forceEmpty bool) (string, android.Paths) {
701	if x != nil {
702		return "--system=" + x.dir.String(), x.deps
703	} else if forceEmpty {
704		return "--system=none", nil
705	} else {
706		return "", nil
707	}
708}
709
710// Returns a --system argument in the form turbine expects with -source 1.9 and the list of files to
711// depend on.  If forceEmpty is true, returns --bootclasspath "" if the list is empty to ensure turbine
712// does not fall back to the default bootclasspath.
713func (x *systemModules) FormTurbineSystemModulesPath(forceEmpty bool) (string, android.Paths) {
714	if x != nil {
715		return "--system " + x.dir.String(), x.deps
716	} else if forceEmpty {
717		return `--bootclasspath ""`, nil
718	} else {
719		return "--system ${config.JavaHome}", nil
720	}
721}
722