java_sdk_library: Allow separate api/stubs source modules
The API file for a scope represents the differences between the API provided by that scope and that provided by the scope that it extends. On the other hand the stubs source for a scope represents the union of the API provided by the scope and the scope it extends (all the way back to public). Unfortunately, while metalava supports this behavior for scopes that extend public (e.g. system and test) it does not support this behavior for scopes that extend others, e.g. module_lib which extends system. This is because it always assumes that the baseline for the API file is 'public' and so has no way to defined other baselines. This change works around that by having separate droidstubs modules to generate the API and stubs sources for scopes that require different arguments to generate the API and stubs sources. Test: m checkapi Bug: 155164730 Change-Id: Iea7d59852d7aeb503120acf3c44e08eb0d9d07b9
This commit is contained in:
parent
fced20c3b4
commit
0ff08bdb07
2 changed files with 179 additions and 54 deletions
|
@ -34,6 +34,7 @@ const (
|
|||
sdkSystemApiSuffix = ".system"
|
||||
sdkTestApiSuffix = ".test"
|
||||
sdkStubsSourceSuffix = ".stubs.source"
|
||||
sdkApiSuffix = ".api"
|
||||
sdkXmlFileSuffix = ".xml"
|
||||
permissionsTemplate = `<?xml version=\"1.0\" encoding=\"utf-8\"?>\n` +
|
||||
`<!-- Copyright (C) 2018 The Android Open Source Project\n` +
|
||||
|
@ -99,6 +100,12 @@ type apiScope struct {
|
|||
// The tag to use to depend on the stubs library module.
|
||||
stubsTag scopeDependencyTag
|
||||
|
||||
// The tag to use to depend on the stubs source module (if separate from the API module).
|
||||
stubsSourceTag scopeDependencyTag
|
||||
|
||||
// The tag to use to depend on the API file generating module (if separate from the stubs source module).
|
||||
apiFileTag scopeDependencyTag
|
||||
|
||||
// The tag to use to depend on the stubs source and API module.
|
||||
stubsSourceAndApiTag scopeDependencyTag
|
||||
|
||||
|
@ -117,6 +124,22 @@ type apiScope struct {
|
|||
// 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
|
||||
// api scope and all the scopes that this one extends.
|
||||
droidstubsArgsForGeneratingStubsSource []string
|
||||
|
||||
// The args that must be passed to droidstubs to generate the API for this scope.
|
||||
//
|
||||
// The API only includes the additional members that this scope adds over the scope
|
||||
// that it extends.
|
||||
droidstubsArgsForGeneratingApi []string
|
||||
|
||||
// True if the stubs source and api can be created by the same metalava invocation.
|
||||
createStubsSourceAndApiTogether bool
|
||||
|
||||
// Whether the api scope can be treated as unstable, and should skip compat checks.
|
||||
unstable bool
|
||||
}
|
||||
|
@ -130,11 +153,41 @@ func initApiScope(scope *apiScope) *apiScope {
|
|||
apiScope: scope,
|
||||
depInfoExtractor: (*scopePaths).extractStubsLibraryInfoFromDependency,
|
||||
}
|
||||
scope.stubsSourceTag = scopeDependencyTag{
|
||||
name: name + "-stubs-source",
|
||||
apiScope: scope,
|
||||
depInfoExtractor: (*scopePaths).extractStubsSourceInfoFromDep,
|
||||
}
|
||||
scope.apiFileTag = scopeDependencyTag{
|
||||
name: name + "-api",
|
||||
apiScope: scope,
|
||||
depInfoExtractor: (*scopePaths).extractApiInfoFromDep,
|
||||
}
|
||||
scope.stubsSourceAndApiTag = scopeDependencyTag{
|
||||
name: name + "-stubs-source-and-api",
|
||||
apiScope: scope,
|
||||
depInfoExtractor: (*scopePaths).extractStubsSourceAndApiInfoFromApiStubsProvider,
|
||||
}
|
||||
|
||||
// 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
|
||||
// members to the stubs.
|
||||
var stubsSourceArgs []string
|
||||
for s := scope; s != nil; s = s.extends {
|
||||
stubsSourceArgs = append(stubsSourceArgs, s.droidstubsArgs...)
|
||||
}
|
||||
scope.droidstubsArgsForGeneratingStubsSource = stubsSourceArgs
|
||||
|
||||
// Currently the args needed to generate the API are the same as the args
|
||||
// needed to add additional members.
|
||||
apiArgs := scope.droidstubsArgs
|
||||
scope.droidstubsArgsForGeneratingApi = apiArgs
|
||||
|
||||
// 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.
|
||||
scope.createStubsSourceAndApiTogether = reflect.DeepEqual(stubsSourceArgs, apiArgs)
|
||||
|
||||
return scope
|
||||
}
|
||||
|
||||
|
@ -146,6 +199,10 @@ func (scope *apiScope) stubsSourceModuleName(baseName string) string {
|
|||
return baseName + sdkStubsSourceSuffix + scope.moduleSuffix
|
||||
}
|
||||
|
||||
func (scope *apiScope) apiModuleName(baseName string) string {
|
||||
return baseName + sdkApiSuffix + scope.moduleSuffix
|
||||
}
|
||||
|
||||
func (scope *apiScope) String() string {
|
||||
return scope.name
|
||||
}
|
||||
|
@ -379,17 +436,47 @@ func (paths *scopePaths) extractStubsLibraryInfoFromDependency(dep android.Modul
|
|||
}
|
||||
}
|
||||
|
||||
func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(dep android.Module) error {
|
||||
if provider, ok := dep.(ApiStubsProvider); ok {
|
||||
paths.currentApiFilePath = provider.ApiFilePath()
|
||||
paths.removedApiFilePath = provider.RemovedApiFilePath()
|
||||
paths.stubsSrcJar = provider.StubsSrcJar()
|
||||
func (paths *scopePaths) treatDepAsApiStubsProvider(dep android.Module, action func(provider ApiStubsProvider)) error {
|
||||
if apiStubsProvider, ok := dep.(ApiStubsProvider); ok {
|
||||
action(apiStubsProvider)
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("expected module that implements ApiStubsProvider, e.g. droidstubs")
|
||||
}
|
||||
}
|
||||
|
||||
func (paths *scopePaths) extractApiInfoFromApiStubsProvider(provider ApiStubsProvider) {
|
||||
paths.currentApiFilePath = provider.ApiFilePath()
|
||||
paths.removedApiFilePath = provider.RemovedApiFilePath()
|
||||
}
|
||||
|
||||
func (paths *scopePaths) extractApiInfoFromDep(dep android.Module) error {
|
||||
return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) {
|
||||
paths.extractApiInfoFromApiStubsProvider(provider)
|
||||
})
|
||||
}
|
||||
|
||||
func (paths *scopePaths) extractStubsSourceInfoFromApiStubsProviders(provider ApiStubsProvider) {
|
||||
paths.stubsSrcJar = provider.StubsSrcJar()
|
||||
}
|
||||
|
||||
func (paths *scopePaths) extractStubsSourceInfoFromDep(dep android.Module) error {
|
||||
return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) {
|
||||
paths.extractStubsSourceInfoFromApiStubsProviders(provider)
|
||||
})
|
||||
}
|
||||
|
||||
func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(dep android.Module) error {
|
||||
return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) {
|
||||
paths.extractApiInfoFromApiStubsProvider(provider)
|
||||
paths.extractStubsSourceInfoFromApiStubsProviders(provider)
|
||||
})
|
||||
}
|
||||
|
||||
type commonToSdkLibraryAndImportProperties struct {
|
||||
Naming_scheme *string
|
||||
}
|
||||
|
||||
// Common code between sdk library and sdk library import
|
||||
type commonToSdkLibraryAndImport struct {
|
||||
scopePaths map[*apiScope]*scopePaths
|
||||
|
@ -488,8 +575,16 @@ func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
|
|||
// Add dependencies to the stubs library
|
||||
ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsName(apiScope))
|
||||
|
||||
// And the stubs source and api files
|
||||
// If the stubs source and API cannot be generated together then add an additional dependency on
|
||||
// the API module.
|
||||
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.stubsSourceName(apiScope))
|
||||
} else {
|
||||
// Add separate dependencies on the creators of the stubs source files and the API.
|
||||
ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, module.stubsSourceName(apiScope))
|
||||
ctx.AddVariationDependencies(nil, apiScope.apiFileTag, module.apiName(apiScope))
|
||||
}
|
||||
}
|
||||
|
||||
if !proptools.Bool(module.sdkLibraryProperties.Api_only) {
|
||||
|
@ -539,12 +634,18 @@ func (module *SdkLibrary) stubsName(apiScope *apiScope) string {
|
|||
return apiScope.stubsModuleName(module.BaseModuleName())
|
||||
}
|
||||
|
||||
// // Name of the droidstubs module that generates the stubs source and
|
||||
// generates/checks the API.
|
||||
// Name of the droidstubs module that generates the stubs source and may also
|
||||
// generate/check the API.
|
||||
func (module *SdkLibrary) stubsSourceName(apiScope *apiScope) string {
|
||||
return apiScope.stubsSourceModuleName(module.BaseModuleName())
|
||||
}
|
||||
|
||||
// Name of the droidstubs module that generates/checks the API. Only used if it
|
||||
// requires different arts to the stubs source generating module.
|
||||
func (module *SdkLibrary) apiName(apiScope *apiScope) string {
|
||||
return apiScope.apiModuleName(module.BaseModuleName())
|
||||
}
|
||||
|
||||
// Module name of the runtime implementation library
|
||||
func (module *SdkLibrary) implName() string {
|
||||
return module.BaseModuleName()
|
||||
|
@ -665,7 +766,7 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext
|
|||
|
||||
// Creates a droidstubs module that creates stubs source files from the given full source
|
||||
// files and also updates and checks the API specification files.
|
||||
func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookContext, apiScope *apiScope) {
|
||||
func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookContext, apiScope *apiScope, name string, createStubSources, createApi bool, scopeSpecificDroidstubsArgs []string) {
|
||||
props := struct {
|
||||
Name *string
|
||||
Visibility []string
|
||||
|
@ -679,6 +780,7 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC
|
|||
Java_version *string
|
||||
Merge_annotations_dirs []string
|
||||
Merge_inclusion_annotations_dirs []string
|
||||
Generate_stubs *bool
|
||||
Check_api struct {
|
||||
Current ApiToCheck
|
||||
Last_released ApiToCheck
|
||||
|
@ -707,7 +809,7 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC
|
|||
// * system_modules
|
||||
// * libs (static_libs/libs)
|
||||
|
||||
props.Name = proptools.StringPtr(module.stubsSourceName(apiScope))
|
||||
props.Name = proptools.StringPtr(name)
|
||||
|
||||
// If stubs_source_visibility is not set then the created module will use the
|
||||
// visibility of this module.
|
||||
|
@ -751,11 +853,17 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC
|
|||
}
|
||||
droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
|
||||
|
||||
if !createStubSources {
|
||||
// Stubs are not required.
|
||||
props.Generate_stubs = proptools.BoolPtr(false)
|
||||
}
|
||||
|
||||
// Add in scope specific arguments.
|
||||
droidstubsArgs = append(droidstubsArgs, apiScope.droidstubsArgs...)
|
||||
droidstubsArgs = append(droidstubsArgs, scopeSpecificDroidstubsArgs...)
|
||||
props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files
|
||||
props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " "))
|
||||
|
||||
if createApi {
|
||||
// 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
|
||||
// last-released (a.k.a numbered) list of API.
|
||||
|
@ -803,6 +911,7 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC
|
|||
props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.txt", module.BaseModuleName()))
|
||||
props.Dist.Dir = proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api"))
|
||||
}
|
||||
}
|
||||
|
||||
mctx.CreateModule(DroidstubsFactory, &props)
|
||||
}
|
||||
|
@ -989,8 +1098,24 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookCont
|
|||
}
|
||||
|
||||
for _, scope := range generatedScopes {
|
||||
stubsSourceArgs := scope.droidstubsArgsForGeneratingStubsSource
|
||||
stubsSourceModuleName := module.stubsSourceName(scope)
|
||||
|
||||
// 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.apiName(scope)
|
||||
module.createStubsSourcesAndApi(mctx, scope, apiName, false, true, apiArgs)
|
||||
}
|
||||
|
||||
module.createStubsLibrary(mctx, scope)
|
||||
module.createStubsSourcesAndApi(mctx, scope)
|
||||
}
|
||||
|
||||
if !proptools.Bool(module.sdkLibraryProperties.Api_only) {
|
||||
|
|
|
@ -1314,8 +1314,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-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.source.module_lib/android_common/myjavalib.stubs.source.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-removed.txt
|
||||
.intermediates/myjavalib.api.module_lib/android_common/myjavalib.api.module_lib_api.txt -> sdk_library/module_lib/myjavalib.txt
|
||||
.intermediates/myjavalib.api.module_lib/android_common/myjavalib.api.module_lib_api.txt -> sdk_library/module_lib/myjavalib-removed.txt
|
||||
`),
|
||||
checkMergeZips(
|
||||
".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
|
||||
|
|
Loading…
Reference in a new issue