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 contains the module types for compiling Java for Android, and converts the properties 18// into the flags and filenames necessary to pass to the compiler. The final creation of the rules 19// is handled in builder.go 20 21import ( 22 "fmt" 23 "strings" 24 25 "github.com/google/blueprint" 26 27 "android/soong" 28 "android/soong/common" 29 "android/soong/genrule" 30) 31 32func init() { 33 soong.RegisterModuleType("java_library", JavaLibraryFactory) 34 soong.RegisterModuleType("java_library_static", JavaLibraryFactory) 35 soong.RegisterModuleType("java_library_host", JavaLibraryHostFactory) 36 soong.RegisterModuleType("java_binary", JavaBinaryFactory) 37 soong.RegisterModuleType("java_binary_host", JavaBinaryHostFactory) 38 soong.RegisterModuleType("prebuilt_java_library", JavaPrebuiltFactory) 39 soong.RegisterModuleType("prebuilt_sdk", SdkPrebuiltFactory) 40 soong.RegisterModuleType("android_app", AndroidAppFactory) 41 42 soong.RegisterSingletonType("logtags", LogtagsSingleton) 43} 44 45// TODO: 46// Autogenerated files: 47// Proto 48// Renderscript 49// Post-jar passes: 50// Proguard 51// Emma 52// Jarjar 53// Dex 54// Rmtypedefs 55// Jack 56// DroidDoc 57// Findbugs 58 59type javaBaseProperties struct { 60 // list of source files used to compile the Java module. May be .java, .logtags, .proto, 61 // or .aidl files. 62 Srcs []string `android:"arch_variant"` 63 64 // list of source files that should not be used to build the Java module. 65 // This is most useful in the arch/multilib variants to remove non-common files 66 Exclude_srcs []string `android:"arch_variant"` 67 68 // list of directories containing Java resources 69 Java_resource_dirs []string `android:"arch_variant"` 70 71 // list of directories that should be excluded from java_resource_dirs 72 Exclude_java_resource_dirs []string `android:"arch_variant"` 73 74 // don't build against the default libraries (core-libart, core-junit, 75 // ext, and framework for device targets) 76 No_standard_libraries bool 77 78 // list of module-specific flags that will be used for javac compiles 79 Javacflags []string `android:"arch_variant"` 80 81 // list of module-specific flags that will be used for jack compiles 82 Jack_flags []string `android:"arch_variant"` 83 84 // list of module-specific flags that will be used for dex compiles 85 Dxflags []string `android:"arch_variant"` 86 87 // list of of java libraries that will be in the classpath 88 Java_libs []string `android:"arch_variant"` 89 90 // list of java libraries that will be compiled into the resulting jar 91 Java_static_libs []string `android:"arch_variant"` 92 93 // manifest file to be included in resulting jar 94 Manifest *string 95 96 // if not blank, set to the version of the sdk to compile against 97 Sdk_version string 98 99 // Set for device java libraries, and for host versions of device java libraries 100 // built for testing 101 Dex bool `blueprint:"mutated"` 102 103 // if not blank, run jarjar using the specified rules file 104 Jarjar_rules *string 105 106 // directories to pass to aidl tool 107 Aidl_includes []string 108 109 // directories that should be added as include directories 110 // for any aidl sources of modules that depend on this module 111 Export_aidl_include_dirs []string 112} 113 114// javaBase contains the properties and members used by all java module types, and implements 115// the blueprint.Module interface. 116type javaBase struct { 117 common.AndroidModuleBase 118 module JavaModuleType 119 120 properties javaBaseProperties 121 122 // output file suitable for inserting into the classpath of another compile 123 classpathFile common.Path 124 125 // output file suitable for installing or running 126 outputFile common.Path 127 128 // jarSpecs suitable for inserting classes from a static library into another jar 129 classJarSpecs []jarSpec 130 131 // jarSpecs suitable for inserting resources from a static library into another jar 132 resourceJarSpecs []jarSpec 133 134 exportAidlIncludeDirs common.Paths 135 136 logtagsSrcs common.Paths 137 138 // filelists of extra source files that should be included in the javac command line, 139 // for example R.java generated by aapt for android apps 140 ExtraSrcLists common.Paths 141 142 // installed file for binary dependency 143 installFile common.Path 144} 145 146type AndroidJavaModuleContext common.AndroidBaseContext 147 148type JavaModuleType interface { 149 GenerateJavaBuildActions(ctx common.AndroidModuleContext) 150 JavaDependencies(ctx AndroidJavaModuleContext) []string 151} 152 153type JavaDependency interface { 154 ClasspathFile() common.Path 155 ClassJarSpecs() []jarSpec 156 ResourceJarSpecs() []jarSpec 157 AidlIncludeDirs() common.Paths 158} 159 160func NewJavaBase(base *javaBase, module JavaModuleType, hod common.HostOrDeviceSupported, 161 props ...interface{}) (blueprint.Module, []interface{}) { 162 163 base.module = module 164 165 props = append(props, &base.properties) 166 167 return common.InitAndroidArchModule(base, hod, common.MultilibCommon, props...) 168} 169 170func (j *javaBase) BootClasspath(ctx common.AndroidBaseContext) string { 171 if ctx.Device() { 172 if j.properties.Sdk_version == "" { 173 return "core-libart" 174 } else if j.properties.Sdk_version == "current" { 175 // TODO: !TARGET_BUILD_APPS 176 // TODO: export preprocessed framework.aidl from android_stubs_current 177 return "android_stubs_current" 178 } else if j.properties.Sdk_version == "system_current" { 179 return "android_system_stubs_current" 180 } else { 181 return "sdk_v" + j.properties.Sdk_version 182 } 183 } else { 184 if j.properties.Dex { 185 return "core-libart" 186 } else { 187 return "" 188 } 189 } 190} 191 192var defaultJavaLibraries = []string{"core-libart", "core-junit", "ext", "framework"} 193 194func javaDepsMutator(ctx common.AndroidBottomUpMutatorContext) { 195 if j, ok := ctx.Module().(JavaModuleType); ok { 196 ctx.AddDependency(ctx.Module(), j.JavaDependencies(ctx)...) 197 } 198} 199 200func (j *javaBase) JavaDependencies(ctx AndroidJavaModuleContext) []string { 201 var deps []string 202 203 if !j.properties.No_standard_libraries { 204 bootClasspath := j.BootClasspath(ctx) 205 if bootClasspath != "" { 206 deps = append(deps, bootClasspath) 207 } 208 if ctx.Device() && j.properties.Sdk_version == "" { 209 deps = append(deps, defaultJavaLibraries...) 210 } 211 } 212 deps = append(deps, j.properties.Java_libs...) 213 deps = append(deps, j.properties.Java_static_libs...) 214 215 return deps 216} 217 218func (j *javaBase) aidlFlags(ctx common.AndroidModuleContext, aidlPreprocess common.OptionalPath, 219 aidlIncludeDirs common.Paths) []string { 220 221 localAidlIncludes := common.PathsForModuleSrc(ctx, j.properties.Aidl_includes) 222 223 var flags []string 224 if aidlPreprocess.Valid() { 225 flags = append(flags, "-p"+aidlPreprocess.String()) 226 } else { 227 flags = append(flags, common.JoinWithPrefix(aidlIncludeDirs.Strings(), "-I")) 228 } 229 230 flags = append(flags, common.JoinWithPrefix(j.exportAidlIncludeDirs.Strings(), "-I")) 231 flags = append(flags, common.JoinWithPrefix(localAidlIncludes.Strings(), "-I")) 232 flags = append(flags, "-I"+common.PathForModuleSrc(ctx).String()) 233 flags = append(flags, "-I"+common.PathForModuleSrc(ctx, "src").String()) 234 235 return flags 236} 237 238func (j *javaBase) collectDeps(ctx common.AndroidModuleContext) (classpath common.Paths, 239 bootClasspath common.OptionalPath, classJarSpecs, resourceJarSpecs []jarSpec, aidlPreprocess common.OptionalPath, 240 aidlIncludeDirs common.Paths, srcFileLists common.Paths) { 241 242 ctx.VisitDirectDeps(func(module blueprint.Module) { 243 otherName := ctx.OtherModuleName(module) 244 if javaDep, ok := module.(JavaDependency); ok { 245 if otherName == j.BootClasspath(ctx) { 246 bootClasspath = common.OptionalPathForPath(javaDep.ClasspathFile()) 247 } else if inList(otherName, defaultJavaLibraries) { 248 classpath = append(classpath, javaDep.ClasspathFile()) 249 } else if inList(otherName, j.properties.Java_libs) { 250 classpath = append(classpath, javaDep.ClasspathFile()) 251 } else if inList(otherName, j.properties.Java_static_libs) { 252 classpath = append(classpath, javaDep.ClasspathFile()) 253 classJarSpecs = append(classJarSpecs, javaDep.ClassJarSpecs()...) 254 resourceJarSpecs = append(resourceJarSpecs, javaDep.ResourceJarSpecs()...) 255 } else if otherName == "framework-res" { 256 if ctx.ModuleName() == "framework" { 257 // framework.jar has a one-off dependency on the R.java and Manifest.java files 258 // generated by framework-res.apk 259 srcFileLists = append(srcFileLists, module.(*javaBase).module.(*AndroidApp).aaptJavaFileList) 260 } 261 } else { 262 panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName())) 263 } 264 aidlIncludeDirs = append(aidlIncludeDirs, javaDep.AidlIncludeDirs()...) 265 if sdkDep, ok := module.(sdkDependency); ok { 266 if sdkDep.AidlPreprocessed().Valid() { 267 if aidlPreprocess.Valid() { 268 ctx.ModuleErrorf("multiple dependencies with preprocessed aidls:\n %q\n %q", 269 aidlPreprocess, sdkDep.AidlPreprocessed()) 270 } else { 271 aidlPreprocess = sdkDep.AidlPreprocessed() 272 } 273 } 274 } 275 } 276 }) 277 278 return classpath, bootClasspath, classJarSpecs, resourceJarSpecs, aidlPreprocess, 279 aidlIncludeDirs, srcFileLists 280} 281 282func (j *javaBase) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) { 283 j.module.GenerateJavaBuildActions(ctx) 284} 285 286func (j *javaBase) GenerateJavaBuildActions(ctx common.AndroidModuleContext) { 287 288 j.exportAidlIncludeDirs = common.PathsForModuleSrc(ctx, j.properties.Export_aidl_include_dirs) 289 290 classpath, bootClasspath, classJarSpecs, resourceJarSpecs, aidlPreprocess, 291 aidlIncludeDirs, srcFileLists := j.collectDeps(ctx) 292 293 var flags javaBuilderFlags 294 295 javacFlags := j.properties.Javacflags 296 if len(javacFlags) > 0 { 297 ctx.Variable(pctx, "javacFlags", strings.Join(javacFlags, " ")) 298 flags.javacFlags = "$javacFlags" 299 } 300 301 aidlFlags := j.aidlFlags(ctx, aidlPreprocess, aidlIncludeDirs) 302 if len(aidlFlags) > 0 { 303 ctx.Variable(pctx, "aidlFlags", strings.Join(aidlFlags, " ")) 304 flags.aidlFlags = "$aidlFlags" 305 } 306 307 var javacDeps common.Paths 308 309 if bootClasspath.Valid() { 310 flags.bootClasspath = "-bootclasspath " + bootClasspath.String() 311 javacDeps = append(javacDeps, bootClasspath.Path()) 312 } 313 314 if len(classpath) > 0 { 315 flags.classpath = "-classpath " + strings.Join(classpath.Strings(), ":") 316 javacDeps = append(javacDeps, classpath...) 317 } 318 319 srcFiles := ctx.ExpandSources(j.properties.Srcs, j.properties.Exclude_srcs) 320 321 srcFiles = j.genSources(ctx, srcFiles, flags) 322 323 ctx.VisitDirectDeps(func(module blueprint.Module) { 324 if gen, ok := module.(genrule.SourceFileGenerator); ok { 325 srcFiles = append(srcFiles, gen.GeneratedSourceFiles()...) 326 } 327 }) 328 329 srcFileLists = append(srcFileLists, j.ExtraSrcLists...) 330 331 if len(srcFiles) > 0 { 332 // Compile java sources into .class files 333 classes := TransformJavaToClasses(ctx, srcFiles, srcFileLists, flags, javacDeps) 334 if ctx.Failed() { 335 return 336 } 337 338 classJarSpecs = append([]jarSpec{classes}, classJarSpecs...) 339 } 340 341 resourceJarSpecs = append(ResourceDirsToJarSpecs(ctx, j.properties.Java_resource_dirs, j.properties.Exclude_java_resource_dirs), 342 resourceJarSpecs...) 343 344 manifest := common.OptionalPathForModuleSrc(ctx, j.properties.Manifest) 345 346 allJarSpecs := append([]jarSpec(nil), classJarSpecs...) 347 allJarSpecs = append(allJarSpecs, resourceJarSpecs...) 348 349 // Combine classes + resources into classes-full-debug.jar 350 outputFile := TransformClassesToJar(ctx, allJarSpecs, manifest) 351 if ctx.Failed() { 352 return 353 } 354 355 if j.properties.Jarjar_rules != nil { 356 jarjar_rules := common.PathForModuleSrc(ctx, *j.properties.Jarjar_rules) 357 // Transform classes-full-debug.jar into classes-jarjar.jar 358 outputFile = TransformJarJar(ctx, outputFile, jarjar_rules) 359 if ctx.Failed() { 360 return 361 } 362 363 classes, _ := TransformPrebuiltJarToClasses(ctx, outputFile) 364 classJarSpecs = []jarSpec{classes} 365 } 366 367 j.resourceJarSpecs = resourceJarSpecs 368 j.classJarSpecs = classJarSpecs 369 j.classpathFile = outputFile 370 371 if j.properties.Dex && len(srcFiles) > 0 { 372 dxFlags := j.properties.Dxflags 373 if false /* emma enabled */ { 374 // If you instrument class files that have local variable debug information in 375 // them emma does not correctly maintain the local variable table. 376 // This will cause an error when you try to convert the class files for Android. 377 // The workaround here is to build different dex file here based on emma switch 378 // then later copy into classes.dex. When emma is on, dx is run with --no-locals 379 // option to remove local variable information 380 dxFlags = append(dxFlags, "--no-locals") 381 } 382 383 if ctx.AConfig().Getenv("NO_OPTIMIZE_DX") != "" { 384 dxFlags = append(dxFlags, "--no-optimize") 385 } 386 387 if ctx.AConfig().Getenv("GENERATE_DEX_DEBUG") != "" { 388 dxFlags = append(dxFlags, 389 "--debug", 390 "--verbose", 391 "--dump-to="+common.PathForModuleOut(ctx, "classes.lst").String(), 392 "--dump-width=1000") 393 } 394 395 flags.dxFlags = strings.Join(dxFlags, " ") 396 397 // Compile classes.jar into classes.dex 398 dexJarSpec := TransformClassesJarToDex(ctx, outputFile, flags) 399 if ctx.Failed() { 400 return 401 } 402 403 // Combine classes.dex + resources into javalib.jar 404 outputFile = TransformDexToJavaLib(ctx, resourceJarSpecs, dexJarSpec) 405 } 406 ctx.CheckbuildFile(outputFile) 407 j.outputFile = outputFile 408} 409 410var _ JavaDependency = (*JavaLibrary)(nil) 411 412func (j *javaBase) ClasspathFile() common.Path { 413 return j.classpathFile 414} 415 416func (j *javaBase) ClassJarSpecs() []jarSpec { 417 return j.classJarSpecs 418} 419 420func (j *javaBase) ResourceJarSpecs() []jarSpec { 421 return j.resourceJarSpecs 422} 423 424func (j *javaBase) AidlIncludeDirs() common.Paths { 425 return j.exportAidlIncludeDirs 426} 427 428var _ logtagsProducer = (*javaBase)(nil) 429 430func (j *javaBase) logtags() common.Paths { 431 return j.logtagsSrcs 432} 433 434// 435// Java libraries (.jar file) 436// 437 438type JavaLibrary struct { 439 javaBase 440} 441 442func (j *JavaLibrary) GenerateJavaBuildActions(ctx common.AndroidModuleContext) { 443 j.javaBase.GenerateJavaBuildActions(ctx) 444 445 j.installFile = ctx.InstallFileName(common.PathForModuleInstall(ctx, "framework"), ctx.ModuleName()+".jar", j.outputFile) 446} 447 448func JavaLibraryFactory() (blueprint.Module, []interface{}) { 449 module := &JavaLibrary{} 450 451 module.properties.Dex = true 452 453 return NewJavaBase(&module.javaBase, module, common.HostAndDeviceSupported) 454} 455 456func JavaLibraryHostFactory() (blueprint.Module, []interface{}) { 457 module := &JavaLibrary{} 458 459 return NewJavaBase(&module.javaBase, module, common.HostSupported) 460} 461 462// 463// Java Binaries (.jar file plus wrapper script) 464// 465 466type javaBinaryProperties struct { 467 // installable script to execute the resulting jar 468 Wrapper string 469} 470 471type JavaBinary struct { 472 JavaLibrary 473 474 binaryProperties javaBinaryProperties 475} 476 477func (j *JavaBinary) GenerateJavaBuildActions(ctx common.AndroidModuleContext) { 478 j.JavaLibrary.GenerateJavaBuildActions(ctx) 479 480 // Depend on the installed jar (j.installFile) so that the wrapper doesn't get executed by 481 // another build rule before the jar has been installed. 482 ctx.InstallFile(common.PathForModuleInstall(ctx, "bin"), common.PathForModuleSrc(ctx, j.binaryProperties.Wrapper), 483 j.installFile) 484} 485 486func JavaBinaryFactory() (blueprint.Module, []interface{}) { 487 module := &JavaBinary{} 488 489 module.properties.Dex = true 490 491 return NewJavaBase(&module.javaBase, module, common.HostAndDeviceSupported, &module.binaryProperties) 492} 493 494func JavaBinaryHostFactory() (blueprint.Module, []interface{}) { 495 module := &JavaBinary{} 496 497 return NewJavaBase(&module.javaBase, module, common.HostSupported, &module.binaryProperties) 498} 499 500// 501// Java prebuilts 502// 503 504type javaPrebuiltProperties struct { 505 Srcs []string 506} 507 508type JavaPrebuilt struct { 509 common.AndroidModuleBase 510 511 properties javaPrebuiltProperties 512 513 classpathFile common.Path 514 classJarSpecs, resourceJarSpecs []jarSpec 515} 516 517func (j *JavaPrebuilt) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) { 518 if len(j.properties.Srcs) != 1 { 519 ctx.ModuleErrorf("expected exactly one jar in srcs") 520 return 521 } 522 prebuilt := common.PathForModuleSrc(ctx, j.properties.Srcs[0]) 523 524 classJarSpec, resourceJarSpec := TransformPrebuiltJarToClasses(ctx, prebuilt) 525 526 j.classpathFile = prebuilt 527 j.classJarSpecs = []jarSpec{classJarSpec} 528 j.resourceJarSpecs = []jarSpec{resourceJarSpec} 529 ctx.InstallFileName(common.PathForModuleInstall(ctx, "framework"), ctx.ModuleName()+".jar", j.classpathFile) 530} 531 532var _ JavaDependency = (*JavaPrebuilt)(nil) 533 534func (j *JavaPrebuilt) ClasspathFile() common.Path { 535 return j.classpathFile 536} 537 538func (j *JavaPrebuilt) ClassJarSpecs() []jarSpec { 539 return j.classJarSpecs 540} 541 542func (j *JavaPrebuilt) ResourceJarSpecs() []jarSpec { 543 return j.resourceJarSpecs 544} 545 546func (j *JavaPrebuilt) AidlIncludeDirs() common.Paths { 547 return nil 548} 549 550func JavaPrebuiltFactory() (blueprint.Module, []interface{}) { 551 module := &JavaPrebuilt{} 552 553 return common.InitAndroidArchModule(module, common.HostAndDeviceSupported, 554 common.MultilibCommon, &module.properties) 555} 556 557// 558// SDK java prebuilts (.jar containing resources plus framework.aidl) 559// 560 561type sdkDependency interface { 562 JavaDependency 563 AidlPreprocessed() common.OptionalPath 564} 565 566var _ sdkDependency = (*sdkPrebuilt)(nil) 567 568type sdkPrebuiltProperties struct { 569 Aidl_preprocessed *string 570} 571 572type sdkPrebuilt struct { 573 JavaPrebuilt 574 575 sdkProperties sdkPrebuiltProperties 576 577 aidlPreprocessed common.OptionalPath 578} 579 580func (j *sdkPrebuilt) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) { 581 j.JavaPrebuilt.GenerateAndroidBuildActions(ctx) 582 583 j.aidlPreprocessed = common.OptionalPathForModuleSrc(ctx, j.sdkProperties.Aidl_preprocessed) 584} 585 586func (j *sdkPrebuilt) AidlPreprocessed() common.OptionalPath { 587 return j.aidlPreprocessed 588} 589 590func SdkPrebuiltFactory() (blueprint.Module, []interface{}) { 591 module := &sdkPrebuilt{} 592 593 return common.InitAndroidArchModule(module, common.HostAndDeviceSupported, 594 common.MultilibCommon, &module.properties, &module.sdkProperties) 595} 596 597func inList(s string, l []string) bool { 598 for _, e := range l { 599 if e == s { 600 return true 601 } 602 } 603 return false 604} 605