Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 86d2d55a authored by Nan Zhang's avatar Nan Zhang
Browse files

Support Dokka in Soong.

Metalava is supposed to treat all the args after
"--generate-documentation" as either Javadoc or Dokka commands, and it starts
 seperate process to invoke javadoc or java -jar dokka...

Dokka doesn't support --bootclasspath in its args, so treat all the
bootclasspath as classpath.

Also continue to refactor code to seperate Dokka runs from Javadoc or
Metalava.

Test: m -j metalava-dokka-core-docs
Bug: b/72394196
Change-Id: I0f0f3dd80cb2dbb53f19da8fa11ae0b1d92ac5d7
parent 1a1f7f24
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -121,6 +121,7 @@ func init() {
	pctx.HostJavaToolVariable("JsilverJar", "jsilver.jar")
	pctx.HostJavaToolVariable("DoclavaJar", "doclava.jar")
	pctx.HostJavaToolVariable("MetalavaJar", "metalava.jar")
	pctx.HostJavaToolVariable("DokkaJar", "dokka.jar")

	pctx.HostBinToolVariable("SoongJavacWrapper", "soong_javac_wrapper")

+162 −120
Original line number Diff line number Diff line
@@ -265,6 +265,10 @@ type DroiddocProperties struct {

	// a list of top-level directories containing files to merge annotations from.
	Metalava_merge_annotations_dirs []string

	// if set to true, generate docs through Dokka instead of Doclava. Valid only when
	// metalava_enabled is set to true.
	Dokka_enabled *bool
}

//
@@ -274,17 +278,18 @@ type droiddocBuilderFlags struct {
	args               string
	bootClasspathArgs  string
	classpathArgs      string
	dokkaClasspathArgs string
	aidlFlags          string

	doclavaDocsFlags  string
	doclavaStubsFlags string
	doclavaDocsFlags  string
	postDoclavaCmds   string

	metalavaAnnotationsFlags string
	metalavaDocsFlags        string
	metalavaStubsFlags       string
	metalavaAnnotationsFlags string
	metalavaJavadocFlags     string

	dokkaFlags string
	metalavaDokkaFlags string
}

func InitDroiddocModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
@@ -720,6 +725,11 @@ func (d *Droiddoc) initBuilderFlags(ctx android.ModuleContext, implicits *androi
		flags.bootClasspathArgs = deps.bootClasspath.FormJavaClassPath("-bootclasspath")
	}
	flags.classpathArgs = deps.classpath.FormJavaClassPath("-classpath")
	// Dokka doesn't support boocClasspath, so combine these two classpath vars for Dokka.
	dokkaClasspath := classpath{}
	dokkaClasspath = append(dokkaClasspath, deps.bootClasspath...)
	dokkaClasspath = append(dokkaClasspath, deps.classpath...)
	flags.dokkaClasspathArgs = dokkaClasspath.FormJavaClassPath("-classpath")

	argFiles := ctx.ExpandSources(d.properties.Arg_files, nil)
	argFilesMap := map[string]android.Path{}
@@ -969,7 +979,7 @@ func (d *Droiddoc) collectMetalavaAnnotationsFlags(
	return flags
}

func (d *Droiddoc) collectMetalavaDocsFlags(ctx android.ModuleContext,
func (d *Droiddoc) collectMetalavaJavadocFlags(ctx android.ModuleContext,
	bootClasspathArgs, classpathArgs, outDir, docStubsDir string) string {
	return " --doc-stubs " + docStubsDir +
		" --write-doc-stubs-source-list " + android.PathForModuleOut(ctx, "doc_stubs.srclist").String() +
@@ -978,54 +988,20 @@ func (d *Droiddoc) collectMetalavaDocsFlags(ctx android.ModuleContext,
		docStubsDir + " -quiet -d " + outDir
}

func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
	deps := d.Javadoc.collectDeps(ctx)

	javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), sdkContext(d))
	// Doclava has problem with "-source 1.9", so override javaVersion when Doclava
	// is running with EXPERIMENTAL_USE_OPENJDK9=true. And eventually Doclava will be
	// replaced by Metalava.
	if !Bool(d.properties.Metalava_enabled) {
		javaVersion = "1.8"
	}

	jsilver := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "jsilver.jar")
	doclava := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "doclava.jar")
	java8Home := ctx.Config().Getenv("ANDROID_JAVA8_HOME")
	checkApiClasspath := classpath{jsilver, doclava, android.PathForSource(ctx, java8Home, "lib/tools.jar")}

	var implicits android.Paths
	implicits = append(implicits, d.Javadoc.srcJars...)
