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 --source_jars $srcJars ` + 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", "$implicits"}, 174 RSPFiles: []string{"${out}.rsp"}, 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", "srcJars"}, []string{"implicits"}) 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 zipalign = pctx.AndroidStaticRule("zipalign", 262 blueprint.RuleParams{ 263 Command: "if ! ${config.ZipAlign} -c -p 4 $in > /dev/null; then " + 264 "${config.ZipAlign} -f -p 4 $in $out; " + 265 "else " + 266 "cp -f $in $out; " + 267 "fi", 268 CommandDeps: []string{"${config.ZipAlign}"}, 269 }, 270 ) 271 272 convertImplementationJarToHeaderJarRule = pctx.AndroidStaticRule("convertImplementationJarToHeaderJar", 273 blueprint.RuleParams{ 274 Command: `${config.Zip2ZipCmd} -i ${in} -o ${out} -x 'META-INF/services/**/*'`, 275 CommandDeps: []string{"${config.Zip2ZipCmd}"}, 276 }) 277 278 writeCombinedProguardFlagsFileRule = pctx.AndroidStaticRule("writeCombinedProguardFlagsFileRule", 279 blueprint.RuleParams{ 280 Command: `rm -f $out && ` + 281 `for f in $in; do ` + 282 ` echo && ` + 283 ` echo "# including $$f" && ` + 284 ` cat $$f; ` + 285 `done > $out`, 286 }) 287 288 gatherReleasedFlaggedApisRule = pctx.AndroidStaticRule("gatherReleasedFlaggedApisRule", 289 blueprint.RuleParams{ 290 Command: `${aconfig} dump-cache --dedup --format='{fully_qualified_name}={state:bool}' ` + 291 `--out ${out} ` + 292 `${flags_path} ` + 293 `${filter_args} `, 294 CommandDeps: []string{"${aconfig}"}, 295 Description: "aconfig_bool", 296 }, "flags_path", "filter_args") 297 298 generateMetalavaRevertAnnotationsRule = pctx.AndroidStaticRule("generateMetalavaRevertAnnotationsRule", 299 blueprint.RuleParams{ 300 Command: `${keep-flagged-apis} ${in} > ${out}`, 301 CommandDeps: []string{"${keep-flagged-apis}"}, 302 }) 303) 304 305func init() { 306 pctx.Import("android/soong/android") 307 pctx.Import("android/soong/java/config") 308 309 pctx.HostBinToolVariable("aconfig", "aconfig") 310 pctx.HostBinToolVariable("keep-flagged-apis", "keep-flagged-apis") 311} 312 313type javaBuilderFlags struct { 314 javacFlags string 315 316 // bootClasspath is the list of jars that form the boot classpath (generally the java.* and 317 // android.* classes) for tools that still use it. javac targeting 1.9 or higher uses 318 // systemModules and java9Classpath instead. 319 bootClasspath classpath 320 321 // classpath is the list of jars that form the classpath for javac and kotlinc rules. It 322 // contains header jars for all static and non-static dependencies. 323 classpath classpath 324 325 // dexClasspath is the list of jars that form the classpath for d8 and r8 rules. It contains 326 // header jars for all non-static dependencies. Static dependencies have already been 327 // combined into the program jar. 328 dexClasspath classpath 329 330 // java9Classpath is the list of jars that will be added to the classpath when targeting 331 // 1.9 or higher. It generally contains the android.* classes, while the java.* classes 332 // are provided by systemModules. 333 java9Classpath classpath 334 335 processorPath classpath 336 processors []string 337 systemModules *systemModules 338 aidlFlags string 339 aidlDeps android.Paths 340 javaVersion javaVersion 341 342 errorProneExtraJavacFlags string 343 errorProneProcessorPath classpath 344 345 kotlincFlags string 346 kotlincClasspath classpath 347 kotlincDeps android.Paths 348 349 proto android.ProtoFlags 350} 351 352func DefaultJavaBuilderFlags() javaBuilderFlags { 353 return javaBuilderFlags{ 354 javaVersion: JAVA_VERSION_8, 355 } 356} 357 358func TransformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath, shardIdx int, 359 srcFiles, srcJars android.Paths, annoSrcJar android.WritablePath, flags javaBuilderFlags, deps android.Paths) { 360 361 // Compile java sources into .class files 362 desc := "javac" 363 if shardIdx >= 0 { 364 desc += strconv.Itoa(shardIdx) 365 } 366 367 transformJavaToClasses(ctx, outputFile, shardIdx, srcFiles, srcJars, annoSrcJar, flags, deps, "javac", desc) 368} 369 370// Emits the rule to generate Xref input file (.kzip file) for the given set of source files and source jars 371// to compile with given set of builder flags, etc. 372func emitXrefRule(ctx android.ModuleContext, xrefFile android.WritablePath, idx int, 373 srcFiles, srcJars android.Paths, 374 flags javaBuilderFlags, deps android.Paths) { 375 376 deps = append(deps, srcJars...) 377 classpath := flags.classpath 378 379 var bootClasspath string 380 if flags.javaVersion.usesJavaModules() { 381 var systemModuleDeps android.Paths 382 bootClasspath, systemModuleDeps = flags.systemModules.FormJavaSystemModulesPath(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 java does not fall back to the default bootclasspath. 390 bootClasspath = `-bootclasspath ""` 391 } else { 392 bootClasspath = flags.bootClasspath.FormJavaClassPath("-bootclasspath") 393 } 394 } 395 396 deps = append(deps, classpath...) 397 deps = append(deps, flags.processorPath...) 398 399 processor := "-proc:none" 400 if len(flags.processors) > 0 { 401 processor = "-processor " + strings.Join(flags.processors, ",") 402 } 403 404 intermediatesDir := "xref" 405 if idx >= 0 { 406 intermediatesDir += strconv.Itoa(idx) 407 } 408 409 ctx.Build(pctx, 410 android.BuildParams{ 411 Rule: kytheExtract, 412 Description: "Xref Java extractor", 413 Output: xrefFile, 414 Inputs: srcFiles, 415 Implicits: deps, 416 Args: map[string]string{ 417 "annoDir": android.PathForModuleOut(ctx, intermediatesDir, "anno").String(), 418 "bootClasspath": bootClasspath, 419 "classpath": classpath.FormJavaClassPath("-classpath"), 420 "javacFlags": flags.javacFlags, 421 "javaVersion": flags.javaVersion.String(), 422 "outDir": android.PathForModuleOut(ctx, "javac", "classes.xref").String(), 423 "processorpath": flags.processorPath.FormJavaClassPath("-processorpath"), 424 "processor": processor, 425 "srcJarDir": android.PathForModuleOut(ctx, intermediatesDir, "srcjars.xref").String(), 426 "srcJars": strings.Join(srcJars.Strings(), " "), 427 }, 428 }) 429} 430 431func turbineFlags(ctx android.ModuleContext, flags javaBuilderFlags, dir string) (string, android.Paths) { 432 var deps android.Paths 433 434 classpath := flags.classpath 435 436 var bootClasspath string 437 if flags.javaVersion.usesJavaModules() { 438 var systemModuleDeps android.Paths 439 bootClasspath, systemModuleDeps = flags.systemModules.FormTurbineSystemModulesPath(ctx.Device()) 440 deps = append(deps, systemModuleDeps...) 441 classpath = append(flags.java9Classpath, classpath...) 442 } else { 443 deps = append(deps, flags.bootClasspath...) 444 if len(flags.bootClasspath) == 0 && ctx.Device() { 445 // explicitly specify -bootclasspath "" if the bootclasspath is empty to 446 // ensure turbine does not fall back to the default bootclasspath. 447 bootClasspath = `--bootclasspath ""` 448 } else { 449 bootClasspath = flags.bootClasspath.FormTurbineClassPath("--bootclasspath ") 450 } 451 } 452 453 deps = append(deps, classpath...) 454 turbineFlags := bootClasspath + " " + classpath.FormTurbineClassPath("--classpath ") 455 456 const flagsLimit = 32 * 1024 457 if len(turbineFlags) > flagsLimit { 458 flagsRspFile := android.PathForModuleOut(ctx, dir, "turbine-flags.rsp") 459 android.WriteFileRule(ctx, flagsRspFile, turbineFlags) 460 turbineFlags = "@" + flagsRspFile.String() 461 deps = append(deps, flagsRspFile) 462 } 463 464 return turbineFlags, deps 465} 466 467func TransformJavaToHeaderClasses(ctx android.ModuleContext, outputFile android.WritablePath, 468 srcFiles, srcJars android.Paths, flags javaBuilderFlags) { 469 470 turbineFlags, deps := turbineFlags(ctx, flags, "turbine") 471 472 deps = append(deps, srcJars...) 473 474 rule := turbine 475 args := map[string]string{ 476 "javacFlags": flags.javacFlags, 477 "srcJars": strings.Join(srcJars.Strings(), " "), 478 "javaVersion": flags.javaVersion.String(), 479 "turbineFlags": turbineFlags, 480 "outputFlags": "--output " + outputFile.String() + ".tmp", 481 "outputs": outputFile.String(), 482 } 483 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_TURBINE") { 484 rule = turbineRE 485 args["implicits"] = strings.Join(deps.Strings(), ",") 486 args["rbeOutputs"] = outputFile.String() + ".tmp" 487 } 488 ctx.Build(pctx, android.BuildParams{ 489 Rule: rule, 490 Description: "turbine", 491 Output: outputFile, 492 Inputs: srcFiles, 493 Implicits: deps, 494 Args: args, 495 }) 496} 497 498// TurbineApt produces a rule to run annotation processors using turbine. 499func TurbineApt(ctx android.ModuleContext, outputSrcJar, outputResJar android.WritablePath, 500 srcFiles, srcJars android.Paths, flags javaBuilderFlags) { 501 502 turbineFlags, deps := turbineFlags(ctx, flags, "kapt") 503 504 deps = append(deps, srcJars...) 505 506 deps = append(deps, flags.processorPath...) 507 turbineFlags += " " + flags.processorPath.FormTurbineClassPath("--processorpath ") 508 turbineFlags += " --processors " + strings.Join(flags.processors, " ") 509 510 outputs := android.WritablePaths{outputSrcJar, outputResJar} 511 outputFlags := "--gensrc_output " + outputSrcJar.String() + ".tmp " + 512 "--resource_output " + outputResJar.String() + ".tmp" 513 514 rule := turbine 515 args := map[string]string{ 516 "javacFlags": flags.javacFlags, 517 "srcJars": strings.Join(srcJars.Strings(), " "), 518 "javaVersion": flags.javaVersion.String(), 519 "turbineFlags": turbineFlags, 520 "outputFlags": outputFlags, 521 "outputs": strings.Join(outputs.Strings(), " "), 522 } 523 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_TURBINE") { 524 rule = turbineRE 525 args["implicits"] = strings.Join(deps.Strings(), ",") 526 args["rbeOutputs"] = outputSrcJar.String() + ".tmp," + outputResJar.String() + ".tmp" 527 } 528 ctx.Build(pctx, android.BuildParams{ 529 Rule: rule, 530 Description: "turbine apt", 531 Output: outputs[0], 532 ImplicitOutputs: outputs[1:], 533 Inputs: srcFiles, 534 Implicits: deps, 535 Args: args, 536 }) 537} 538 539// transformJavaToClasses takes source files and converts them to a jar containing .class files. 540// srcFiles is a list of paths to sources, srcJars is a list of paths to jar files that contain 541// sources. flags contains various command line flags to be passed to the compiler. 542// 543// This method may be used for different compilers, including javac and Error Prone. The rule 544// argument specifies which command line to use and desc sets the description of the rule that will 545// be printed at build time. The stem argument provides the file name of the output jar, and 546// suffix will be appended to various intermediate files and directories to avoid collisions when 547// this function is called twice in the same module directory. 548func transformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath, 549 shardIdx int, srcFiles, srcJars android.Paths, annoSrcJar android.WritablePath, 550 flags javaBuilderFlags, deps android.Paths, 551 intermediatesDir, desc string) { 552 553 deps = append(deps, srcJars...) 554 555 javacClasspath := flags.classpath 556 557 var bootClasspath string 558 if flags.javaVersion.usesJavaModules() { 559 var systemModuleDeps android.Paths 560 bootClasspath, systemModuleDeps = flags.systemModules.FormJavaSystemModulesPath(ctx.Device()) 561 deps = append(deps, systemModuleDeps...) 562 javacClasspath = append(flags.java9Classpath, javacClasspath...) 563 } else { 564 deps = append(deps, flags.bootClasspath...) 565 if len(flags.bootClasspath) == 0 && ctx.Device() { 566 // explicitly specify -bootclasspath "" if the bootclasspath is empty to 567 // ensure java does not fall back to the default bootclasspath. 568 bootClasspath = `-bootclasspath ""` 569 } else { 570 bootClasspath = flags.bootClasspath.FormJavaClassPath("-bootclasspath") 571 } 572 } 573 574 classpathArg := javacClasspath.FormJavaClassPath("-classpath") 575 576 // Keep the command line under the MAX_ARG_STRLEN limit by putting the classpath argument into an rsp file 577 // if it is too long. 578 const classpathLimit = 64 * 1024 579 if len(classpathArg) > classpathLimit { 580 classpathRspFile := outputFile.ReplaceExtension(ctx, "classpath") 581 android.WriteFileRule(ctx, classpathRspFile, classpathArg) 582 deps = append(deps, classpathRspFile) 583 classpathArg = "@" + classpathRspFile.String() 584 } 585 586 deps = append(deps, javacClasspath...) 587 deps = append(deps, flags.processorPath...) 588 589 processor := "-proc:none" 590 if len(flags.processors) > 0 { 591 processor = "-processor " + strings.Join(flags.processors, ",") 592 } 593 594 srcJarDir := "srcjars" 595 outDir := "classes" 596 annoDir := "anno" 597 if shardIdx >= 0 { 598 shardDir := "shard" + strconv.Itoa(shardIdx) 599 srcJarDir = filepath.Join(shardDir, srcJarDir) 600 outDir = filepath.Join(shardDir, outDir) 601 annoDir = filepath.Join(shardDir, annoDir) 602 } 603 rule := javac 604 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_JAVAC") { 605 rule = javacRE 606 } 607 ctx.Build(pctx, android.BuildParams{ 608 Rule: rule, 609 Description: desc, 610 Output: outputFile, 611 ImplicitOutput: annoSrcJar, 612 Inputs: srcFiles, 613 Implicits: deps, 614 Args: map[string]string{ 615 "javacFlags": flags.javacFlags, 616 "bootClasspath": bootClasspath, 617 "classpath": classpathArg, 618 "processorpath": flags.processorPath.FormJavaClassPath("-processorpath"), 619 "processor": processor, 620 "srcJars": strings.Join(srcJars.Strings(), " "), 621 "srcJarDir": android.PathForModuleOut(ctx, intermediatesDir, srcJarDir).String(), 622 "outDir": android.PathForModuleOut(ctx, intermediatesDir, outDir).String(), 623 "annoDir": android.PathForModuleOut(ctx, intermediatesDir, annoDir).String(), 624 "annoSrcJar": annoSrcJar.String(), 625 "javaVersion": flags.javaVersion.String(), 626 }, 627 }) 628} 629 630func TransformResourcesToJar(ctx android.ModuleContext, outputFile android.WritablePath, 631 jarArgs []string, deps android.Paths) { 632 633 rule := jar 634 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_JAR") { 635 rule = jarRE 636 } 637 ctx.Build(pctx, android.BuildParams{ 638 Rule: rule, 639 Description: "jar", 640 Output: outputFile, 641 Implicits: deps, 642 Args: map[string]string{ 643 "jarArgs": strings.Join(proptools.NinjaAndShellEscapeList(jarArgs), " "), 644 }, 645 }) 646} 647 648func TransformJarsToJar(ctx android.ModuleContext, outputFile android.WritablePath, desc string, 649 jars android.Paths, manifest android.OptionalPath, stripDirEntries bool, filesToStrip []string, 650 dirsToStrip []string) { 651 652 var deps android.Paths 653 654 var jarArgs []string 655 if manifest.Valid() { 656 jarArgs = append(jarArgs, "-m ", manifest.String()) 657 deps = append(deps, manifest.Path()) 658 } 659 660 for _, dir := range dirsToStrip { 661 jarArgs = append(jarArgs, "-stripDir ", dir) 662 } 663 664 for _, file := range filesToStrip { 665 jarArgs = append(jarArgs, "-stripFile ", file) 666 } 667 668 // Remove any module-info.class files that may have come from prebuilt jars, they cause problems 669 // for downstream tools like desugar. 670 jarArgs = append(jarArgs, "-stripFile module-info.class") 671 672 if stripDirEntries { 673 jarArgs = append(jarArgs, "-D") 674 } 675 676 rule := combineJar 677 // Keep the command line under the MAX_ARG_STRLEN limit by putting the list of jars into an rsp file 678 // if it is too long. 679 const jarsLengthLimit = 64 * 1024 680 jarsLength := 0 681 for i, jar := range jars { 682 if i != 0 { 683 jarsLength += 1 684 } 685 jarsLength += len(jar.String()) 686 } 687 if jarsLength > jarsLengthLimit { 688 rule = combineJarRsp 689 } 690 691 ctx.Build(pctx, android.BuildParams{ 692 Rule: rule, 693 Description: desc, 694 Output: outputFile, 695 Inputs: jars, 696 Implicits: deps, 697 Args: map[string]string{ 698 "jarArgs": strings.Join(jarArgs, " "), 699 }, 700 }) 701} 702 703func convertImplementationJarToHeaderJar(ctx android.ModuleContext, implementationJarFile android.Path, 704 headerJarFile android.WritablePath) { 705 ctx.Build(pctx, android.BuildParams{ 706 Rule: convertImplementationJarToHeaderJarRule, 707 Input: implementationJarFile, 708 Output: headerJarFile, 709 }) 710} 711 712func TransformJarJar(ctx android.ModuleContext, outputFile android.WritablePath, 713 classesJar android.Path, rulesFile android.Path) { 714 ctx.Build(pctx, android.BuildParams{ 715 Rule: jarjar, 716 Description: "jarjar", 717 Output: outputFile, 718 Input: classesJar, 719 Implicit: rulesFile, 720 Args: map[string]string{ 721 "rulesFile": rulesFile.String(), 722 }, 723 }) 724} 725 726func CheckJarPackages(ctx android.ModuleContext, outputFile android.WritablePath, 727 classesJar android.Path, permittedPackages []string) { 728 ctx.Build(pctx, android.BuildParams{ 729 Rule: packageCheck, 730 Description: "packageCheck", 731 Output: outputFile, 732 Input: classesJar, 733 Args: map[string]string{ 734 "packages": strings.Join(permittedPackages, " "), 735 }, 736 }) 737} 738 739func TransformJetifier(ctx android.ModuleContext, outputFile android.WritablePath, 740 inputFile android.Path) { 741 ctx.Build(pctx, android.BuildParams{ 742 Rule: jetifier, 743 Description: "jetifier", 744 Output: outputFile, 745 Input: inputFile, 746 }) 747} 748 749func GenerateMainClassManifest(ctx android.ModuleContext, outputFile android.WritablePath, mainClass string) { 750 android.WriteFileRule(ctx, outputFile, "Main-Class: "+mainClass+"\n") 751} 752 753func TransformZipAlign(ctx android.ModuleContext, outputFile android.WritablePath, inputFile android.Path, validations android.Paths) { 754 ctx.Build(pctx, android.BuildParams{ 755 Rule: zipalign, 756 Description: "align", 757 Input: inputFile, 758 Output: outputFile, 759 Validations: validations, 760 }) 761} 762 763func writeCombinedProguardFlagsFile(ctx android.ModuleContext, outputFile android.WritablePath, files android.Paths) { 764 ctx.Build(pctx, android.BuildParams{ 765 Rule: writeCombinedProguardFlagsFileRule, 766 Description: "write combined proguard flags file", 767 Inputs: files, 768 Output: outputFile, 769 }) 770} 771 772type classpath android.Paths 773 774func (x *classpath) formJoinedClassPath(optName string, sep string) string { 775 if optName != "" && !strings.HasSuffix(optName, "=") && !strings.HasSuffix(optName, " ") { 776 optName += " " 777 } 778 if len(*x) > 0 { 779 return optName + strings.Join(x.Strings(), sep) 780 } else { 781 return "" 782 } 783} 784func (x *classpath) FormJavaClassPath(optName string) string { 785 return x.formJoinedClassPath(optName, ":") 786} 787 788func (x *classpath) FormTurbineClassPath(optName string) string { 789 return x.formJoinedClassPath(optName, " ") 790} 791 792// FormRepeatedClassPath returns a list of arguments with the given optName prefixed to each element of the classpath. 793func (x *classpath) FormRepeatedClassPath(optName string) []string { 794 if x == nil || *x == nil { 795 return nil 796 } 797 flags := make([]string, len(*x)) 798 for i, v := range *x { 799 flags[i] = optName + v.String() 800 } 801 802 return flags 803} 804 805// Convert a classpath to an android.Paths 806func (x *classpath) Paths() android.Paths { 807 return append(android.Paths(nil), (*x)...) 808} 809 810func (x *classpath) Strings() []string { 811 if x == nil { 812 return nil 813 } 814 ret := make([]string, len(*x)) 815 for i, path := range *x { 816 ret[i] = path.String() 817 } 818 return ret 819} 820 821type systemModules struct { 822 dir android.Path 823 deps android.Paths 824} 825 826// Returns a --system argument in the form javac expects with -source 1.9 and the list of files to 827// depend on. If forceEmpty is true, returns --system=none if the list is empty to ensure javac 828// does not fall back to the default system modules. 829func (x *systemModules) FormJavaSystemModulesPath(forceEmpty bool) (string, android.Paths) { 830 if x != nil { 831 return "--system=" + x.dir.String(), x.deps 832 } else if forceEmpty { 833 return "--system=none", nil 834 } else { 835 return "", nil 836 } 837} 838 839// Returns a --system argument in the form turbine expects with -source 1.9 and the list of files to 840// depend on. If forceEmpty is true, returns --bootclasspath "" if the list is empty to ensure turbine 841// does not fall back to the default bootclasspath. 842func (x *systemModules) FormTurbineSystemModulesPath(forceEmpty bool) (string, android.Paths) { 843 if x != nil { 844 return "--system " + x.dir.String(), x.deps 845 } else if forceEmpty { 846 return `--bootclasspath ""`, nil 847 } else { 848 return "--system ${config.JavaHome}", nil 849 } 850} 851