Merge "Refactor sdk update mechanism"

am: 0f568b1237

Change-Id: I03637fd9ac74fb4530cfee5946ac4e96ac45d934
This commit is contained in:
Paul Duffin 2019-11-15 07:24:45 -08:00 committed by android-build-merger
commit 6c6e830af8
3 changed files with 261 additions and 211 deletions

View File

@ -31,6 +31,9 @@ type SdkAware interface {
MemberName() string
BuildWithSdks(sdks SdkRefs)
RequiredSdks() SdkRefs
// Build a snapshot of the module.
BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder)
}
// SdkRef refers to a version of an SDK
@ -103,6 +106,7 @@ type sdkProperties struct {
// interface. InitSdkAwareModule should be called to initialize this struct.
type SdkBase struct {
properties sdkProperties
module SdkAware
}
func (s *SdkBase) sdkBase() *SdkBase {
@ -142,9 +146,34 @@ func (s *SdkBase) RequiredSdks() SdkRefs {
return s.properties.RequiredSdks
}
func (s *SdkBase) BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder) {
sdkModuleContext.ModuleErrorf("module type " + sdkModuleContext.OtherModuleType(s.module) + " cannot be used in an sdk")
}
// InitSdkAwareModule initializes the SdkBase struct. This must be called by all modules including
// SdkBase.
func InitSdkAwareModule(m SdkAware) {
base := m.sdkBase()
base.module = m
m.AddProperties(&base.properties)
}
// Provide support for generating the build rules which will build the snapshot.
type SnapshotBuilder interface {
// Copy src to the dest (which is a snapshot relative path) and add the dest
// to the zip
CopyToSnapshot(src Path, dest string)
// Get the AndroidBpFile for the snapshot.
AndroidBpFile() GeneratedSnapshotFile
// Get a versioned name appropriate for the SDK snapshot version being taken.
VersionedSdkMemberName(unversionedName string) interface{}
}
// Provides support for generating a file, e.g. the Android.bp file.
type GeneratedSnapshotFile interface {
Printfln(format string, args ...interface{})
Indent()
Dedent()
}

View File

@ -1664,6 +1664,57 @@ func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {
j.deps(ctx)
}
const (
aidlIncludeDir = "aidl"
javaStubDir = "java"
javaStubFileSuffix = ".jar"
)
// path to the stub file of a java library. Relative to <sdk_root>/<api_dir>
func (j *Library) javaStubFilePathFor() string {
return filepath.Join(javaStubDir, j.Name()+javaStubFileSuffix)
}
func (j *Library) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder) {
headerJars := j.HeaderJars()
if len(headerJars) != 1 {
panic(fmt.Errorf("there must be only one header jar from %q", j.Name()))
}
snapshotRelativeJavaLibPath := j.javaStubFilePathFor()
builder.CopyToSnapshot(headerJars[0], snapshotRelativeJavaLibPath)
for _, dir := range j.AidlIncludeDirs() {
// TODO(jiyong): copy parcelable declarations only
aidlFiles, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.aidl", nil)
for _, file := range aidlFiles {
builder.CopyToSnapshot(android.PathForSource(sdkModuleContext, file), filepath.Join(aidlIncludeDir, file))
}
}
name := j.Name()
bp := builder.AndroidBpFile()
bp.Printfln("java_import {")
bp.Indent()
bp.Printfln("name: %q,", builder.VersionedSdkMemberName(name))
bp.Printfln("sdk_member_name: %q,", name)
bp.Printfln("jars: [%q],", snapshotRelativeJavaLibPath)
bp.Dedent()
bp.Printfln("}")
bp.Printfln("")
// This module is for the case when the source tree for the unversioned module
// doesn't exist (i.e. building in an unbundled tree). "prefer:" is set to false
// so that this module does not eclipse the unversioned module if it exists.
bp.Printfln("java_import {")
bp.Indent()
bp.Printfln("name: %q,", name)
bp.Printfln("jars: [%q],", snapshotRelativeJavaLibPath)
bp.Printfln("prefer: false,")
bp.Dedent()
bp.Printfln("}")
bp.Printfln("")
}
// java_library builds and links sources into a `.jar` file for the device, and possibly for the host as well.
//
// By default, a java_library has a single variant that produces a `.jar` file containing `.class` files that were

