Home | History | Annotate | Download | only in java
      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 
     15 package java
     16 
     17 import (
     18 	"android/soong/android"
     19 	"android/soong/java/config"
     20 	"fmt"
     21 	"strings"
     22 
     23 	"github.com/google/blueprint"
     24 )
     25 
     26 var (
     27 	javadoc = pctx.AndroidStaticRule("javadoc",
     28 		blueprint.RuleParams{
     29 			Command: `rm -rf "$outDir" "$srcJarDir" "$stubsDir" && mkdir -p "$outDir" "$srcJarDir" "$stubsDir" && ` +
     30 				`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
     31 				`${config.JavadocCmd} -encoding UTF-8 @$out.rsp @$srcJarDir/list ` +
     32 				`$opts $bootclasspathArgs $classpathArgs -sourcepath $sourcepath ` +
     33 				`-d $outDir -quiet  && ` +
     34 				`${config.SoongZipCmd} -write_if_changed -d -o $docZip -C $outDir -D $outDir && ` +
     35 				`${config.SoongZipCmd} -write_if_changed -jar -o $out -C $stubsDir -D $stubsDir`,
     36 			CommandDeps: []string{
     37 				"${config.ZipSyncCmd}",
     38 				"${config.JavadocCmd}",
     39 				"${config.SoongZipCmd}",
     40 				"$JsilverJar",
     41 				"$DoclavaJar",
     42 			},
     43 			Rspfile:        "$out.rsp",
     44 			RspfileContent: "$in",
     45 			Restat:         true,
     46 		},
     47 		"outDir", "srcJarDir", "stubsDir", "srcJars", "opts",
     48 		"bootclasspathArgs", "classpathArgs", "sourcepath", "docZip", "JsilverJar", "DoclavaJar")
     49 )
     50 
     51 func init() {
     52 	android.RegisterModuleType("droiddoc", DroiddocFactory)
     53 	android.RegisterModuleType("droiddoc_host", DroiddocHostFactory)
     54 	android.RegisterModuleType("droiddoc_template", DroiddocTemplateFactory)
     55 	android.RegisterModuleType("javadoc", JavadocFactory)
     56 	android.RegisterModuleType("javadoc_host", JavadocHostFactory)
     57 }
     58 
     59 type JavadocProperties 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 directories rooted at the Android.bp file that will
     65 	// be added to the search paths for finding source files when passing package names.
     66 	Local_sourcepaths []string `android:"arch_variant"`
     67 
     68 	// list of source files that should not be used to build the Java module.
     69 	// This is most useful in the arch/multilib variants to remove non-common files
     70 	// filegroup or genrule can be included within this property.
     71 	Exclude_srcs []string `android:"arch_variant"`
     72 
     73 	// list of of java libraries that will be in the classpath.
     74 	Libs []string `android:"arch_variant"`
     75 
     76 	// If set to false, don't allow this module(-docs.zip) to be exported. Defaults to true.
     77 	Installable *bool `android:"arch_variant"`
     78 
     79 	// if not blank, set to the version of the sdk to compile against
     80 	Sdk_version *string `android:"arch_variant"`
     81 }
     82 
     83 type DroiddocProperties struct {
     84 	// directory relative to top of the source tree that contains doc templates files.
     85 	Custom_template *string `android:"arch_variant"`
     86 
     87 	// directories relative to top of the source tree which contains html/jd files.
     88 	Html_dirs []string `android:"arch_variant"`
     89 
     90 	// set a value in the Clearsilver hdf namespace.
     91 	Hdf []string `android:"arch_variant"`
     92 
     93 	// proofread file contains all of the text content of the javadocs concatenated into one file,
     94 	// suitable for spell-checking and other goodness.
     95 	Proofread_file *string `android:"arch_variant"`
     96 
     97 	// a todo file lists the program elements that are missing documentation.
     98 	// At some point, this might be improved to show more warnings.
     99 	Todo_file *string `android:"arch_variant"`
    100 
    101 	// local files that are used within user customized droiddoc options.
    102 	Arg_files []string `android:"arch_variant"`
    103 
    104 	// user customized droiddoc args.
    105 	// Available variables for substitution:
    106 	//
    107 	//  $(location <label>): the path to the arg_files with name <label>
    108 	Args *string `android:"arch_variant"`
    109 
    110 	// names of the output files used in args that will be generated
    111 	Out []string `android:"arch_variant"`
    112 
    113 	// a list of files under current module source dir which contains known tags in Java sources.
    114 	// filegroup or genrule can be included within this property.
    115 	Knowntags []string `android:"arch_variant"`
    116 }
    117 
    118 type Javadoc struct {
    119 	android.ModuleBase
    120 	android.DefaultableModuleBase
    121 
    122 	properties JavadocProperties
    123 
    124 	srcJars     android.Paths
    125 	srcFiles    android.Paths
    126 	sourcepaths android.Paths
    127 
    128 	docZip   android.WritablePath
    129 	stubsJar android.WritablePath
    130 }
    131 
    132 type Droiddoc struct {
    133 	Javadoc
    134 
    135 	properties DroiddocProperties
    136 }
    137 
    138 func InitDroiddocModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
    139 	android.InitAndroidArchModule(module, hod, android.MultilibCommon)
    140 	android.InitDefaultableModule(module)
    141 }
    142 
    143 func JavadocFactory() android.Module {
    144 	module := &Javadoc{}
    145 
    146 	module.AddProperties(&module.properties)
    147 
    148 	InitDroiddocModule(module, android.HostAndDeviceSupported)
    149 	return module
    150 }
    151 
    152 func JavadocHostFactory() android.Module {
    153 	module := &Javadoc{}
    154 
    155 	module.AddProperties(&module.properties)
    156 
    157 	InitDroiddocModule(module, android.HostSupported)
    158 	return module
    159 }
    160 
    161 func DroiddocFactory() android.Module {
    162 	module := &Droiddoc{}
    163 
    164 	module.AddProperties(&module.properties,
    165 		&module.Javadoc.properties)
    166 
    167 	InitDroiddocModule(module, android.HostAndDeviceSupported)
    168 	return module
    169 }
    170 
    171 func DroiddocHostFactory() android.Module {
    172 	module := &Droiddoc{}
    173 
    174 	module.AddProperties(&module.properties,
    175 		&module.Javadoc.properties)
    176 
    177 	InitDroiddocModule(module, android.HostSupported)
    178 	return module
    179 }
    180 
    181 func (j *Javadoc) addDeps(ctx android.BottomUpMutatorContext) {
    182 	if ctx.Device() {
    183 		sdkDep := decodeSdkDep(ctx, String(j.properties.Sdk_version))
    184 		if sdkDep.useDefaultLibs {
    185 			ctx.AddDependency(ctx.Module(), bootClasspathTag, config.DefaultBootclasspathLibraries...)
    186 			ctx.AddDependency(ctx.Module(), libTag, []string{"ext", "framework"}...)
    187 		} else if sdkDep.useModule {
    188 			ctx.AddDependency(ctx.Module(), bootClasspathTag, sdkDep.module)
    189 		}
    190 	}
    191 
    192 	ctx.AddDependency(ctx.Module(), libTag, j.properties.Libs...)
    193 
    194 	android.ExtractSourcesDeps(ctx, j.properties.Srcs)
    195 
    196 	// exclude_srcs may contain filegroup or genrule.
    197 	android.ExtractSourcesDeps(ctx, j.properties.Exclude_srcs)
    198 }
    199 
    200 func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps {
    201 	var deps deps
    202 
    203 	sdkDep := decodeSdkDep(ctx, String(j.properties.Sdk_version))
    204 	if sdkDep.invalidVersion {
    205 		ctx.AddMissingDependencies([]string{sdkDep.module})
    206 	} else if sdkDep.useFiles {
    207 		deps.bootClasspath = append(deps.bootClasspath, sdkDep.jar)
    208 	}
    209 
    210 	ctx.VisitDirectDeps(func(module android.Module) {
    211 		otherName := ctx.OtherModuleName(module)
    212 		tag := ctx.OtherModuleDependencyTag(module)
    213 
    214 		switch dep := module.(type) {
    215 		case Dependency:
    216 			switch tag {
    217 			case bootClasspathTag:
    218 				deps.bootClasspath = append(deps.bootClasspath, dep.ImplementationJars()...)
    219 			case libTag:
    220 				deps.classpath = append(deps.classpath, dep.ImplementationJars()...)
    221 			default:
    222 				panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
    223 			}
    224 		case android.SourceFileProducer:
    225 			switch tag {
    226 			case libTag:
    227 				checkProducesJars(ctx, dep)
    228 				deps.classpath = append(deps.classpath, dep.Srcs()...)
    229 			case android.DefaultsDepTag, android.SourceDepTag:
    230 				// Nothing to do
    231 			default:
    232 				ctx.ModuleErrorf("dependency on genrule %q may only be in srcs, libs", otherName)
    233 			}
    234 		default:
    235 			switch tag {
    236 			case android.DefaultsDepTag, android.SourceDepTag, droiddocTemplateTag:
    237 				// Nothing to do
    238 			default:
    239 				ctx.ModuleErrorf("depends on non-java module %q", otherName)
    240 			}
    241 		}
    242 	})
    243 	// do not pass exclude_srcs directly when expanding srcFiles since exclude_srcs
    244 	// may contain filegroup or genrule.
    245 	srcFiles := ctx.ExpandSources(j.properties.Srcs, j.properties.Exclude_srcs)
    246 
    247 	// srcs may depend on some genrule output.
    248 	j.srcJars = srcFiles.FilterByExt(".srcjar")
    249 	j.srcFiles = srcFiles.FilterOutByExt(".srcjar")
    250 
    251 	j.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip")
    252 	j.stubsJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
    253 
    254 	if j.properties.Local_sourcepaths == nil {
    255 		j.properties.Local_sourcepaths = append(j.properties.Local_sourcepaths, ".")
    256 	}
    257 	j.sourcepaths = android.PathsForModuleSrc(ctx, j.properties.Local_sourcepaths)
    258 	j.sourcepaths = append(j.sourcepaths, deps.bootClasspath...)
    259 	j.sourcepaths = append(j.sourcepaths, deps.classpath...)
    260 
    261 	return deps
    262 }
    263 
    264 func (j *Javadoc) DepsMutator(ctx android.BottomUpMutatorContext) {
    265 	j.addDeps(ctx)
    266 }
    267 
    268 func (j *Javadoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
    269 	deps := j.collectDeps(ctx)
    270 
    271 	var implicits android.Paths
    272 	implicits = append(implicits, deps.bootClasspath...)
    273 	implicits = append(implicits, deps.classpath...)
    274 
    275 	var bootClasspathArgs, classpathArgs string
    276 	if ctx.Config().UseOpenJDK9() {
    277 		if len(deps.bootClasspath) > 0 {
    278 			// For OpenJDK 9 we use --patch-module to define the core libraries code.
    279 			// TODO(tobiast): Reorganize this when adding proper support for OpenJDK 9
    280 			// modules. Here we treat all code in core libraries as being in java.base
    281 			// to work around the OpenJDK 9 module system. http://b/62049770
    282 			bootClasspathArgs = "--patch-module=java.base=" + strings.Join(deps.bootClasspath.Strings(), ":")
    283 		}
    284 	} else {
    285 		if len(deps.bootClasspath.Strings()) > 0 {
    286 			// For OpenJDK 8 we can use -bootclasspath to define the core libraries code.
    287 			bootClasspathArgs = deps.bootClasspath.FormJavaClassPath("-bootclasspath")
    288 		}
    289 	}
    290 	if len(deps.classpath.Strings()) > 0 {
    291 		classpathArgs = "-classpath " + strings.Join(deps.classpath.Strings(), ":")
    292 	}
    293 
    294 	implicits = append(implicits, j.srcJars...)
    295 
    296 	opts := "-J-Xmx1024m -XDignore.symbol.file -Xdoclint:none"
    297 
    298 	ctx.Build(pctx, android.BuildParams{
    299 		Rule:           javadoc,
    300 		Description:    "Javadoc",
    301 		Output:         j.stubsJar,
    302 		ImplicitOutput: j.docZip,
    303 		Inputs:         j.srcFiles,
    304 		Implicits:      implicits,
    305 		Args: map[string]string{
    306 			"outDir":            android.PathForModuleOut(ctx, "docs", "out").String(),
    307 			"srcJarDir":         android.PathForModuleOut(ctx, "docs", "srcjars").String(),
    308 			"stubsDir":          android.PathForModuleOut(ctx, "docs", "stubsDir").String(),
    309 			"srcJars":           strings.Join(j.srcJars.Strings(), " "),
    310 			"opts":              opts,
    311 			"bootClasspathArgs": bootClasspathArgs,
    312 			"classpathArgs":     classpathArgs,
    313 			"sourcepath":        strings.Join(j.sourcepaths.Strings(), ":"),
    314 			"docZip":            j.docZip.String(),
    315 		},
    316 	})
    317 }
    318 
    319 func (d *Droiddoc) DepsMutator(ctx android.BottomUpMutatorContext) {
    320 	d.Javadoc.addDeps(ctx)
    321 
    322 	if String(d.properties.Custom_template) == "" {
    323 		// TODO: This is almost always droiddoc-templates-sdk
    324 		ctx.PropertyErrorf("custom_template", "must specify a template")
    325 	} else {
    326 		ctx.AddDependency(ctx.Module(), droiddocTemplateTag, String(d.properties.Custom_template))
    327 	}
    328 
    329 	// extra_arg_files may contains filegroup or genrule.
    330 	android.ExtractSourcesDeps(ctx, d.properties.Arg_files)
    331 
    332 	// knowntags may contain filegroup or genrule.
    333 	android.ExtractSourcesDeps(ctx, d.properties.Knowntags)
    334 }
    335 
    336 func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
    337 	deps := d.Javadoc.collectDeps(ctx)
    338 
    339 	var implicits android.Paths
    340 	implicits = append(implicits, deps.bootClasspath...)
    341 	implicits = append(implicits, deps.classpath...)
    342 
    343 	argFiles := ctx.ExpandSources(d.properties.Arg_files, nil)
    344 	argFilesMap := map[string]android.Path{}
    345 
    346 	for _, f := range argFiles {
    347 		implicits = append(implicits, f)
    348 		if _, exists := argFilesMap[f.Rel()]; !exists {
    349 			argFilesMap[f.Rel()] = f
    350 		} else {
    351 			ctx.ModuleErrorf("multiple arg_files for %q, %q and %q",
    352 				f, argFilesMap[f.Rel()], f.Rel())
    353 		}
    354 	}
    355 
    356 	args, err := android.Expand(String(d.properties.Args), func(name string) (string, error) {
    357 		if strings.HasPrefix(name, "location ") {
    358 			label := strings.TrimSpace(strings.TrimPrefix(name, "location "))
    359 			if f, ok := argFilesMap[label]; ok {
    360 				return f.String(), nil
    361 			} else {
    362 				return "", fmt.Errorf("unknown location label %q", label)
    363 			}
    364 		} else if name == "genDir" {
    365 			return android.PathForModuleGen(ctx).String(), nil
    366 		}
    367 		return "", fmt.Errorf("unknown variable '$(%s)'", name)
    368 	})
    369 
    370 	if err != nil {
    371 		ctx.PropertyErrorf("extra_args", "%s", err.Error())
    372 		return
    373 	}
    374 
    375 	var bootClasspathArgs, classpathArgs string
    376 	if len(deps.bootClasspath.Strings()) > 0 {
    377 		bootClasspathArgs = "-bootclasspath " + strings.Join(deps.bootClasspath.Strings(), ":")
    378 	}
    379 	if len(deps.classpath.Strings()) > 0 {
    380 		classpathArgs = "-classpath " + strings.Join(deps.classpath.Strings(), ":")
    381 	}
    382 
    383 	var templateDir string
    384 	ctx.VisitDirectDepsWithTag(droiddocTemplateTag, func(m android.Module) {
    385 		if t, ok := m.(*DroiddocTemplate); ok {
    386 			implicits = append(implicits, t.deps...)
    387 			templateDir = t.dir.String()
    388 		} else {
    389 			ctx.PropertyErrorf("custom_template", "module %q is not a droiddoc_template", ctx.OtherModuleName(m))
    390 		}
    391 	})
    392 
    393 	var htmlDirArgs string
    394 	if len(d.properties.Html_dirs) > 0 {
    395 		htmlDir := android.PathForModuleSrc(ctx, d.properties.Html_dirs[0])
    396 		implicits = append(implicits, ctx.Glob(htmlDir.Join(ctx, "**/*").String(), nil)...)
    397 		htmlDirArgs = "-htmldir " + htmlDir.String()
    398 	}
    399 
    400 	var htmlDir2Args string
    401 	if len(d.properties.Html_dirs) > 1 {
    402 		htmlDir2 := android.PathForModuleSrc(ctx, d.properties.Html_dirs[1])
    403 		implicits = append(implicits, ctx.Glob(htmlDir2.Join(ctx, "**/*").String(), nil)...)
    404 		htmlDir2Args = "-htmldir2 " + htmlDir2.String()
    405 	}
    406 
    407 	if len(d.properties.Html_dirs) > 2 {
    408 		ctx.PropertyErrorf("html_dirs", "Droiddoc only supports up to 2 html dirs")
    409 	}
    410 
    411 	knownTags := ctx.ExpandSources(d.properties.Knowntags, nil)
    412 	implicits = append(implicits, knownTags...)
    413 
    414 	for _, kt := range knownTags {
    415 		args = args + " -knowntags " + kt.String()
    416 	}
    417 	for _, hdf := range d.properties.Hdf {
    418 		args = args + " -hdf " + hdf
    419 	}
    420 
    421 	if String(d.properties.Proofread_file) != "" {
    422 		proofreadFile := android.PathForModuleOut(ctx, String(d.properties.Proofread_file))
    423 		args = args + " -proofread " + proofreadFile.String()
    424 	}
    425 	if String(d.properties.Todo_file) != "" {
    426 		// tricky part:
    427 		// we should not compute full path for todo_file through PathForModuleOut().
    428 		// the non-standard doclet will get the full path relative to "-o".
    429 		args = args + " -todo " + String(d.properties.Todo_file)
    430 	}
    431 
    432 	implicits = append(implicits, d.Javadoc.srcJars...)
    433 
    434 	opts := "-source 1.8 -J-Xmx1600m -J-XX:-OmitStackTraceInFastThrow -XDignore.symbol.file " +
    435 		"-doclet com.google.doclava.Doclava -docletpath ${config.JsilverJar}:${config.DoclavaJar} " +
    436 		"-templatedir " + templateDir + " " + htmlDirArgs + " " + htmlDir2Args + " " +
    437 		"-hdf page.build " + ctx.Config().BuildId() + "-" + ctx.Config().BuildNumberFromFile() + " " +
    438 		"-hdf page.now " + `"$$(date -d @$$(cat ` + ctx.Config().Getenv("BUILD_DATETIME_FILE") + `) "+%d %b %Y %k:%M")"` + " " +
    439 		args + " -stubs " + android.PathForModuleOut(ctx, "docs", "stubsDir").String()
    440 
    441 	var implicitOutputs android.WritablePaths
    442 	implicitOutputs = append(implicitOutputs, d.Javadoc.docZip)
    443 	for _, o := range d.properties.Out {
    444 		implicitOutputs = append(implicitOutputs, android.PathForModuleGen(ctx, o))
    445 	}
    446 
    447 	ctx.Build(pctx, android.BuildParams{
    448 		Rule:            javadoc,
    449 		Description:     "Droiddoc",
    450 		Output:          d.Javadoc.stubsJar,
    451 		Inputs:          d.Javadoc.srcFiles,
    452 		Implicits:       implicits,
    453 		ImplicitOutputs: implicitOutputs,
    454 		Args: map[string]string{
    455 			"outDir":            android.PathForModuleOut(ctx, "docs", "out").String(),
    456 			"srcJarDir":         android.PathForModuleOut(ctx, "docs", "srcjars").String(),
    457 			"stubsDir":          android.PathForModuleOut(ctx, "docs", "stubsDir").String(),
    458 			"srcJars":           strings.Join(d.Javadoc.srcJars.Strings(), " "),
    459 			"opts":              opts,
    460 			"bootclasspathArgs": bootClasspathArgs,
    461 			"classpathArgs":     classpathArgs,
    462 			"sourcepath":        strings.Join(d.Javadoc.sourcepaths.Strings(), ":"),
    463 			"docZip":            d.Javadoc.docZip.String(),
    464 			"JsilverJar":        "${config.JsilverJar}",
    465 			"DoclavaJar":        "${config.DoclavaJar}",
    466 		},
    467 	})
    468 }
    469 
    470 var droiddocTemplateTag = dependencyTag{name: "droiddoc-template"}
    471 
    472 type DroiddocTemplateProperties struct {
    473 	// path to the directory containing the droiddoc templates.
    474 	Path *string
    475 }
    476 
    477 type DroiddocTemplate struct {
    478 	android.ModuleBase
    479 
    480 	properties DroiddocTemplateProperties
    481 
    482 	deps android.Paths
    483 	dir  android.Path
    484 }
    485 
    486 func DroiddocTemplateFactory() android.Module {
    487 	module := &DroiddocTemplate{}
    488 	module.AddProperties(&module.properties)
    489 	android.InitAndroidModule(module)
    490 	return module
    491 }
    492 
    493 func (d *DroiddocTemplate) DepsMutator(android.BottomUpMutatorContext) {}
    494 
    495 func (d *DroiddocTemplate) GenerateAndroidBuildActions(ctx android.ModuleContext) {
    496 	path := android.PathForModuleSrc(ctx, String(d.properties.Path))
    497 	d.dir = path
    498 	d.deps = ctx.Glob(path.Join(ctx, "**/*").String(), nil)
    499 }
    500