SDK snapshot is dist'ed

`m module_sdk dist` produces snapshots of all SDKs in the source tree.
A snapshot is a zip file consists of Android.bp, exported headers,
exported AIDL files, stubs for native libs and jars. The zip file is
expected to be downloaded from the build server and extracted to a
directory (which probably will be
/prebuilts/module_sdks/<module_name>/current).

Bug: 138182343
Test: m (sdk_test.go updated)

Change-Id: Idbe4bc24795fe08f26fc1cf7497028f9d162053a
This commit is contained in:
Jiyong Park
2019-11-04 12:23:40 +09:00
parent b9a80a0716
commit 232e785b98
4 changed files with 167 additions and 139 deletions

View File

@@ -858,21 +858,28 @@ func (c *Module) ExportedIncludeDirs() android.Paths {
if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok { if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok {
return flagsProducer.exportedDirs() return flagsProducer.exportedDirs()
} }
return []android.Path{} return nil
} }
func (c *Module) ExportedSystemIncludeDirs() android.Paths { func (c *Module) ExportedSystemIncludeDirs() android.Paths {
if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok { if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok {
return flagsProducer.exportedSystemDirs() return flagsProducer.exportedSystemDirs()
} }
return []android.Path{} return nil
} }
func (c *Module) ExportedFlags() []string { func (c *Module) ExportedFlags() []string {
if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok { if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok {
return flagsProducer.exportedFlags() return flagsProducer.exportedFlags()
} }
return []string{} return nil
}
func (c *Module) ExportedDeps() android.Paths {
if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok {
return flagsProducer.exportedDeps()
}
return nil
} }
func isBionic(name string) bool { func isBionic(name string) bool {

View File

@@ -29,6 +29,7 @@ import (
) )
func init() { func init() {
pctx.Import("android/soong/android")
android.RegisterModuleType("sdk", ModuleFactory) android.RegisterModuleType("sdk", ModuleFactory)
android.RegisterModuleType("sdk_snapshot", SnapshotModuleFactory) android.RegisterModuleType("sdk_snapshot", SnapshotModuleFactory)
android.PreDepsMutators(RegisterPreDepsMutators) android.PreDepsMutators(RegisterPreDepsMutators)
@@ -41,8 +42,7 @@ type sdk struct {
properties sdkProperties properties sdkProperties
updateScript android.OutputPath snapshotFile android.OptionalPath
freezeScript android.OutputPath
} }
type sdkProperties struct { type sdkProperties struct {
@@ -104,11 +104,24 @@ func (s *sdk) frozenVersions(ctx android.BaseModuleContext) []string {
} }
func (s *sdk) GenerateAndroidBuildActions(ctx android.ModuleContext) { func (s *sdk) GenerateAndroidBuildActions(ctx android.ModuleContext) {
s.buildSnapshotGenerationScripts(ctx) if !s.snapshot() {
// We don't need to create a snapshot out of sdk_snapshot.
// That doesn't make sense. We need a snapshot to create sdk_snapshot.
s.snapshotFile = android.OptionalPathForPath(s.buildSnapshot(ctx))
}
} }
func (s *sdk) AndroidMkEntries() android.AndroidMkEntries { func (s *sdk) AndroidMkEntries() android.AndroidMkEntries {
return s.androidMkEntriesForScript() if !s.snapshotFile.Valid() {
return android.AndroidMkEntries{}
}
return android.AndroidMkEntries{
Class: "FAKE",
OutputFile: s.snapshotFile,
DistFile: s.snapshotFile,
Include: "$(BUILD_PHONY_PACKAGE)",
}
} }
// RegisterPreDepsMutators registers pre-deps mutators to support modules implementing SdkAware // RegisterPreDepsMutators registers pre-deps mutators to support modules implementing SdkAware

View File

@@ -17,6 +17,7 @@ package sdk
import ( import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath"
"strings" "strings"
"testing" "testing"
@@ -100,6 +101,8 @@ func testSdkContext(t *testing.T, bp string) (*android.TestContext, android.Conf
"myapex.pk8": nil, "myapex.pk8": nil,
"Test.java": nil, "Test.java": nil,
"Test.cpp": nil, "Test.cpp": nil,
"include/Test.h": nil,
"aidl/foo/bar/Test.aidl": nil,
"libfoo.so": nil, "libfoo.so": nil,
}) })
@@ -398,7 +401,9 @@ func TestSdkIsCompileMultilibBoth(t *testing.T) {
var inputs []string var inputs []string
buildParams := ctx.ModuleForTests("mysdk", "android_common").Module().BuildParamsForTests() buildParams := ctx.ModuleForTests("mysdk", "android_common").Module().BuildParamsForTests()
for _, bp := range buildParams { for _, bp := range buildParams {
inputs = append(inputs, bp.Implicits.Strings()...) if bp.Input != nil {
inputs = append(inputs, bp.Input.String())
}
} }
// ensure that both 32/64 outputs are inputs of the sdk snapshot // ensure that both 32/64 outputs are inputs of the sdk snapshot
@@ -406,6 +411,69 @@ func TestSdkIsCompileMultilibBoth(t *testing.T) {
ensureListContains(t, inputs, arm64Output.String()) ensureListContains(t, inputs, arm64Output.String())
} }
func TestSnapshot(t *testing.T) {
ctx, config := testSdk(t, `
sdk {
name: "mysdk",
java_libs: ["myjavalib"],
native_shared_libs: ["mynativelib"],
}
java_library {
name: "myjavalib",
srcs: ["Test.java"],
aidl: {
export_include_dirs: ["aidl"],
},
system_modules: "none",
sdk_version: "none",
compile_dex: true,
host_supported: true,
}
cc_library_shared {
name: "mynativelib",
srcs: [
"Test.cpp",
"aidl/foo/bar/Test.aidl",
],
export_include_dirs: ["include"],
aidl: {
export_aidl_headers: true,
},
system_shared_libs: [],
stl: "none",
}
`)
var copySrcs []string
var copyDests []string
buildParams := ctx.ModuleForTests("mysdk", "android_common").Module().BuildParamsForTests()
for _, bp := range buildParams {
if bp.Rule.String() == "android/soong/android.Cp" {
copySrcs = append(copySrcs, bp.Input.String())
copyDests = append(copyDests, bp.Output.Rel()) // rooted at the snapshot root
}
}
buildDir := config.BuildDir()
ensureListContains(t, copySrcs, "aidl/foo/bar/Test.aidl")
ensureListContains(t, copySrcs, "include/Test.h")
ensureListContains(t, copySrcs, filepath.Join(buildDir, ".intermediates/mynativelib/android_arm64_armv8-a_core_shared/gen/aidl/aidl/foo/bar/BnTest.h"))
ensureListContains(t, copySrcs, filepath.Join(buildDir, ".intermediates/mynativelib/android_arm64_armv8-a_core_shared/gen/aidl/aidl/foo/bar/BpTest.h"))
ensureListContains(t, copySrcs, filepath.Join(buildDir, ".intermediates/mynativelib/android_arm64_armv8-a_core_shared/gen/aidl/aidl/foo/bar/Test.h"))
ensureListContains(t, copySrcs, filepath.Join(buildDir, ".intermediates/myjavalib/android_common/turbine-combined/myjavalib.jar"))
ensureListContains(t, copySrcs, filepath.Join(buildDir, ".intermediates/mynativelib/android_arm64_armv8-a_core_shared/mynativelib.so"))
ensureListContains(t, copyDests, "aidl/aidl/foo/bar/Test.aidl")
ensureListContains(t, copyDests, "arm64/include/include/Test.h")
ensureListContains(t, copyDests, "arm64/include_gen/mynativelib/aidl/foo/bar/BnTest.h")
ensureListContains(t, copyDests, "arm64/include_gen/mynativelib/aidl/foo/bar/BpTest.h")
ensureListContains(t, copyDests, "arm64/include_gen/mynativelib/aidl/foo/bar/Test.h")
ensureListContains(t, copyDests, "java/myjavalib.jar")
ensureListContains(t, copyDests, "arm64/lib/mynativelib.so")
}
var buildDir string var buildDir string
func setUp() { func setUp() {

View File

@@ -16,9 +16,7 @@ package sdk
import ( import (
"fmt" "fmt"
"io"
"path/filepath" "path/filepath"
"strconv"
"strings" "strings"
"github.com/google/blueprint/proptools" "github.com/google/blueprint/proptools"
@@ -38,9 +36,9 @@ type generatedFile struct {
indentLevel int indentLevel int
} }
func newGeneratedFile(ctx android.ModuleContext, name string) *generatedFile { func newGeneratedFile(ctx android.ModuleContext, path ...string) *generatedFile {
return &generatedFile{ return &generatedFile{
path: android.PathForModuleOut(ctx, name).OutputPath, path: android.PathForModuleOut(ctx, path...).OutputPath,
indentLevel: 0, indentLevel: 0,
} }
} }
@@ -89,6 +87,7 @@ type archSpecificNativeLibInfo struct {
exportedIncludeDirs android.Paths exportedIncludeDirs android.Paths
exportedSystemIncludeDirs android.Paths exportedSystemIncludeDirs android.Paths
exportedFlags []string exportedFlags []string
exportedDeps android.Paths
outputFile android.Path outputFile android.Path
} }
@@ -132,6 +131,7 @@ func (s *sdk) nativeMemberInfos(ctx android.ModuleContext) []*nativeLibInfo {
exportedIncludeDirs: ccModule.ExportedIncludeDirs(), exportedIncludeDirs: ccModule.ExportedIncludeDirs(),
exportedSystemIncludeDirs: ccModule.ExportedSystemIncludeDirs(), exportedSystemIncludeDirs: ccModule.ExportedSystemIncludeDirs(),
exportedFlags: ccModule.ExportedFlags(), exportedFlags: ccModule.ExportedFlags(),
exportedDeps: ccModule.ExportedDeps(),
outputFile: ccModule.OutputFile().Path(), outputFile: ccModule.OutputFile().Path(),
}) })
}) })
@@ -169,11 +169,11 @@ func (s *sdk) nativeMemberInfos(ctx android.ModuleContext) []*nativeLibInfo {
// aidl/ // aidl/
// frameworks/base/core/..../IFoo.aidl : an exported AIDL file // frameworks/base/core/..../IFoo.aidl : an exported AIDL file
// java/ // java/
// java/<module_name>/stub.jar : a stub jar for a java library 'module_name' // <module_name>.jar : the stub jar for a java library 'module_name'
// include/ // include/
// bionic/libc/include/stdlib.h : an exported header file // bionic/libc/include/stdlib.h : an exported header file
// include_gen/ // include_gen/
// com/android/.../IFoo.h : a generated header file // <module_name>/com/android/.../IFoo.h : a generated header file
// <arch>/include/ : arch-specific exported headers // <arch>/include/ : arch-specific exported headers
// <arch>/include_gen/ : arch-specific generated headers // <arch>/include_gen/ : arch-specific generated headers
// <arch>/lib/ // <arch>/lib/
@@ -182,7 +182,7 @@ func (s *sdk) nativeMemberInfos(ctx android.ModuleContext) []*nativeLibInfo {
const ( const (
aidlIncludeDir = "aidl" aidlIncludeDir = "aidl"
javaStubDir = "java" javaStubDir = "java"
javaStubFile = "stub.jar" javaStubFileSuffix = ".jar"
nativeIncludeDir = "include" nativeIncludeDir = "include"
nativeGeneratedIncludeDir = "include_gen" nativeGeneratedIncludeDir = "include_gen"
nativeStubDir = "lib" nativeStubDir = "lib"
@@ -191,7 +191,7 @@ const (
// path to the stub file of a java library. Relative to <sdk_root>/<api_dir> // path to the stub file of a java library. Relative to <sdk_root>/<api_dir>
func javaStubFilePathFor(javaLib *java.Library) string { func javaStubFilePathFor(javaLib *java.Library) string {
return filepath.Join(javaStubDir, javaLib.Name(), javaStubFile) return filepath.Join(javaStubDir, javaLib.Name()+javaStubFileSuffix)
} }
// path to the stub file of a native shared library. Relative to <sdk_root>/<api_dir> // path to the stub file of a native shared library. Relative to <sdk_root>/<api_dir>
@@ -204,7 +204,6 @@ func nativeStubFilePathFor(lib archSpecificNativeLibInfo) string {
func nativeIncludeDirPathsFor(ctx android.ModuleContext, lib archSpecificNativeLibInfo, func nativeIncludeDirPathsFor(ctx android.ModuleContext, lib archSpecificNativeLibInfo,
systemInclude bool, archSpecific bool) []string { systemInclude bool, archSpecific bool) []string {
var result []string var result []string
buildDir := ctx.Config().BuildDir()
var includeDirs []android.Path var includeDirs []android.Path
if !systemInclude { if !systemInclude {
includeDirs = lib.exportedIncludeDirs includeDirs = lib.exportedIncludeDirs
@@ -213,8 +212,8 @@ func nativeIncludeDirPathsFor(ctx android.ModuleContext, lib archSpecificNativeL
} }
for _, dir := range includeDirs { for _, dir := range includeDirs {
var path string var path string
if gen := strings.HasPrefix(dir.String(), buildDir); gen { if _, gen := dir.(android.WritablePath); gen {
path = filepath.Join(nativeGeneratedIncludeDir, dir.Rel()) path = filepath.Join(nativeGeneratedIncludeDir, lib.name)
} else { } else {
path = filepath.Join(nativeIncludeDir, dir.String()) path = filepath.Join(nativeIncludeDir, dir.String())
} }
@@ -226,21 +225,19 @@ func nativeIncludeDirPathsFor(ctx android.ModuleContext, lib archSpecificNativeL
return result return result
} }
// A name that uniquely identifies an prebuilt SDK member for a version of SDK snapshot // A name that uniquely identifies a prebuilt SDK member for a version of SDK snapshot
// This isn't visible to users, so could be changed in future. // This isn't visible to users, so could be changed in future.
func versionedSdkMemberName(ctx android.ModuleContext, memberName string, version string) string { func versionedSdkMemberName(ctx android.ModuleContext, memberName string, version string) string {
return ctx.ModuleName() + "_" + memberName + string(android.SdkVersionSeparator) + version return ctx.ModuleName() + "_" + memberName + string(android.SdkVersionSeparator) + version
} }
// arm64, arm, x86, x86_64, etc.
func archTypeOf(module android.Module) string {
return module.Target().Arch.ArchType.String()
}
// buildAndroidBp creates the blueprint file that defines prebuilt modules for each of // 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 // 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 { func (s *sdk) buildAndroidBp(ctx android.ModuleContext, version string) android.OutputPath {
bp := newGeneratedFile(ctx, "blueprint-"+version+".bp") bp := newGeneratedFile(ctx, "snapshot", "Android.bp")
bp.printfln("// This is auto-generated. DO NOT EDIT.") bp.printfln("// This is auto-generated. DO NOT EDIT.")
bp.printfln("") bp.printfln("")
@@ -352,52 +349,42 @@ func (s *sdk) buildAndroidBp(ctx android.ModuleContext, version string) android.
return bp.path return bp.path
} }
func (s *sdk) buildScript(ctx android.ModuleContext, version string) android.OutputPath { // buildSnapshot is the main function in this source file. It creates rules to copy
sh := newGeneratedFile(ctx, "update_prebuilt-"+version+".sh") // the contents (header files, stub libraries, etc) into the zip file.
buildDir := ctx.Config().BuildDir() func (s *sdk) buildSnapshot(ctx android.ModuleContext) android.OutputPath {
snapshotPath := func(paths ...string) android.OutputPath {
snapshotPath := func(paths ...string) string { return android.PathForModuleOut(ctx, "snapshot").Join(ctx, paths...)
return filepath.Join(ctx.ModuleDir(), version, filepath.Join(paths...))
} }
// TODO(jiyong) instead of creating script, create a zip file having the Android.bp, the headers, var filesToZip android.Paths
// and the stubs and put it to the dist directory. The dist'ed zip file then would be downloaded, // copy src to dest and add the dest to the zip
// unzipped and then uploaded to gerrit again. copy := func(src android.Path, dest android.OutputPath) {
sh.printfln("#!/bin/bash") ctx.Build(pctx, android.BuildParams{
sh.printfln("echo Updating snapshot of %s in %s", ctx.ModuleName(), snapshotPath()) Rule: android.Cp,
sh.printfln("pushd $ANDROID_BUILD_TOP > /dev/null") Input: src,
sh.printfln("mkdir -p %s", snapshotPath(aidlIncludeDir)) Output: dest,
sh.printfln("mkdir -p %s", snapshotPath(javaStubDir)) })
sh.printfln("mkdir -p %s", snapshotPath(nativeIncludeDir)) filesToZip = append(filesToZip, dest)
sh.printfln("mkdir -p %s", snapshotPath(nativeGeneratedIncludeDir))
for _, target := range ctx.MultiTargets() {
arch := target.Arch.ArchType.String()
sh.printfln("mkdir -p %s", snapshotPath(arch, nativeStubDir))
sh.printfln("mkdir -p %s", snapshotPath(arch, nativeIncludeDir))
sh.printfln("mkdir -p %s", snapshotPath(arch, nativeGeneratedIncludeDir))
} }
var implicits android.Paths // copy exported AIDL files and stub jar files
for _, m := range s.javaLibs(ctx) { for _, m := range s.javaLibs(ctx) {
headerJars := m.HeaderJars() headerJars := m.HeaderJars()
if len(headerJars) != 1 { if len(headerJars) != 1 {
panic(fmt.Errorf("there must be only one header jar from %q", m.Name())) panic(fmt.Errorf("there must be only one header jar from %q", m.Name()))
} }
implicits = append(implicits, headerJars...) copy(headerJars[0], snapshotPath(javaStubFilePathFor(m)))
exportedAidlIncludeDirs := m.AidlIncludeDirs() for _, dir := range m.AidlIncludeDirs() {
for _, dir := range exportedAidlIncludeDirs {
// Using tar to copy with the directory structure
// TODO(jiyong): copy parcelable declarations only // TODO(jiyong): copy parcelable declarations only
sh.printfln("find %s -name \"*.aidl\" | tar cf - -T - | (cd %s; tar xf -)", aidlFiles, _ := ctx.GlobWithDeps(dir.String()+"/**/*.aidl", nil)
dir.String(), snapshotPath(aidlIncludeDir)) for _, file := range aidlFiles {
} copy(android.PathForSource(ctx, file), snapshotPath(aidlIncludeDir, file))
}
copyTarget := snapshotPath(javaStubFilePathFor(m)) }
sh.printfln("mkdir -p %s && cp %s %s",
filepath.Dir(copyTarget), headerJars[0].String(), copyTarget)
} }
// copy exported header files and stub *.so files
nativeLibInfos := s.nativeMemberInfos(ctx) nativeLibInfos := s.nativeMemberInfos(ctx)
for _, info := range nativeLibInfos { for _, info := range nativeLibInfos {
@@ -409,26 +396,32 @@ func (s *sdk) buildScript(ctx android.ModuleContext, version string) android.Out
return return
} }
for _, dir := range includeDirs { for _, dir := range includeDirs {
gen := strings.HasPrefix(dir.String(), buildDir) if _, gen := dir.(android.WritablePath); gen {
targetDir := nativeIncludeDir // generated headers are copied via exportedDeps. See below.
if gen { continue
targetDir = nativeGeneratedIncludeDir
} }
targetDir := nativeIncludeDir
if info.hasArchSpecificFlags { if info.hasArchSpecificFlags {
targetDir = filepath.Join(lib.archType, targetDir) targetDir = filepath.Join(lib.archType, targetDir)
} }
targetDir = snapshotPath(targetDir)
sourceDirRoot := "."
sourceDirRel := dir.String()
if gen {
// ex) out/soong/.intermediate/foo/bar/gen/aidl
sourceDirRoot = strings.TrimSuffix(dir.String(), dir.Rel())
sourceDirRel = dir.Rel()
}
// TODO(jiyong) copy headers having other suffixes // TODO(jiyong) copy headers having other suffixes
sh.printfln("(cd %s; find %s -name \"*.h\" | tar cf - -T - ) | (cd %s; tar xf -)", headers, _ := ctx.GlobWithDeps(dir.String()+"/**/*.h", nil)
sourceDirRoot, sourceDirRel, targetDir) for _, file := range headers {
src := android.PathForSource(ctx, file)
dest := snapshotPath(targetDir, file)
copy(src, dest)
}
}
genHeaders := lib.exportedDeps
for _, file := range genHeaders {
targetDir := nativeGeneratedIncludeDir
if info.hasArchSpecificFlags {
targetDir = filepath.Join(lib.archType, targetDir)
}
dest := snapshotPath(targetDir, lib.name, file.Rel())
copy(file, dest)
} }
} }
@@ -438,10 +431,7 @@ func (s *sdk) buildScript(ctx android.ModuleContext, version string) android.Out
// for each architecture // for each architecture
for _, av := range info.archVariants { for _, av := range info.archVariants {
stub := av.outputFile copy(av.outputFile, snapshotPath(nativeStubFilePathFor(av)))
implicits = append(implicits, stub)
copiedStub := snapshotPath(nativeStubFilePathFor(av))
sh.printfln("cp %s %s", stub.String(), copiedStub)
if info.hasArchSpecificFlags { if info.hasArchSpecificFlags {
printExportedDirCopyCommandsForNativeLibs(av) printExportedDirCopyCommandsForNativeLibs(av)
@@ -449,69 +439,19 @@ func (s *sdk) buildScript(ctx android.ModuleContext, version string) android.Out
} }
} }
bp := s.buildAndroidBp(ctx, version) // generate Android.bp
implicits = append(implicits, bp) bp := s.buildAndroidBp(ctx, "current")
sh.printfln("cp %s %s", bp.String(), snapshotPath("Android.bp")) filesToZip = append(filesToZip, bp)
sh.printfln("popd > /dev/null") // zip them all
sh.printfln("rm -- \"$0\"") // self deleting so that stale script is not used zipFile := android.PathForModuleOut(ctx, ctx.ModuleName()+"-current.zip").OutputPath
sh.printfln("echo Done") 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())
sh.build(pctx, ctx, implicits) return zipFile
return sh.path
}
func (s *sdk) buildSnapshotGenerationScripts(ctx android.ModuleContext) {
if s.snapshot() {
// we don't need a script for sdk_snapshot.. as they are frozen
return
}
// script to update the 'current' snapshot
s.updateScript = s.buildScript(ctx, "current")
versions := s.frozenVersions(ctx)
newVersion := "1"
if len(versions) >= 1 {
lastVersion := versions[len(versions)-1]
lastVersionNum, err := strconv.Atoi(lastVersion)
if err != nil {
panic(err)
return
}
newVersion = strconv.Itoa(lastVersionNum + 1)
}
// script to create a new frozen version of snapshot
s.freezeScript = s.buildScript(ctx, newVersion)
}
func (s *sdk) androidMkEntriesForScript() android.AndroidMkEntries {
if s.snapshot() {
// we don't need a script for sdk_snapshot.. as they are frozen
return android.AndroidMkEntries{}
}
entries := android.AndroidMkEntries{
Class: "FAKE",
// TODO(jiyong): remove this? but androidmk.go expects OutputFile to be specified anyway
OutputFile: android.OptionalPathForPath(s.updateScript),
Include: "$(BUILD_SYSTEM)/base_rules.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(entries *android.AndroidMkEntries) {
entries.AddStrings("LOCAL_ADDITIONAL_DEPENDENCIES",
s.updateScript.String(), s.freezeScript.String())
},
},
ExtraFooters: []android.AndroidMkExtraFootersFunc{
func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
fmt.Fprintln(w, "$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)")
fmt.Fprintln(w, " touch $@")
fmt.Fprintln(w, " echo ##################################################")
fmt.Fprintln(w, " echo To update current SDK: execute", filepath.Join("\\$$ANDROID_BUILD_TOP", s.updateScript.String()))
fmt.Fprintln(w, " echo To freeze current SDK: execute", filepath.Join("\\$$ANDROID_BUILD_TOP", s.freezeScript.String()))
fmt.Fprintln(w, " echo ##################################################")
},
},
}
return entries
} }