func (d *Droiddoc) collectMetalavaDokkaFlags(ctx android.ModuleContext, implicits *android.Paths,
	classpathArgs, outDir, docStubsDir string) string {
	dokka := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "dokka.jar")
	*implicits = append(*implicits, dokka)

	var implicitOutputs android.WritablePaths
	implicitOutputs = append(implicitOutputs, d.Javadoc.docZip)
	for _, o := range d.properties.Out {
		implicitOutputs = append(implicitOutputs, android.PathForModuleGen(ctx, o))
	return " --doc-stubs " + docStubsDir + " --write-doc-stubs-source-list " +
		android.PathForModuleOut(ctx, "doc_stubs.srclist").String() +
		" --generate-documentation ${config.JavaCmd} -jar " + dokka.String() + " " +
		docStubsDir + " " + classpathArgs + " -format dac -dacRoot /reference/kotlin -output " + outDir
}

	flags, err := d.initBuilderFlags(ctx, &implicits, deps)
	if err != nil {
		return
	}

	outDir := android.PathForModuleOut(ctx, "out").String()
	flags.doclavaStubsFlags, flags.metalavaStubsFlags = d.collectStubsFlags(ctx, &implicitOutputs)
	if Bool(d.properties.Metalava_enabled) {
		opts := flags.metalavaStubsFlags
		flags.metalavaAnnotationsFlags = d.collectMetalavaAnnotationsFlags(ctx, &implicits, &implicitOutputs)
		opts += flags.metalavaAnnotationsFlags
		docStubsDir := android.PathForModuleOut(ctx, "docStubsDir").String()
		if strings.Contains(flags.args, "--generate-documentation") {
			// TODO(nanzhang): Add a Soong property to handle documentation args.
			flags.doclavaDocsFlags = d.collectDoclavaDocsFlags(ctx, &implicits, javaVersion, jsilver, doclava)
			flags.metalavaDocsFlags = d.collectMetalavaDocsFlags(ctx,
				flags.bootClasspathArgs, flags.classpathArgs, outDir, docStubsDir)
			opts += " " + strings.Split(flags.args, "--generate-documentation")[0] + " " +
				flags.metalavaDocsFlags + flags.doclavaDocsFlags +
				" " + strings.Split(flags.args, "--generate-documentation")[1]
		} else {
			opts += " " + flags.args
		}
func (d *Droiddoc) transformMetalava(ctx android.ModuleContext, implicits android.Paths,
	implicitOutputs android.WritablePaths, outDir, docStubsDir, javaVersion,
	bootclasspathArgs, classpathArgs, opts string) {
	ctx.Build(pctx, android.BuildParams{
		Rule:            metalava,
		Description:     "Metalava",
@@ -1040,78 +1016,66 @@ func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
			"docStubsDir":       docStubsDir,
			"srcJars":           strings.Join(d.Javadoc.srcJars.Strings(), " "),
			"javaVersion":       javaVersion,
				"bootclasspathArgs": flags.bootClasspathArgs,
				"classpathArgs":     flags.classpathArgs,
			"bootclasspathArgs": bootclasspathArgs,
			"classpathArgs":     classpathArgs,
			"sourcepath":        strings.Join(d.Javadoc.sourcepaths.Strings(), ":"),
			"docZip":            d.Javadoc.docZip.String(),
			"opts":              opts,
		},
	})
	} else {
		flags.doclavaDocsFlags = d.collectDoclavaDocsFlags(ctx, &implicits, javaVersion, jsilver, doclava)
		flags.postDoclavaCmds = d.getPostDoclavaCmds(ctx, &implicits)
}

