Generate module lib API and scope together
Previously, due to limitations in metalava the module lib API and stubs source were generated separately. That limitation has since been removed so this change optimizes the generating code. Changes: * Add an annotation field to apiScope to contain the annotation that identifies the scope. * Rename droidstubArgs to extraArgs to better reflect that they are not passed to droidstubs. * Rename droidstubsArgsForGeneratingStubsSource to droidstubsArgs. * Remove droidstubsArgsForGeneratingApi and createStubsSourceAndApiTogether fields along with code that supports generating stubs source and the API separately. * Fix the module lib test. Test: m checkapi Bug: 161364853 Change-Id: I821886bb68645addf5ae9c96ed2f4f3649151d1a
This commit is contained in:
@@ -126,25 +126,23 @@ type apiScope struct {
|
|||||||
// the prebuilt jar.
|
// the prebuilt jar.
|
||||||
sdkVersion string
|
sdkVersion string
|
||||||
|
|
||||||
|
// The annotation that identifies this API level, empty for the public API scope.
|
||||||
|
annotation string
|
||||||
|
|
||||||
// Extra arguments to pass to droidstubs for this scope.
|
// Extra arguments to pass to droidstubs for this scope.
|
||||||
droidstubsArgs []string
|
|
||||||
|
|
||||||
// The args that must be passed to droidstubs to generate the stubs source
|
|
||||||
// for this scope.
|
|
||||||
//
|
//
|
||||||
// The stubs source must include the definitions of everything that is in this
|
// This is not used directly but is used to construct the droidstubsArgs.
|
||||||
// api scope and all the scopes that this one extends.
|
extraArgs []string
|
||||||
droidstubsArgsForGeneratingStubsSource []string
|
|
||||||
|
|
||||||
// The args that must be passed to droidstubs to generate the API for this scope.
|
// The args that must be passed to droidstubs to generate the API and stubs source
|
||||||
|
// for this scope, constructed dynamically by initApiScope().
|
||||||
//
|
//
|
||||||
// The API only includes the additional members that this scope adds over the scope
|
// The API only includes the additional members that this scope adds over the scope
|
||||||
// that it extends.
|
// that it extends.
|
||||||
droidstubsArgsForGeneratingApi []string
|
//
|
||||||
|
// The stubs source must include the definitions of everything that is in this
|
||||||
// True if the stubs source and api can be created by the same metalava invocation.
|
// api scope and all the scopes that this one extends.
|
||||||
// TODO(b/146727827) Now that metalava supports "API hierarchy", do we still need it?
|
droidstubsArgs []string
|
||||||
createStubsSourceAndApiTogether bool
|
|
||||||
|
|
||||||
// Whether the api scope can be treated as unstable, and should skip compat checks.
|
// Whether the api scope can be treated as unstable, and should skip compat checks.
|
||||||
unstable bool
|
unstable bool
|
||||||
@@ -181,21 +179,23 @@ func initApiScope(scope *apiScope) *apiScope {
|
|||||||
// To get the args needed to generate the stubs source append all the args from
|
// To get the args needed to generate the stubs source append all the args from
|
||||||
// this scope and all the scopes it extends as each set of args adds additional
|
// this scope and all the scopes it extends as each set of args adds additional
|
||||||
// members to the stubs.
|
// members to the stubs.
|
||||||
var stubsSourceArgs []string
|
var scopeSpecificArgs []string
|
||||||
for s := scope; s != nil; s = s.extends {
|
if scope.annotation != "" {
|
||||||
stubsSourceArgs = append(stubsSourceArgs, s.droidstubsArgs...)
|
scopeSpecificArgs = []string{"--show-annotation", scope.annotation}
|
||||||
}
|
}
|
||||||
scope.droidstubsArgsForGeneratingStubsSource = stubsSourceArgs
|
for s := scope; s != nil; s = s.extends {
|
||||||
|
scopeSpecificArgs = append(scopeSpecificArgs, s.extraArgs...)
|
||||||
|
|
||||||
// Currently the args needed to generate the API are the same as the args
|
// Ensure that the generated stubs includes all the API elements from the API scope
|
||||||
// needed to add additional members.
|
// that this scope extends.
|
||||||
apiArgs := scope.droidstubsArgs
|
if s != scope && s.annotation != "" {
|
||||||
scope.droidstubsArgsForGeneratingApi = apiArgs
|
scopeSpecificArgs = append(scopeSpecificArgs, "--show-for-stub-purposes-annotation", s.annotation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If the args needed to generate the stubs and API are the same then they
|
// Escape any special characters in the arguments. This is needed because droidstubs
|
||||||
// can be generated in a single invocation of metalava, otherwise they will
|
// passes these directly to the shell command.
|
||||||
// need separate invocations.
|
scope.droidstubsArgs = proptools.ShellEscapeList(scopeSpecificArgs)
|
||||||
scope.createStubsSourceAndApiTogether = reflect.DeepEqual(stubsSourceArgs, apiArgs)
|
|
||||||
|
|
||||||
return scope
|
return scope
|
||||||
}
|
}
|
||||||
@@ -250,10 +250,10 @@ var (
|
|||||||
scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
|
scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
|
||||||
return &module.sdkLibraryProperties.System
|
return &module.sdkLibraryProperties.System
|
||||||
},
|
},
|
||||||
apiFilePrefix: "system-",
|
apiFilePrefix: "system-",
|
||||||
moduleSuffix: ".system",
|
moduleSuffix: ".system",
|
||||||
sdkVersion: "system_current",
|
sdkVersion: "system_current",
|
||||||
droidstubsArgs: []string{"-showAnnotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\)"},
|
annotation: "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS)",
|
||||||
})
|
})
|
||||||
apiScopeTest = initApiScope(&apiScope{
|
apiScopeTest = initApiScope(&apiScope{
|
||||||
name: "test",
|
name: "test",
|
||||||
@@ -262,11 +262,11 @@ var (
|
|||||||
scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
|
scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
|
||||||
return &module.sdkLibraryProperties.Test
|
return &module.sdkLibraryProperties.Test
|
||||||
},
|
},
|
||||||
apiFilePrefix: "test-",
|
apiFilePrefix: "test-",
|
||||||
moduleSuffix: ".test",
|
moduleSuffix: ".test",
|
||||||
sdkVersion: "test_current",
|
sdkVersion: "test_current",
|
||||||
droidstubsArgs: []string{"-showAnnotation android.annotation.TestApi"},
|
annotation: "android.annotation.TestApi",
|
||||||
unstable: true,
|
unstable: true,
|
||||||
})
|
})
|
||||||
apiScopeModuleLib = initApiScope(&apiScope{
|
apiScopeModuleLib = initApiScope(&apiScope{
|
||||||
name: "module-lib",
|
name: "module-lib",
|
||||||
@@ -283,10 +283,7 @@ var (
|
|||||||
apiFilePrefix: "module-lib-",
|
apiFilePrefix: "module-lib-",
|
||||||
moduleSuffix: ".module_lib",
|
moduleSuffix: ".module_lib",
|
||||||
sdkVersion: "module_current",
|
sdkVersion: "module_current",
|
||||||
droidstubsArgs: []string{
|
annotation: "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES)",
|
||||||
"--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES\\)",
|
|
||||||
"--show-for-stub-purposes-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\)",
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
apiScopeSystemServer = initApiScope(&apiScope{
|
apiScopeSystemServer = initApiScope(&apiScope{
|
||||||
name: "system-server",
|
name: "system-server",
|
||||||
@@ -303,11 +300,11 @@ var (
|
|||||||
apiFilePrefix: "system-server-",
|
apiFilePrefix: "system-server-",
|
||||||
moduleSuffix: ".system_server",
|
moduleSuffix: ".system_server",
|
||||||
sdkVersion: "system_server_current",
|
sdkVersion: "system_server_current",
|
||||||
droidstubsArgs: []string{
|
annotation: "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.SYSTEM_SERVER)",
|
||||||
"--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.SYSTEM_SERVER\\) ",
|
extraArgs: []string{
|
||||||
"--hide-annotation android.annotation.Hide",
|
"--hide-annotation", "android.annotation.Hide",
|
||||||
// com.android.* classes are okay in this interface"
|
// com.android.* classes are okay in this interface"
|
||||||
"--hide InternalClasses",
|
"--hide", "InternalClasses",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
allApiScopes = apiScopes{
|
allApiScopes = apiScopes{
|
||||||
@@ -987,16 +984,8 @@ func (module *SdkLibrary) ComponentDepsMutator(ctx android.BottomUpMutatorContex
|
|||||||
// Add dependencies to the stubs library
|
// Add dependencies to the stubs library
|
||||||
ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsLibraryModuleName(apiScope))
|
ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsLibraryModuleName(apiScope))
|
||||||
|
|
||||||
// If the stubs source and API cannot be generated together then add an additional dependency on
|
// Add a dependency on the stubs source in order to access both stubs source and api information.
|
||||||
// the API module.
|
ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.stubsSourceModuleName(apiScope))
|
||||||
if apiScope.createStubsSourceAndApiTogether {
|
|
||||||
// Add a dependency on the stubs source in order to access both stubs source and api information.
|
|
||||||
ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.stubsSourceModuleName(apiScope))
|
|
||||||
} else {
|
|
||||||
// Add separate dependencies on the creators of the stubs source files and the API.
|
|
||||||
ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, module.stubsSourceModuleName(apiScope))
|
|
||||||
ctx.AddVariationDependencies(nil, apiScope.apiFileTag, module.apiModuleName(apiScope))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if module.requiresRuntimeImplementationLibrary() {
|
if module.requiresRuntimeImplementationLibrary() {
|
||||||
@@ -1199,7 +1188,7 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext
|
|||||||
|
|
||||||
// Creates a droidstubs module that creates stubs source files from the given full source
|
// Creates a droidstubs module that creates stubs source files from the given full source
|
||||||
// files and also updates and checks the API specification files.
|
// files and also updates and checks the API specification files.
|
||||||
func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookContext, apiScope *apiScope, name string, createStubSources, createApi bool, scopeSpecificDroidstubsArgs []string) {
|
func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookContext, apiScope *apiScope, name string, scopeSpecificDroidstubsArgs []string) {
|
||||||
props := struct {
|
props := struct {
|
||||||
Name *string
|
Name *string
|
||||||
Visibility []string
|
Visibility []string
|
||||||
@@ -1286,64 +1275,57 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC
|
|||||||
}
|
}
|
||||||
droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
|
droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
|
||||||
|
|
||||||
if !createStubSources {
|
|
||||||
// Stubs are not required.
|
|
||||||
props.Generate_stubs = proptools.BoolPtr(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add in scope specific arguments.
|
// Add in scope specific arguments.
|
||||||
droidstubsArgs = append(droidstubsArgs, scopeSpecificDroidstubsArgs...)
|
droidstubsArgs = append(droidstubsArgs, scopeSpecificDroidstubsArgs...)
|
||||||
props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files
|
props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files
|
||||||
props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " "))
|
props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " "))
|
||||||
|
|
||||||
if createApi {
|
// List of APIs identified from the provided source files are created. They are later
|
||||||
// List of APIs identified from the provided source files are created. They are later
|
// compared against to the not-yet-released (a.k.a current) list of APIs and to the
|
||||||
// compared against to the not-yet-released (a.k.a current) list of APIs and to the
|
// last-released (a.k.a numbered) list of API.
|
||||||
// last-released (a.k.a numbered) list of API.
|
currentApiFileName := apiScope.apiFilePrefix + "current.txt"
|
||||||
currentApiFileName := apiScope.apiFilePrefix + "current.txt"
|
removedApiFileName := apiScope.apiFilePrefix + "removed.txt"
|
||||||
removedApiFileName := apiScope.apiFilePrefix + "removed.txt"
|
apiDir := module.getApiDir()
|
||||||
apiDir := module.getApiDir()
|
currentApiFileName = path.Join(apiDir, currentApiFileName)
|
||||||
currentApiFileName = path.Join(apiDir, currentApiFileName)
|
removedApiFileName = path.Join(apiDir, removedApiFileName)
|
||||||
removedApiFileName = path.Join(apiDir, removedApiFileName)
|
|
||||||
|
|
||||||
// check against the not-yet-release API
|
// check against the not-yet-release API
|
||||||
props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName)
|
props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName)
|
||||||
props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName)
|
props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName)
|
||||||
|
|
||||||
if !apiScope.unstable {
|
if !apiScope.unstable {
|
||||||
// check against the latest released API
|
// check against the latest released API
|
||||||
latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope))
|
latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope))
|
||||||
props.Check_api.Last_released.Api_file = latestApiFilegroupName
|
props.Check_api.Last_released.Api_file = latestApiFilegroupName
|
||||||
props.Check_api.Last_released.Removed_api_file = proptools.StringPtr(
|
props.Check_api.Last_released.Removed_api_file = proptools.StringPtr(
|
||||||
module.latestRemovedApiFilegroupName(apiScope))
|
module.latestRemovedApiFilegroupName(apiScope))
|
||||||
props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true)
|
props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true)
|
||||||
|
|
||||||
if proptools.Bool(module.sdkLibraryProperties.Api_lint.Enabled) {
|
if proptools.Bool(module.sdkLibraryProperties.Api_lint.Enabled) {
|
||||||
// Enable api lint.
|
// Enable api lint.
|
||||||
props.Check_api.Api_lint.Enabled = proptools.BoolPtr(true)
|
props.Check_api.Api_lint.Enabled = proptools.BoolPtr(true)
|
||||||
props.Check_api.Api_lint.New_since = latestApiFilegroupName
|
props.Check_api.Api_lint.New_since = latestApiFilegroupName
|
||||||
|
|
||||||
// If it exists then pass a lint-baseline.txt through to droidstubs.
|
// If it exists then pass a lint-baseline.txt through to droidstubs.
|
||||||
baselinePath := path.Join(apiDir, apiScope.apiFilePrefix+"lint-baseline.txt")
|
baselinePath := path.Join(apiDir, apiScope.apiFilePrefix+"lint-baseline.txt")
|
||||||
baselinePathRelativeToRoot := path.Join(mctx.ModuleDir(), baselinePath)
|
baselinePathRelativeToRoot := path.Join(mctx.ModuleDir(), baselinePath)
|
||||||
paths, err := mctx.GlobWithDeps(baselinePathRelativeToRoot, nil)
|
paths, err := mctx.GlobWithDeps(baselinePathRelativeToRoot, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mctx.ModuleErrorf("error checking for presence of %s: %s", baselinePathRelativeToRoot, err)
|
mctx.ModuleErrorf("error checking for presence of %s: %s", baselinePathRelativeToRoot, err)
|
||||||
}
|
}
|
||||||
if len(paths) == 1 {
|
if len(paths) == 1 {
|
||||||
props.Check_api.Api_lint.Baseline_file = proptools.StringPtr(baselinePath)
|
props.Check_api.Api_lint.Baseline_file = proptools.StringPtr(baselinePath)
|
||||||
} else if len(paths) != 0 {
|
} else if len(paths) != 0 {
|
||||||
mctx.ModuleErrorf("error checking for presence of %s: expected one path, found: %v", baselinePathRelativeToRoot, paths)
|
mctx.ModuleErrorf("error checking for presence of %s: expected one path, found: %v", baselinePathRelativeToRoot, paths)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Dist the api txt artifact for sdk builds.
|
// Dist the api txt artifact for sdk builds.
|
||||||
if !Bool(module.sdkLibraryProperties.No_dist) {
|
if !Bool(module.sdkLibraryProperties.No_dist) {
|
||||||
props.Dist.Targets = []string{"sdk", "win_sdk"}
|
props.Dist.Targets = []string{"sdk", "win_sdk"}
|
||||||
props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.txt", module.BaseModuleName()))
|
props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.txt", module.BaseModuleName()))
|
||||||
props.Dist.Dir = proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api"))
|
props.Dist.Dir = proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api"))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mctx.CreateModule(DroidstubsFactory, &props)
|
mctx.CreateModule(DroidstubsFactory, &props)
|
||||||
@@ -1526,22 +1508,8 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookCont
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, scope := range generatedScopes {
|
for _, scope := range generatedScopes {
|
||||||
stubsSourceArgs := scope.droidstubsArgsForGeneratingStubsSource
|
// Use the stubs source name for legacy reasons.
|
||||||
stubsSourceModuleName := module.stubsSourceModuleName(scope)
|
module.createStubsSourcesAndApi(mctx, scope, module.stubsSourceModuleName(scope), scope.droidstubsArgs)
|
||||||
|
|
||||||
// If the args needed to generate the stubs and API are the same then they
|
|
||||||
// can be generated in a single invocation of metalava, otherwise they will
|
|
||||||
// need separate invocations.
|
|
||||||
if scope.createStubsSourceAndApiTogether {
|
|
||||||
// Use the stubs source name for legacy reasons.
|
|
||||||
module.createStubsSourcesAndApi(mctx, scope, stubsSourceModuleName, true, true, stubsSourceArgs)
|
|
||||||
} else {
|
|
||||||
module.createStubsSourcesAndApi(mctx, scope, stubsSourceModuleName, true, false, stubsSourceArgs)
|
|
||||||
|
|
||||||
apiArgs := scope.droidstubsArgsForGeneratingApi
|
|
||||||
apiName := module.apiModuleName(scope)
|
|
||||||
module.createStubsSourcesAndApi(mctx, scope, apiName, false, true, apiArgs)
|
|
||||||
}
|
|
||||||
|
|
||||||
module.createStubsLibrary(mctx, scope)
|
module.createStubsLibrary(mctx, scope)
|
||||||
}
|
}
|
||||||
|
@@ -1424,8 +1424,8 @@ sdk_snapshot {
|
|||||||
.intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt
|
.intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt
|
||||||
.intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_removed.txt -> sdk_library/system/myjavalib-removed.txt
|
.intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_removed.txt -> sdk_library/system/myjavalib-removed.txt
|
||||||
.intermediates/myjavalib.stubs.module_lib/android_common/javac/myjavalib.stubs.module_lib.jar -> sdk_library/module-lib/myjavalib-stubs.jar
|
.intermediates/myjavalib.stubs.module_lib/android_common/javac/myjavalib.stubs.module_lib.jar -> sdk_library/module-lib/myjavalib-stubs.jar
|
||||||
.intermediates/myjavalib.api.module_lib/android_common/myjavalib.api.module_lib_api.txt -> sdk_library/module-lib/myjavalib.txt
|
.intermediates/myjavalib.stubs.source.module_lib/android_common/myjavalib.stubs.source.module_lib_api.txt -> sdk_library/module-lib/myjavalib.txt
|
||||||
.intermediates/myjavalib.api.module_lib/android_common/myjavalib.api.module_lib_removed.txt -> sdk_library/module-lib/myjavalib-removed.txt
|
.intermediates/myjavalib.stubs.source.module_lib/android_common/myjavalib.stubs.source.module_lib_removed.txt -> sdk_library/module-lib/myjavalib-removed.txt
|
||||||
`),
|
`),
|
||||||
checkMergeZips(
|
checkMergeZips(
|
||||||
".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
|
".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
|
||||||
|
Reference in New Issue
Block a user