1// Copyright 2018 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 17import ( 18 "fmt" 19 "path/filepath" 20 "strings" 21 22 "github.com/google/blueprint/proptools" 23 24 "android/soong/android" 25 "android/soong/java/config" 26) 27 28func init() { 29 RegisterDocsBuildComponents(android.InitRegistrationContext) 30} 31 32func RegisterDocsBuildComponents(ctx android.RegistrationContext) { 33 ctx.RegisterModuleType("doc_defaults", DocDefaultsFactory) 34 35 ctx.RegisterModuleType("droiddoc", DroiddocFactory) 36 ctx.RegisterModuleType("droiddoc_host", DroiddocHostFactory) 37 ctx.RegisterModuleType("droiddoc_exported_dir", ExportedDroiddocDirFactory) 38 ctx.RegisterModuleType("javadoc", JavadocFactory) 39 ctx.RegisterModuleType("javadoc_host", JavadocHostFactory) 40} 41 42type JavadocProperties struct { 43 // list of source files used to compile the Java module. May be .java, .logtags, .proto, 44 // or .aidl files. 45 Srcs []string `android:"path,arch_variant"` 46 47 // list of source files that should not be used to build the Java module. 48 // This is most useful in the arch/multilib variants to remove non-common files 49 // filegroup or genrule can be included within this property. 50 Exclude_srcs []string `android:"path,arch_variant"` 51 52 // list of package names that should actually be used. If this property is left unspecified, 53 // all the sources from the srcs property is used. 54 Filter_packages []string 55 56 // list of java libraries that will be in the classpath. 57 Libs proptools.Configurable[[]string] `android:"arch_variant"` 58 59 // If set to false, don't allow this module(-docs.zip) to be exported. Defaults to true. 60 Installable *bool 61 62 // if not blank, set to the version of the sdk to compile against. 63 // Defaults to compiling against the current platform. 64 Sdk_version *string `android:"arch_variant"` 65 66 // When targeting 1.9 and above, override the modules to use with --system, 67 // otherwise provides defaults libraries to add to the bootclasspath. 68 // Defaults to "none" 69 System_modules *string 70 71 Aidl struct { 72 // Top level directories to pass to aidl tool 73 Include_dirs []string 74 75 // Directories rooted at the Android.bp file to pass to aidl tool 76 Local_include_dirs []string 77 } 78 79 // If not blank, set the java version passed to javadoc as -source 80 Java_version *string 81 82 // local files that are used within user customized droiddoc options. 83 Arg_files []string `android:"path"` 84 85 // user customized droiddoc args. Deprecated, use flags instead. 86 // Available variables for substitution: 87 // 88 // $(location <label>): the path to the arg_files with name <label> 89 // $$: a literal $ 90 Args *string 91 92 // user customized droiddoc args. Not compatible with property args. 93 // Available variables for substitution: 94 // 95 // $(location <label>): the path to the arg_files with name <label> 96 // $$: a literal $ 97 Flags []string 98 99 // names of the output files used in args that will be generated 100 Out []string 101} 102 103type ApiToCheck struct { 104 // path to the API txt file that the new API extracted from source code is checked 105 // against. The path can be local to the module or from other module (via :module syntax). 106 Api_file *string `android:"path"` 107 108 // path to the API txt file that the new @removed API extractd from source code is 109 // checked against. The path can be local to the module or from other module (via 110 // :module syntax). 111 Removed_api_file *string `android:"path"` 112 113 // If not blank, path to the baseline txt file for approved API check violations. 114 Baseline_file *string `android:"path"` 115 116 // Arguments to the apicheck tool. 117 Args *string 118} 119 120type DroiddocProperties struct { 121 // directory relative to top of the source tree that contains doc templates files. 122 Custom_template *string 123 124 // directories under current module source which contains html/jd files. 125 Html_dirs []string 126 127 // set a value in the Clearsilver hdf namespace. 128 Hdf []string 129 130 // proofread file contains all of the text content of the javadocs concatenated into one file, 131 // suitable for spell-checking and other goodness. 132 Proofread_file *string 133 134 // a todo file lists the program elements that are missing documentation. 135 // At some point, this might be improved to show more warnings. 136 Todo_file *string `android:"path"` 137 138 // A file containing a baseline for allowed lint errors. 139 Lint_baseline *string `android:"path"` 140 141 // directory under current module source that provide additional resources (images). 142 Resourcesdir *string 143 144 // resources output directory under out/soong/.intermediates. 145 Resourcesoutdir *string 146 147 // index.html under current module will be copied to docs out dir, if not null. 148 Static_doc_index_redirect *string `android:"path"` 149 150 // source.properties under current module will be copied to docs out dir, if not null. 151 Static_doc_properties *string `android:"path"` 152 153 // a list of files under current module source dir which contains known tags in Java sources. 154 // filegroup or genrule can be included within this property. 155 Knowntags []string `android:"path"` 156 157 // if set to true, generate docs through Dokka instead of Doclava. 158 Dokka_enabled *bool 159 160 // Compat config XML. Generates compat change documentation if set. 161 Compat_config *string `android:"path"` 162} 163 164// Common flags passed down to build rule 165type droiddocBuilderFlags struct { 166 bootClasspathArgs string 167 classpathArgs string 168 sourcepathArgs string 169 dokkaClasspathArgs string 170 aidlFlags string 171 aidlDeps android.Paths 172 173 doclavaStubsFlags string 174 doclavaDocsFlags string 175 postDoclavaCmds string 176} 177 178func InitDroiddocModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) { 179 android.InitAndroidArchModule(module, hod, android.MultilibCommon) 180 android.InitDefaultableModule(module) 181} 182 183func apiCheckEnabled(ctx android.ModuleContext, apiToCheck ApiToCheck, apiVersionTag string) bool { 184 if ctx.Config().IsEnvTrue("WITHOUT_CHECK_API") { 185 if ctx.Config().BuildFromTextStub() { 186 ctx.ModuleErrorf("Generating stubs from api signature files is not available " + 187 "with WITHOUT_CHECK_API=true, as sync between the source Java files and the " + 188 "api signature files is not guaranteed.\n" + 189 "In order to utilize WITHOUT_CHECK_API, generate stubs from the source Java " + 190 "files with BUILD_FROM_SOURCE_STUB=true.\n" + 191 "However, the usage of WITHOUT_CHECK_API is not preferred as the incremental " + 192 "build is slower when generating stubs from the source Java files.\n" + 193 "Consider updating the api signature files and generating the stubs from " + 194 "them instead.") 195 } 196 return false 197 } else if String(apiToCheck.Api_file) != "" && String(apiToCheck.Removed_api_file) != "" { 198 return true 199 } else if String(apiToCheck.Api_file) != "" { 200 panic("for " + apiVersionTag + " removed_api_file has to be non-empty!") 201 } else if String(apiToCheck.Removed_api_file) != "" { 202 panic("for " + apiVersionTag + " api_file has to be non-empty!") 203 } 204 205 return false 206} 207 208// Javadoc 209type Javadoc struct { 210 android.ModuleBase 211 android.DefaultableModuleBase 212 213 properties JavadocProperties 214 215 srcJars android.Paths 216 srcFiles android.Paths 217 sourcepaths android.Paths 218 implicits android.Paths 219 220 docZip android.WritablePath 221 stubsSrcJar android.WritablePath 222 223 exportableStubsSrcJar android.WritablePath 224} 225 226// javadoc converts .java source files to documentation using javadoc. 227func JavadocFactory() android.Module { 228 module := &Javadoc{} 229 230 module.AddProperties(&module.properties) 231 232 InitDroiddocModule(module, android.HostAndDeviceSupported) 233 return module 234} 235 236// javadoc_host converts .java source files to documentation using javadoc. 237func JavadocHostFactory() android.Module { 238 module := &Javadoc{} 239 240 module.AddProperties(&module.properties) 241 242 InitDroiddocModule(module, android.HostSupported) 243 return module 244} 245 246func (j *Javadoc) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { 247 return android.SdkSpecFrom(ctx, String(j.properties.Sdk_version)) 248} 249 250func (j *Javadoc) SystemModules() string { 251 return proptools.String(j.properties.System_modules) 252} 253 254func (j *Javadoc) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { 255 return j.SdkVersion(ctx).ApiLevel 256} 257 258func (j *Javadoc) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.ApiLevel { 259 return j.SdkVersion(ctx).ApiLevel 260} 261 262func (j *Javadoc) TargetSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { 263 return j.SdkVersion(ctx).ApiLevel 264} 265 266func (j *Javadoc) addDeps(ctx android.BottomUpMutatorContext) { 267 if ctx.Device() { 268 sdkDep := decodeSdkDep(ctx, android.SdkContext(j)) 269 if sdkDep.useModule { 270 ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...) 271 ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules) 272 ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...) 273 ctx.AddVariationDependencies(nil, sdkLibTag, sdkDep.classpath...) 274 } 275 } 276 277 ctx.AddVariationDependencies(nil, libTag, j.properties.Libs.GetOrDefault(ctx, nil)...) 278} 279 280func (j *Javadoc) collectAidlFlags(ctx android.ModuleContext, deps deps) droiddocBuilderFlags { 281 var flags droiddocBuilderFlags 282 283 flags.aidlFlags, flags.aidlDeps = j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs) 284 285 return flags 286} 287 288func (j *Javadoc) aidlFlags(ctx android.ModuleContext, aidlPreprocess android.OptionalPath, 289 aidlIncludeDirs android.Paths) (string, android.Paths) { 290 291 aidlIncludes := android.PathsForModuleSrc(ctx, j.properties.Aidl.Local_include_dirs) 292 aidlIncludes = append(aidlIncludes, android.PathsForSource(ctx, j.properties.Aidl.Include_dirs)...) 293 294 var flags []string 295 var deps android.Paths 296 297 if aidlPreprocess.Valid() { 298 flags = append(flags, "-p"+aidlPreprocess.String()) 299 deps = append(deps, aidlPreprocess.Path()) 300 } else { 301 flags = append(flags, android.JoinWithPrefix(aidlIncludeDirs.Strings(), "-I")) 302 } 303 304 flags = append(flags, android.JoinWithPrefix(aidlIncludes.Strings(), "-I")) 305 flags = append(flags, "-I"+ctx.ModuleDir()) 306 if src := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "src"); src.Valid() { 307 flags = append(flags, "-I"+src.String()) 308 } 309 310 minSdkVersion := j.MinSdkVersion(ctx).FinalOrFutureInt() 311 flags = append(flags, fmt.Sprintf("--min_sdk_version=%v", minSdkVersion)) 312 313 return strings.Join(flags, " "), deps 314} 315 316// TODO: remove the duplication between this and the one in gen.go 317func (j *Javadoc) genSources(ctx android.ModuleContext, srcFiles android.Paths, 318 flags droiddocBuilderFlags) android.Paths { 319 320 outSrcFiles := make(android.Paths, 0, len(srcFiles)) 321 var aidlSrcs android.Paths 322 323 aidlIncludeFlags := genAidlIncludeFlags(ctx, srcFiles, android.Paths{}) 324 325 for _, srcFile := range srcFiles { 326 switch srcFile.Ext() { 327 case ".aidl": 328 aidlSrcs = append(aidlSrcs, srcFile) 329 case ".logtags": 330 javaFile := genLogtags(ctx, srcFile) 331 outSrcFiles = append(outSrcFiles, javaFile) 332 default: 333 outSrcFiles = append(outSrcFiles, srcFile) 334 } 335 } 336 337 // Process all aidl files together to support sharding them into one or more rules that produce srcjars. 338 if len(aidlSrcs) > 0 { 339 srcJarFiles := genAidl(ctx, aidlSrcs, flags.aidlFlags+aidlIncludeFlags, nil, flags.aidlDeps) 340 outSrcFiles = append(outSrcFiles, srcJarFiles...) 341 } 342 343 return outSrcFiles 344} 345 346func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { 347 var deps deps 348 349 sdkDep := decodeSdkDep(ctx, android.SdkContext(j)) 350 if sdkDep.invalidVersion { 351 ctx.AddMissingDependencies(sdkDep.bootclasspath) 352 ctx.AddMissingDependencies(sdkDep.java9Classpath) 353 } else if sdkDep.useFiles { 354 deps.bootClasspath = append(deps.bootClasspath, sdkDep.jars...) 355 deps.aidlPreprocess = sdkDep.aidl 356 } else { 357 deps.aidlPreprocess = sdkDep.aidl 358 } 359 360 ctx.VisitDirectDeps(func(module android.Module) { 361 otherName := ctx.OtherModuleName(module) 362 tag := ctx.OtherModuleDependencyTag(module) 363 364 switch tag { 365 case bootClasspathTag: 366 if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { 367 deps.bootClasspath = append(deps.bootClasspath, dep.ImplementationJars...) 368 } else if sm, ok := android.OtherModuleProvider(ctx, module, SystemModulesProvider); ok { 369 // A system modules dependency has been added to the bootclasspath 370 // so add its libs to the bootclasspath. 371 deps.bootClasspath = append(deps.bootClasspath, sm.HeaderJars...) 372 } else { 373 panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName())) 374 } 375 case libTag, sdkLibTag: 376 if sdkInfo, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok { 377 generatingLibsString := android.PrettyConcat( 378 getGeneratingLibs(ctx, j.SdkVersion(ctx), module.Name(), sdkInfo), true, "or") 379 ctx.ModuleErrorf("cannot depend directly on java_sdk_library %q; try depending on %s instead", module.Name(), generatingLibsString) 380 } else if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { 381 deps.classpath = append(deps.classpath, dep.HeaderJars...) 382 deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...) 383 deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.AconfigIntermediateCacheOutputPaths...) 384 } else if dep, ok := module.(android.SourceFileProducer); ok { 385 checkProducesJars(ctx, dep) 386 deps.classpath = append(deps.classpath, dep.Srcs()...) 387 } else { 388 ctx.ModuleErrorf("depends on non-java module %q", otherName) 389 } 390 391 case java9LibTag: 392 if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { 393 deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars...) 394 } else { 395 ctx.ModuleErrorf("depends on non-java module %q", otherName) 396 } 397 case systemModulesTag: 398 if deps.systemModules != nil { 399 panic("Found two system module dependencies") 400 } 401 if sm, ok := android.OtherModuleProvider(ctx, module, SystemModulesProvider); ok { 402 deps.systemModules = &systemModules{sm.OutputDir, sm.OutputDirDeps} 403 } else { 404 ctx.PropertyErrorf("boot classpath dependency %q does not provide SystemModulesProvider", 405 ctx.OtherModuleName(module)) 406 } 407 case aconfigDeclarationTag: 408 if dep, ok := android.OtherModuleProvider(ctx, module, android.AconfigDeclarationsProviderKey); ok { 409 deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPath) 410 } else if dep, ok := android.OtherModuleProvider(ctx, module, android.CodegenInfoProvider); ok { 411 deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...) 412 } else { 413 ctx.ModuleErrorf("Only aconfig_declarations and aconfig_declarations_group "+ 414 "module type is allowed for flags_packages property, but %s is neither "+ 415 "of these supported module types", 416 module.Name(), 417 ) 418 } 419 } 420 }) 421 // do not pass exclude_srcs directly when expanding srcFiles since exclude_srcs 422 // may contain filegroup or genrule. 423 srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs) 424 j.implicits = append(j.implicits, srcFiles...) 425 426 // Module can depend on a java_aconfig_library module using the ":module_name{.tag}" syntax. 427 // Find the corresponding aconfig_declarations module name for such case. 428 for _, src := range j.properties.Srcs { 429 if moduleName, tag := android.SrcIsModuleWithTag(src); moduleName != "" { 430 otherModule := android.GetModuleProxyFromPathDep(ctx, moduleName, tag) 431 if otherModule != nil { 432 if dep, ok := android.OtherModuleProvider(ctx, *otherModule, android.CodegenInfoProvider); ok { 433 deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...) 434 } 435 } 436 } 437 } 438 439 filterByPackage := func(srcs []android.Path, filterPackages []string) []android.Path { 440 if filterPackages == nil { 441 return srcs 442 } 443 filtered := []android.Path{} 444 for _, src := range srcs { 445 if src.Ext() != ".java" { 446 // Don't filter-out non-Java (=generated sources) by package names. This is not ideal, 447 // but otherwise metalava emits stub sources having references to the generated AIDL classes 448 // in filtered-out pacages (e.g. com.android.internal.*). 449 // TODO(b/141149570) We need to fix this by introducing default private constructors or 450 // fixing metalava to not emit constructors having references to unknown classes. 451 filtered = append(filtered, src) 452 continue 453 } 454 packageName := strings.ReplaceAll(filepath.Dir(src.Rel()), "/", ".") 455 if android.HasAnyPrefix(packageName, filterPackages) { 456 filtered = append(filtered, src) 457 } 458 } 459 return filtered 460 } 461 srcFiles = filterByPackage(srcFiles, j.properties.Filter_packages) 462 463 aidlFlags := j.collectAidlFlags(ctx, deps) 464 srcFiles = j.genSources(ctx, srcFiles, aidlFlags) 465 466 // srcs may depend on some genrule output. 467 j.srcJars = srcFiles.FilterByExt(".srcjar") 468 j.srcJars = append(j.srcJars, deps.srcJars...) 469 470 j.srcFiles = srcFiles.FilterOutByExt(".srcjar") 471 j.srcFiles = append(j.srcFiles, deps.srcs...) 472 473 if len(j.srcFiles) > 0 { 474 j.sourcepaths = android.PathsForModuleSrc(ctx, []string{"."}) 475 } 476 477 return deps 478} 479 480func (j *Javadoc) expandArgs(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { 481 var argFiles android.Paths 482 argFilesMap := map[string]string{} 483 argFileLabels := []string{} 484 485 for _, label := range j.properties.Arg_files { 486 var paths = android.PathsForModuleSrc(ctx, []string{label}) 487 if _, exists := argFilesMap[label]; !exists { 488 argFilesMap[label] = strings.Join(cmd.PathsForInputs(paths), " ") 489 argFileLabels = append(argFileLabels, label) 490 argFiles = append(argFiles, paths...) 491 } else { 492 ctx.ModuleErrorf("multiple arg_files for %q, %q and %q", 493 label, argFilesMap[label], paths) 494 } 495 } 496 497 var argsPropertyName string 498 flags := make([]string, 0) 499 if j.properties.Args != nil && j.properties.Flags != nil { 500 ctx.PropertyErrorf("args", "flags is set. Cannot set args") 501 } else if args := proptools.String(j.properties.Args); args != "" { 502 flags = append(flags, args) 503 argsPropertyName = "args" 504 } else { 505 flags = append(flags, j.properties.Flags...) 506 argsPropertyName = "flags" 507 } 508 509 for _, flag := range flags { 510 expanded, err := android.Expand(flag, func(name string) (string, error) { 511 if strings.HasPrefix(name, "location ") { 512 label := strings.TrimSpace(strings.TrimPrefix(name, "location ")) 513 if paths, ok := argFilesMap[label]; ok { 514 return paths, nil 515 } else { 516 return "", fmt.Errorf("unknown location label %q, expecting one of %q", 517 label, strings.Join(argFileLabels, ", ")) 518 } 519 } else if name == "genDir" { 520 return android.PathForModuleGen(ctx).String(), nil 521 } 522 return "", fmt.Errorf("unknown variable '$(%s)'", name) 523 }) 524 525 if err != nil { 526 ctx.PropertyErrorf(argsPropertyName, "%s", err.Error()) 527 } 528 cmd.Flag(expanded) 529 } 530 531 cmd.Implicits(argFiles) 532} 533 534func (j *Javadoc) DepsMutator(ctx android.BottomUpMutatorContext) { 535 j.addDeps(ctx) 536} 537 538func (j *Javadoc) GenerateAndroidBuildActions(ctx android.ModuleContext) { 539 deps := j.collectDeps(ctx) 540 541 j.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip") 542 543 outDir := android.PathForModuleOut(ctx, "out") 544 srcJarDir := android.PathForModuleOut(ctx, "srcjars") 545 546 j.stubsSrcJar = nil 547 548 rule := android.NewRuleBuilder(pctx, ctx) 549 550 rule.Command().Text("rm -rf").Text(outDir.String()) 551 rule.Command().Text("mkdir -p").Text(outDir.String()) 552 553 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, j.srcJars) 554 555 javaVersion := getJavaVersion(ctx, String(j.properties.Java_version), android.SdkContext(j)) 556 557 cmd := javadocSystemModulesCmd(ctx, rule, j.srcFiles, outDir, srcJarDir, srcJarList, 558 deps.systemModules, deps.classpath, j.sourcepaths) 559 560 cmd.FlagWithArg("-source ", javaVersion.String()). 561 Flag("-J-Xmx1024m"). 562 Flag("-XDignore.symbol.file"). 563 Flag("-Xdoclint:none") 564 565 j.expandArgs(ctx, cmd) 566 567 rule.Command(). 568 BuiltTool("soong_zip"). 569 Flag("-write_if_changed"). 570 Flag("-d"). 571 FlagWithOutput("-o ", j.docZip). 572 FlagWithArg("-C ", outDir.String()). 573 FlagWithArg("-D ", outDir.String()) 574 575 rule.Restat() 576 577 zipSyncCleanupCmd(rule, srcJarDir) 578 579 rule.Build("javadoc", "javadoc") 580 581 ctx.SetOutputFiles(android.Paths{j.docZip}, ".docs.zip") 582} 583 584// Droiddoc 585type Droiddoc struct { 586 Javadoc 587 588 properties DroiddocProperties 589} 590 591// droiddoc converts .java source files to documentation using doclava or dokka. 592func DroiddocFactory() android.Module { 593 module := &Droiddoc{} 594 595 module.AddProperties(&module.properties, 596 &module.Javadoc.properties) 597 598 InitDroiddocModule(module, android.HostAndDeviceSupported) 599 return module 600} 601 602// droiddoc_host converts .java source files to documentation using doclava or dokka. 603func DroiddocHostFactory() android.Module { 604 module := &Droiddoc{} 605 606 module.AddProperties(&module.properties, 607 &module.Javadoc.properties) 608 609 InitDroiddocModule(module, android.HostSupported) 610 return module 611} 612 613func (d *Droiddoc) DepsMutator(ctx android.BottomUpMutatorContext) { 614 d.Javadoc.addDeps(ctx) 615 616 if String(d.properties.Custom_template) != "" { 617 ctx.AddDependency(ctx.Module(), droiddocTemplateTag, String(d.properties.Custom_template)) 618 } 619} 620 621func (d *Droiddoc) doclavaDocsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, docletPath classpath) { 622 buildNumberFile := ctx.Config().BuildNumberFile(ctx) 623 // Droiddoc always gets "-source 1.8" because it doesn't support 1.9 sources. For modules with 1.9 624 // sources, droiddoc will get sources produced by metalava which will have already stripped out the 625 // 1.9 language features. 626 cmd.FlagWithArg("-source ", getStubsJavaVersion().String()). 627 Flag("-J-Xmx1600m"). 628 Flag("-J-XX:-OmitStackTraceInFastThrow"). 629 Flag("-XDignore.symbol.file"). 630 Flag("--ignore-source-errors"). 631 FlagWithArg("-doclet ", "com.google.doclava.Doclava"). 632 FlagWithInputList("-docletpath ", docletPath.Paths(), ":"). 633 FlagWithArg("-Xmaxerrs ", "10"). 634 FlagWithArg("-Xmaxwarns ", "10"). 635 Flag("-J--add-exports=jdk.javadoc/jdk.javadoc.internal.doclets.formats.html=ALL-UNNAMED"). 636 Flag("-J--add-exports=jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED"). 637 Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED"). 638 Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED"). 639 Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED"). 640 Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED"). 641 Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED"). 642 FlagWithArg("-hdf page.build ", ctx.Config().BuildId()+"-$(cat "+buildNumberFile.String()+")").OrderOnly(buildNumberFile). 643 FlagWithArg("-hdf page.now ", `"$(date -d @$(cat `+ctx.Config().Getenv("BUILD_DATETIME_FILE")+`) "+%d %b %Y %k:%M")" `) 644 645 if String(d.properties.Custom_template) == "" { 646 // TODO: This is almost always droiddoc-templates-sdk 647 ctx.PropertyErrorf("custom_template", "must specify a template") 648 } 649 650 ctx.VisitDirectDepsWithTag(droiddocTemplateTag, func(m android.Module) { 651 if t, ok := m.(*ExportedDroiddocDir); ok { 652 cmd.FlagWithArg("-templatedir ", t.dir.String()).Implicits(t.deps) 653 } else { 654 ctx.PropertyErrorf("custom_template", "module %q is not a droiddoc_exported_dir", ctx.OtherModuleName(m)) 655 } 656 }) 657 658 if len(d.properties.Html_dirs) > 0 { 659 htmlDir := android.PathForModuleSrc(ctx, d.properties.Html_dirs[0]) 660 cmd.FlagWithArg("-htmldir ", htmlDir.String()). 661 Implicits(android.PathsForModuleSrc(ctx, []string{filepath.Join(d.properties.Html_dirs[0], "**/*")})) 662 } 663 664 if len(d.properties.Html_dirs) > 1 { 665 htmlDir2 := android.PathForModuleSrc(ctx, d.properties.Html_dirs[1]) 666 cmd.FlagWithArg("-htmldir2 ", htmlDir2.String()). 667 Implicits(android.PathsForModuleSrc(ctx, []string{filepath.Join(d.properties.Html_dirs[1], "**/*")})) 668 } 669 670 if len(d.properties.Html_dirs) > 2 { 671 ctx.PropertyErrorf("html_dirs", "Droiddoc only supports up to 2 html dirs") 672 } 673 674 knownTags := android.PathsForModuleSrc(ctx, d.properties.Knowntags) 675 cmd.FlagForEachInput("-knowntags ", knownTags) 676 677 cmd.FlagForEachArg("-hdf ", d.properties.Hdf) 678 679 if String(d.properties.Proofread_file) != "" { 680 proofreadFile := android.PathForModuleOut(ctx, String(d.properties.Proofread_file)) 681 cmd.FlagWithOutput("-proofread ", proofreadFile) 682 } 683 684 if String(d.properties.Todo_file) != "" { 685 // tricky part: 686 // we should not compute full path for todo_file through PathForModuleOut(). 687 // the non-standard doclet will get the full path relative to "-o". 688 cmd.FlagWithArg("-todo ", String(d.properties.Todo_file)). 689 ImplicitOutput(android.PathForModuleOut(ctx, String(d.properties.Todo_file))) 690 } 691 692 if String(d.properties.Lint_baseline) != "" { 693 cmd.FlagWithInput("-lintbaseline ", android.PathForModuleSrc(ctx, String(d.properties.Lint_baseline))) 694 } 695 696 if String(d.properties.Resourcesdir) != "" { 697 // TODO: should we add files under resourcesDir to the implicits? It seems that 698 // resourcesDir is one sub dir of htmlDir 699 resourcesDir := android.PathForModuleSrc(ctx, String(d.properties.Resourcesdir)) 700 cmd.FlagWithArg("-resourcesdir ", resourcesDir.String()) 701 } 702 703 if String(d.properties.Resourcesoutdir) != "" { 704 // TODO: it seems -resourceoutdir reference/android/images/ didn't get generated anywhere. 705 cmd.FlagWithArg("-resourcesoutdir ", String(d.properties.Resourcesoutdir)) 706 } 707} 708 709func (d *Droiddoc) postDoclavaCmds(ctx android.ModuleContext, rule *android.RuleBuilder) { 710 if String(d.properties.Static_doc_index_redirect) != "" { 711 staticDocIndexRedirect := android.PathForModuleSrc(ctx, String(d.properties.Static_doc_index_redirect)) 712 rule.Command().Text("cp"). 713 Input(staticDocIndexRedirect). 714 Output(android.PathForModuleOut(ctx, "out", "index.html")) 715 } 716 717 if String(d.properties.Static_doc_properties) != "" { 718 staticDocProperties := android.PathForModuleSrc(ctx, String(d.properties.Static_doc_properties)) 719 rule.Command().Text("cp"). 720 Input(staticDocProperties). 721 Output(android.PathForModuleOut(ctx, "out", "source.properties")) 722 } 723} 724 725func javadocCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths, 726 outDir, srcJarDir, srcJarList android.Path, sourcepaths android.Paths) *android.RuleBuilderCommand { 727 728 cmd := rule.Command(). 729 BuiltTool("soong_javac_wrapper").Tool(config.JavadocCmd(ctx)). 730 Flag(config.JavacVmFlags). 731 FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "javadoc.rsp"), srcs). 732 FlagWithInput("@", srcJarList) 733 734 // TODO(ccross): Remove this if- statement once we finish migration for all Doclava 735 // based stubs generation. 736 // In the future, all the docs generation depends on Metalava stubs (droidstubs) srcjar 737 // dir. We need add the srcjar dir to -sourcepath arg, so that Javadoc can figure out 738 // the correct package name base path. 739 if len(sourcepaths) > 0 { 740 cmd.FlagWithList("-sourcepath ", sourcepaths.Strings(), ":") 741 } else { 742 cmd.FlagWithArg("-sourcepath ", srcJarDir.String()) 743 } 744 745 cmd.FlagWithArg("-d ", outDir.String()). 746 Flag("-quiet") 747 748 return cmd 749} 750 751func javadocSystemModulesCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths, 752 outDir, srcJarDir, srcJarList android.Path, systemModules *systemModules, 753 classpath classpath, sourcepaths android.Paths) *android.RuleBuilderCommand { 754 755 cmd := javadocCmd(ctx, rule, srcs, outDir, srcJarDir, srcJarList, sourcepaths) 756 757 flag, deps := systemModules.FormJavaSystemModulesPath(ctx.Device()) 758 cmd.Flag(flag).Implicits(deps) 759 760 cmd.FlagWithArg("--patch-module ", "java.base=.") 761 762 if len(classpath) > 0 { 763 cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":") 764 } 765 766 return cmd 767} 768 769func javadocBootclasspathCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths, 770 outDir, srcJarDir, srcJarList android.Path, bootclasspath, classpath classpath, 771 sourcepaths android.Paths) *android.RuleBuilderCommand { 772 773 cmd := javadocCmd(ctx, rule, srcs, outDir, srcJarDir, srcJarList, sourcepaths) 774 775 if len(bootclasspath) == 0 && ctx.Device() { 776 // explicitly specify -bootclasspath "" if the bootclasspath is empty to 777 // ensure java does not fall back to the default bootclasspath. 778 cmd.FlagWithArg("-bootclasspath ", `""`) 779 } else if len(bootclasspath) > 0 { 780 cmd.FlagWithInputList("-bootclasspath ", bootclasspath.Paths(), ":") 781 } 782 783 if len(classpath) > 0 { 784 cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":") 785 } 786 787 return cmd 788} 789 790func dokkaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, 791 outDir, srcJarDir android.Path, bootclasspath, classpath classpath) *android.RuleBuilderCommand { 792 793 // Dokka doesn't support bootClasspath, so combine these two classpath vars for Dokka. 794 dokkaClasspath := append(bootclasspath.Paths(), classpath.Paths()...) 795 796 return rule.Command(). 797 BuiltTool("dokka"). 798 Flag(config.JavacVmFlags). 799 Flag("-J--add-opens=java.base/java.lang=ALL-UNNAMED"). 800 Flag(srcJarDir.String()). 801 FlagWithInputList("-classpath ", dokkaClasspath, ":"). 802 FlagWithArg("-format ", "dac"). 803 FlagWithArg("-dacRoot ", "/reference/kotlin"). 804 FlagWithArg("-output ", outDir.String()) 805} 806 807func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) { 808 deps := d.Javadoc.collectDeps(ctx) 809 810 d.Javadoc.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip") 811 812 jsilver := ctx.Config().HostJavaToolPath(ctx, "jsilver.jar") 813 doclava := ctx.Config().HostJavaToolPath(ctx, "doclava.jar") 814 815 outDir := android.PathForModuleOut(ctx, "out") 816 srcJarDir := android.PathForModuleOut(ctx, "srcjars") 817 818 rule := android.NewRuleBuilder(pctx, ctx) 819 820 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars) 821 822 var cmd *android.RuleBuilderCommand 823 if Bool(d.properties.Dokka_enabled) { 824 cmd = dokkaCmd(ctx, rule, outDir, srcJarDir, deps.bootClasspath, deps.classpath) 825 } else { 826 cmd = javadocBootclasspathCmd(ctx, rule, d.Javadoc.srcFiles, outDir, srcJarDir, srcJarList, 827 deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths) 828 } 829 830 d.expandArgs(ctx, cmd) 831 832 if d.properties.Compat_config != nil { 833 compatConfig := android.PathForModuleSrc(ctx, String(d.properties.Compat_config)) 834 cmd.FlagWithInput("-compatconfig ", compatConfig) 835 } 836 837 var desc string 838 if Bool(d.properties.Dokka_enabled) { 839 desc = "dokka" 840 } else { 841 d.doclavaDocsFlags(ctx, cmd, classpath{jsilver, doclava}) 842 843 for _, o := range d.Javadoc.properties.Out { 844 cmd.ImplicitOutput(android.PathForModuleGen(ctx, o)) 845 } 846 847 d.postDoclavaCmds(ctx, rule) 848 desc = "doclava" 849 } 850 851 rule.Command(). 852 BuiltTool("soong_zip"). 853 Flag("-write_if_changed"). 854 Flag("-d"). 855 FlagWithOutput("-o ", d.docZip). 856 FlagWithArg("-C ", outDir.String()). 857 FlagWithArg("-D ", outDir.String()) 858 859 rule.Restat() 860 861 zipSyncCleanupCmd(rule, srcJarDir) 862 863 rule.Build("javadoc", desc) 864 865 ctx.SetOutputFiles(android.Paths{d.Javadoc.docZip}, "") 866 ctx.SetOutputFiles(android.Paths{d.Javadoc.docZip}, ".docs.zip") 867} 868 869// Exported Droiddoc Directory 870var droiddocTemplateTag = dependencyTag{name: "droiddoc-template"} 871 872type ExportedDroiddocDirProperties struct { 873 // path to the directory containing Droiddoc related files. 874 Path *string 875} 876 877type ExportedDroiddocDir struct { 878 android.ModuleBase 879 880 properties ExportedDroiddocDirProperties 881 882 deps android.Paths 883 dir android.Path 884} 885 886// droiddoc_exported_dir exports a directory of html templates or nullability annotations for use by doclava. 887func ExportedDroiddocDirFactory() android.Module { 888 module := &ExportedDroiddocDir{} 889 module.AddProperties(&module.properties) 890 android.InitAndroidModule(module) 891 return module 892} 893 894func (d *ExportedDroiddocDir) DepsMutator(android.BottomUpMutatorContext) {} 895 896func (d *ExportedDroiddocDir) GenerateAndroidBuildActions(ctx android.ModuleContext) { 897 path := String(d.properties.Path) 898 d.dir = android.PathForModuleSrc(ctx, path) 899 d.deps = android.PathsForModuleSrc(ctx, []string{filepath.Join(path, "**/*")}) 900} 901 902// Defaults 903type DocDefaults struct { 904 android.ModuleBase 905 android.DefaultsModuleBase 906} 907 908func DocDefaultsFactory() android.Module { 909 module := &DocDefaults{} 910 911 module.AddProperties( 912 &JavadocProperties{}, 913 &DroiddocProperties{}, 914 ) 915 916 android.InitDefaultsModule(module) 917 918 return module 919} 920 921func zipSyncCmd(ctx android.ModuleContext, rule *android.RuleBuilder, 922 srcJarDir android.ModuleOutPath, srcJars android.Paths) android.OutputPath { 923 924 cmd := rule.Command() 925 cmd.Text("rm -rf").Text(cmd.PathForOutput(srcJarDir)) 926 cmd = rule.Command() 927 cmd.Text("mkdir -p").Text(cmd.PathForOutput(srcJarDir)) 928 srcJarList := srcJarDir.Join(ctx, "list") 929 930 rule.Temporary(srcJarList) 931 932 cmd = rule.Command() 933 cmd.BuiltTool("zipsync"). 934 FlagWithArg("-d ", cmd.PathForOutput(srcJarDir)). 935 FlagWithOutput("-l ", srcJarList). 936 FlagWithArg("-f ", `"*.java"`). 937 Inputs(srcJars) 938 939 return srcJarList 940} 941 942func zipSyncCleanupCmd(rule *android.RuleBuilder, srcJarDir android.ModuleOutPath) { 943 rule.Command().Text("rm -rf").Text(srcJarDir.String()) 944} 945