func (d *Droiddoc) transformDoclava(ctx android.ModuleContext, implicits android.Paths,
	implicitOutputs android.WritablePaths, bootclasspathArgs, classpathArgs, opts, postDoclavaCmds string) {
	ctx.Build(pctx, android.BuildParams{
		Rule:            javadoc,
			Description:     "Droiddoc",
		Description:     "Doclava",
		Output:          d.Javadoc.stubsSrcJar,
		Inputs:          d.Javadoc.srcFiles,
		Implicits:       implicits,
		ImplicitOutputs: implicitOutputs,
		Args: map[string]string{
				"outDir":            outDir,
			"outDir":            android.PathForModuleOut(ctx, "out").String(),
			"srcJarDir":         android.PathForModuleOut(ctx, "srcjars").String(),
			"stubsDir":          android.PathForModuleOut(ctx, "stubsDir").String(),
			"srcJars":           strings.Join(d.Javadoc.srcJars.Strings(), " "),
				"opts":              flags.doclavaDocsFlags + flags.doclavaStubsFlags + " " + flags.args,
				"bootclasspathArgs": flags.bootClasspathArgs,
				"classpathArgs":     flags.classpathArgs,
			"opts":              opts,
			"bootclasspathArgs": bootclasspathArgs,
			"classpathArgs":     classpathArgs,
			"sourcepath":        strings.Join(d.Javadoc.sourcepaths.Strings(), ":"),
			"docZip":            d.Javadoc.docZip.String(),
				"postDoclavaCmds":   flags.postDoclavaCmds,
			"postDoclavaCmds":   postDoclavaCmds,
		},
	})
}

	if d.checkCurrentApi() && !ctx.Config().IsPdkBuild() {
		d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "check_current_api.timestamp")

		apiFile := ctx.ExpandSource(String(d.properties.Check_api.Current.Api_file),
			"check_api.current.api_file")
		removedApiFile := ctx.ExpandSource(String(d.properties.Check_api.Current.Removed_api_file),
			"check_api.current_removed_api_file")

func (d *Droiddoc) transformCheckApi(ctx android.ModuleContext, apiFile, removedApiFile android.Path,
	checkApiClasspath classpath, msg, opts string, output android.WritablePath) {
	ctx.Build(pctx, android.BuildParams{
		Rule:        apiCheck,
			Description: "Current API check",
			Output:      d.checkCurrentApiTimestamp,
		Description: "Check API",
		Output:      output,
		Inputs:      nil,
		Implicits: append(android.Paths{apiFile, removedApiFile, d.apiFile, d.removedApiFile},
			checkApiClasspath...),
		Args: map[string]string{
			"classpath":             checkApiClasspath.FormJavaClassPath(""),
				"opts":                  String(d.properties.Check_api.Current.Args),
			"opts":                  opts,
			"apiFile":               apiFile.String(),
			"apiFileToCheck":        d.apiFile.String(),
			"removedApiFile":        removedApiFile.String(),
			"removedApiFileToCheck": d.removedApiFile.String(),
				"msg": fmt.Sprintf(`\n******************************\n`+
					`You have tried to change the API from what has been previously approved.\n\n`+
					`To make these errors go away, you have two choices:\n`+
					`   1. You can add '@hide' javadoc comments to the methods, etc. listed in the\n`+
					`      errors above.\n\n`+
					`   2. You can update current.txt by executing the following command:\n`+
					`         make %s-update-current-api\n\n`+
					`      To submit the revised current.txt to the main Android repository,\n`+
					`      you will need approval.\n`+
					`******************************\n`, ctx.ModuleName()),
			"msg": msg,
		},
	})
}

		d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "update_current_api.timestamp")
