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