Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3b49c9c6 authored by Automerger Merge Worker's avatar Automerger Merge Worker
Browse files

Merge "Separate sdk membership support out of cc/library.go" am: edb4e21d am: 260f9a21

Change-Id: I3be8d878b48b2ad3d0493ebc42f0fb26a0819cbc
parents c229e5a6 260f9a21
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -186,6 +186,7 @@ bootstrap_go_package {
        "cc/binary.go",
        "cc/fuzz.go",
        "cc/library.go",
        "cc/library_sdk_member.go",
        "cc/object.go",
        "cc/test.go",
        "cc/toolchain_library.go",
+0 −297
Original line number Diff line number Diff line
@@ -18,14 +18,12 @@ import (
	"fmt"
	"io"
	"path/filepath"
	"reflect"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"sync"

	"github.com/google/blueprint"
	"github.com/google/blueprint/pathtools"

	"android/soong/android"
@@ -1438,298 +1436,3 @@ func maybeInjectBoringSSLHash(ctx android.ModuleContext, outputFile android.Modu

	return outputFile
}

var SharedLibrarySdkMemberType = &librarySdkMemberType{
	prebuiltModuleType: "cc_prebuilt_library_shared",
	linkTypes:          []string{"shared"},
}

var StaticLibrarySdkMemberType = &librarySdkMemberType{
	prebuiltModuleType: "cc_prebuilt_library_static",
	linkTypes:          []string{"static"},
}

type librarySdkMemberType struct {
	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)
			}
			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 {
	_, ok := module.(*Module)
	return ok
}

// copy exported header files and stub *.so files
func (mt *librarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
	info := mt.organizeVariants(member)
	buildSharedNativeLibSnapshot(sdkModuleContext, info, builder, member)
}

// Organize the variants by architecture.
func (mt *librarySdkMemberType) organizeVariants(member android.SdkMember) *nativeLibInfo {
	memberName := member.Name()
	info := &nativeLibInfo{
		name:       memberName,
		memberType: mt,
	}

	for _, variant := range member.Variants() {
		ccModule := variant.(*Module)

		// 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)

		info.archVariantProperties = append(info.archVariantProperties, nativeLibInfoProperties{
			name:                         memberName,
			archType:                     ccModule.Target().Arch.ArchType.String(),
			ExportedIncludeDirs:          exportedIncludeDirs,
			ExportedGeneratedIncludeDirs: exportedGeneratedIncludeDirs,
			ExportedSystemIncludeDirs:    ccModule.ExportedSystemIncludeDirs(),
			ExportedFlags:                ccModule.ExportedFlags(),
			exportedGeneratedHeaders:     ccModule.ExportedGeneratedHeaders(),
			outputFile:                   ccModule.OutputFile().Path(),
		})
	}

	// Initialize the unexported properties that will not be set during the
	// extraction process.
	info.commonProperties.name = memberName

	// Extract common properties from the arch specific properties.
	extractCommonProperties(&info.commonProperties, info.archVariantProperties)

	return info
}

func isGeneratedHeaderDirectory(p android.Path) bool {
	_, gen := p.(android.WritablePath)
	return gen
}

// Extract common properties from a slice of property structures of the same type.
//
// All the property structures must be of the same type.
// commonProperties - must be a pointer to the structure into which common properties will be added.
// inputPropertiesSlice - must be a slice of input properties structures.
//
// Iterates over each exported field (capitalized name) and checks to see whether they
// have the same value (using DeepEquals) across all the input properties. If it does not then no
// change is made. Otherwise, the common value is stored in the field in the commonProperties
// and the field in each of the input properties structure is set to its default value.
func extractCommonProperties(commonProperties interface{}, inputPropertiesSlice interface{}) {
	commonStructValue := reflect.ValueOf(commonProperties).Elem()
	propertiesStructType := commonStructValue.Type()

	// Create an empty structure from which default values for the field can be copied.
	emptyStructValue := reflect.New(propertiesStructType).Elem()

	for f := 0; f < propertiesStructType.NumField(); f++ {
		// Check to see if all the structures have the same value for the field. The commonValue
		// is nil on entry to the loop and if it is nil on exit then there is no common value,
		// otherwise it points to the common value.
		var commonValue *reflect.Value
		sliceValue := reflect.ValueOf(inputPropertiesSlice)

		for i := 0; i < sliceValue.Len(); i++ {
			structValue := sliceValue.Index(i)
			fieldValue := structValue.Field(f)
			if !fieldValue.CanInterface() {
				// The field is not exported so ignore it.
				continue
			}

			if commonValue == nil {
				// Use the first value as the commonProperties value.
				commonValue = &fieldValue
			} else {
				// If the value does not match the current common value then there is
				// no value in common so break out.
				if !reflect.DeepEqual(fieldValue.Interface(), commonValue.Interface()) {
					commonValue = nil
					break
				}
			}
		}

		// If the fields all have a common value then store it in the common struct field
		// and set the input struct's field to the empty value.
		if commonValue != nil {
			emptyValue := emptyStructValue.Field(f)
			commonStructValue.Field(f).Set(*commonValue)
			for i := 0; i < sliceValue.Len(); i++ {
				structValue := sliceValue.Index(i)
				fieldValue := structValue.Field(f)
				fieldValue.Set(emptyValue)
			}
		}
	}
}

func buildSharedNativeLibSnapshot(sdkModuleContext android.ModuleContext, info *nativeLibInfo, builder android.SnapshotBuilder, member android.SdkMember) {
	// a function for emitting include dirs
	addExportedDirCopyCommandsForNativeLibs := func(lib nativeLibInfoProperties) {
		// Do not include ExportedGeneratedIncludeDirs in the list of directories whose
		// contents are copied as they are copied from exportedGeneratedHeaders below.
		includeDirs := lib.ExportedIncludeDirs
		includeDirs = append(includeDirs, lib.ExportedSystemIncludeDirs...)
		for _, dir := range includeDirs {
			// lib.ArchType is "" for common properties.
			targetDir := filepath.Join(lib.archType, nativeIncludeDir)

			// TODO(jiyong) copy headers having other suffixes
			headers, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.h", nil)
			for _, file := range headers {
				src := android.PathForSource(sdkModuleContext, file)
				dest := filepath.Join(targetDir, file)
				builder.CopyToSnapshot(src, dest)
			}
		}

		genHeaders := lib.exportedGeneratedHeaders
		for _, file := range genHeaders {
			// lib.ArchType is "" for common properties.
			targetDir := filepath.Join(lib.archType, nativeGeneratedIncludeDir)

			dest := filepath.Join(targetDir, lib.name, file.Rel())
			builder.CopyToSnapshot(file, dest)
		}
	}

	addExportedDirCopyCommandsForNativeLibs(info.commonProperties)

	// for each architecture
	for _, av := range info.archVariantProperties {
		builder.CopyToSnapshot(av.outputFile, nativeLibraryPathFor(av))

		addExportedDirCopyCommandsForNativeLibs(av)
	}

	info.generatePrebuiltLibrary(sdkModuleContext, builder, member)
}

func (info *nativeLibInfo) generatePrebuiltLibrary(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {

	// a function for emitting include dirs
	addExportedDirsForNativeLibs := func(lib nativeLibInfoProperties, properties android.BpPropertySet, systemInclude bool) {
		includeDirs := nativeIncludeDirPathsFor(lib, systemInclude)
		if len(includeDirs) == 0 {
			return
		}
		var propertyName string
		if !systemInclude {
			propertyName = "export_include_dirs"
		} else {
			propertyName = "export_system_include_dirs"
		}
		properties.AddProperty(propertyName, includeDirs)
	}

	pbm := builder.AddPrebuiltModule(member, info.memberType.prebuiltModuleType)

	addExportedDirsForNativeLibs(info.commonProperties, pbm, false /*systemInclude*/)
	addExportedDirsForNativeLibs(info.commonProperties, pbm, true /*systemInclude*/)

	archProperties := pbm.AddPropertySet("arch")
	for _, av := range info.archVariantProperties {
		archTypeProperties := archProperties.AddPropertySet(av.archType)
		archTypeProperties.AddProperty("srcs", []string{nativeLibraryPathFor(av)})

		// export_* properties are added inside the arch: {<arch>: {...}} block
		addExportedDirsForNativeLibs(av, archTypeProperties, false /*systemInclude*/)
		addExportedDirsForNativeLibs(av, archTypeProperties, true /*systemInclude*/)
	}
	pbm.AddProperty("stl", "none")
	pbm.AddProperty("system_shared_libs", []string{})
}

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.archType,
		nativeStubDir, lib.outputFile.Base())
}

