platform_build_soong/cc/library_stub.go
Kiyoung Kim 487689eaee Introduce cc_api_library
Introduce cc_api_library, which reflects imported API from other
inner-tree. This cc_api_library module type will later refer from
the other ninja module which generates stub library from the interface
description.

Tested environment :
* original libc definition has been removed temporarily, to ensure that
  imported api stub library is being used from build
* Added new definition of libc as below
 cc_api_library {
  name: "libc",
  arch: {
    x86: {
      src: "libs/x86/libc.so",
    },
    x86_64: {
      src: "libs/x86_64/libc.so",
    },
  },
  header_libs: [
    "libc_headers",
  ],
  export_header_lib_headers: ["libc_headers"],
  min_sdk_version: "9",
  vendor_available: true,
 }

Bug: 236087698
Test: `ALLOW_MISSING_DEPENDENCIES=true m vendorimage` succeeded
Change-Id: I67070b0f3561aa2afd73b6c1c0fdf4255218baac
2022-08-10 10:12:18 +09:00

250 lines
8.7 KiB
Go

// Copyright 2021 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cc
import (
"android/soong/android"
"android/soong/multitree"
"strings"
)
func init() {
RegisterLibraryStubBuildComponents(android.InitRegistrationContext)
}
func RegisterLibraryStubBuildComponents(ctx android.RegistrationContext) {
// cc_api_stub_library shares a lot of ndk_library, and this will be refactored later
ctx.RegisterModuleType("cc_api_library", CcApiLibraryFactory)
ctx.RegisterModuleType("cc_api_stub_library", CcApiStubLibraryFactory)
ctx.RegisterModuleType("cc_api_contribution", CcApiContributionFactory)
}
// 'cc_api_library' is a module type which is from the exported API surface
// with C shared library type. The module will replace original module, and
// offer a link to the module that generates shared library object from the
// map file.
type apiLibraryProperties struct {
Src *string `android:"arch_variant"`
}
type apiLibraryDecorator struct {
*libraryDecorator
properties apiLibraryProperties
}
func CcApiLibraryFactory() android.Module {
module, decorator := NewLibrary(android.DeviceSupported)
apiLibraryDecorator := &apiLibraryDecorator{
libraryDecorator: decorator,
}
apiLibraryDecorator.BuildOnlyShared()
module.stl = nil
module.sanitize = nil
decorator.disableStripping()
module.compiler = nil
module.linker = apiLibraryDecorator
module.installer = nil
module.AddProperties(&module.Properties, &apiLibraryDecorator.properties)
// Mark module as stub, so APEX would not include this stub in the package.
module.library.setBuildStubs(true)
// Prevent default system libs (libc, libm, and libdl) from being linked
if apiLibraryDecorator.baseLinker.Properties.System_shared_libs == nil {
apiLibraryDecorator.baseLinker.Properties.System_shared_libs = []string{}
}
module.Init()
return module
}
func (d *apiLibraryDecorator) Name(basename string) string {
return basename + multitree.GetApiImportSuffix()
}
func (d *apiLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objects Objects) android.Path {
// Flags reexported from dependencies. (e.g. vndk_prebuilt_shared)
d.libraryDecorator.flagExporter.exportIncludes(ctx)
d.libraryDecorator.reexportDirs(deps.ReexportedDirs...)
d.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...)
d.libraryDecorator.reexportFlags(deps.ReexportedFlags...)
d.libraryDecorator.reexportDeps(deps.ReexportedDeps...)
d.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
d.libraryDecorator.flagExporter.setProvider(ctx)
in := android.PathForModuleSrc(ctx, *d.properties.Src)
d.unstrippedOutputFile = in
libName := d.libraryDecorator.getLibName(ctx) + flags.Toolchain.ShlibSuffix()
tocFile := android.PathForModuleOut(ctx, libName+".toc")
d.tocFile = android.OptionalPathForPath(tocFile)
TransformSharedObjectToToc(ctx, in, tocFile)
ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
SharedLibrary: in,
Target: ctx.Target(),
TableOfContents: d.tocFile,
})
return in
}
func (d *apiLibraryDecorator) availableFor(what string) bool {
// Stub from API surface should be available for any APEX.
return true
}
func (d *apiLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
d.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), multitree.GetApiImportSuffix())
return d.libraryDecorator.linkerFlags(ctx, flags)
}
func CcApiStubLibraryFactory() android.Module {
module, decorator := NewLibrary(android.DeviceSupported)
apiStubDecorator := &apiStubDecorator{
libraryDecorator: decorator,
}
apiStubDecorator.BuildOnlyShared()
module.compiler = apiStubDecorator
module.linker = apiStubDecorator
module.installer = nil
module.library = apiStubDecorator
module.Properties.HideFromMake = true // TODO: remove
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
module.AddProperties(&module.Properties,
&apiStubDecorator.properties,
&apiStubDecorator.MutatedProperties,
&apiStubDecorator.apiStubLibraryProperties)
return module
}
type apiStubLiraryProperties struct {
Imported_includes []string `android:"path"`
}
type apiStubDecorator struct {
*libraryDecorator
properties libraryProperties
apiStubLibraryProperties apiStubLiraryProperties
}
func (compiler *apiStubDecorator) stubsVersions(ctx android.BaseMutatorContext) []string {
firstVersion := String(compiler.properties.First_version)
return ndkLibraryVersions(ctx, android.ApiLevelOrPanic(ctx, firstVersion))
}
func (decorator *apiStubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
if decorator.stubsVersion() == "" {
decorator.setStubsVersion("current")
} // TODO: fix
symbolFile := String(decorator.properties.Symbol_file)
nativeAbiResult := parseNativeAbiDefinition(ctx, symbolFile,
android.ApiLevelOrPanic(ctx, decorator.stubsVersion()),
"")
return compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc)
}
func (decorator *apiStubDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objects Objects) android.Path {
decorator.reexportDirs(android.PathsForModuleSrc(ctx, decorator.apiStubLibraryProperties.Imported_includes)...)
return decorator.libraryDecorator.link(ctx, flags, deps, objects)
}
func init() {
pctx.HostBinToolVariable("gen_api_surface_build_files", "gen_api_surface_build_files")
}
type CcApiContribution struct {
android.ModuleBase
properties ccApiContributionProperties
}
type ccApiContributionProperties struct {
Symbol_file *string `android:"path"`
First_version *string
Export_include_dir *string
}
func CcApiContributionFactory() android.Module {
module := &CcApiContribution{}
module.AddProperties(&module.properties)
android.InitAndroidModule(module)
return module
}
// Do some simple validations
// Majority of the build rules will be created in the ctx of the api surface this module contributes to
func (contrib *CcApiContribution) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if contrib.properties.Symbol_file == nil {
ctx.PropertyErrorf("symbol_file", "%v does not have symbol file", ctx.ModuleName())
}
if contrib.properties.First_version == nil {
ctx.PropertyErrorf("first_version", "%v does not have first_version for stub variants", ctx.ModuleName())
}
}
// Path is out/soong/.export/ but will be different in final multi-tree layout
func outPathApiSurface(ctx android.ModuleContext, myModuleName string, pathComponent string) android.OutputPath {
return android.PathForOutput(ctx, ".export", ctx.ModuleName(), myModuleName, pathComponent)
}
func (contrib *CcApiContribution) CopyFilesWithTag(apiSurfaceContext android.ModuleContext) map[string]android.Paths {
// copy map.txt for now
// hardlinks cannot be created since nsjail creates a different mountpoint for out/
myDir := apiSurfaceContext.OtherModuleDir(contrib)
genMapTxt := outPathApiSurface(apiSurfaceContext, contrib.Name(), String(contrib.properties.Symbol_file))
apiSurfaceContext.Build(pctx, android.BuildParams{
Rule: android.Cp,
Description: "import map.txt file",
Input: android.PathForSource(apiSurfaceContext, myDir, String(contrib.properties.Symbol_file)),
Output: genMapTxt,
})
outputs := make(map[string]android.Paths)
outputs["map"] = []android.Path{genMapTxt}
if contrib.properties.Export_include_dir != nil {
includeDir := android.PathForSource(apiSurfaceContext, myDir, String(contrib.properties.Export_include_dir))
outputs["export_include_dir"] = []android.Path{includeDir}
}
return outputs
}
var _ multitree.ApiContribution = (*CcApiContribution)(nil)
/*
func (contrib *CcApiContribution) GenerateBuildFiles(apiSurfaceContext android.ModuleContext) android.Paths {
genAndroidBp := outPathApiSurface(apiSurfaceContext, contrib.Name(), "Android.bp")
// generate Android.bp
apiSurfaceContext.Build(pctx, android.BuildParams{
Rule: genApiSurfaceBuildFiles,
Description: "generate API surface build files",
Outputs: []android.WritablePath{genAndroidBp},
Args: map[string]string{
"name": contrib.Name() + "." + apiSurfaceContext.ModuleName(), //e.g. liblog.ndk
"symbol_file": String(contrib.properties.Symbol_file),
"first_version": String(contrib.properties.First_version),
},
})
return []android.Path{genAndroidBp}
}
*/