View File

@ -43,17 +43,17 @@ func newGeneratedFile(ctx android.ModuleContext, path ...string) *generatedFile
}
}
func (gf *generatedFile) indent() {
func (gf *generatedFile) Indent() {
gf.indentLevel++
}
func (gf *generatedFile) dedent() {
func (gf *generatedFile) Dedent() {
gf.indentLevel--
}
func (gf *generatedFile) printfln(format string, args ...interface{}) {
func (gf *generatedFile) Printfln(format string, args ...interface{}) {
// ninja consumes newline characters in rspfile_content. Prevent it by
// escaping the backslash in the newline character. The extra backshash
// escaping the backslash in the newline character. The extra backslash
// is removed when the rspfile is written to the actual script file
fmt.Fprintf(&(gf.content), strings.Repeat(" ", gf.indentLevel)+format+"\\n", args...)
}
@ -70,8 +70,8 @@ func (gf *generatedFile) build(pctx android.PackageContext, ctx android.BuilderC
rb.Build(pctx, ctx, gf.path.Base(), "Build "+gf.path.Base())
}
func (s *sdk) javaLibs(ctx android.ModuleContext) []*java.Library {
result := []*java.Library{}
func (s *sdk) javaLibs(ctx android.ModuleContext) []android.SdkAware {
result := []android.SdkAware{}
ctx.VisitDirectDeps(func(m android.Module) {
if j, ok := m.(*java.Library); ok {
result = append(result, j)
@ -180,20 +180,12 @@ func (s *sdk) nativeMemberInfos(ctx android.ModuleContext) []*nativeLibInfo {
// libFoo.so : a stub library
const (
aidlIncludeDir = "aidl"
javaStubDir = "java"
javaStubFileSuffix = ".jar"
nativeIncludeDir = "include"
nativeGeneratedIncludeDir = "include_gen"
nativeStubDir = "lib"
nativeStubFileSuffix = ".so"
)
// path to the stub file of a java library. Relative to <sdk_root>/<api_dir>
func javaStubFilePathFor(javaLib *java.Library) string {
return filepath.Join(javaStubDir, javaLib.Name()+javaStubFileSuffix)
}
// path to the stub file of a native shared library. Relative to <sdk_root>/<api_dir>
func nativeStubFilePathFor(lib archSpecificNativeLibInfo) string {
return filepath.Join(lib.archType,
@ -231,163 +223,80 @@ func versionedSdkMemberName(ctx android.ModuleContext, memberName string, versio
return ctx.ModuleName() + "_" + memberName + string(android.SdkVersionSeparator) + version
}
// buildAndroidBp creates the blueprint file that defines prebuilt modules for each of
// the SDK members, and the entire sdk_snapshot module for the specified version
// TODO(jiyong): create a meta info file (e.g. json, protobuf, etc.) instead, and convert it to
// Android.bp in the (presumably old) branch where the snapshots will be used. This will give us
// some flexibility to introduce backwards incompatible changes in soong.
func (s *sdk) buildAndroidBp(ctx android.ModuleContext, version string) android.OutputPath {
bp := newGeneratedFile(ctx, "snapshot", "Android.bp")
bp.printfln("// This is auto-generated. DO NOT EDIT.")
bp.printfln("")
javaLibModules := s.javaLibs(ctx)
for _, m := range javaLibModules {
name := m.Name()
bp.printfln("java_import {")
bp.indent()
bp.printfln("name: %q,", versionedSdkMemberName(ctx, name, version))
bp.printfln("sdk_member_name: %q,", name)
bp.printfln("jars: [%q],", javaStubFilePathFor(m))
bp.dedent()
bp.printfln("}")
bp.printfln("")
// This module is for the case when the source tree for the unversioned module
// doesn't exist (i.e. building in an unbundled tree). "prefer:" is set to false
// so that this module does not eclipse the unversioned module if it exists.
bp.printfln("java_import {")
bp.indent()
bp.printfln("name: %q,", name)
bp.printfln("jars: [%q],", javaStubFilePathFor(m))
bp.printfln("prefer: false,")
bp.dedent()
bp.printfln("}")
bp.printfln("")
}
nativeLibInfos := s.nativeMemberInfos(ctx)
for _, info := range nativeLibInfos {
bp.printfln("cc_prebuilt_library_shared {")
bp.indent()
bp.printfln("name: %q,", versionedSdkMemberName(ctx, info.name, version))
bp.printfln("sdk_member_name: %q,", info.name)
// a function for emitting include dirs
printExportedDirsForNativeLibs := func(lib archSpecificNativeLibInfo, systemInclude bool) {
includeDirs := nativeIncludeDirPathsFor(ctx, lib, systemInclude, info.hasArchSpecificFlags)
if len(includeDirs) == 0 {
return
}
if !systemInclude {
bp.printfln("export_include_dirs: [")
} else {
bp.printfln("export_system_include_dirs: [")
}
bp.indent()
for _, dir := range includeDirs {
bp.printfln("%q,", dir)
}
bp.dedent()
bp.printfln("],")
}
if !info.hasArchSpecificFlags {
printExportedDirsForNativeLibs(info.archVariants[0], false /*systemInclude*/)
printExportedDirsForNativeLibs(info.archVariants[0], true /*systemInclude*/)
}
bp.printfln("arch: {")
bp.indent()
for _, av := range info.archVariants {
bp.printfln("%s: {", av.archType)
bp.indent()
bp.printfln("srcs: [%q],", nativeStubFilePathFor(av))
if info.hasArchSpecificFlags {
// export_* properties are added inside the arch: {<arch>: {...}} block
printExportedDirsForNativeLibs(av, false /*systemInclude*/)
printExportedDirsForNativeLibs(av, true /*systemInclude*/)
}
bp.dedent()
bp.printfln("},") // <arch>
}
bp.dedent()
bp.printfln("},") // arch
bp.printfln("stl: \"none\",")
bp.printfln("system_shared_libs: [],")
bp.dedent()
bp.printfln("}") // cc_prebuilt_library_shared
bp.printfln("")
}
bp.printfln("sdk_snapshot {")
bp.indent()
bp.printfln("name: %q,", ctx.ModuleName()+string(android.SdkVersionSeparator)+version)
if len(javaLibModules) > 0 {
bp.printfln("java_libs: [")
bp.indent()
for _, m := range javaLibModules {
bp.printfln("%q,", versionedSdkMemberName(ctx, m.Name(), version))
}
bp.dedent()
bp.printfln("],") // java_libs
}
if len(nativeLibInfos) > 0 {
bp.printfln("native_shared_libs: [")
bp.indent()
for _, info := range nativeLibInfos {
bp.printfln("%q,", versionedSdkMemberName(ctx, info.name, version))
}
bp.dedent()
bp.printfln("],") // native_shared_libs
}
bp.dedent()
bp.printfln("}") // sdk_snapshot
bp.printfln("")
bp.build(pctx, ctx, nil)
return bp.path
}
// buildSnapshot is the main function in this source file. It creates rules to copy
// the contents (header files, stub libraries, etc) into the zip file.
func (s *sdk) buildSnapshot(ctx android.ModuleContext) android.OutputPath {
snapshotPath := func(paths ...string) android.OutputPath {
return android.PathForModuleOut(ctx, "snapshot").Join(ctx, paths...)
}
snapshotDir := android.PathForModuleOut(ctx, "snapshot")
var filesToZip android.Paths
// copy src to dest and add the dest to the zip
copy := func(src android.Path, dest android.OutputPath) {
ctx.Build(pctx, android.BuildParams{
Rule: android.Cp,
Input: src,
Output: dest,
})
filesToZip = append(filesToZip, dest)
bp := newGeneratedFile(ctx, "snapshot", "Android.bp")
bp.Printfln("// This is auto-generated. DO NOT EDIT.")
bp.Printfln("")
builder := &snapshotBuilder{
ctx: ctx,
version: "current",
snapshotDir: snapshotDir.OutputPath,
androidBpFile: bp,
filesToZip: []android.Path{bp.path},
}
// copy exported AIDL files and stub jar files
for _, m := range s.javaLibs(ctx) {
headerJars := m.HeaderJars()
if len(headerJars) != 1 {
panic(fmt.Errorf("there must be only one header jar from %q", m.Name()))
}
copy(headerJars[0], snapshotPath(javaStubFilePathFor(m)))
for _, dir := range m.AidlIncludeDirs() {
// TODO(jiyong): copy parcelable declarations only
aidlFiles, _ := ctx.GlobWithDeps(dir.String()+"/**/*.aidl", nil)
for _, file := range aidlFiles {
copy(android.PathForSource(ctx, file), snapshotPath(aidlIncludeDir, file))
}
}
javaLibs := s.javaLibs(ctx)
for _, m := range javaLibs {
m.BuildSnapshot(ctx, builder)
}
// copy exported header files and stub *.so files
nativeLibInfos := s.nativeMemberInfos(ctx)
for _, info := range nativeLibInfos {
buildSharedNativeLibSnapshot(ctx, info, builder)
}
// generate Android.bp
bp.Printfln("sdk_snapshot {")
bp.Indent()
bp.Printfln("name: %q,", ctx.ModuleName()+string(android.SdkVersionSeparator)+builder.version)
if len(javaLibs) > 0 {
bp.Printfln("java_libs: [")
bp.Indent()
for _, m := range javaLibs {
bp.Printfln("%q,", builder.VersionedSdkMemberName(m.Name()))
}
bp.Dedent()
bp.Printfln("],") // java_libs
}
if len(nativeLibInfos) > 0 {
bp.Printfln("native_shared_libs: [")
bp.Indent()
for _, info := range nativeLibInfos {
bp.Printfln("%q,", builder.VersionedSdkMemberName(info.name))
}
bp.Dedent()
bp.Printfln("],") // native_shared_libs
}
bp.Dedent()
bp.Printfln("}") // sdk_snapshot
bp.Printfln("")
bp.build(pctx, ctx, nil)
filesToZip := builder.filesToZip
// zip them all
zipFile := android.PathForModuleOut(ctx, ctx.ModuleName()+"-current.zip").OutputPath
rb := android.NewRuleBuilder()
rb.Command().
BuiltTool(ctx, "soong_zip").
FlagWithArg("-C ", builder.snapshotDir.String()).
FlagWithRspFileInputList("-l ", filesToZip).
FlagWithOutput("-o ", zipFile)
rb.Build(pctx, ctx, "snapshot", "Building snapshot for "+ctx.ModuleName())
return zipFile
}
func buildSharedNativeLibSnapshot(ctx android.ModuleContext, info *nativeLibInfo, builder android.SnapshotBuilder) {
// a function for emitting include dirs
printExportedDirCopyCommandsForNativeLibs := func(lib archSpecificNativeLibInfo) {
includeDirs := lib.exportedIncludeDirs
@ -409,8 +318,8 @@ func (s *sdk) buildSnapshot(ctx android.ModuleContext) android.OutputPath {
headers, _ := ctx.GlobWithDeps(dir.String()+"/**/*.h", nil)
for _, file := range headers {
src := android.PathForSource(ctx, file)
dest := snapshotPath(targetDir, file)
copy(src, dest)
dest := filepath.Join(targetDir, file)
builder.CopyToSnapshot(src, dest)
}
}
@ -420,8 +329,8 @@ func (s *sdk) buildSnapshot(ctx android.ModuleContext) android.OutputPath {
if info.hasArchSpecificFlags {
targetDir = filepath.Join(lib.archType, targetDir)
}
dest := snapshotPath(targetDir, lib.name, file.Rel())
copy(file, dest)
dest := filepath.Join(targetDir, lib.name, file.Rel())
builder.CopyToSnapshot(file, dest)
}
}
@ -431,27 +340,88 @@ func (s *sdk) buildSnapshot(ctx android.ModuleContext) android.OutputPath {
// for each architecture
for _, av := range info.archVariants {
copy(av.outputFile, snapshotPath(nativeStubFilePathFor(av)))
builder.CopyToSnapshot(av.outputFile, nativeStubFilePathFor(av))
if info.hasArchSpecificFlags {
printExportedDirCopyCommandsForNativeLibs(av)
}
}
bp := builder.AndroidBpFile()
bp.Printfln("cc_prebuilt_library_shared {")
bp.Indent()
bp.Printfln("name: %q,", builder.VersionedSdkMemberName(info.name))
bp.Printfln("sdk_member_name: %q,", info.name)
// a function for emitting include dirs
printExportedDirsForNativeLibs := func(lib archSpecificNativeLibInfo, systemInclude bool) {
includeDirs := nativeIncludeDirPathsFor(ctx, lib, systemInclude, info.hasArchSpecificFlags)
if len(includeDirs) == 0 {
return
}
if !systemInclude {
bp.Printfln("export_include_dirs: [")
} else {
bp.Printfln("export_system_include_dirs: [")
}
bp.Indent()
for _, dir := range includeDirs {
bp.Printfln("%q,", dir)
}
bp.Dedent()
bp.Printfln("],")
}
// generate Android.bp
bp := s.buildAndroidBp(ctx, "current")
filesToZip = append(filesToZip, bp)
if !info.hasArchSpecificFlags {
printExportedDirsForNativeLibs(info.archVariants[0], false /*systemInclude*/)
printExportedDirsForNativeLibs(info.archVariants[0], true /*systemInclude*/)
}
// zip them all
zipFile := android.PathForModuleOut(ctx, ctx.ModuleName()+"-current.zip").OutputPath
rb := android.NewRuleBuilder()
rb.Command().
BuiltTool(ctx, "soong_zip").
FlagWithArg("-C ", snapshotPath().String()).
FlagWithRspFileInputList("-l ", filesToZip).
FlagWithOutput("-o ", zipFile)
rb.Build(pctx, ctx, "snapshot", "Building snapshot for "+ctx.ModuleName())
return zipFile
bp.Printfln("arch: {")
bp.Indent()
for _, av := range info.archVariants {
bp.Printfln("%s: {", av.archType)
bp.Indent()
bp.Printfln("srcs: [%q],", nativeStubFilePathFor(av))
if info.hasArchSpecificFlags {
// export_* properties are added inside the arch: {<arch>: {...}} block
printExportedDirsForNativeLibs(av, false /*systemInclude*/)
printExportedDirsForNativeLibs(av, true /*systemInclude*/)
}
bp.Dedent()
bp.Printfln("},") // <arch>
}
bp.Dedent()
bp.Printfln("},") // arch
bp.Printfln("stl: \"none\",")
bp.Printfln("system_shared_libs: [],")
bp.Dedent()
bp.Printfln("}") // cc_prebuilt_library_shared
bp.Printfln("")
}
type snapshotBuilder struct {
ctx android.ModuleContext
version string
snapshotDir android.OutputPath
filesToZip android.Paths
androidBpFile *generatedFile
}
func (s *snapshotBuilder) CopyToSnapshot(src android.Path, dest string) {
path := s.snapshotDir.Join(s.ctx, dest)
s.ctx.Build(pctx, android.BuildParams{
Rule: android.Cp,
Input: src,
Output: path,
})
s.filesToZip = append(s.filesToZip, path)
}
func (s *snapshotBuilder) AndroidBpFile() android.GeneratedSnapshotFile {
return s.androidBpFile
}
func (s *snapshotBuilder) VersionedSdkMemberName(unversionedName string) interface{} {
return versionedSdkMemberName(s.ctx, unversionedName, s.version)
}