// paths to the include dirs of a native shared library. Relative to <sdk_root>/<api_dir>
func nativeIncludeDirPathsFor(lib nativeLibInfoProperties, systemInclude bool) []string {
	var result []string
	var includeDirs []android.Path
	if !systemInclude {
		// Include the generated include dirs in the exported include dirs.
		includeDirs = append(lib.ExportedIncludeDirs, lib.ExportedGeneratedIncludeDirs...)
	} else {
		includeDirs = lib.ExportedSystemIncludeDirs
	}
	for _, dir := range includeDirs {
		var path string
		if isGeneratedHeaderDirectory(dir) {
			path = filepath.Join(nativeGeneratedIncludeDir, lib.name)
		} else {
			path = filepath.Join(nativeIncludeDir, dir.String())
		}

		// lib.ArchType is "" for common properties.
		path = filepath.Join(lib.archType, path)
		result = append(result, path)
	}
	return result
}

// 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 {
	// 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

	ExportedIncludeDirs          android.Paths
	ExportedGeneratedIncludeDirs android.Paths
	ExportedSystemIncludeDirs    android.Paths
	ExportedFlags                []string

	// exportedGeneratedHeaders is not exported as if set it is always arch specific.
	exportedGeneratedHeaders android.Paths

	// outputFile is not exported as it is always arch specific.
	outputFile android.Path
}

