// Copyright 2015 Google Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package java // This file generates the final rules for compiling all Java. All properties related to // compiling should have been translated into javaBuilderFlags or another argument to the Transform* // functions. import ( "path/filepath" "strings" "android/soong/common" "github.com/google/blueprint" _ "github.com/google/blueprint/bootstrap" ) var ( pctx = common.NewPackageContext("android/soong/java") // Compiling java is not conducive to proper dependency tracking. The path-matches-class-name // requirement leads to unpredictable generated source file names, and a single .java file // will get compiled into multiple .class files if it contains inner classes. To work around // this, all java rules write into separate directories and then a post-processing step lists // the files in the the directory into a list file that later rules depend on (and sometimes // read from directly using @) javac = pctx.StaticRule("javac", blueprint.RuleParams{ Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + `$javacCmd -encoding UTF-8 $javacFlags $bootClasspath $classpath ` + `-extdirs "" -d $outDir @$out.rsp || ( rm -rf "$outDir"; exit 41 ) && ` + `find $outDir -name "*.class" > $out`, Rspfile: "$out.rsp", RspfileContent: "$in", Description: "javac $outDir", }, "javacCmd", "javacFlags", "bootClasspath", "classpath", "outDir") jar = pctx.StaticRule("jar", blueprint.RuleParams{ Command: `$jarCmd -o $out $jarArgs`, CommandDeps: []string{"$jarCmd"}, Description: "jar $out", }, "jarCmd", "jarArgs") dx = pctx.StaticRule("dx", blueprint.RuleParams{ Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + `$dxCmd --dex --output=$outDir $dxFlags $in || ( rm -rf "$outDir"; exit 41 ) && ` + `find "$outDir" -name "classes*.dex" > $out`, CommandDeps: []string{"$dxCmd"}, Description: "dex $out", }, "outDir", "dxFlags") jarjar = pctx.StaticRule("jarjar", blueprint.RuleParams{ Command: "java -jar $jarjarCmd process $rulesFile $in $out", CommandDeps: []string{"$jarjarCmd", "$rulesFile"}, Description: "jarjar $out", }, "rulesFile") extractPrebuilt = pctx.StaticRule("extractPrebuilt", blueprint.RuleParams{ Command: `rm -rf $outDir && unzip -qo $in -d $outDir && ` + `find $outDir -name "*.class" > $classFile && ` + `find $outDir -type f -a \! -name "*.class" -a \! -name "MANIFEST.MF" > $resourceFile || ` + `(rm -rf $outDir; exit 42)`, Description: "extract java prebuilt $outDir", }, "outDir", "classFile", "resourceFile") ) func init() { pctx.Import("github.com/google/blueprint/bootstrap") pctx.StaticVariable("commonJdkFlags", "-source 1.7 -target 1.7 -Xmaxerrs 9999999") pctx.StaticVariable("javacCmd", "javac -J-Xmx1024M $commonJdkFlags") pctx.StaticVariable("jarCmd", filepath.Join("${bootstrap.BinDir}", "soong_jar")) pctx.HostBinToolVariable("dxCmd", "dx") pctx.HostJavaToolVariable("jarjarCmd", "jarjar.jar") } type javaBuilderFlags struct { javacFlags string dxFlags string bootClasspath string classpath string aidlFlags string } type jarSpec struct { fileList, dir common.Path } func (j jarSpec) soongJarArgs() string { return "-C " + j.dir.String() + " -l " + j.fileList.String() } func TransformJavaToClasses(ctx common.AndroidModuleContext, srcFiles common.Paths, srcFileLists common.Paths, flags javaBuilderFlags, deps common.Paths) jarSpec { classDir := common.PathForModuleOut(ctx, "classes") classFileList := common.PathForModuleOut(ctx, "classes.list") javacFlags := flags.javacFlags + common.JoinWithPrefix(srcFileLists.Strings(), "@") deps = append(deps, srcFileLists...) ctx.ModuleBuild(pctx, common.ModuleBuildParams{ Rule: javac, Output: classFileList, Inputs: srcFiles, Implicits: deps, Args: map[string]string{ "javacFlags": javacFlags, "bootClasspath": flags.bootClasspath, "classpath": flags.classpath, "outDir": classDir.String(), }, }) return jarSpec{classFileList, classDir} } func TransformClassesToJar(ctx common.AndroidModuleContext, classes []jarSpec, manifest common.OptionalPath) common.Path { outputFile := common.PathForModuleOut(ctx, "classes-full-debug.jar") deps := common.Paths{} jarArgs := []string{} for _, j := range classes { deps = append(deps, j.fileList) jarArgs = append(jarArgs, j.soongJarArgs()) } if manifest.Valid() { deps = append(deps, manifest.Path()) jarArgs = append(jarArgs, "-m "+manifest.String()) } ctx.ModuleBuild(pctx, common.ModuleBuildParams{ Rule: jar, Output: outputFile, Implicits: deps, Args: map[string]string{ "jarArgs": strings.Join(jarArgs, " "), }, }) return outputFile } func TransformClassesJarToDex(ctx common.AndroidModuleContext, classesJar common.Path, flags javaBuilderFlags) jarSpec { outDir := common.PathForModuleOut(ctx, "dex") outputFile := common.PathForModuleOut(ctx, "dex.filelist") ctx.ModuleBuild(pctx, common.ModuleBuildParams{ Rule: dx, Output: outputFile, Input: classesJar, Args: map[string]string{ "dxFlags": flags.dxFlags, "outDir": outDir.String(), }, }) return jarSpec{outputFile, outDir} } func TransformDexToJavaLib(ctx common.AndroidModuleContext, resources []jarSpec, dexJarSpec jarSpec) common.Path { outputFile := common.PathForModuleOut(ctx, "javalib.jar") var deps common.Paths var jarArgs []string for _, j := range resources { deps = append(deps, j.fileList) jarArgs = append(jarArgs, j.soongJarArgs()) } deps = append(deps, dexJarSpec.fileList) jarArgs = append(jarArgs, dexJarSpec.soongJarArgs()) ctx.ModuleBuild(pctx, common.ModuleBuildParams{ Rule: jar, Output: outputFile, Implicits: deps, Args: map[string]string{ "jarArgs": strings.Join(jarArgs, " "), }, }) return outputFile } func TransformJarJar(ctx common.AndroidModuleContext, classesJar common.Path, rulesFile common.Path) common.Path { outputFile := common.PathForModuleOut(ctx, "classes-jarjar.jar") ctx.ModuleBuild(pctx, common.ModuleBuildParams{ Rule: jarjar, Output: outputFile, Input: classesJar, Implicit: rulesFile, Args: map[string]string{ "rulesFile": rulesFile.String(), }, }) return outputFile } func TransformPrebuiltJarToClasses(ctx common.AndroidModuleContext, prebuilt common.Path) (classJarSpec, resourceJarSpec jarSpec) { classDir := common.PathForModuleOut(ctx, "extracted/classes") classFileList := common.PathForModuleOut(ctx, "extracted/classes.list") resourceFileList := common.PathForModuleOut(ctx, "extracted/resources.list") ctx.ModuleBuild(pctx, common.ModuleBuildParams{ Rule: extractPrebuilt, Outputs: common.WritablePaths{classFileList, resourceFileList}, Input: prebuilt, Args: map[string]string{ "outDir": classDir.String(), "classFile": classFileList.String(), "resourceFile": resourceFileList.String(), }, }) return jarSpec{classFileList, classDir}, jarSpec{resourceFileList, classDir} }