func (d *Droiddoc) transformUpdateApi(ctx android.ModuleContext, apiFile, removedApiFile android.Path,
	output android.WritablePath) {
	ctx.Build(pctx, android.BuildParams{
		Rule:        updateApi,
			Description: "update current API",
			Output:      d.updateCurrentApiTimestamp,
		Description: "Update API",
		Output:      output,
		Implicits:   append(android.Paths{}, apiFile, removedApiFile, d.apiFile, d.removedApiFile),
		Args: map[string]string{
			"apiFile":               apiFile.String(),
@@ -1122,6 +1086,98 @@ func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
	})
}

func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
	deps := d.Javadoc.collectDeps(ctx)

	javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), sdkContext(d))
	// Doclava has problem with "-source 1.9", so override javaVersion when Doclava
	// is running with EXPERIMENTAL_USE_OPENJDK9=true. And eventually Doclava will be
	// replaced by Metalava.
	if !Bool(d.properties.Metalava_enabled) {
		javaVersion = "1.8"
	}

	jsilver := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "jsilver.jar")
	doclava := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "doclava.jar")
	java8Home := ctx.Config().Getenv("ANDROID_JAVA8_HOME")
	checkApiClasspath := classpath{jsilver, doclava, android.PathForSource(ctx, java8Home, "lib/tools.jar")}

	var implicits android.Paths
	implicits = append(implicits, d.Javadoc.srcJars...)

	var implicitOutputs android.WritablePaths
	implicitOutputs = append(implicitOutputs, d.Javadoc.docZip)
	for _, o := range d.properties.Out {
		implicitOutputs = append(implicitOutputs, android.PathForModuleGen(ctx, o))
	}

	flags, err := d.initBuilderFlags(ctx, &implicits, deps)
	if err != nil {
		return
	}

	flags.doclavaStubsFlags, flags.metalavaStubsFlags = d.collectStubsFlags(ctx, &implicitOutputs)
	if Bool(d.properties.Metalava_enabled) {
		flags.metalavaAnnotationsFlags = d.collectMetalavaAnnotationsFlags(ctx, &implicits, &implicitOutputs)
		outDir := android.PathForModuleOut(ctx, "out").String()
		docStubsDir := android.PathForModuleOut(ctx, "docStubsDir").String()
		// TODO(nanzhang): Add a Soong property to handle documentation args.
		if strings.Contains(flags.args, "--generate-documentation") { // enable docs generation
			if Bool(d.properties.Dokka_enabled) {
				flags.metalavaDokkaFlags = d.collectMetalavaDokkaFlags(ctx, &implicits,
					flags.dokkaClasspathArgs, outDir, docStubsDir)
				d.transformMetalava(ctx, implicits, implicitOutputs, outDir, docStubsDir, javaVersion,
					flags.bootClasspathArgs, flags.classpathArgs, flags.metalavaStubsFlags+
						flags.metalavaAnnotationsFlags+" "+strings.Split(flags.args, "--generate-documentation")[0]+
						flags.metalavaDokkaFlags+" "+strings.Split(flags.args, "--generate-documentation")[1])
			} else {
				flags.metalavaJavadocFlags = d.collectMetalavaJavadocFlags(
					ctx, flags.bootClasspathArgs, flags.classpathArgs, outDir, docStubsDir)
				flags.doclavaDocsFlags = d.collectDoclavaDocsFlags(ctx, &implicits, javaVersion, jsilver, doclava)
				d.transformMetalava(ctx, implicits, implicitOutputs, outDir, docStubsDir, javaVersion,
					flags.bootClasspathArgs, flags.classpathArgs, flags.metalavaStubsFlags+
						flags.metalavaAnnotationsFlags+" "+strings.Split(flags.args, "--generate-documentation")[0]+
						flags.metalavaJavadocFlags+flags.doclavaDocsFlags+
						" "+strings.Split(flags.args, "--generate-documentation")[1])
			}
		} else {
			d.transformMetalava(ctx, implicits, implicitOutputs, outDir, docStubsDir, javaVersion,
				flags.bootClasspathArgs, flags.classpathArgs,
				flags.metalavaStubsFlags+flags.metalavaAnnotationsFlags+flags.args)
		}
	} else {
		flags.doclavaDocsFlags = d.collectDoclavaDocsFlags(ctx, &implicits, javaVersion, jsilver, doclava)
		flags.postDoclavaCmds = d.getPostDoclavaCmds(ctx, &implicits)
		d.transformDoclava(ctx, implicits, implicitOutputs, flags.bootClasspathArgs, flags.classpathArgs,
			flags.doclavaDocsFlags+flags.doclavaStubsFlags+" "+flags.args,
			flags.postDoclavaCmds)
	}

	if d.checkCurrentApi() && !ctx.Config().IsPdkBuild() {
		d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "check_current_api.timestamp")

		apiFile := ctx.ExpandSource(String(d.properties.Check_api.Current.Api_file),
			"check_api.current.api_file")
		removedApiFile := ctx.ExpandSource(String(d.properties.Check_api.Current.Removed_api_file),
			"check_api.current_removed_api_file")

		d.transformCheckApi(ctx, apiFile, removedApiFile, checkApiClasspath,
			fmt.Sprintf(`\n******************************\n`+
				`You have tried to change the API from what has been previously approved.\n\n`+
				`To make these errors go away, you have two choices:\n`+
				`   1. You can add '@hide' javadoc comments to the methods, etc. listed in the\n`+
				`      errors above.\n\n`+
				`   2. You can update current.txt by executing the following command:\n`+
				`         make %s-update-current-api\n\n`+
				`      To submit the revised current.txt to the main Android repository,\n`+
				`      you will need approval.\n`+
				`******************************\n`, ctx.ModuleName()), String(d.properties.Check_api.Current.Args),
			d.checkCurrentApiTimestamp)

		d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "update_current_api.timestamp")
		d.transformUpdateApi(ctx, apiFile, removedApiFile, d.updateCurrentApiTimestamp)
	}

	if d.checkLastReleasedApi() && !ctx.Config().IsPdkBuild() {
		d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "check_last_released_api.timestamp")