// nativeLibInfo represents a collection of arch-specific modules having the same name
type nativeLibInfo struct {
	name                  string
	memberType            *librarySdkMemberType
	archVariantProperties []nativeLibInfoProperties
	commonProperties      nativeLibInfoProperties
}
+320 −0
Original line number Diff line number Diff line
// 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"
	"reflect"

	"android/soong/android"
	"github.com/google/blueprint"
)

// This file contains support for using cc library modules within an sdk.

var SharedLibrarySdkMemberType = &librarySdkMemberType{
	prebuiltModuleType: "cc_prebuilt_library_shared",
	linkTypes:          []string{"shared"},
}

var StaticLibrarySdkMemberType = &librarySdkMemberType{
	prebuiltModuleType: "cc_prebuilt_library_static",
	linkTypes:          []string{"static"},
}

type librarySdkMemberType struct {
	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)
			}
			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 {
	_, ok := module.(*Module)
	return ok
}

// copy exported header files and stub *.so files
func (mt *librarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
	info := mt.organizeVariants(member)
	buildSharedNativeLibSnapshot(sdkModuleContext, info, builder, member)
}

// Organize the variants by architecture.
func (mt *librarySdkMemberType) organizeVariants(member android.SdkMember) *nativeLibInfo {
	memberName := member.Name()
	info := &nativeLibInfo{
		name:       memberName,
		memberType: mt,
	}

	for _, variant := range member.Variants() {
		ccModule := variant.(*Module)

		// 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)

		info.archVariantProperties = append(info.archVariantProperties, nativeLibInfoProperties{
			name:                         memberName,
			archType:                     ccModule.Target().Arch.ArchType.String(),
			ExportedIncludeDirs:          exportedIncludeDirs,
			ExportedGeneratedIncludeDirs: exportedGeneratedIncludeDirs,
			ExportedSystemIncludeDirs:    ccModule.ExportedSystemIncludeDirs(),
			ExportedFlags:                ccModule.ExportedFlags(),
			exportedGeneratedHeaders:     ccModule.ExportedGeneratedHeaders(),
			outputFile:                   ccModule.OutputFile().Path(),
		})
	}

	// Initialize the unexported properties that will not be set during the
	// extraction process.
	info.commonProperties.name = memberName

	// Extract common properties from the arch specific properties.
	extractCommonProperties(&info.commonProperties, info.archVariantProperties)

	return info
}

