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 15 package 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 21 import ( 22 "path/filepath" 23 "strings" 24 25 "android/soong/common" 26 27 "github.com/google/blueprint" 28 _ "github.com/google/blueprint/bootstrap" 29 ) 30 31 var ( 32 pctx = common.NewPackageContext("android/soong/java") 33 34 // Compiling java is not conducive to proper dependency tracking. The path-matches-class-name 35 // requirement leads to unpredictable generated source file names, and a single .java file 36 // will get compiled into multiple .class files if it contains inner classes. To work around 37 // this, all java rules write into separate directories and then a post-processing step lists 38 // the files in the the directory into a list file that later rules depend on (and sometimes 39 // read from directly using @<listfile>) 40 javac = pctx.StaticRule("javac", 41 blueprint.RuleParams{ 42 Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + 43 `$javacCmd -encoding UTF-8 $javacFlags $bootClasspath $classpath ` + 44 `-extdirs "" -d $outDir @$out.rsp || ( rm -rf "$outDir"; exit 41 ) && ` + 45 `find $outDir -name "*.class" > $out`, 46 Rspfile: "$out.rsp", 47 RspfileContent: "$in", 48 Description: "javac $outDir", 49 }, 50 "javacCmd", "javacFlags", "bootClasspath", "classpath", "outDir") 51 52 jar = pctx.StaticRule("jar", 53 blueprint.RuleParams{ 54 Command: `$jarCmd -o $out $jarArgs`, 55 CommandDeps: []string{"$jarCmd"}, 56 Description: "jar $out", 57 }, 58 "jarCmd", "jarArgs") 59 60 dx = pctx.StaticRule("dx", 61 blueprint.RuleParams{ 62 Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + 63 `$dxCmd --dex --output=$outDir $dxFlags $in || ( rm -rf "$outDir"; exit 41 ) && ` + 64 `find "$outDir" -name "classes*.dex" > $out`, 65 CommandDeps: []string{"$dxCmd"}, 66 Description: "dex $out", 67 }, 68 "outDir", "dxFlags") 69 70 jarjar = pctx.StaticRule("jarjar", 71 blueprint.RuleParams{ 72 Command: "java -jar $jarjarCmd process $rulesFile $in $out", 73 CommandDeps: []string{"$jarjarCmd", "$rulesFile"}, 74 Description: "jarjar $out", 75 }, 76 "rulesFile") 77 78 extractPrebuilt = pctx.StaticRule("extractPrebuilt", 79 blueprint.RuleParams{ 80 Command: `rm -rf $outDir && unzip -qo $in -d $outDir && ` + 81 `find $outDir -name "*.class" > $classFile && ` + 82 `find $outDir -type f -a \! -name "*.class" -a \! -name "MANIFEST.MF" > $resourceFile || ` + 83 `(rm -rf $outDir; exit 42)`, 84 Description: "extract java prebuilt $outDir", 85 }, 86 "outDir", "classFile", "resourceFile") 87 ) 88 89 func init() { 90 pctx.Import("github.com/google/blueprint/bootstrap") 91 pctx.StaticVariable("commonJdkFlags", "-source 1.7 -target 1.7 -Xmaxerrs 9999999") 92 pctx.StaticVariable("javacCmd", "javac -J-Xmx1024M $commonJdkFlags") 93 pctx.StaticVariable("jarCmd", filepath.Join("${bootstrap.BinDir}", "soong_jar")) 94 pctx.HostBinToolVariable("dxCmd", "dx") 95 pctx.HostJavaToolVariable("jarjarCmd", "jarjar.jar") 96 } 97 98 type javaBuilderFlags struct { 99 javacFlags string 100 dxFlags string 101 bootClasspath string 102 classpath string 103 aidlFlags string 104 } 105 106 type jarSpec struct { 107 fileList, dir common.Path 108 } 109 110 func (j jarSpec) soongJarArgs() string { 111 return "-C " + j.dir.String() + " -l " + j.fileList.String() 112 } 113 114 func TransformJavaToClasses(ctx common.AndroidModuleContext, srcFiles common.Paths, srcFileLists common.Paths, 115 flags javaBuilderFlags, deps common.Paths) jarSpec { 116 117 classDir := common.PathForModuleOut(ctx, "classes") 118 classFileList := common.PathForModuleOut(ctx, "classes.list") 119 120 javacFlags := flags.javacFlags + common.JoinWithPrefix(srcFileLists.Strings(), "@") 121 122 deps = append(deps, srcFileLists...) 123 124 ctx.ModuleBuild(pctx, common.ModuleBuildParams{ 125 Rule: javac, 126 Output: classFileList, 127 Inputs: srcFiles, 128 Implicits: deps, 129 Args: map[string]string{ 130 "javacFlags": javacFlags, 131 "bootClasspath": flags.bootClasspath, 132 "classpath": flags.classpath, 133 "outDir": classDir.String(), 134 }, 135 }) 136 137 return jarSpec{classFileList, classDir} 138 } 139 140 func TransformClassesToJar(ctx common.AndroidModuleContext, classes []jarSpec, 141 manifest common.OptionalPath) common.Path { 142 143 outputFile := common.PathForModuleOut(ctx, "classes-full-debug.jar") 144 145 deps := common.Paths{} 146 jarArgs := []string{} 147 148 for _, j := range classes { 149 deps = append(deps, j.fileList) 150 jarArgs = append(jarArgs, j.soongJarArgs()) 151 } 152 153 if manifest.Valid() { 154 deps = append(deps, manifest.Path()) 155 jarArgs = append(jarArgs, "-m "+manifest.String()) 156 } 157 158 ctx.ModuleBuild(pctx, common.ModuleBuildParams{ 159 Rule: jar, 160 Output: outputFile, 161 Implicits: deps, 162 Args: map[string]string{ 163 "jarArgs": strings.Join(jarArgs, " "), 164 }, 165 }) 166 167 return outputFile 168 } 169 170 func TransformClassesJarToDex(ctx common.AndroidModuleContext, classesJar common.Path, 171 flags javaBuilderFlags) jarSpec { 172 173 outDir := common.PathForModuleOut(ctx, "dex") 174 outputFile := common.PathForModuleOut(ctx, "dex.filelist") 175 176 ctx.ModuleBuild(pctx, common.ModuleBuildParams{ 177 Rule: dx, 178 Output: outputFile, 179 Input: classesJar, 180 Args: map[string]string{ 181 "dxFlags": flags.dxFlags, 182 "outDir": outDir.String(), 183 }, 184 }) 185 186 return jarSpec{outputFile, outDir} 187 } 188 189 func TransformDexToJavaLib(ctx common.AndroidModuleContext, resources []jarSpec, 190 dexJarSpec jarSpec) common.Path { 191 192 outputFile := common.PathForModuleOut(ctx, "javalib.jar") 193 var deps common.Paths 194 var jarArgs []string 195 196 for _, j := range resources { 197 deps = append(deps, j.fileList) 198 jarArgs = append(jarArgs, j.soongJarArgs()) 199 } 200 201 deps = append(deps, dexJarSpec.fileList) 202 jarArgs = append(jarArgs, dexJarSpec.soongJarArgs()) 203 204 ctx.ModuleBuild(pctx, common.ModuleBuildParams{ 205 Rule: jar, 206 Output: outputFile, 207 Implicits: deps, 208 Args: map[string]string{ 209 "jarArgs": strings.Join(jarArgs, " "), 210 }, 211 }) 212 213 return outputFile 214 } 215 216 func TransformJarJar(ctx common.AndroidModuleContext, classesJar common.Path, rulesFile common.Path) common.Path { 217 outputFile := common.PathForModuleOut(ctx, "classes-jarjar.jar") 218 ctx.ModuleBuild(pctx, common.ModuleBuildParams{ 219 Rule: jarjar, 220 Output: outputFile, 221 Input: classesJar, 222 Implicit: rulesFile, 223 Args: map[string]string{ 224 "rulesFile": rulesFile.String(), 225 }, 226 }) 227 228 return outputFile 229 } 230 231 func TransformPrebuiltJarToClasses(ctx common.AndroidModuleContext, 232 prebuilt common.Path) (classJarSpec, resourceJarSpec jarSpec) { 233 234 classDir := common.PathForModuleOut(ctx, "extracted/classes") 235 classFileList := common.PathForModuleOut(ctx, "extracted/classes.list") 236 resourceFileList := common.PathForModuleOut(ctx, "extracted/resources.list") 237 238 ctx.ModuleBuild(pctx, common.ModuleBuildParams{ 239 Rule: extractPrebuilt, 240 Outputs: common.WritablePaths{classFileList, resourceFileList}, 241 Input: prebuilt, 242 Args: map[string]string{ 243 "outDir": classDir.String(), 244 "classFile": classFileList.String(), 245 "resourceFile": resourceFileList.String(), 246 }, 247 }) 248 249 return jarSpec{classFileList, classDir}, jarSpec{resourceFileList, classDir} 250 } 251