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