func isGeneratedHeaderDirectory(p android.Path) bool {
	_, gen := p.(android.WritablePath)
	return gen
}

// Extract common properties from a slice of property structures of the same type.
//
// All the property structures must be of the same type.
// commonProperties - must be a pointer to the structure into which common properties will be added.
// inputPropertiesSlice - must be a slice of input properties structures.
//
// Iterates over each exported field (capitalized name) and checks to see whether they
// have the same value (using DeepEquals) across all the input properties. If it does not then no
// change is made. Otherwise, the common value is stored in the field in the commonProperties
// and the field in each of the input properties structure is set to its default value.
func extractCommonProperties(commonProperties interface{}, inputPropertiesSlice interface{}) {
	commonStructValue := reflect.ValueOf(commonProperties).Elem()
	propertiesStructType := commonStructValue.Type()

	// Create an empty structure from which default values for the field can be copied.
	emptyStructValue := reflect.New(propertiesStructType).Elem()

	for f := 0; f < propertiesStructType.NumField(); f++ {
		// Check to see if all the structures have the same value for the field. The commonValue
		// is nil on entry to the loop and if it is nil on exit then there is no common value,
		// otherwise it points to the common value.
		var commonValue *reflect.Value
		sliceValue := reflect.ValueOf(inputPropertiesSlice)

		for i := 0; i < sliceValue.Len(); i++ {
			structValue := sliceValue.Index(i)
			fieldValue := structValue.Field(f)
			if !fieldValue.CanInterface() {
				// The field is not exported so ignore it.
				continue
			}

			if commonValue == nil {
				// Use the first value as the commonProperties value.
				commonValue = &fieldValue
			} else {
				// If the value does not match the current common value then there is
				// no value in common so break out.
				if !reflect.DeepEqual(fieldValue.Interface(), commonValue.Interface()) {
					commonValue = nil
					break
				}
			}
		}

		// If the fields all have a common value then store it in the common struct field
		// and set the input struct's field to the empty value.
		if commonValue != nil {
			emptyValue := emptyStructValue.Field(f)
			commonStructValue.Field(f).Set(*commonValue)
			for i := 0; i < sliceValue.Len(); i++ {
				structValue := sliceValue.Index(i)
				fieldValue := structValue.Field(f)
				fieldValue.Set(emptyValue)
			}
		}
	}
}

func buildSharedNativeLibSnapshot(sdkModuleContext android.ModuleContext, info *nativeLibInfo, builder android.SnapshotBuilder, member android.SdkMember) {
	// a function for emitting include dirs
	addExportedDirCopyCommandsForNativeLibs := func(lib nativeLibInfoProperties) {
		// Do not include ExportedGeneratedIncludeDirs in the list of directories whose
		// contents are copied as they are copied from exportedGeneratedHeaders below.
		includeDirs := lib.ExportedIncludeDirs
		includeDirs = append(includeDirs, lib.ExportedSystemIncludeDirs...)
		for _, dir := range includeDirs {
			// lib.ArchType is "" for common properties.
			targetDir := filepath.Join(lib.archType, nativeIncludeDir)

			// TODO(jiyong) copy headers having other suffixes
			headers, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.h", nil)
			for _, file := range headers {
				src := android.PathForSource(sdkModuleContext, file)
				dest := filepath.Join(targetDir, file)
				builder.CopyToSnapshot(src, dest)
			}
		}

		genHeaders := lib.exportedGeneratedHeaders
		for _, file := range genHeaders {
			// lib.ArchType is "" for common properties.
			targetDir := filepath.Join(lib.archType, nativeGeneratedIncludeDir)

			dest := filepath.Join(targetDir, lib.name, file.Rel())
			builder.CopyToSnapshot(file, dest)
		}
	}

	addExportedDirCopyCommandsForNativeLibs(info.commonProperties)

	// for each architecture
	for _, av := range info.archVariantProperties {
		builder.CopyToSnapshot(av.outputFile, nativeLibraryPathFor(av))

		addExportedDirCopyCommandsForNativeLibs(av)
	}

	info.generatePrebuiltLibrary(sdkModuleContext, builder, member)
}

