platform_build_soong/cc/library_sdk_member.go
Paul Duffin 9b358d7a58 Add support for multiple os types
Updates the member snapshot creation code to support multiple os types.
It basically sorts the variants by os type, then applies the code to
optimize the arch properties and then it optimizes the properties that
are common across architectures and extracts any properties that are
common across os types.

The java and cc member types needed to be modified to make the location
of the generated files within the snapshot os type dependent when there
is more than one os type. That was done by adding an OsPrefix() method
to the SdkMemberPropertiesBase which returns the os prefix to use when
there is > 1 os type and otherwise returns an empty string.

Added three tests, one for cc shared libraries, one for cc binary and
one for java header libraries.

Bug: 150451422
Bug: 153306490
Test: m nothing
Merged-In: I08f5fbdd7852b06c9a9a2f1cfdc364338a3d5bac
Change-Id: I08f5fbdd7852b06c9a9a2f1cfdc364338a3d5bac
2020-04-22 12:51:34 +01:00

331 lines
12 KiB
Go

// Copyright 2019 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 (
"path/filepath"
"android/soong/android"
"github.com/google/blueprint"
)
// This file contains support for using cc library modules within an sdk.
var sharedLibrarySdkMemberType = &librarySdkMemberType{
SdkMemberTypeBase: android.SdkMemberTypeBase{
PropertyName: "native_shared_libs",
SupportsSdk: true,
},
prebuiltModuleType: "cc_prebuilt_library_shared",
linkTypes: []string{"shared"},
}
var staticLibrarySdkMemberType = &librarySdkMemberType{
SdkMemberTypeBase: android.SdkMemberTypeBase{
PropertyName: "native_static_libs",
SupportsSdk: true,
},
prebuiltModuleType: "cc_prebuilt_library_static",
linkTypes: []string{"static"},
}
func init() {
// Register sdk member types.
android.RegisterSdkMemberType(sharedLibrarySdkMemberType)
android.RegisterSdkMemberType(staticLibrarySdkMemberType)
}
type librarySdkMemberType struct {
android.SdkMemberTypeBase
prebuiltModuleType string
// The set of link types supported, set of "static", "shared".
linkTypes []string
}
func (mt *librarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
targets := mctx.MultiTargets()
for _, lib := range names {
for _, target := range targets {
name, version := StubsLibNameAndVersion(lib)
if version == "" {
version = LatestStubsVersionFor(mctx.Config(), name)
}
if mt.linkTypes == nil {
mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
{Mutator: "image", Variation: android.CoreVariation},
{Mutator: "version", Variation: version},
}...), dependencyTag, name)
} else {
for _, linkType := range mt.linkTypes {
mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
{Mutator: "image", Variation: android.CoreVariation},
{Mutator: "link", Variation: linkType},
{Mutator: "version", Variation: version},
}...), dependencyTag, name)
}
}
}
}
}
func (mt *librarySdkMemberType) IsInstance(module android.Module) bool {
// Check the module to see if it can be used with this module type.
if m, ok := module.(*Module); ok {
for _, allowableMemberType := range m.sdkMemberTypes {
if allowableMemberType == mt {
return true
}
}
}
return false
}
func (mt *librarySdkMemberType) AddPrebuiltModule(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) android.BpModule {
pbm := builder.AddPrebuiltModule(member, mt.prebuiltModuleType)
ccModule := member.Variants()[0].(*Module)
sdkVersion := ccModule.SdkVersion()
if sdkVersion != "" {
pbm.AddProperty("sdk_version", sdkVersion)
}
return pbm
}
func (mt *librarySdkMemberType) FinalizeModule(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember, bpModule android.BpModule) {
bpModule.AddProperty("stl", "none")
bpModule.AddProperty("system_shared_libs", []string{})
}
func (mt *librarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
return &nativeLibInfoProperties{memberType: mt}
}
func isGeneratedHeaderDirectory(p android.Path) bool {
_, gen := p.(android.WritablePath)
return gen
}
type includeDirsProperty struct {
// Accessor to retrieve the paths
pathsGetter func(libInfo *nativeLibInfoProperties) android.Paths
// The name of the property in the prebuilt library, "" means there is no property.
propertyName string
// The directory within the snapshot directory into which items should be copied.
snapshotDir string
// True if the items on the path should be copied.
copy bool
// True if the paths represent directories, files if they represent files.
dirs bool
}
var includeDirProperties = []includeDirsProperty{
{
// ExportedIncludeDirs lists directories that contains some header files to be
// copied into a directory in the snapshot. The snapshot directories must be added to
// the export_include_dirs property in the prebuilt module in the snapshot.
pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.ExportedIncludeDirs },
propertyName: "export_include_dirs",
snapshotDir: nativeIncludeDir,
copy: true,
dirs: true,
},
{
// ExportedSystemIncludeDirs lists directories that contains some system header files to
// be copied into a directory in the snapshot. The snapshot directories must be added to
// the export_system_include_dirs property in the prebuilt module in the snapshot.
pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.ExportedSystemIncludeDirs },
propertyName: "export_system_include_dirs",
snapshotDir: nativeIncludeDir,
copy: true,
dirs: true,
},
{
// exportedGeneratedIncludeDirs lists directories that contains some header files
// that are explicitly listed in the exportedGeneratedHeaders property. So, the contents
// of these directories do not need to be copied, but these directories do need adding to
// the export_include_dirs property in the prebuilt module in the snapshot.
pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedIncludeDirs },
propertyName: "export_include_dirs",
snapshotDir: nativeGeneratedIncludeDir,
copy: false,
dirs: true,
},
{
// exportedGeneratedHeaders lists header files that are in one of the directories
// specified in exportedGeneratedIncludeDirs must be copied into the snapshot.
// As they are in a directory in exportedGeneratedIncludeDirs they do not need adding to a
// property in the prebuilt module in the snapshot.
pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedHeaders },
propertyName: "",
snapshotDir: nativeGeneratedIncludeDir,
copy: true,
dirs: false,
},
}
// Add properties that may, or may not, be arch specific.
func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo *nativeLibInfoProperties, outputProperties android.BpPropertySet) {
// Copy the generated library to the snapshot and add a reference to it in the .bp module.
if libInfo.outputFile != nil {
nativeLibraryPath := nativeLibraryPathFor(libInfo)
builder.CopyToSnapshot(libInfo.outputFile, nativeLibraryPath)
outputProperties.AddProperty("srcs", []string{nativeLibraryPath})
}
// Map from property name to the include dirs to add to the prebuilt module in the snapshot.
includeDirs := make(map[string][]string)
// Iterate over each include directory property, copying files and collating property
// values where necessary.
for _, propertyInfo := range includeDirProperties {
// Calculate the base directory in the snapshot into which the files will be copied.
// lib.ArchType is "" for common properties.
targetDir := filepath.Join(libInfo.archType, propertyInfo.snapshotDir)
propertyName := propertyInfo.propertyName
// Iterate over each path in one of the include directory properties.
for _, path := range propertyInfo.pathsGetter(libInfo) {
// Copy the files/directories when necessary.
if propertyInfo.copy {
if propertyInfo.dirs {
// When copying a directory glob and copy all the headers within it.
// TODO(jiyong) copy headers having other suffixes
headers, _ := sdkModuleContext.GlobWithDeps(path.String()+"/**/*.h", nil)
for _, file := range headers {
src := android.PathForSource(sdkModuleContext, file)
dest := filepath.Join(targetDir, file)
builder.CopyToSnapshot(src, dest)
}
} else {
// Otherwise, just copy the files.
dest := filepath.Join(targetDir, libInfo.name, path.Rel())
builder.CopyToSnapshot(path, dest)
}
}
// Only directories are added to a property.
if propertyInfo.dirs {
var snapshotPath string
if isGeneratedHeaderDirectory(path) {
snapshotPath = filepath.Join(targetDir, libInfo.name)
} else {
snapshotPath = filepath.Join(targetDir, path.String())
}
includeDirs[propertyName] = append(includeDirs[propertyName], snapshotPath)
}
}
}
// Add the collated include dir properties to the output.
for property, dirs := range includeDirs {
outputProperties.AddProperty(property, dirs)
}
}
const (
nativeIncludeDir = "include"
nativeGeneratedIncludeDir = "include_gen"
nativeStubDir = "lib"
)
// path to the native library. Relative to <sdk_root>/<api_dir>
func nativeLibraryPathFor(lib *nativeLibInfoProperties) string {
return filepath.Join(lib.OsPrefix(), lib.archType,
nativeStubDir, lib.outputFile.Base())
}
// nativeLibInfoProperties represents properties of a native lib
//
// The exported (capitalized) fields will be examined and may be changed during common value extraction.
// The unexported fields will be left untouched.
type nativeLibInfoProperties struct {
android.SdkMemberPropertiesBase
memberType *librarySdkMemberType
// The name of the library, is not exported as this must not be changed during optimization.
name string
// archType is not exported as if set (to a non default value) it is always arch specific.
// This is "" for common properties.
archType string
// The list of possibly common exported include dirs.
//
// This field is exported as its contents may not be arch specific.
ExportedIncludeDirs android.Paths
// The list of arch specific exported generated include dirs.
//
// This field is not exported as its contents are always arch specific.
exportedGeneratedIncludeDirs android.Paths
// The list of arch specific exported generated header files.
//
// This field is not exported as its contents are is always arch specific.
exportedGeneratedHeaders android.Paths
// The list of possibly common exported system include dirs.
//
// This field is exported as its contents may not be arch specific.
ExportedSystemIncludeDirs android.Paths
// The list of possibly common exported flags.
//
// This field is exported as its contents may not be arch specific.
ExportedFlags []string
// outputFile is not exported as it is always arch specific.
outputFile android.Path
}
func (p *nativeLibInfoProperties) PopulateFromVariant(variant android.SdkAware) {
ccModule := variant.(*Module)
// If the library has some link types then it produces an output binary file, otherwise it
// is header only.
if p.memberType.linkTypes != nil {
p.outputFile = ccModule.OutputFile().Path()
}
// Separate out the generated include dirs (which are arch specific) from the
// include dirs (which may not be).
exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate(
ccModule.ExportedIncludeDirs(), isGeneratedHeaderDirectory)
p.name = variant.Name()
p.archType = ccModule.Target().Arch.ArchType.String()
p.ExportedIncludeDirs = exportedIncludeDirs
p.exportedGeneratedIncludeDirs = exportedGeneratedIncludeDirs
p.ExportedSystemIncludeDirs = ccModule.ExportedSystemIncludeDirs()
p.ExportedFlags = ccModule.ExportedFlags()
p.exportedGeneratedHeaders = ccModule.ExportedGeneratedHeaders()
}
func (p *nativeLibInfoProperties) AddToPropertySet(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, propertySet android.BpPropertySet) {
addPossiblyArchSpecificProperties(sdkModuleContext, builder, p, propertySet)
}