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