func (info *nativeLibInfo) generatePrebuiltLibrary(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {

	// a function for emitting include dirs
	addExportedDirsForNativeLibs := func(lib nativeLibInfoProperties, properties android.BpPropertySet, systemInclude bool) {
		includeDirs := nativeIncludeDirPathsFor(lib, systemInclude)
		if len(includeDirs) == 0 {
			return
		}
		var propertyName string
		if !systemInclude {
			propertyName = "export_include_dirs"
		} else {
			propertyName = "export_system_include_dirs"
		}
		properties.AddProperty(propertyName, includeDirs)
	}

	pbm := builder.AddPrebuiltModule(member, info.memberType.prebuiltModuleType)

	addExportedDirsForNativeLibs(info.commonProperties, pbm, false /*systemInclude*/)
	addExportedDirsForNativeLibs(info.commonProperties, pbm, true /*systemInclude*/)

	archProperties := pbm.AddPropertySet("arch")
	for _, av := range info.archVariantProperties {
		archTypeProperties := archProperties.AddPropertySet(av.archType)
		archTypeProperties.AddProperty("srcs", []string{nativeLibraryPathFor(av)})

		// export_* properties are added inside the arch: {<arch>: {...}} block
		addExportedDirsForNativeLibs(av, archTypeProperties, false /*systemInclude*/)
		addExportedDirsForNativeLibs(av, archTypeProperties, true /*systemInclude*/)
	}
	pbm.AddProperty("stl", "none")
	pbm.AddProperty("system_shared_libs", []string{})
}

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.archType,
		nativeStubDir, lib.outputFile.Base())
}

// paths to the include dirs of a native shared library. Relative to <sdk_root>/<api_dir>
func nativeIncludeDirPathsFor(lib nativeLibInfoProperties, systemInclude bool) []string {
	var result []string
	var includeDirs []android.Path
	if !systemInclude {
		// Include the generated include dirs in the exported include dirs.
		includeDirs = append(lib.ExportedIncludeDirs, lib.ExportedGeneratedIncludeDirs...)
	} else {
		includeDirs = lib.ExportedSystemIncludeDirs
	}
	for _, dir := range includeDirs {
		var path string
		if isGeneratedHeaderDirectory(dir) {
			path = filepath.Join(nativeGeneratedIncludeDir, lib.name)
		} else {
			path = filepath.Join(nativeIncludeDir, dir.String())
		}

		// lib.ArchType is "" for common properties.
		path = filepath.Join(lib.archType, path)
		result = append(result, path)
	}
	return result
}

// 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 {
	// 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

	ExportedIncludeDirs          android.Paths
	ExportedGeneratedIncludeDirs android.Paths
	ExportedSystemIncludeDirs    android.Paths
	ExportedFlags                []string

	// exportedGeneratedHeaders is not exported as if set it is always arch specific.
	exportedGeneratedHeaders android.Paths

	// outputFile is not exported as it is always arch specific.
	outputFile android.Path
}

// nativeLibInfo represents a collection of arch-specific modules having the same name
type nativeLibInfo struct {
	name                  string
	memberType            *librarySdkMemberType
	archVariantProperties []nativeLibInfoProperties
	commonProperties      nativeLibInfoProperties
}