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