diff --git a/android/onceper.go b/android/onceper.go index ff865c2e6..481cdea05 100644 --- a/android/onceper.go +++ b/android/onceper.go @@ -95,6 +95,16 @@ func (once *OncePer) Once2StringSlice(key OnceKey, value func() ([]string, []str return s[0], s[1] } +// OncePath is the same as Once, but returns the value cast to a Path +func (once *OncePer) OncePath(key OnceKey, value func() Path) Path { + return once.Once(key, func() interface{} { return value() }).(Path) +} + +// OncePath is the same as Once, but returns the value cast to a SourcePath +func (once *OncePer) OnceSourcePath(key OnceKey, value func() SourcePath) SourcePath { + return once.Once(key, func() interface{} { return value() }).(SourcePath) +} + // OnceKey is an opaque type to be used as the key in calls to Once. type OnceKey struct { key interface{} diff --git a/android/rule_builder.go b/android/rule_builder.go index 1238ddc6d..48d070eb4 100644 --- a/android/rule_builder.go +++ b/android/rule_builder.go @@ -478,6 +478,16 @@ func (c *RuleBuilderCommand) Flag(flag string) *RuleBuilderCommand { return c.Text(flag) } +// OptionalFlag adds the specified raw text to the command line if it is not nil. The text should not contain input or +// output paths or the rule will not have them listed in its dependencies or outputs. +func (c *RuleBuilderCommand) OptionalFlag(flag *string) *RuleBuilderCommand { + if flag != nil { + c.Text(*flag) + } + + return c +} + // Flags adds the specified raw text to the command line. The text should not contain input or output paths or the // rule will not have them listed in its dependencies or outputs. func (c *RuleBuilderCommand) Flags(flags []string) *RuleBuilderCommand { diff --git a/java/builder.go b/java/builder.go index a48e8b1a2..22eff7c4b 100644 --- a/java/builder.go +++ b/java/builder.go @@ -148,16 +148,15 @@ func init() { } type javaBuilderFlags struct { - javacFlags string - bootClasspath classpath - classpath classpath - processorPath classpath - processor string - systemModules classpath - systemModulesDeps android.Paths - aidlFlags string - aidlDeps android.Paths - javaVersion string + javacFlags string + bootClasspath classpath + classpath classpath + processorPath classpath + processor string + systemModules *systemModules + aidlFlags string + aidlDeps android.Paths + javaVersion string errorProneExtraJavacFlags string errorProneProcessorPath classpath @@ -249,8 +248,9 @@ func transformJavaToClasses(ctx android.ModuleContext, outputFile android.Writab var bootClasspath string if flags.javaVersion == "1.9" { - deps = append(deps, flags.systemModulesDeps...) - bootClasspath = flags.systemModules.FormJavaSystemModulesPath("--system=", ctx.Device()) + var systemModuleDeps android.Paths + bootClasspath, systemModuleDeps = flags.systemModules.FormJavaSystemModulesPath(ctx.Device()) + deps = append(deps, systemModuleDeps...) } else { deps = append(deps, flags.bootClasspath...) if len(flags.bootClasspath) == 0 && ctx.Device() { @@ -411,7 +411,7 @@ func TransformZipAlign(ctx android.ModuleContext, outputFile android.WritablePat }) } -type classpath []android.Path +type classpath android.Paths func (x *classpath) FormJavaClassPath(optName string) string { if optName != "" && !strings.HasSuffix(optName, "=") && !strings.HasSuffix(optName, " ") { @@ -424,21 +424,6 @@ func (x *classpath) FormJavaClassPath(optName string) string { } } -// Returns a --system argument in the form javac expects with -source 1.9. If forceEmpty is true, -// returns --system=none if the list is empty to ensure javac does not fall back to the default -// system modules. -func (x *classpath) FormJavaSystemModulesPath(optName string, forceEmpty bool) string { - if len(*x) > 1 { - panic("more than one system module") - } else if len(*x) == 1 { - return optName + (*x)[0].String() - } else if forceEmpty { - return optName + "none" - } else { - return "" - } -} - func (x *classpath) FormTurbineClasspath(optName string) []string { if x == nil || *x == nil { return nil @@ -466,3 +451,21 @@ func (x *classpath) Strings() []string { } return ret } + +type systemModules struct { + dir android.Path + deps android.Paths +} + +// Returns a --system argument in the form javac expects with -source 1.9. If forceEmpty is true, +// returns --system=none if the list is empty to ensure javac does not fall back to the default +// system modules. +func (x *systemModules) FormJavaSystemModulesPath(forceEmpty bool) (string, android.Paths) { + if x != nil { + return "--system=" + x.dir.String(), x.deps + } else if forceEmpty { + return "--system=none", nil + } else { + return "", nil + } +} diff --git a/java/config/config.go b/java/config/config.go index d017ae67f..6a0a10a86 100644 --- a/java/config/config.go +++ b/java/config/config.go @@ -47,6 +47,11 @@ var ( } ) +const ( + JavaVmFlags = `-XX:OnError="cat hs_err_pid%p.log" -XX:CICompilerCount=6 -XX:+UseDynamicNumberOfGCThreads` + JavacVmFlags = `-J-XX:OnError="cat hs_err_pid%p.log" -J-XX:CICompilerCount=6 -J-XX:+UseDynamicNumberOfGCThreads` +) + func init() { pctx.Import("github.com/google/blueprint/bootstrap") @@ -69,8 +74,9 @@ func init() { // b/65004097: prevent using java.lang.invoke.StringConcatFactory when using -target 1.9 `-XDstringConcat=inline`, }, " ")) - pctx.StaticVariable("JavaVmFlags", "-XX:OnError=\"cat hs_err_pid%p.log\" -XX:CICompilerCount=6 -XX:+UseDynamicNumberOfGCThreads") - pctx.StaticVariable("JavacVmFlags", "-J-XX:OnError=\"cat hs_err_pid%p.log\" -J-XX:CICompilerCount=6 -J-XX:+UseDynamicNumberOfGCThreads") + + pctx.StaticVariable("JavaVmFlags", JavaVmFlags) + pctx.StaticVariable("JavacVmFlags", JavacVmFlags) pctx.VariableConfigMethod("hostPrebuiltTag", android.Config.PrebuiltOS) @@ -154,3 +160,41 @@ func init() { pctx.HostBinToolVariable("Class2Greylist", "class2greylist") pctx.HostBinToolVariable("HiddenAPI", "hiddenapi") } + +// JavaCmd returns a SourcePath object with the path to the java command. +func JavaCmd(ctx android.PathContext) android.SourcePath { + return javaTool(ctx, "java") +} + +// JavadocCmd returns a SourcePath object with the path to the java command. +func JavadocCmd(ctx android.PathContext) android.SourcePath { + return javaTool(ctx, "javadoc") +} + +func javaTool(ctx android.PathContext, tool string) android.SourcePath { + type javaToolKey string + + key := android.NewCustomOnceKey(javaToolKey(tool)) + + return ctx.Config().OnceSourcePath(key, func() android.SourcePath { + return javaToolchain(ctx).Join(ctx, tool) + }) + +} + +var javaToolchainKey = android.NewOnceKey("javaToolchain") + +func javaToolchain(ctx android.PathContext) android.SourcePath { + return ctx.Config().OnceSourcePath(javaToolchainKey, func() android.SourcePath { + return javaHome(ctx).Join(ctx, "bin") + }) +} + +var javaHomeKey = android.NewOnceKey("javaHome") + +func javaHome(ctx android.PathContext) android.SourcePath { + return ctx.Config().OnceSourcePath(javaHomeKey, func() android.SourcePath { + // This is set up and guaranteed by soong_ui + return android.PathForSource(ctx, ctx.Config().Getenv("ANDROID_JAVA_HOME")) + }) +} diff --git a/java/droiddoc.go b/java/droiddoc.go index 6de2ddf2e..78bfa80d2 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -15,126 +15,15 @@ package java import ( - "android/soong/android" - "android/soong/java/config" "fmt" "path/filepath" "runtime" "strings" - "github.com/google/blueprint" "github.com/google/blueprint/proptools" -) -var ( - javadoc = pctx.AndroidStaticRule("javadoc", - blueprint.RuleParams{ - Command: `rm -rf "$outDir" "$srcJarDir" "$stubsDir" && mkdir -p "$outDir" "$srcJarDir" "$stubsDir" && ` + - `${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` + - `${config.SoongJavacWrapper} ${config.JavadocCmd} -encoding UTF-8 @$out.rsp @$srcJarDir/list ` + - `$opts $bootclasspathArgs $classpathArgs $sourcepathArgs ` + - `-d $outDir -quiet && ` + - `${config.SoongZipCmd} -write_if_changed -d -o $docZip -C $outDir -D $outDir && ` + - `${config.SoongZipCmd} -write_if_changed -jar -o $out -C $stubsDir -D $stubsDir $postDoclavaCmds && ` + - `rm -rf "$srcJarDir"`, - - CommandDeps: []string{ - "${config.ZipSyncCmd}", - "${config.JavadocCmd}", - "${config.SoongZipCmd}", - }, - CommandOrderOnly: []string{"${config.SoongJavacWrapper}"}, - Rspfile: "$out.rsp", - RspfileContent: "$in", - Restat: true, - }, - "outDir", "srcJarDir", "stubsDir", "srcJars", "opts", - "bootclasspathArgs", "classpathArgs", "sourcepathArgs", "docZip", "postDoclavaCmds") - - apiCheck = pctx.AndroidStaticRule("apiCheck", - blueprint.RuleParams{ - Command: `( ${config.ApiCheckCmd} -JXmx1024m -J"classpath $classpath" $opts ` + - `$apiFile $apiFileToCheck $removedApiFile $removedApiFileToCheck ` + - `&& touch $out ) || (echo -e "$msg" ; exit 38)`, - CommandDeps: []string{ - "${config.ApiCheckCmd}", - }, - }, - "classpath", "opts", "apiFile", "apiFileToCheck", "removedApiFile", "removedApiFileToCheck", "msg") - - updateApi = pctx.AndroidStaticRule("updateApi", - blueprint.RuleParams{ - Command: `( ( cp -f $srcApiFile $destApiFile && cp -f $srcRemovedApiFile $destRemovedApiFile ) ` + - `&& touch $out ) || (echo failed to update public API ; exit 38)`, - }, - "srcApiFile", "destApiFile", "srcRemovedApiFile", "destRemovedApiFile") - - metalava = pctx.AndroidStaticRule("metalava", - blueprint.RuleParams{ - Command: `rm -rf "$outDir" "$srcJarDir" "$stubsDir" && ` + - `mkdir -p "$outDir" "$srcJarDir" "$stubsDir" && ` + - `${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` + - `${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.MetalavaJar} -encoding UTF-8 -source $javaVersion @$out.rsp @$srcJarDir/list ` + - `$bootclasspathArgs $classpathArgs $sourcepathArgs --no-banner --color --quiet --format=v2 ` + - `$opts && ` + - `${config.SoongZipCmd} -write_if_changed -jar -o $out -C $stubsDir -D $stubsDir && ` + - `rm -rf "$srcJarDir"`, - CommandDeps: []string{ - "${config.ZipSyncCmd}", - "${config.JavaCmd}", - "${config.MetalavaJar}", - "${config.SoongZipCmd}", - }, - Rspfile: "$out.rsp", - RspfileContent: "$in", - Restat: true, - }, - "outDir", "srcJarDir", "stubsDir", "srcJars", "javaVersion", "bootclasspathArgs", - "classpathArgs", "sourcepathArgs", "opts") - - metalavaApiCheck = pctx.AndroidStaticRule("metalavaApiCheck", - blueprint.RuleParams{ - Command: `( rm -rf "$srcJarDir" && mkdir -p "$srcJarDir" && ` + - `${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` + - `${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.MetalavaJar} -encoding UTF-8 -source $javaVersion @$out.rsp @$srcJarDir/list ` + - `$bootclasspathArgs $classpathArgs $sourcepathArgs --no-banner --color --quiet --format=v2 ` + - `$opts && touch $out && rm -rf "$srcJarDir") || ` + - `( echo -e "$msg" ; exit 38 )`, - CommandDeps: []string{ - "${config.ZipSyncCmd}", - "${config.JavaCmd}", - "${config.MetalavaJar}", - }, - Rspfile: "$out.rsp", - RspfileContent: "$in", - }, - "srcJarDir", "srcJars", "javaVersion", "bootclasspathArgs", "classpathArgs", "sourcepathArgs", "opts", "msg") - - nullabilityWarningsCheck = pctx.AndroidStaticRule("nullabilityWarningsCheck", - blueprint.RuleParams{ - Command: `( diff $expected $actual && touch $out ) || ( echo -e "$msg" ; exit 38 )`, - }, - "expected", "actual", "msg") - - dokka = pctx.AndroidStaticRule("dokka", - blueprint.RuleParams{ - Command: `rm -rf "$outDir" "$srcJarDir" "$stubsDir" && ` + - `mkdir -p "$outDir" "$srcJarDir" "$stubsDir" && ` + - `${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` + - `${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.DokkaJar} $srcJarDir ` + - `$classpathArgs -format dac -dacRoot /reference/kotlin -output $outDir $opts && ` + - `${config.SoongZipCmd} -write_if_changed -d -o $docZip -C $outDir -D $outDir && ` + - `${config.SoongZipCmd} -write_if_changed -jar -o $out -C $stubsDir -D $stubsDir && ` + - `rm -rf "$srcJarDir"`, - CommandDeps: []string{ - "${config.ZipSyncCmd}", - "${config.DokkaJar}", - "${config.MetalavaJar}", - "${config.SoongZipCmd}", - }, - Restat: true, - }, - "outDir", "srcJarDir", "stubsDir", "srcJars", "classpathArgs", "opts", "docZip") + "android/soong/android" + "android/soong/java/config" ) func init() { @@ -238,7 +127,7 @@ type DroiddocProperties struct { // proofread file contains all of the text content of the javadocs concatenated into one file, // suitable for spell-checking and other goodness. - Proofread_file *string `android:"path"` + Proofread_file *string // a todo file lists the program elements that are missing documentation. // At some point, this might be improved to show more warnings. @@ -404,14 +293,6 @@ type droiddocBuilderFlags struct { doclavaStubsFlags string doclavaDocsFlags string postDoclavaCmds string - - metalavaStubsFlags string - metalavaAnnotationsFlags string - metalavaMergeAnnoDirFlags string - metalavaInclusionAnnotationsFlags string - metalavaApiLevelsAnnotationsFlags string - - metalavaApiToXmlFlags string } func InitDroiddocModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) { @@ -454,23 +335,6 @@ type ApiFilePath interface { ApiFilePath() android.Path } -func transformUpdateApi(ctx android.ModuleContext, destApiFile, destRemovedApiFile, - srcApiFile, srcRemovedApiFile android.Path, output android.WritablePath) { - ctx.Build(pctx, android.BuildParams{ - Rule: updateApi, - Description: "Update API", - Output: output, - Implicits: append(android.Paths{}, srcApiFile, srcRemovedApiFile, - destApiFile, destRemovedApiFile), - Args: map[string]string{ - "destApiFile": destApiFile.String(), - "srcApiFile": srcApiFile.String(), - "destRemovedApiFile": destRemovedApiFile.String(), - "srcRemovedApiFile": srcRemovedApiFile.String(), - }, - }) -} - // // Javadoc // @@ -692,8 +556,7 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { if sm.outputDir == nil && len(sm.outputDeps) == 0 { panic("Missing directory for system module dependency") } - deps.systemModules = sm.outputDir - deps.systemModulesDeps = sm.outputDeps + deps.systemModules = &systemModules{sm.outputDir, sm.outputDeps} } }) // do not pass exclude_srcs directly when expanding srcFiles since exclude_srcs @@ -709,9 +572,6 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { j.srcFiles = srcFiles.FilterOutByExt(".srcjar") j.srcFiles = append(j.srcFiles, deps.srcs...) - j.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip") - j.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar") - if j.properties.Local_sourcepaths == nil && len(j.srcFiles) > 0 { j.properties.Local_sourcepaths = append(j.properties.Local_sourcepaths, ".") } @@ -762,52 +622,43 @@ func (j *Javadoc) DepsMutator(ctx android.BottomUpMutatorContext) { func (j *Javadoc) GenerateAndroidBuildActions(ctx android.ModuleContext) { deps := j.collectDeps(ctx) - var implicits android.Paths - implicits = append(implicits, deps.bootClasspath...) - implicits = append(implicits, deps.classpath...) + j.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip") - var bootClasspathArgs, classpathArgs, sourcepathArgs string + outDir := android.PathForModuleOut(ctx, "out") + srcJarDir := android.PathForModuleOut(ctx, "srcjars") + + j.stubsSrcJar = nil + + rule := android.NewRuleBuilder() + + rule.Command().Text("rm -rf").Text(outDir.String()) + rule.Command().Text("mkdir -p").Text(outDir.String()) + + srcJarList := zipSyncCmd(ctx, rule, srcJarDir, j.srcJars) javaVersion := getJavaVersion(ctx, String(j.properties.Java_version), sdkContext(j)) - if len(deps.bootClasspath) > 0 { - var systemModules classpath - if deps.systemModules != nil { - systemModules = append(systemModules, deps.systemModules) - } - implicits = append(implicits, deps.systemModulesDeps...) - bootClasspathArgs = systemModules.FormJavaSystemModulesPath("--system ", ctx.Device()) - bootClasspathArgs = bootClasspathArgs + " --patch-module java.base=." - } - if len(deps.classpath.Strings()) > 0 { - classpathArgs = "-classpath " + strings.Join(deps.classpath.Strings(), ":") - } - implicits = append(implicits, j.srcJars...) - implicits = append(implicits, j.argFiles...) + cmd := javadocSystemModulesCmd(ctx, rule, j.srcFiles, outDir, srcJarDir, srcJarList, + deps.systemModules, deps.classpath, j.sourcepaths) - opts := "-source " + javaVersion + " -J-Xmx1024m -XDignore.symbol.file -Xdoclint:none" + cmd.FlagWithArg("-source ", javaVersion). + Flag("-J-Xmx1024m"). + Flag("-XDignore.symbol.file"). + Flag("-Xdoclint:none") - sourcepathArgs = "-sourcepath " + strings.Join(j.sourcepaths.Strings(), ":") + rule.Command(). + BuiltTool(ctx, "soong_zip"). + Flag("-write_if_changed"). + Flag("-d"). + FlagWithOutput("-o ", j.docZip). + FlagWithArg("-C ", outDir.String()). + FlagWithArg("-D ", outDir.String()) - ctx.Build(pctx, android.BuildParams{ - Rule: javadoc, - Description: "Javadoc", - Output: j.stubsSrcJar, - ImplicitOutput: j.docZip, - Inputs: j.srcFiles, - Implicits: implicits, - Args: map[string]string{ - "outDir": android.PathForModuleOut(ctx, "out").String(), - "srcJarDir": android.PathForModuleOut(ctx, "srcjars").String(), - "stubsDir": android.PathForModuleOut(ctx, "stubsDir").String(), - "srcJars": strings.Join(j.srcJars.Strings(), " "), - "opts": proptools.NinjaEscape(opts), - "bootclasspathArgs": bootClasspathArgs, - "classpathArgs": classpathArgs, - "sourcepathArgs": sourcepathArgs, - "docZip": j.docZip.String(), - }, - }) + rule.Restat() + + zipSyncCleanupCmd(rule, srcJarDir) + + rule.Build(pctx, ctx, "javadoc", "javadoc") } // @@ -872,58 +723,25 @@ func (d *Droiddoc) DepsMutator(ctx android.BottomUpMutatorContext) { } } -func (d *Droiddoc) initBuilderFlags(ctx android.ModuleContext, implicits *android.Paths, - deps deps) (droiddocBuilderFlags, error) { - var flags droiddocBuilderFlags - - *implicits = append(*implicits, deps.bootClasspath...) - *implicits = append(*implicits, deps.classpath...) - - if len(deps.bootClasspath.Strings()) > 0 { - // For OpenJDK 8 we can use -bootclasspath to define the core libraries code. - flags.bootClasspathArgs = deps.bootClasspath.FormJavaClassPath("-bootclasspath") - } - flags.classpathArgs = deps.classpath.FormJavaClassPath("-classpath") - // Dokka doesn't support bootClasspath, 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") - - // TODO(nanzhang): Remove this if- statement once we finish migration for all Doclava - // based stubs generation. - // In the future, all the docs generation depends on Metalava stubs (droidstubs) srcjar - // dir. We need add the srcjar dir to -sourcepath arg, so that Javadoc can figure out - // the correct package name base path. - if len(d.Javadoc.properties.Local_sourcepaths) > 0 { - flags.sourcepathArgs = "-sourcepath " + strings.Join(d.Javadoc.sourcepaths.Strings(), ":") - } else { - flags.sourcepathArgs = "-sourcepath " + android.PathForModuleOut(ctx, "srcjars").String() - } - - return flags, nil -} - -func (d *Droiddoc) collectDoclavaDocsFlags(ctx android.ModuleContext, implicits *android.Paths, - jsilver, doclava android.Path) string { - - *implicits = append(*implicits, jsilver) - *implicits = append(*implicits, doclava) - +func (d *Droiddoc) doclavaDocsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, docletPath classpath) { var date string if runtime.GOOS == "darwin" { date = `date -r` } else { - date = `date -d` + date = `date -d @` } // Droiddoc always gets "-source 1.8" because it doesn't support 1.9 sources. For modules with 1.9 // sources, droiddoc will get sources produced by metalava which will have already stripped out the // 1.9 language features. - args := " -source 1.8 -J-Xmx1600m -J-XX:-OmitStackTraceInFastThrow -XDignore.symbol.file " + - "-doclet com.google.doclava.Doclava -docletpath " + jsilver.String() + ":" + doclava.String() + " " + - "-hdf page.build " + ctx.Config().BuildId() + "-" + ctx.Config().BuildNumberFromFile() + " " + - `-hdf page.now "$(` + date + ` @$(cat ` + ctx.Config().Getenv("BUILD_DATETIME_FILE") + `) "+%d %b %Y %k:%M")" ` + cmd.FlagWithArg("-source ", "1.8"). + Flag("-J-Xmx1600m"). + Flag("-J-XX:-OmitStackTraceInFastThrow"). + Flag("-XDignore.symbol.file"). + FlagWithArg("-doclet ", "com.google.doclava.Doclava"). + FlagWithInputList("-docletpath ", docletPath.Paths(), ":"). + FlagWithArg("-hdf page.build ", ctx.Config().BuildId()+"-"+ctx.Config().BuildNumberFromFile()). + FlagWithArg("-hdf page.now ", `"$(`+date+`$(cat `+ctx.Config().Getenv("BUILD_DATETIME_FILE")+`) "+%d %b %Y %k:%M")" `) if String(d.properties.Custom_template) == "" { // TODO: This is almost always droiddoc-templates-sdk @@ -932,23 +750,22 @@ func (d *Droiddoc) collectDoclavaDocsFlags(ctx android.ModuleContext, implicits ctx.VisitDirectDepsWithTag(droiddocTemplateTag, func(m android.Module) { if t, ok := m.(*ExportedDroiddocDir); ok { - *implicits = append(*implicits, t.deps...) - args = args + " -templatedir " + t.dir.String() + cmd.FlagWithArg("-templatedir ", t.dir.String()).Implicits(t.deps) } else { ctx.PropertyErrorf("custom_template", "module %q is not a droiddoc_template", ctx.OtherModuleName(m)) } }) if len(d.properties.Html_dirs) > 0 { - htmlDir := d.properties.Html_dirs[0] - *implicits = append(*implicits, android.PathsForModuleSrc(ctx, []string{filepath.Join(d.properties.Html_dirs[0], "**/*")})...) - args = args + " -htmldir " + htmlDir + htmlDir := android.PathForModuleSrc(ctx, d.properties.Html_dirs[0]) + cmd.FlagWithArg("-htmldir ", htmlDir.String()). + Implicits(android.PathsForModuleSrc(ctx, []string{filepath.Join(d.properties.Html_dirs[0], "**/*")})) } if len(d.properties.Html_dirs) > 1 { - htmlDir2 := d.properties.Html_dirs[1] - *implicits = append(*implicits, android.PathsForModuleSrc(ctx, []string{filepath.Join(htmlDir2, "**/*")})...) - args = args + " -htmldir2 " + htmlDir2 + htmlDir2 := android.PathForModuleSrc(ctx, d.properties.Html_dirs[1]) + cmd.FlagWithArg("-htmldir2 ", htmlDir2.String()). + Implicits(android.PathsForModuleSrc(ctx, []string{filepath.Join(d.properties.Html_dirs[1], "**/*")})) } if len(d.properties.Html_dirs) > 2 { @@ -956,51 +773,43 @@ func (d *Droiddoc) collectDoclavaDocsFlags(ctx android.ModuleContext, implicits } knownTags := android.PathsForModuleSrc(ctx, d.properties.Knowntags) - *implicits = append(*implicits, knownTags...) + cmd.FlagForEachInput("-knowntags ", knownTags) - for _, kt := range knownTags { - args = args + " -knowntags " + kt.String() - } - - for _, hdf := range d.properties.Hdf { - args = args + " -hdf " + hdf - } + cmd.FlagForEachArg("-hdf ", d.properties.Hdf) if String(d.properties.Proofread_file) != "" { proofreadFile := android.PathForModuleOut(ctx, String(d.properties.Proofread_file)) - args = args + " -proofread " + proofreadFile.String() + cmd.FlagWithOutput("-proofread ", proofreadFile) } if String(d.properties.Todo_file) != "" { // tricky part: // we should not compute full path for todo_file through PathForModuleOut(). // the non-standard doclet will get the full path relative to "-o". - args = args + " -todo " + String(d.properties.Todo_file) + cmd.FlagWithArg("-todo ", String(d.properties.Todo_file)). + ImplicitOutput(android.PathForModuleOut(ctx, String(d.properties.Todo_file))) } if String(d.properties.Resourcesdir) != "" { // TODO: should we add files under resourcesDir to the implicits? It seems that // resourcesDir is one sub dir of htmlDir resourcesDir := android.PathForModuleSrc(ctx, String(d.properties.Resourcesdir)) - args = args + " -resourcesdir " + resourcesDir.String() + cmd.FlagWithArg("-resourcesdir ", resourcesDir.String()) } if String(d.properties.Resourcesoutdir) != "" { // TODO: it seems -resourceoutdir reference/android/images/ didn't get generated anywhere. - args = args + " -resourcesoutdir " + String(d.properties.Resourcesoutdir) + cmd.FlagWithArg("-resourcesoutdir ", String(d.properties.Resourcesoutdir)) } - return args } -func (d *Droiddoc) collectStubsFlags(ctx android.ModuleContext, - implicitOutputs *android.WritablePaths) string { - var doclavaFlags string +func (d *Droiddoc) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.WritablePath) { if apiCheckEnabled(d.properties.Check_api.Current, "current") || apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") || String(d.properties.Api_filename) != "" { + d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt") - doclavaFlags += " -api " + d.apiFile.String() - *implicitOutputs = append(*implicitOutputs, d.apiFile) + cmd.FlagWithOutput("-api ", d.apiFile) d.apiFilePath = d.apiFile } @@ -1008,223 +817,324 @@ func (d *Droiddoc) collectStubsFlags(ctx android.ModuleContext, apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") || String(d.properties.Removed_api_filename) != "" { d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt") - doclavaFlags += " -removedApi " + d.removedApiFile.String() - *implicitOutputs = append(*implicitOutputs, d.removedApiFile) + cmd.FlagWithOutput("-removedApi ", d.removedApiFile) } if String(d.properties.Private_api_filename) != "" { d.privateApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_api_filename)) - doclavaFlags += " -privateApi " + d.privateApiFile.String() - *implicitOutputs = append(*implicitOutputs, d.privateApiFile) + cmd.FlagWithOutput("-privateApi ", d.privateApiFile) } if String(d.properties.Dex_api_filename) != "" { d.dexApiFile = android.PathForModuleOut(ctx, String(d.properties.Dex_api_filename)) - doclavaFlags += " -dexApi " + d.dexApiFile.String() - *implicitOutputs = append(*implicitOutputs, d.dexApiFile) + cmd.FlagWithOutput("-dexApi ", d.dexApiFile) } if String(d.properties.Private_dex_api_filename) != "" { d.privateDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_dex_api_filename)) - doclavaFlags += " -privateDexApi " + d.privateDexApiFile.String() - *implicitOutputs = append(*implicitOutputs, d.privateDexApiFile) + cmd.FlagWithOutput("-privateDexApi ", d.privateDexApiFile) } if String(d.properties.Removed_dex_api_filename) != "" { d.removedDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Removed_dex_api_filename)) - doclavaFlags += " -removedDexApi " + d.removedDexApiFile.String() - *implicitOutputs = append(*implicitOutputs, d.removedDexApiFile) + cmd.FlagWithOutput("-removedDexApi ", d.removedDexApiFile) } if String(d.properties.Exact_api_filename) != "" { d.exactApiFile = android.PathForModuleOut(ctx, String(d.properties.Exact_api_filename)) - doclavaFlags += " -exactApi " + d.exactApiFile.String() - *implicitOutputs = append(*implicitOutputs, d.exactApiFile) + cmd.FlagWithOutput("-exactApi ", d.exactApiFile) } if String(d.properties.Dex_mapping_filename) != "" { d.apiMappingFile = android.PathForModuleOut(ctx, String(d.properties.Dex_mapping_filename)) - doclavaFlags += " -apiMapping " + d.apiMappingFile.String() - *implicitOutputs = append(*implicitOutputs, d.apiMappingFile) + cmd.FlagWithOutput("-apiMapping ", d.apiMappingFile) } if String(d.properties.Proguard_filename) != "" { d.proguardFile = android.PathForModuleOut(ctx, String(d.properties.Proguard_filename)) - doclavaFlags += " -proguard " + d.proguardFile.String() - *implicitOutputs = append(*implicitOutputs, d.proguardFile) + cmd.FlagWithOutput("-proguard ", d.proguardFile) } if BoolDefault(d.properties.Create_stubs, true) { - doclavaFlags += " -stubs " + android.PathForModuleOut(ctx, "stubsDir").String() + cmd.FlagWithArg("-stubs ", stubsDir.String()) } if Bool(d.properties.Write_sdk_values) { - doclavaFlags += " -sdkvalues " + android.PathForModuleOut(ctx, "out").String() + cmd.FlagWithArg("-sdkvalues ", android.PathForModuleOut(ctx, "out").String()) } - - return doclavaFlags } -func (d *Droiddoc) getPostDoclavaCmds(ctx android.ModuleContext, implicits *android.Paths) string { - var cmds string +func (d *Droiddoc) postDoclavaCmds(ctx android.ModuleContext, rule *android.RuleBuilder) { if String(d.properties.Static_doc_index_redirect) != "" { - static_doc_index_redirect := ctx.ExpandSource(String(d.properties.Static_doc_index_redirect), - "static_doc_index_redirect") - *implicits = append(*implicits, static_doc_index_redirect) - cmds = cmds + " && cp " + static_doc_index_redirect.String() + " " + - android.PathForModuleOut(ctx, "out", "index.html").String() + staticDocIndexRedirect := android.PathForModuleSrc(ctx, String(d.properties.Static_doc_index_redirect)) + rule.Command().Text("cp"). + Input(staticDocIndexRedirect). + Output(android.PathForModuleOut(ctx, "out", "index.html")) } if String(d.properties.Static_doc_properties) != "" { - static_doc_properties := ctx.ExpandSource(String(d.properties.Static_doc_properties), - "static_doc_properties") - *implicits = append(*implicits, static_doc_properties) - cmds = cmds + " && cp " + static_doc_properties.String() + " " + - android.PathForModuleOut(ctx, "out", "source.properties").String() + staticDocProperties := android.PathForModuleSrc(ctx, String(d.properties.Static_doc_properties)) + rule.Command().Text("cp"). + Input(staticDocProperties). + Output(android.PathForModuleOut(ctx, "out", "source.properties")) } - return cmds } -func (d *Droiddoc) transformDoclava(ctx android.ModuleContext, implicits android.Paths, - implicitOutputs android.WritablePaths, - bootclasspathArgs, classpathArgs, sourcepathArgs, opts, postDoclavaCmds string) { - ctx.Build(pctx, android.BuildParams{ - Rule: javadoc, - Description: "Doclava", - Output: d.Javadoc.stubsSrcJar, - Inputs: d.Javadoc.srcFiles, - Implicits: implicits, - ImplicitOutputs: implicitOutputs, - Args: map[string]string{ - "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": proptools.NinjaEscape(opts), - "bootclasspathArgs": bootclasspathArgs, - "classpathArgs": classpathArgs, - "sourcepathArgs": sourcepathArgs, - "docZip": d.Javadoc.docZip.String(), - "postDoclavaCmds": postDoclavaCmds, - }, - }) +func javadocCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths, + outDir, srcJarDir, srcJarList android.Path, sourcepaths android.Paths) *android.RuleBuilderCommand { + + cmd := rule.Command(). + BuiltTool(ctx, "soong_javac_wrapper").Tool(config.JavadocCmd(ctx)). + Flag(config.JavacVmFlags). + FlagWithArg("-encoding ", "UTF-8"). + FlagWithRspFileInputList("@", srcs). + FlagWithInput("@", srcJarList) + + // TODO(ccross): Remove this if- statement once we finish migration for all Doclava + // based stubs generation. + // In the future, all the docs generation depends on Metalava stubs (droidstubs) srcjar + // dir. We need add the srcjar dir to -sourcepath arg, so that Javadoc can figure out + // the correct package name base path. + if len(sourcepaths) > 0 { + cmd.FlagWithList("-sourcepath ", sourcepaths.Strings(), ":") + } else { + cmd.FlagWithArg("-sourcepath ", srcJarDir.String()) + } + + cmd.FlagWithArg("-d ", outDir.String()). + Flag("-quiet") + + return cmd } -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: "Doclava Check API", - Output: output, - Inputs: nil, - Implicits: append(android.Paths{apiFile, removedApiFile, d.apiFile, d.removedApiFile}, - checkApiClasspath...), - Args: map[string]string{ - "msg": msg, - "classpath": checkApiClasspath.FormJavaClassPath(""), - "opts": proptools.NinjaEscape(opts), - "apiFile": apiFile.String(), - "apiFileToCheck": d.apiFile.String(), - "removedApiFile": removedApiFile.String(), - "removedApiFileToCheck": d.removedApiFile.String(), - }, - }) +func javadocSystemModulesCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths, + outDir, srcJarDir, srcJarList android.Path, systemModules *systemModules, + classpath classpath, sourcepaths android.Paths) *android.RuleBuilderCommand { + + cmd := javadocCmd(ctx, rule, srcs, outDir, srcJarDir, srcJarList, sourcepaths) + + flag, deps := systemModules.FormJavaSystemModulesPath(ctx.Device()) + cmd.Flag(flag).Implicits(deps) + + cmd.FlagWithArg("--patch-module ", "java.base=.") + + if len(classpath) > 0 { + cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":") + } + + return cmd } -func (d *Droiddoc) transformDokka(ctx android.ModuleContext, implicits android.Paths, - classpathArgs, opts string) { - ctx.Build(pctx, android.BuildParams{ - Rule: dokka, - Description: "Dokka", - Output: d.Javadoc.stubsSrcJar, - Inputs: d.Javadoc.srcFiles, - Implicits: implicits, - Args: map[string]string{ - "outDir": android.PathForModuleOut(ctx, "dokka-out").String(), - "srcJarDir": android.PathForModuleOut(ctx, "dokka-srcjars").String(), - "stubsDir": android.PathForModuleOut(ctx, "dokka-stubsDir").String(), - "srcJars": strings.Join(d.Javadoc.srcJars.Strings(), " "), - "classpathArgs": classpathArgs, - "opts": proptools.NinjaEscape(opts), - "docZip": d.Javadoc.docZip.String(), - }, - }) +func javadocBootclasspathCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths, + outDir, srcJarDir, srcJarList android.Path, bootclasspath, classpath classpath, + sourcepaths android.Paths) *android.RuleBuilderCommand { + + cmd := javadocCmd(ctx, rule, srcs, outDir, srcJarDir, srcJarList, sourcepaths) + + if len(bootclasspath) == 0 && ctx.Device() { + // explicitly specify -bootclasspath "" if the bootclasspath is empty to + // ensure java does not fall back to the default bootclasspath. + cmd.FlagWithArg("-bootclasspath ", `""`) + } else if len(bootclasspath) > 0 { + cmd.FlagWithInputList("-bootclasspath ", bootclasspath.Paths(), ":") + } + + if len(classpath) > 0 { + cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":") + } + + return cmd +} + +func dokkaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, + outDir, srcJarDir android.Path, bootclasspath, classpath classpath) *android.RuleBuilderCommand { + + // Dokka doesn't support bootClasspath, so combine these two classpath vars for Dokka. + dokkaClasspath := append(bootclasspath.Paths(), classpath.Paths()...) + + return rule.Command(). + BuiltTool(ctx, "dokka"). + Flag(config.JavacVmFlags). + Flag(srcJarDir.String()). + FlagWithInputList("-classpath ", dokkaClasspath, ":"). + FlagWithArg("-format ", "dac"). + FlagWithArg("-dacRoot ", "/reference/kotlin"). + FlagWithArg("-output ", outDir.String()) } func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) { deps := d.Javadoc.collectDeps(ctx) + d.Javadoc.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip") + d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar") + 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...) - implicits = append(implicits, d.Javadoc.argFiles...) + outDir := android.PathForModuleOut(ctx, "out") + srcJarDir := android.PathForModuleOut(ctx, "srcjars") + stubsDir := android.PathForModuleOut(ctx, "stubsDir") - var implicitOutputs android.WritablePaths - implicitOutputs = append(implicitOutputs, d.Javadoc.docZip) - for _, o := range d.Javadoc.properties.Out { - implicitOutputs = append(implicitOutputs, android.PathForModuleGen(ctx, o)) - } + rule := android.NewRuleBuilder() - flags, err := d.initBuilderFlags(ctx, &implicits, deps) - if err != nil { - return - } + rule.Command().Text("rm -rf").Text(outDir.String()).Text(stubsDir.String()) + rule.Command().Text("mkdir -p").Text(outDir.String()).Text(stubsDir.String()) - flags.doclavaStubsFlags = d.collectStubsFlags(ctx, &implicitOutputs) + srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars) + + var cmd *android.RuleBuilderCommand if Bool(d.properties.Dokka_enabled) { - d.transformDokka(ctx, implicits, flags.classpathArgs, d.Javadoc.args) + cmd = dokkaCmd(ctx, rule, outDir, srcJarDir, deps.bootClasspath, deps.classpath) } else { - flags.doclavaDocsFlags = d.collectDoclavaDocsFlags(ctx, &implicits, jsilver, doclava) - flags.postDoclavaCmds = d.getPostDoclavaCmds(ctx, &implicits) - d.transformDoclava(ctx, implicits, implicitOutputs, flags.bootClasspathArgs, flags.classpathArgs, - flags.sourcepathArgs, flags.doclavaDocsFlags+flags.doclavaStubsFlags+" "+d.Javadoc.args, - flags.postDoclavaCmds) + cmd = javadocBootclasspathCmd(ctx, rule, d.Javadoc.srcFiles, outDir, srcJarDir, srcJarList, + deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths) } + d.stubsFlags(ctx, cmd, stubsDir) + + cmd.Flag(d.Javadoc.args).Implicits(d.Javadoc.argFiles) + + var desc string + if Bool(d.properties.Dokka_enabled) { + desc = "dokka" + } else { + d.doclavaDocsFlags(ctx, cmd, classpath{jsilver, doclava}) + + for _, o := range d.Javadoc.properties.Out { + cmd.ImplicitOutput(android.PathForModuleGen(ctx, o)) + } + + d.postDoclavaCmds(ctx, rule) + desc = "doclava" + } + + rule.Command(). + BuiltTool(ctx, "soong_zip"). + Flag("-write_if_changed"). + Flag("-d"). + FlagWithOutput("-o ", d.docZip). + FlagWithArg("-C ", outDir.String()). + FlagWithArg("-D ", outDir.String()) + + rule.Command(). + BuiltTool(ctx, "soong_zip"). + Flag("-write_if_changed"). + Flag("-jar"). + FlagWithOutput("-o ", d.stubsSrcJar). + FlagWithArg("-C ", stubsDir.String()). + FlagWithArg("-D ", stubsDir.String()) + + rule.Restat() + + zipSyncCleanupCmd(rule, srcJarDir) + + rule.Build(pctx, ctx, "javadoc", desc) + if apiCheckEnabled(d.properties.Check_api.Current, "current") && !ctx.Config().IsPdkBuild() { - 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") + + apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file)) + removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file)) d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "check_current_api.timestamp") - 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) + + rule := android.NewRuleBuilder() + + rule.Command().Text("( true") + + rule.Command(). + BuiltTool(ctx, "apicheck"). + Flag("-JXmx1024m"). + FlagWithInputList("-Jclasspath\\ ", checkApiClasspath.Paths(), ":"). + OptionalFlag(d.properties.Check_api.Current.Args). + Input(apiFile). + Input(d.apiFile). + Input(removedApiFile). + Input(d.removedApiFile) + + 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()) + + rule.Command(). + Text("touch").Output(d.checkCurrentApiTimestamp). + Text(") || ("). + Text("echo").Flag("-e").Flag(`"` + msg + `"`). + Text("; exit 38"). + Text(")") + + rule.Build(pctx, ctx, "doclavaCurrentApiCheck", "check current API") d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "update_current_api.timestamp") - transformUpdateApi(ctx, apiFile, removedApiFile, d.apiFile, d.removedApiFile, - d.updateCurrentApiTimestamp) + + // update API rule + rule = android.NewRuleBuilder() + + rule.Command().Text("( true") + + rule.Command(). + Text("cp").Flag("-f"). + Input(d.apiFile).Flag(apiFile.String()) + + rule.Command(). + Text("cp").Flag("-f"). + Input(d.removedApiFile).Flag(removedApiFile.String()) + + msg = "failed to update public API" + + rule.Command(). + Text("touch").Output(d.updateCurrentApiTimestamp). + Text(") || ("). + Text("echo").Flag("-e").Flag(`"` + msg + `"`). + Text("; exit 38"). + Text(")") + + rule.Build(pctx, ctx, "doclavaCurrentApiUpdate", "update current API") } if apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") && !ctx.Config().IsPdkBuild() { - apiFile := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Api_file), - "check_api.last_released.api_file") - removedApiFile := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Removed_api_file), - "check_api.last_released.removed_api_file") + + apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file)) + removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file)) d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "check_last_released_api.timestamp") - 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`, String(d.properties.Check_api.Last_released.Args), - d.checkLastReleasedApiTimestamp) + + rule := android.NewRuleBuilder() + + rule.Command(). + Text("("). + BuiltTool(ctx, "apicheck"). + Flag("-JXmx1024m"). + FlagWithInputList("-Jclasspath\\ ", checkApiClasspath.Paths(), ":"). + OptionalFlag(d.properties.Check_api.Last_released.Args). + Input(apiFile). + Input(d.apiFile). + Input(removedApiFile). + Input(d.removedApiFile) + + msg := `\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` + + rule.Command(). + Text("touch").Output(d.checkLastReleasedApiTimestamp). + Text(") || ("). + Text("echo").Flag("-e").Flag(`"` + msg + `"`). + Text("; exit 38"). + Text(")") + + rule.Build(pctx, ctx, "doclavaLastApiCheck", "check last API") } } @@ -1320,34 +1230,12 @@ func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) { } } -func (d *Droidstubs) initBuilderFlags(ctx android.ModuleContext, implicits *android.Paths, - deps deps) (droiddocBuilderFlags, error) { - var flags droiddocBuilderFlags - - *implicits = append(*implicits, deps.bootClasspath...) - *implicits = append(*implicits, deps.classpath...) - - // continue to use -bootclasspath even if Metalava under -source 1.9 is enabled - // since it doesn't support system modules yet. - if len(deps.bootClasspath.Strings()) > 0 { - // For OpenJDK 8 we can use -bootclasspath to define the core libraries code. - flags.bootClasspathArgs = deps.bootClasspath.FormJavaClassPath("-bootclasspath") - } - flags.classpathArgs = deps.classpath.FormJavaClassPath("-classpath") - - flags.sourcepathArgs = "-sourcepath \"" + strings.Join(d.Javadoc.sourcepaths.Strings(), ":") + "\"" - return flags, nil -} - -func (d *Droidstubs) collectStubsFlags(ctx android.ModuleContext, - implicitOutputs *android.WritablePaths) string { - var metalavaFlags string +func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.WritablePath) { if apiCheckEnabled(d.properties.Check_api.Current, "current") || apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") || String(d.properties.Api_filename) != "" { d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt") - metalavaFlags = metalavaFlags + " --api " + d.apiFile.String() - *implicitOutputs = append(*implicitOutputs, d.apiFile) + cmd.FlagWithOutput("--api ", d.apiFile) d.apiFilePath = d.apiFile } @@ -1355,159 +1243,144 @@ func (d *Droidstubs) collectStubsFlags(ctx android.ModuleContext, apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") || String(d.properties.Removed_api_filename) != "" { d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt") - metalavaFlags = metalavaFlags + " --removed-api " + d.removedApiFile.String() - *implicitOutputs = append(*implicitOutputs, d.removedApiFile) + cmd.FlagWithOutput("--removed-api ", d.removedApiFile) } if String(d.properties.Private_api_filename) != "" { d.privateApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_api_filename)) - metalavaFlags = metalavaFlags + " --private-api " + d.privateApiFile.String() - *implicitOutputs = append(*implicitOutputs, d.privateApiFile) + cmd.FlagWithOutput("--private-api ", d.privateApiFile) } if String(d.properties.Dex_api_filename) != "" { d.dexApiFile = android.PathForModuleOut(ctx, String(d.properties.Dex_api_filename)) - metalavaFlags += " --dex-api " + d.dexApiFile.String() - *implicitOutputs = append(*implicitOutputs, d.dexApiFile) + cmd.FlagWithOutput("--dex-api ", d.dexApiFile) } if String(d.properties.Private_dex_api_filename) != "" { d.privateDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_dex_api_filename)) - metalavaFlags = metalavaFlags + " --private-dex-api " + d.privateDexApiFile.String() - *implicitOutputs = append(*implicitOutputs, d.privateDexApiFile) + cmd.FlagWithOutput("--private-dex-api ", d.privateDexApiFile) } if String(d.properties.Removed_dex_api_filename) != "" { d.removedDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Removed_dex_api_filename)) - metalavaFlags = metalavaFlags + " --removed-dex-api " + d.removedDexApiFile.String() - *implicitOutputs = append(*implicitOutputs, d.removedDexApiFile) + cmd.FlagWithOutput("--removed-dex-api ", d.removedDexApiFile) } if String(d.properties.Exact_api_filename) != "" { d.exactApiFile = android.PathForModuleOut(ctx, String(d.properties.Exact_api_filename)) - metalavaFlags = metalavaFlags + " --exact-api " + d.exactApiFile.String() - *implicitOutputs = append(*implicitOutputs, d.exactApiFile) + cmd.FlagWithOutput("--exact-api ", d.exactApiFile) } if String(d.properties.Dex_mapping_filename) != "" { d.apiMappingFile = android.PathForModuleOut(ctx, String(d.properties.Dex_mapping_filename)) - metalavaFlags = metalavaFlags + " --dex-api-mapping " + d.apiMappingFile.String() - *implicitOutputs = append(*implicitOutputs, d.apiMappingFile) + cmd.FlagWithOutput("--dex-api-mapping ", d.apiMappingFile) } if String(d.properties.Proguard_filename) != "" { d.proguardFile = android.PathForModuleOut(ctx, String(d.properties.Proguard_filename)) - metalavaFlags += " --proguard " + d.proguardFile.String() - *implicitOutputs = append(*implicitOutputs, d.proguardFile) + cmd.FlagWithOutput("--proguard ", d.proguardFile) } if Bool(d.properties.Write_sdk_values) { - metalavaFlags = metalavaFlags + " --sdk-values " + android.PathForModuleOut(ctx, "out").String() + cmd.FlagWithArg("--sdk-values ", android.PathForModuleOut(ctx, "out").String()) } if Bool(d.properties.Create_doc_stubs) { - metalavaFlags += " --doc-stubs " + android.PathForModuleOut(ctx, "stubsDir").String() + cmd.FlagWithArg("--doc-stubs ", stubsDir.String()) } else { - metalavaFlags += " --stubs " + android.PathForModuleOut(ctx, "stubsDir").String() + cmd.FlagWithArg("--stubs ", stubsDir.String()) } - return metalavaFlags } -func (d *Droidstubs) collectAnnotationsFlags(ctx android.ModuleContext, - implicits *android.Paths, implicitOutputs *android.WritablePaths) (string, string) { - var flags, mergeAnnoDirFlags string +func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { if Bool(d.properties.Annotations_enabled) { - flags += " --include-annotations" + cmd.Flag("--include-annotations") + validatingNullability := strings.Contains(d.Javadoc.args, "--validate-nullability-from-merged-stubs") || String(d.properties.Validate_nullability_from_list) != "" migratingNullability := String(d.properties.Previous_api) != "" + if !(migratingNullability || validatingNullability) { ctx.PropertyErrorf("previous_api", "has to be non-empty if annotations was enabled (unless validating nullability)") } + if migratingNullability { previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api)) - *implicits = append(*implicits, previousApi) - flags += " --migrate-nullness " + previousApi.String() + cmd.FlagWithInput("--migrate-nullness ", previousApi) } + if s := String(d.properties.Validate_nullability_from_list); s != "" { - flags += " --validate-nullability-from-list " + android.PathForModuleSrc(ctx, s).String() + cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s)) } + if validatingNullability { d.nullabilityWarningsFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_nullability_warnings.txt") - *implicitOutputs = append(*implicitOutputs, d.nullabilityWarningsFile) - flags += " --nullability-warnings-txt " + d.nullabilityWarningsFile.String() + cmd.FlagWithOutput("--nullability-warnings-txt ", d.nullabilityWarningsFile) } d.annotationsZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"_annotations.zip") - *implicitOutputs = append(*implicitOutputs, d.annotationsZip) - - flags += " --extract-annotations " + d.annotationsZip.String() + cmd.FlagWithOutput("--extract-annotations ", d.annotationsZip) if len(d.properties.Merge_annotations_dirs) == 0 { ctx.PropertyErrorf("merge_annotations_dirs", "has to be non-empty if annotations was enabled!") } - ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) { - if t, ok := m.(*ExportedDroiddocDir); ok { - *implicits = append(*implicits, t.deps...) - mergeAnnoDirFlags += " --merge-qualifier-annotations " + t.dir.String() - } else { - ctx.PropertyErrorf("merge_annotations_dirs", - "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m)) - } - }) - flags += mergeAnnoDirFlags - // TODO(tnorbye): find owners to fix these warnings when annotation was enabled. - flags += " --hide HiddenTypedefConstant --hide SuperfluousPrefix --hide AnnotationExtraction" - } - return flags, mergeAnnoDirFlags + d.mergeAnnoDirFlags(ctx, cmd) + + // TODO(tnorbye): find owners to fix these warnings when annotation was enabled. + cmd.FlagWithArg("--hide ", "HiddenTypedefConstant"). + FlagWithArg("--hide ", "SuperfluousPrefix"). + FlagWithArg("--hide ", "AnnotationExtraction") + } } -func (d *Droidstubs) collectInclusionAnnotationsFlags(ctx android.ModuleContext, - implicits *android.Paths, implicitOutputs *android.WritablePaths) string { - var flags string +func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { + ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) { + if t, ok := m.(*ExportedDroiddocDir); ok { + cmd.FlagWithArg("--merge-qualifier-annotations ", t.dir.String()).Implicits(t.deps) + } else { + ctx.PropertyErrorf("merge_annotations_dirs", + "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m)) + } + }) +} + +func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { ctx.VisitDirectDepsWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.Module) { if t, ok := m.(*ExportedDroiddocDir); ok { - *implicits = append(*implicits, t.deps...) - flags += " --merge-inclusion-annotations " + t.dir.String() + cmd.FlagWithArg("--merge-inclusion-annotations ", t.dir.String()).Implicits(t.deps) } else { ctx.PropertyErrorf("merge_inclusion_annotations_dirs", "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m)) } }) - - return flags } -func (d *Droidstubs) collectAPILevelsAnnotationsFlags(ctx android.ModuleContext, - implicits *android.Paths, implicitOutputs *android.WritablePaths) string { - var flags string +func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { if Bool(d.properties.Api_levels_annotations_enabled) { d.apiVersionsXml = android.PathForModuleOut(ctx, "api-versions.xml") - *implicitOutputs = append(*implicitOutputs, d.apiVersionsXml) if len(d.properties.Api_levels_annotations_dirs) == 0 { ctx.PropertyErrorf("api_levels_annotations_dirs", "has to be non-empty if api levels annotations was enabled!") } - flags = " --generate-api-levels " + d.apiVersionsXml.String() + " --apply-api-levels " + - d.apiVersionsXml.String() + " --current-version " + ctx.Config().PlatformSdkVersion() + - " --current-codename " + ctx.Config().PlatformSdkCodename() + " " + cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml) + cmd.FlagWithInput("--apply-api-levels ", d.apiVersionsXml) + cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion()) + cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename()) ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) { if t, ok := m.(*ExportedDroiddocDir); ok { - var androidJars android.Paths for _, dep := range t.deps { if strings.HasSuffix(dep.String(), "android.jar") { - androidJars = append(androidJars, dep) + cmd.Implicit(dep) } } - *implicits = append(*implicits, androidJars...) - flags += " --android-jar-pattern " + t.dir.String() + "/%/public/android.jar " + cmd.FlagWithArg("--android-jar-pattern ", t.dir.String()+"/%/public/android.jar") } else { ctx.PropertyErrorf("api_levels_annotations_dirs", "module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m)) @@ -1515,112 +1388,57 @@ func (d *Droidstubs) collectAPILevelsAnnotationsFlags(ctx android.ModuleContext, }) } - - return flags } -func (d *Droidstubs) collectApiToXmlFlags(ctx android.ModuleContext, implicits *android.Paths, - implicitOutputs *android.WritablePaths) string { - var flags string +func (d *Droidstubs) apiToXmlFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() { if d.apiFile.String() == "" { ctx.ModuleErrorf("API signature file has to be specified in Metalava when jdiff is enabled.") } d.apiXmlFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.xml") - *implicitOutputs = append(*implicitOutputs, d.apiXmlFile) - - flags = " --api-xml " + d.apiXmlFile.String() + cmd.FlagWithOutput("--api-xml ", d.apiXmlFile) if String(d.properties.Check_api.Last_released.Api_file) == "" { ctx.PropertyErrorf("check_api.last_released.api_file", "has to be non-empty if jdiff was enabled!") } - lastReleasedApi := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Api_file), - "check_api.last_released.api_file") - *implicits = append(*implicits, lastReleasedApi) + lastReleasedApi := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file)) d.lastReleasedApiXmlFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_last_released_api.xml") - *implicitOutputs = append(*implicitOutputs, d.lastReleasedApiXmlFile) + cmd.FlagWithInput("--convert-to-jdiff ", lastReleasedApi).Output(d.lastReleasedApiXmlFile) + } +} - flags += " --convert-to-jdiff " + lastReleasedApi.String() + " " + - d.lastReleasedApiXmlFile.String() +func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion string, srcs android.Paths, + srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths) *android.RuleBuilderCommand { + cmd := rule.Command().BuiltTool(ctx, "metalava"). + Flag(config.JavacVmFlags). + FlagWithArg("-encoding ", "UTF-8"). + FlagWithArg("-source ", javaVersion). + FlagWithRspFileInputList("@", srcs). + FlagWithInput("@", srcJarList) + + if len(bootclasspath) > 0 { + cmd.FlagWithInputList("-bootclasspath ", bootclasspath.Paths(), ":") } - return flags -} + if len(classpath) > 0 { + cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":") + } -func (d *Droidstubs) transformMetalava(ctx android.ModuleContext, implicits android.Paths, - implicitOutputs android.WritablePaths, javaVersion, - bootclasspathArgs, classpathArgs, sourcepathArgs, opts string) { + if len(sourcepaths) > 0 { + cmd.FlagWithList("-sourcepath ", sourcepaths.Strings(), ":") + } else { + cmd.FlagWithArg("-sourcepath ", `""`) + } - ctx.Build(pctx, android.BuildParams{ - Rule: metalava, - Description: "Metalava", - Output: d.Javadoc.stubsSrcJar, - Inputs: d.Javadoc.srcFiles, - Implicits: implicits, - ImplicitOutputs: implicitOutputs, - Args: map[string]string{ - "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(), " "), - "javaVersion": javaVersion, - "bootclasspathArgs": bootclasspathArgs, - "classpathArgs": classpathArgs, - "sourcepathArgs": sourcepathArgs, - "opts": proptools.NinjaEscape(opts), - }, - }) -} + cmd.Flag("--no-banner"). + Flag("--color"). + Flag("--quiet"). + Flag("--format=v2") -func (d *Droidstubs) transformCheckApi(ctx android.ModuleContext, - apiFile, removedApiFile android.Path, implicits android.Paths, - javaVersion, bootclasspathArgs, classpathArgs, sourcepathArgs, opts, subdir, msg string, - output android.WritablePath) { - ctx.Build(pctx, android.BuildParams{ - Rule: metalavaApiCheck, - Description: "Metalava Check API", - Output: output, - Inputs: d.Javadoc.srcFiles, - Implicits: append(android.Paths{apiFile, removedApiFile, d.apiFile, d.removedApiFile}, - implicits...), - Args: map[string]string{ - "srcJarDir": android.PathForModuleOut(ctx, subdir, "srcjars").String(), - "srcJars": strings.Join(d.Javadoc.srcJars.Strings(), " "), - "javaVersion": javaVersion, - "bootclasspathArgs": bootclasspathArgs, - "classpathArgs": classpathArgs, - "sourcepathArgs": sourcepathArgs, - "opts": proptools.NinjaEscape(opts), - "msg": msg, - }, - }) -} - -func (d *Droidstubs) transformJdiff(ctx android.ModuleContext, implicits android.Paths, - implicitOutputs android.WritablePaths, - bootclasspathArgs, classpathArgs, sourcepathArgs, opts string) { - ctx.Build(pctx, android.BuildParams{ - Rule: javadoc, - Description: "Jdiff", - Output: d.jdiffStubsSrcJar, - Inputs: d.Javadoc.srcFiles, - Implicits: implicits, - ImplicitOutputs: implicitOutputs, - Args: map[string]string{ - "outDir": android.PathForModuleOut(ctx, "jdiff-out").String(), - "srcJarDir": android.PathForModuleOut(ctx, "jdiff-srcjars").String(), - "stubsDir": android.PathForModuleOut(ctx, "jdiff-stubsDir").String(), - "srcJars": strings.Join(d.Javadoc.srcJars.Strings(), " "), - "opts": proptools.NinjaEscape(opts), - "bootclasspathArgs": bootclasspathArgs, - "classpathArgs": classpathArgs, - "sourcepathArgs": sourcepathArgs, - "docZip": d.jdiffDocZip.String(), - }, - }) + return cmd } func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -1628,29 +1446,29 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), sdkContext(d)) - var implicits android.Paths - implicits = append(implicits, d.Javadoc.srcJars...) - implicits = append(implicits, d.Javadoc.argFiles...) + // Create rule for metalava - var implicitOutputs android.WritablePaths - for _, o := range d.Javadoc.properties.Out { - implicitOutputs = append(implicitOutputs, android.PathForModuleGen(ctx, o)) - } + d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar") - flags, err := d.initBuilderFlags(ctx, &implicits, deps) - metalavaCheckApiImplicits := implicits - jdiffImplicits := implicits + srcJarDir := android.PathForModuleOut(ctx, "srcjars") + stubsDir := android.PathForModuleOut(ctx, "stubsDir") - if err != nil { - return - } + rule := android.NewRuleBuilder() - flags.metalavaStubsFlags = d.collectStubsFlags(ctx, &implicitOutputs) - flags.metalavaAnnotationsFlags, flags.metalavaMergeAnnoDirFlags = - d.collectAnnotationsFlags(ctx, &implicits, &implicitOutputs) - flags.metalavaInclusionAnnotationsFlags = d.collectInclusionAnnotationsFlags(ctx, &implicits, &implicitOutputs) - flags.metalavaApiLevelsAnnotationsFlags = d.collectAPILevelsAnnotationsFlags(ctx, &implicits, &implicitOutputs) - flags.metalavaApiToXmlFlags = d.collectApiToXmlFlags(ctx, &implicits, &implicitOutputs) + rule.Command().Text("rm -rf").Text(stubsDir.String()) + rule.Command().Text("mkdir -p").Text(stubsDir.String()) + + srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars) + + cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList, + deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths) + + d.stubsFlags(ctx, cmd, stubsDir) + + d.annotationsFlags(ctx, cmd) + d.inclusionAnnotationsFlags(ctx, cmd) + d.apiLevelsAnnotationsFlags(ctx, cmd) + d.apiToXmlFlags(ctx, cmd) if strings.Contains(d.Javadoc.args, "--generate-documentation") { // Currently Metalava have the ability to invoke Javadoc in a seperate process. @@ -1658,61 +1476,150 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { // "--generate-documentation" arg. This is not needed when Metalava removes this feature. d.Javadoc.args = d.Javadoc.args + " -nodocs " } - d.transformMetalava(ctx, implicits, implicitOutputs, javaVersion, - flags.bootClasspathArgs, flags.classpathArgs, flags.sourcepathArgs, - flags.metalavaStubsFlags+flags.metalavaAnnotationsFlags+flags.metalavaInclusionAnnotationsFlags+ - flags.metalavaApiLevelsAnnotationsFlags+flags.metalavaApiToXmlFlags+" "+d.Javadoc.args) + + cmd.Flag(d.Javadoc.args).Implicits(d.Javadoc.argFiles) + for _, o := range d.Javadoc.properties.Out { + cmd.ImplicitOutput(android.PathForModuleGen(ctx, o)) + } + + rule.Command(). + BuiltTool(ctx, "soong_zip"). + Flag("-write_if_changed"). + Flag("-jar"). + FlagWithOutput("-o ", d.Javadoc.stubsSrcJar). + FlagWithArg("-C ", stubsDir.String()). + FlagWithArg("-D ", stubsDir.String()) + rule.Restat() + + zipSyncCleanupCmd(rule, srcJarDir) + + rule.Build(pctx, ctx, "metalava", "metalava") + + // Create rule for apicheck if apiCheckEnabled(d.properties.Check_api.Current, "current") && !ctx.Config().IsPdkBuild() { - 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") + + if len(d.Javadoc.properties.Out) > 0 { + ctx.PropertyErrorf("out", "out property may not be combined with check_api") + } + + apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file)) + removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file)) d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "check_current_api.timestamp") - opts := " " + d.Javadoc.args + " --check-compatibility:api:current " + apiFile.String() + - " --check-compatibility:removed:current " + removedApiFile.String() + - flags.metalavaInclusionAnnotationsFlags + flags.metalavaMergeAnnoDirFlags + " " - d.transformCheckApi(ctx, apiFile, removedApiFile, metalavaCheckApiImplicits, - javaVersion, flags.bootClasspathArgs, flags.classpathArgs, flags.sourcepathArgs, opts, "current-apicheck", - 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()), - d.checkCurrentApiTimestamp) + rule := android.NewRuleBuilder() + + rule.Command().Text("( true") + + srcJarDir := android.PathForModuleOut(ctx, "current-apicheck", "srcjars") + srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars) + + cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList, + deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths) + + cmd.Flag(d.Javadoc.args).Implicits(d.Javadoc.argFiles). + FlagWithInput("--check-compatibility:api:current ", apiFile). + FlagWithInput("--check-compatibility:removed:current ", removedApiFile) + + d.inclusionAnnotationsFlags(ctx, cmd) + d.mergeAnnoDirFlags(ctx, cmd) + + zipSyncCleanupCmd(rule, srcJarDir) + + 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()) + + rule.Command(). + Text("touch").Output(d.checkCurrentApiTimestamp). + Text(") || ("). + Text("echo").Flag("-e").Flag(`"` + msg + `"`). + Text("; exit 38"). + Text(")") + + rule.Build(pctx, ctx, "metalavaCurrentApiCheck", "metalava check current API") d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "update_current_api.timestamp") - transformUpdateApi(ctx, apiFile, removedApiFile, d.apiFile, d.removedApiFile, - d.updateCurrentApiTimestamp) + + // update API rule + rule = android.NewRuleBuilder() + + rule.Command().Text("( true") + + rule.Command(). + Text("cp").Flag("-f"). + Input(d.apiFile).Flag(apiFile.String()) + + rule.Command(). + Text("cp").Flag("-f"). + Input(d.removedApiFile).Flag(removedApiFile.String()) + + msg = "failed to update public API" + + rule.Command(). + Text("touch").Output(d.updateCurrentApiTimestamp). + Text(") || ("). + Text("echo").Flag("-e").Flag(`"` + msg + `"`). + Text("; exit 38"). + Text(")") + + rule.Build(pctx, ctx, "metalavaCurrentApiUpdate", "update current API") } if apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") && !ctx.Config().IsPdkBuild() { - apiFile := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Api_file), - "check_api.last_released.api_file") - removedApiFile := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Removed_api_file), - "check_api.last_released.removed_api_file") + + if len(d.Javadoc.properties.Out) > 0 { + ctx.PropertyErrorf("out", "out property may not be combined with check_api") + } + + apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file)) + removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file)) d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "check_last_released_api.timestamp") - opts := " " + d.Javadoc.args + " --check-compatibility:api:released " + apiFile.String() + - flags.metalavaInclusionAnnotationsFlags + " --check-compatibility:removed:released " + - removedApiFile.String() + flags.metalavaMergeAnnoDirFlags + " " - d.transformCheckApi(ctx, apiFile, removedApiFile, metalavaCheckApiImplicits, - javaVersion, flags.bootClasspathArgs, flags.classpathArgs, flags.sourcepathArgs, opts, "last-apicheck", - `\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`, - d.checkLastReleasedApiTimestamp) + rule := android.NewRuleBuilder() + + rule.Command().Text("( true") + + srcJarDir := android.PathForModuleOut(ctx, "last-apicheck", "srcjars") + srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars) + + cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList, + deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths) + + cmd.Flag(d.Javadoc.args).Implicits(d.Javadoc.argFiles). + FlagWithInput("--check-compatibility:api:released ", apiFile) + + d.inclusionAnnotationsFlags(ctx, cmd) + + cmd.FlagWithInput("--check-compatibility:removed:released ", removedApiFile) + + d.mergeAnnoDirFlags(ctx, cmd) + + zipSyncCleanupCmd(rule, srcJarDir) + + msg := `\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` + rule.Command(). + Text("touch").Output(d.checkLastReleasedApiTimestamp). + Text(") || ("). + Text("echo").Flag("-e").Flag(`"` + msg + `"`). + Text("; exit 38"). + Text(")") + + rule.Build(pctx, ctx, "metalavaLastApiCheck", "metalava check last API") } if String(d.properties.Check_nullability_warnings) != "" { @@ -1720,9 +1627,11 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.PropertyErrorf("check_nullability_warnings", "Cannot specify check_nullability_warnings unless validating nullability") } - checkNullabilityWarnings := ctx.ExpandSource(String(d.properties.Check_nullability_warnings), - "check_nullability_warnings") + + checkNullabilityWarnings := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings)) + d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, "check_nullability_warnings.timestamp") + msg := fmt.Sprintf(`\n******************************\n`+ `The warnings encountered during nullability annotation validation did\n`+ `not match the checked in file of expected warnings. The diffs are shown\n`+ @@ -1732,20 +1641,32 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { ` cp %s %s\n`+ ` and submitting the updated file as part of your change.`, d.nullabilityWarningsFile, checkNullabilityWarnings) - ctx.Build(pctx, android.BuildParams{ - Rule: nullabilityWarningsCheck, - Description: "Nullability Warnings Check", - Output: d.checkNullabilityWarningsTimestamp, - Implicits: android.Paths{checkNullabilityWarnings, d.nullabilityWarningsFile}, - Args: map[string]string{ - "expected": checkNullabilityWarnings.String(), - "actual": d.nullabilityWarningsFile.String(), - "msg": msg, - }, - }) + + rule := android.NewRuleBuilder() + + rule.Command(). + Text("("). + Text("diff").Input(checkNullabilityWarnings).Input(d.nullabilityWarningsFile). + Text("&&"). + Text("touch").Output(d.checkNullabilityWarningsTimestamp). + Text(") || ("). + Text("echo").Flag("-e").Flag(`"` + msg + `"`). + Text("; exit 38"). + Text(")") + + rule.Build(pctx, ctx, "nullabilityWarningsCheck", "nullability warnings check") } if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() { + if len(d.Javadoc.properties.Out) > 0 { + ctx.PropertyErrorf("out", "out property may not be combined with jdiff") + } + + outDir := android.PathForModuleOut(ctx, "jdiff-out") + srcJarDir := android.PathForModuleOut(ctx, "jdiff-srcjars") + stubsDir := android.PathForModuleOut(ctx, "jdiff-stubsDir") + + rule := android.NewRuleBuilder() // Please sync with android-api-council@ before making any changes for the name of jdiffDocZip below // since there's cron job downstream that fetch this .zip file periodically. @@ -1753,21 +1674,49 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { d.jdiffDocZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"jdiff-docs.zip") d.jdiffStubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"jdiff-stubs.srcjar") - var jdiffImplicitOutputs android.WritablePaths - jdiffImplicitOutputs = append(jdiffImplicitOutputs, d.jdiffDocZip) - jdiff := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "jdiff.jar") - jdiffImplicits = append(jdiffImplicits, android.Paths{jdiff, d.apiXmlFile, d.lastReleasedApiXmlFile}...) - opts := " -source 1.8 -J-Xmx1600m -XDignore.symbol.file " + - "-doclet jdiff.JDiff -docletpath " + jdiff.String() + " -quiet " + - "-newapi " + strings.TrimSuffix(d.apiXmlFile.Base(), d.apiXmlFile.Ext()) + - " -newapidir " + filepath.Dir(d.apiXmlFile.String()) + - " -oldapi " + strings.TrimSuffix(d.lastReleasedApiXmlFile.Base(), d.lastReleasedApiXmlFile.Ext()) + - " -oldapidir " + filepath.Dir(d.lastReleasedApiXmlFile.String()) + rule.Command().Text("rm -rf").Text(outDir.String()).Text(stubsDir.String()) + rule.Command().Text("mkdir -p").Text(outDir.String()).Text(stubsDir.String()) - d.transformJdiff(ctx, jdiffImplicits, jdiffImplicitOutputs, flags.bootClasspathArgs, flags.classpathArgs, - flags.sourcepathArgs, opts) + srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars) + + cmd := javadocBootclasspathCmd(ctx, rule, d.Javadoc.srcFiles, outDir, srcJarDir, srcJarList, + deps.bootClasspath, deps.classpath, d.sourcepaths) + + cmd.Flag("-J-Xmx1600m"). + Flag("-XDignore.symbol.file"). + FlagWithArg("-doclet ", "jdiff.JDiff"). + FlagWithInput("-docletpath ", jdiff). + Flag("-quiet"). + FlagWithArg("-newapi ", strings.TrimSuffix(d.apiXmlFile.Base(), d.apiXmlFile.Ext())). + FlagWithArg("-newapidir ", filepath.Dir(d.apiXmlFile.String())). + Implicit(d.apiXmlFile). + FlagWithArg("-oldapi ", strings.TrimSuffix(d.lastReleasedApiXmlFile.Base(), d.lastReleasedApiXmlFile.Ext())). + FlagWithArg("-oldapidir ", filepath.Dir(d.lastReleasedApiXmlFile.String())). + Implicit(d.lastReleasedApiXmlFile) + + rule.Command(). + BuiltTool(ctx, "soong_zip"). + Flag("-write_if_changed"). + Flag("-d"). + FlagWithOutput("-o ", d.jdiffDocZip). + FlagWithArg("-C ", outDir.String()). + FlagWithArg("-D ", outDir.String()) + + rule.Command(). + BuiltTool(ctx, "soong_zip"). + Flag("-write_if_changed"). + Flag("-jar"). + FlagWithOutput("-o ", d.jdiffStubsSrcJar). + FlagWithArg("-C ", stubsDir.String()). + FlagWithArg("-D ", stubsDir.String()) + + rule.Restat() + + zipSyncCleanupCmd(rule, srcJarDir) + + rule.Build(pctx, ctx, "jdiff", "jdiff") } } @@ -1842,3 +1791,25 @@ func StubsDefaultsFactory() android.Module { return module } + +func zipSyncCmd(ctx android.ModuleContext, rule *android.RuleBuilder, + srcJarDir android.ModuleOutPath, srcJars android.Paths) android.OutputPath { + + rule.Command().Text("rm -rf").Text(srcJarDir.String()) + rule.Command().Text("mkdir -p").Text(srcJarDir.String()) + srcJarList := srcJarDir.Join(ctx, "list") + + rule.Temporary(srcJarList) + + rule.Command().BuiltTool(ctx, "zipsync"). + FlagWithArg("-d ", srcJarDir.String()). + FlagWithOutput("-l ", srcJarList). + FlagWithArg("-f ", `"*.java"`). + Inputs(srcJars) + + return srcJarList +} + +func zipSyncCleanupCmd(rule *android.RuleBuilder, srcJarDir android.ModuleOutPath) { + rule.Command().Text("rm -rf").Text(srcJarDir.String()) +} diff --git a/java/java.go b/java/java.go index a49aad775..f3e10bebd 100644 --- a/java/java.go +++ b/java/java.go @@ -632,8 +632,7 @@ type deps struct { aidlIncludeDirs android.Paths srcs android.Paths srcJars android.Paths - systemModules android.Path - systemModulesDeps android.Paths + systemModules *systemModules aidlPreprocess android.OptionalPath kotlinStdlib android.Paths kotlinAnnotations android.Paths @@ -844,8 +843,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { if sm.outputDir == nil || len(sm.outputDeps) == 0 { panic("Missing directory for system module dependency") } - deps.systemModules = sm.outputDir - deps.systemModulesDeps = sm.outputDeps + deps.systemModules = &systemModules{sm.outputDir, sm.outputDeps} } } }) @@ -973,10 +971,7 @@ func (j *Module) collectBuilderFlags(ctx android.ModuleContext, deps deps) javaB } // systemModules - if deps.systemModules != nil { - flags.systemModules = append(flags.systemModules, deps.systemModules) - flags.systemModulesDeps = append(flags.systemModulesDeps, deps.systemModulesDeps...) - } + flags.systemModules = deps.systemModules // aidl flags. flags.aidlFlags, flags.aidlDeps = j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs) diff --git a/java/java_test.go b/java/java_test.go index 4c85bed99..f95f88bb4 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -783,11 +783,6 @@ func TestDroiddoc(t *testing.T) { } `) - stubsJar := filepath.Join(buildDir, ".intermediates", "bar-doc", "android_common", "bar-doc-stubs.srcjar") - barDoc := ctx.ModuleForTests("bar-doc", "android_common").Output("bar-doc-stubs.srcjar") - if stubsJar != barDoc.Output.String() { - t.Errorf("expected stubs Jar [%q], got %q", stubsJar, barDoc.Output.String()) - } inputs := ctx.ModuleForTests("bar-doc", "android_common").Rule("javadoc").Inputs var javaSrcs []string for _, i := range inputs {