@@ -1130,26 +1186,12 @@ func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
		removedApiFile := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Removed_api_file),
			"check_api.last_released.removed_api_file")

		ctx.Build(pctx, android.BuildParams{
			Rule:        apiCheck,
			Description: "Last Released API check",
			Output:      d.checkLastReleasedApiTimestamp,
			Inputs:      nil,
			Implicits: append(android.Paths{apiFile, removedApiFile, d.apiFile, d.removedApiFile},
				checkApiClasspath...),
			Args: map[string]string{
				"classpath":             checkApiClasspath.FormJavaClassPath(""),
				"opts":                  String(d.properties.Check_api.Last_released.Args),
				"apiFile":               apiFile.String(),
				"apiFileToCheck":        d.apiFile.String(),
				"removedApiFile":        removedApiFile.String(),
				"removedApiFileToCheck": d.removedApiFile.String(),
				"msg": `\n******************************\n` +
		d.transformCheckApi(ctx, apiFile, removedApiFile, checkApiClasspath,
			`\n******************************\n`+
				`You have tried to change the API from what has been previously released in\n`+
				`an SDK.  Please fix the errors listed above.\n`+
					`******************************\n`,
			},
		})
				`******************************\n`, String(d.properties.Check_api.Last_released.Args),
			d.checkLastReleasedApiTimestamp)
	}
}