Merge "Introduce module type 'sdk'"
This commit is contained in:
21
Android.bp
21
Android.bp
@@ -67,6 +67,7 @@ bootstrap_go_package {
|
|||||||
"android/proto.go",
|
"android/proto.go",
|
||||||
"android/register.go",
|
"android/register.go",
|
||||||
"android/rule_builder.go",
|
"android/rule_builder.go",
|
||||||
|
"android/sdk.go",
|
||||||
"android/sh_binary.go",
|
"android/sh_binary.go",
|
||||||
"android/singleton.go",
|
"android/singleton.go",
|
||||||
"android/testing.go",
|
"android/testing.go",
|
||||||
@@ -475,6 +476,26 @@ bootstrap_go_package {
|
|||||||
pluginFor: ["soong_build"],
|
pluginFor: ["soong_build"],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bootstrap_go_package {
|
||||||
|
name: "soong-sdk",
|
||||||
|
pkgPath: "android/soong/sdk",
|
||||||
|
deps: [
|
||||||
|
"blueprint",
|
||||||
|
"soong",
|
||||||
|
"soong-android",
|
||||||
|
"soong-apex",
|
||||||
|
"soong-cc",
|
||||||
|
"soong-java",
|
||||||
|
],
|
||||||
|
srcs: [
|
||||||
|
"sdk/sdk.go",
|
||||||
|
],
|
||||||
|
testSrcs: [
|
||||||
|
"sdk/sdk_test.go",
|
||||||
|
],
|
||||||
|
pluginFor: ["soong_build"],
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Defaults to enable various configurations of host bionic
|
// Defaults to enable various configurations of host bionic
|
||||||
//
|
//
|
||||||
|
146
android/sdk.go
Normal file
146
android/sdk.go
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
// Copyright (C) 2019 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// 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 android
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/blueprint/proptools"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SdkAware is the interface that must be supported by any module to become a member of SDK or to be
|
||||||
|
// built with SDK
|
||||||
|
type SdkAware interface {
|
||||||
|
Module
|
||||||
|
sdkBase() *SdkBase
|
||||||
|
MakeMemberOf(sdk SdkRef)
|
||||||
|
IsInAnySdk() bool
|
||||||
|
ContainingSdk() SdkRef
|
||||||
|
MemberName() string
|
||||||
|
BuildWithSdks(sdks SdkRefs)
|
||||||
|
RequiredSdks() SdkRefs
|
||||||
|
}
|
||||||
|
|
||||||
|
// SdkRef refers to a version of an SDK
|
||||||
|
type SdkRef struct {
|
||||||
|
Name string
|
||||||
|
Version string
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// currentVersion refers to the in-development version of an SDK
|
||||||
|
currentVersion = "current"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsCurrentVersion determines if the SdkRef is referencing to an in-development version of an SDK
|
||||||
|
func (s SdkRef) IsCurrentVersion() bool {
|
||||||
|
return s.Version == currentVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsCurrentVersionOf determines if the SdkRef is referencing to an in-development version of the
|
||||||
|
// specified SDK
|
||||||
|
func (s SdkRef) IsCurrentVersionOf(name string) bool {
|
||||||
|
return s.Name == name && s.IsCurrentVersion()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseSdkRef parses a `name#version` style string into a corresponding SdkRef struct
|
||||||
|
func ParseSdkRef(ctx BaseModuleContext, str string, property string) SdkRef {
|
||||||
|
tokens := strings.Split(str, "#")
|
||||||
|
if len(tokens) < 1 || len(tokens) > 2 {
|
||||||
|
ctx.PropertyErrorf(property, "%q does not follow name#version syntax", str)
|
||||||
|
return SdkRef{Name: "invalid sdk name", Version: "invalid sdk version"}
|
||||||
|
}
|
||||||
|
|
||||||
|
name := tokens[0]
|
||||||
|
|
||||||
|
version := currentVersion // If version is omitted, defaults to "current"
|
||||||
|
if len(tokens) == 2 {
|
||||||
|
version = tokens[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return SdkRef{Name: name, Version: version}
|
||||||
|
}
|
||||||
|
|
||||||
|
type SdkRefs []SdkRef
|
||||||
|
|
||||||
|
func (refs SdkRefs) Contains(s SdkRef) bool {
|
||||||
|
for _, r := range refs {
|
||||||
|
if r == s {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type sdkProperties struct {
|
||||||
|
// The SDK that this module is a member of. nil if it is not a member of any SDK
|
||||||
|
ContainingSdk *SdkRef `blueprint:"mutated"`
|
||||||
|
|
||||||
|
// The list of SDK names and versions that are used to build this module
|
||||||
|
RequiredSdks SdkRefs `blueprint:"mutated"`
|
||||||
|
|
||||||
|
// Name of the module that this sdk member is representing
|
||||||
|
Sdk_member_name *string
|
||||||
|
}
|
||||||
|
|
||||||
|
// SdkBase is a struct that is expected to be included in module types to implement the SdkAware
|
||||||
|
// interface. InitSdkAwareModule should be called to initialize this struct.
|
||||||
|
type SdkBase struct {
|
||||||
|
properties sdkProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SdkBase) sdkBase() *SdkBase {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeMemberof sets this module to be a member of a specific SDK
|
||||||
|
func (s *SdkBase) MakeMemberOf(sdk SdkRef) {
|
||||||
|
s.properties.ContainingSdk = &sdk
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsInAnySdk returns true if this module is a member of any SDK
|
||||||
|
func (s *SdkBase) IsInAnySdk() bool {
|
||||||
|
return s.properties.ContainingSdk != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainingSdk returns the SDK that this module is a member of
|
||||||
|
func (s *SdkBase) ContainingSdk() SdkRef {
|
||||||
|
if s.properties.ContainingSdk != nil {
|
||||||
|
return *s.properties.ContainingSdk
|
||||||
|
}
|
||||||
|
return SdkRef{Name: "", Version: currentVersion}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Membername returns the name of the module that this SDK member is overriding
|
||||||
|
func (s *SdkBase) MemberName() string {
|
||||||
|
return proptools.String(s.properties.Sdk_member_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildWithSdks is used to mark that this module has to be built with the given SDK(s).
|
||||||
|
func (s *SdkBase) BuildWithSdks(sdks SdkRefs) {
|
||||||
|
s.properties.RequiredSdks = sdks
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequiredSdks returns the SDK(s) that this module has to be built with
|
||||||
|
func (s *SdkBase) RequiredSdks() SdkRefs {
|
||||||
|
return s.properties.RequiredSdks
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitSdkAwareModule initializes the SdkBase struct. This must be called by all modules including
|
||||||
|
// SdkBase.
|
||||||
|
func InitSdkAwareModule(m SdkAware) {
|
||||||
|
base := m.sdkBase()
|
||||||
|
m.AddProperties(&base.properties)
|
||||||
|
}
|
36
apex/apex.go
36
apex/apex.go
@@ -185,7 +185,7 @@ func init() {
|
|||||||
pctx.HostBinToolVariable("zipalign", "zipalign")
|
pctx.HostBinToolVariable("zipalign", "zipalign")
|
||||||
pctx.HostBinToolVariable("jsonmodify", "jsonmodify")
|
pctx.HostBinToolVariable("jsonmodify", "jsonmodify")
|
||||||
|
|
||||||
android.RegisterModuleType("apex", apexBundleFactory)
|
android.RegisterModuleType("apex", BundleFactory)
|
||||||
android.RegisterModuleType("apex_test", testApexBundleFactory)
|
android.RegisterModuleType("apex_test", testApexBundleFactory)
|
||||||
android.RegisterModuleType("apex_vndk", vndkApexBundleFactory)
|
android.RegisterModuleType("apex_vndk", vndkApexBundleFactory)
|
||||||
android.RegisterModuleType("apex_defaults", defaultsFactory)
|
android.RegisterModuleType("apex_defaults", defaultsFactory)
|
||||||
@@ -195,12 +195,14 @@ func init() {
|
|||||||
ctx.TopDown("apex_vndk_gather", apexVndkGatherMutator).Parallel()
|
ctx.TopDown("apex_vndk_gather", apexVndkGatherMutator).Parallel()
|
||||||
ctx.BottomUp("apex_vndk_add_deps", apexVndkAddDepsMutator).Parallel()
|
ctx.BottomUp("apex_vndk_add_deps", apexVndkAddDepsMutator).Parallel()
|
||||||
})
|
})
|
||||||
android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
|
android.PostDepsMutators(RegisterPostDepsMutators)
|
||||||
ctx.TopDown("apex_deps", apexDepsMutator)
|
}
|
||||||
ctx.BottomUp("apex", apexMutator).Parallel()
|
|
||||||
ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel()
|
func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
|
||||||
ctx.BottomUp("apex_uses", apexUsesMutator).Parallel()
|
ctx.TopDown("apex_deps", apexDepsMutator)
|
||||||
})
|
ctx.BottomUp("apex", apexMutator).Parallel()
|
||||||
|
ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel()
|
||||||
|
ctx.BottomUp("apex_uses", apexUsesMutator).Parallel()
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -410,6 +412,12 @@ type apexBundleProperties struct {
|
|||||||
// To distinguish between flattened and non-flattened variants.
|
// To distinguish between flattened and non-flattened variants.
|
||||||
// if set true, then this variant is flattened variant.
|
// if set true, then this variant is flattened variant.
|
||||||
Flattened bool `blueprint:"mutated"`
|
Flattened bool `blueprint:"mutated"`
|
||||||
|
|
||||||
|
// List of SDKs that are used to build this APEX. A reference to an SDK should be either
|
||||||
|
// `name#version` or `name` which is an alias for `name#current`. If left empty, `platform#current`
|
||||||
|
// is implied. This value affects all modules included in this APEX. In other words, they are
|
||||||
|
// also built with the SDKs specified here.
|
||||||
|
Uses_sdks []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type apexTargetBundleProperties struct {
|
type apexTargetBundleProperties struct {
|
||||||
@@ -536,6 +544,7 @@ type apexFile struct {
|
|||||||
type apexBundle struct {
|
type apexBundle struct {
|
||||||
android.ModuleBase
|
android.ModuleBase
|
||||||
android.DefaultableModuleBase
|
android.DefaultableModuleBase
|
||||||
|
android.SdkBase
|
||||||
|
|
||||||
properties apexBundleProperties
|
properties apexBundleProperties
|
||||||
targetProperties apexTargetBundleProperties
|
targetProperties apexTargetBundleProperties
|
||||||
@@ -738,6 +747,16 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) {
|
|||||||
if cert != "" {
|
if cert != "" {
|
||||||
ctx.AddDependency(ctx.Module(), certificateTag, cert)
|
ctx.AddDependency(ctx.Module(), certificateTag, cert)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(jiyong): ensure that all apexes are with non-empty uses_sdks
|
||||||
|
if len(a.properties.Uses_sdks) > 0 {
|
||||||
|
sdkRefs := []android.SdkRef{}
|
||||||
|
for _, str := range a.properties.Uses_sdks {
|
||||||
|
parsed := android.ParseSdkRef(ctx, str, "uses_sdks")
|
||||||
|
sdkRefs = append(sdkRefs, parsed)
|
||||||
|
}
|
||||||
|
a.BuildWithSdks(sdkRefs)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *apexBundle) getCertString(ctx android.BaseModuleContext) string {
|
func (a *apexBundle) getCertString(ctx android.BaseModuleContext) string {
|
||||||
@@ -1707,6 +1726,7 @@ func newApexBundle() *apexBundle {
|
|||||||
})
|
})
|
||||||
android.InitAndroidMultiTargetsArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
|
android.InitAndroidMultiTargetsArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
|
||||||
android.InitDefaultableModule(module)
|
android.InitDefaultableModule(module)
|
||||||
|
android.InitSdkAwareModule(module)
|
||||||
return module
|
return module
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1722,7 +1742,7 @@ func testApexBundleFactory() android.Module {
|
|||||||
return bundle
|
return bundle
|
||||||
}
|
}
|
||||||
|
|
||||||
func apexBundleFactory() android.Module {
|
func BundleFactory() android.Module {
|
||||||
return newApexBundle()
|
return newApexBundle()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -95,10 +95,10 @@ func testApexContext(t *testing.T, bp string, handlers ...testCustomizer) (*andr
|
|||||||
config.TestProductVariables.Platform_vndk_version = proptools.StringPtr("VER")
|
config.TestProductVariables.Platform_vndk_version = proptools.StringPtr("VER")
|
||||||
|
|
||||||
ctx := android.NewTestArchContext()
|
ctx := android.NewTestArchContext()
|
||||||
ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(apexBundleFactory))
|
ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(BundleFactory))
|
||||||
ctx.RegisterModuleType("apex_test", android.ModuleFactoryAdaptor(testApexBundleFactory))
|
ctx.RegisterModuleType("apex_test", android.ModuleFactoryAdaptor(testApexBundleFactory))
|
||||||
ctx.RegisterModuleType("apex_vndk", android.ModuleFactoryAdaptor(vndkApexBundleFactory))
|
ctx.RegisterModuleType("apex_vndk", android.ModuleFactoryAdaptor(vndkApexBundleFactory))
|
||||||
ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(apexKeyFactory))
|
ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(ApexKeyFactory))
|
||||||
ctx.RegisterModuleType("apex_defaults", android.ModuleFactoryAdaptor(defaultsFactory))
|
ctx.RegisterModuleType("apex_defaults", android.ModuleFactoryAdaptor(defaultsFactory))
|
||||||
ctx.RegisterModuleType("prebuilt_apex", android.ModuleFactoryAdaptor(PrebuiltFactory))
|
ctx.RegisterModuleType("prebuilt_apex", android.ModuleFactoryAdaptor(PrebuiltFactory))
|
||||||
|
|
||||||
|
@@ -27,7 +27,7 @@ import (
|
|||||||
var String = proptools.String
|
var String = proptools.String
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
android.RegisterModuleType("apex_key", apexKeyFactory)
|
android.RegisterModuleType("apex_key", ApexKeyFactory)
|
||||||
android.RegisterSingletonType("apex_keys_text", apexKeysTextFactory)
|
android.RegisterSingletonType("apex_keys_text", apexKeysTextFactory)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ type apexKeyProperties struct {
|
|||||||
Installable *bool
|
Installable *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func apexKeyFactory() android.Module {
|
func ApexKeyFactory() android.Module {
|
||||||
module := &apexKey{}
|
module := &apexKey{}
|
||||||
module.AddProperties(&module.properties)
|
module.AddProperties(&module.properties)
|
||||||
android.InitAndroidArchModule(module, android.HostAndDeviceDefault, android.MultilibCommon)
|
android.InitAndroidArchModule(module, android.HostAndDeviceDefault, android.MultilibCommon)
|
||||||
|
2
cc/cc.go
2
cc/cc.go
@@ -408,6 +408,7 @@ type Module struct {
|
|||||||
android.ModuleBase
|
android.ModuleBase
|
||||||
android.DefaultableModuleBase
|
android.DefaultableModuleBase
|
||||||
android.ApexModuleBase
|
android.ApexModuleBase
|
||||||
|
android.SdkBase
|
||||||
|
|
||||||
Properties BaseProperties
|
Properties BaseProperties
|
||||||
VendorProperties VendorProperties
|
VendorProperties VendorProperties
|
||||||
@@ -547,6 +548,7 @@ func (c *Module) Init() android.Module {
|
|||||||
android.InitDefaultableModule(c)
|
android.InitDefaultableModule(c)
|
||||||
|
|
||||||
android.InitApexModule(c)
|
android.InitApexModule(c)
|
||||||
|
android.InitSdkAwareModule(c)
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
@@ -152,6 +152,7 @@ func NewPrebuiltSharedLibrary(hod android.HostOrDeviceSupported) (*Module, *libr
|
|||||||
|
|
||||||
// Prebuilt libraries can be included in APEXes
|
// Prebuilt libraries can be included in APEXes
|
||||||
android.InitApexModule(module)
|
android.InitApexModule(module)
|
||||||
|
android.InitSdkAwareModule(module)
|
||||||
|
|
||||||
return module, library
|
return module, library
|
||||||
}
|
}
|
||||||
@@ -176,6 +177,7 @@ func NewPrebuiltStaticLibrary(hod android.HostOrDeviceSupported) (*Module, *libr
|
|||||||
module.AddProperties(&prebuilt.properties)
|
module.AddProperties(&prebuilt.properties)
|
||||||
|
|
||||||
android.InitPrebuiltModule(module, &prebuilt.properties.Srcs)
|
android.InitPrebuiltModule(module, &prebuilt.properties.Srcs)
|
||||||
|
android.InitSdkAwareModule(module)
|
||||||
return module, library
|
return module, library
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -155,7 +155,7 @@ func (j *TestHelperLibrary) AndroidMk() android.AndroidMkData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (prebuilt *Import) AndroidMk() android.AndroidMkData {
|
func (prebuilt *Import) AndroidMk() android.AndroidMkData {
|
||||||
if !prebuilt.IsForPlatform() {
|
if !prebuilt.IsForPlatform() || !prebuilt.ContainingSdk().IsCurrentVersion() {
|
||||||
return android.AndroidMkData{
|
return android.AndroidMkData{
|
||||||
Disabled: true,
|
Disabled: true,
|
||||||
}
|
}
|
||||||
|
@@ -290,6 +290,7 @@ type Module struct {
|
|||||||
android.ModuleBase
|
android.ModuleBase
|
||||||
android.DefaultableModuleBase
|
android.DefaultableModuleBase
|
||||||
android.ApexModuleBase
|
android.ApexModuleBase
|
||||||
|
android.SdkBase
|
||||||
|
|
||||||
properties CompilerProperties
|
properties CompilerProperties
|
||||||
protoProperties android.ProtoProperties
|
protoProperties android.ProtoProperties
|
||||||
@@ -1633,6 +1634,7 @@ func LibraryFactory() android.Module {
|
|||||||
|
|
||||||
InitJavaModule(module, android.HostAndDeviceSupported)
|
InitJavaModule(module, android.HostAndDeviceSupported)
|
||||||
android.InitApexModule(module)
|
android.InitApexModule(module)
|
||||||
|
android.InitSdkAwareModule(module)
|
||||||
return module
|
return module
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1913,6 +1915,7 @@ type Import struct {
|
|||||||
android.DefaultableModuleBase
|
android.DefaultableModuleBase
|
||||||
android.ApexModuleBase
|
android.ApexModuleBase
|
||||||
prebuilt android.Prebuilt
|
prebuilt android.Prebuilt
|
||||||
|
android.SdkBase
|
||||||
|
|
||||||
properties ImportProperties
|
properties ImportProperties
|
||||||
|
|
||||||
@@ -2069,6 +2072,7 @@ func ImportFactory() android.Module {
|
|||||||
android.InitPrebuiltModule(module, &module.properties.Jars)
|
android.InitPrebuiltModule(module, &module.properties.Jars)
|
||||||
InitJavaModule(module, android.HostAndDeviceSupported)
|
InitJavaModule(module, android.HostAndDeviceSupported)
|
||||||
android.InitApexModule(module)
|
android.InitApexModule(module)
|
||||||
|
android.InitSdkAwareModule(module)
|
||||||
return module
|
return module
|
||||||
}
|
}
|
||||||
|
|
||||||
|
172
sdk/sdk.go
Normal file
172
sdk/sdk.go
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
// Copyright (C) 2019 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// 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 sdk
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/blueprint"
|
||||||
|
|
||||||
|
"android/soong/android"
|
||||||
|
// This package doesn't depend on the apex package, but import it to make its mutators to be
|
||||||
|
// registered before mutators in this package. See RegisterPostDepsMutators for more details.
|
||||||
|
_ "android/soong/apex"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
android.RegisterModuleType("sdk", ModuleFactory)
|
||||||
|
android.PreDepsMutators(RegisterPreDepsMutators)
|
||||||
|
android.PostDepsMutators(RegisterPostDepsMutators)
|
||||||
|
}
|
||||||
|
|
||||||
|
type sdk struct {
|
||||||
|
android.ModuleBase
|
||||||
|
android.DefaultableModuleBase
|
||||||
|
|
||||||
|
properties sdkProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
type sdkProperties struct {
|
||||||
|
// The list of java_import modules that provide Java stubs for this SDK
|
||||||
|
Java_libs []string
|
||||||
|
Native_shared_libs []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// sdk defines an SDK which is a logical group of modules (e.g. native libs, headers, java libs, etc.)
|
||||||
|
// which Mainline modules like APEX can choose to build with.
|
||||||
|
func ModuleFactory() android.Module {
|
||||||
|
s := &sdk{}
|
||||||
|
s.AddProperties(&s.properties)
|
||||||
|
android.InitAndroidMultiTargetsArchModule(s, android.HostAndDeviceSupported, android.MultilibCommon)
|
||||||
|
android.InitDefaultableModule(s)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *sdk) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||||
|
// TODO(jiyong): add build rules for creating stubs from members of this SDK
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterPreDepsMutators registers pre-deps mutators to support modules implementing SdkAware
|
||||||
|
// interface and the sdk module type. This function has been made public to be called by tests
|
||||||
|
// outside of the sdk package
|
||||||
|
func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) {
|
||||||
|
ctx.BottomUp("SdkMember", memberMutator).Parallel()
|
||||||
|
ctx.TopDown("SdkMember_deps", memberDepsMutator).Parallel()
|
||||||
|
ctx.BottomUp("SdkMemberInterVersion", memberInterVersionMutator).Parallel()
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterPostDepshMutators registers post-deps mutators to support modules implementing SdkAware
|
||||||
|
// interface and the sdk module type. This function has been made public to be called by tests
|
||||||
|
// outside of the sdk package
|
||||||
|
func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
|
||||||
|
// These must run AFTER apexMutator. Note that the apex package is imported even though there is
|
||||||
|
// no direct dependency to the package here. sdkDepsMutator sets the SDK requirements from an
|
||||||
|
// APEX to its dependents. Since different versions of the same SDK can be used by different
|
||||||
|
// APEXes, the apex and its dependents (which includes the dependencies to the sdk members)
|
||||||
|
// should have been mutated for the apex before the SDK requirements are set.
|
||||||
|
ctx.TopDown("SdkDepsMutator", sdkDepsMutator).Parallel()
|
||||||
|
ctx.BottomUp("SdkDepsReplaceMutator", sdkDepsReplaceMutator).Parallel()
|
||||||
|
}
|
||||||
|
|
||||||
|
type dependencyTag struct {
|
||||||
|
blueprint.BaseDependencyTag
|
||||||
|
}
|
||||||
|
|
||||||
|
// For dependencies from an SDK module to its members
|
||||||
|
// e.g. mysdk -> libfoo and libbar
|
||||||
|
var sdkMemberDepTag dependencyTag
|
||||||
|
|
||||||
|
// For dependencies from an in-development version of an SDK member to frozen versions of the same member
|
||||||
|
// e.g. libfoo -> libfoo.mysdk.11 and libfoo.mysdk.12
|
||||||
|
type sdkMemberVesionedDepTag struct {
|
||||||
|
dependencyTag
|
||||||
|
member string
|
||||||
|
version string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 1: create dependencies from an SDK module to its members.
|
||||||
|
func memberMutator(mctx android.BottomUpMutatorContext) {
|
||||||
|
if m, ok := mctx.Module().(*sdk); ok {
|
||||||
|
mctx.AddVariationDependencies(nil, sdkMemberDepTag, m.properties.Java_libs...)
|
||||||
|
|
||||||
|
targets := mctx.MultiTargets()
|
||||||
|
for _, target := range targets {
|
||||||
|
mctx.AddFarVariationDependencies([]blueprint.Variation{
|
||||||
|
{Mutator: "arch", Variation: target.String()},
|
||||||
|
{Mutator: "image", Variation: "core"},
|
||||||
|
{Mutator: "link", Variation: "shared"},
|
||||||
|
}, sdkMemberDepTag, m.properties.Native_shared_libs...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: record that dependencies of SDK modules are members of the SDK modules
|
||||||
|
func memberDepsMutator(mctx android.TopDownMutatorContext) {
|
||||||
|
if _, ok := mctx.Module().(*sdk); ok {
|
||||||
|
mySdkRef := android.ParseSdkRef(mctx, mctx.ModuleName(), "name")
|
||||||
|
mctx.VisitDirectDeps(func(child android.Module) {
|
||||||
|
if member, ok := child.(android.SdkAware); ok {
|
||||||
|
member.MakeMemberOf(mySdkRef)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: create dependencies from the in-development version of an SDK member to frozen versions
|
||||||
|
// of the same member. By having these dependencies, they are mutated for multiple Mainline modules
|
||||||
|
// (apex and apk), each of which might want different sdks to be built with. For example, if both
|
||||||
|
// apex A and B are referencing libfoo which is a member of sdk 'mysdk', the two APEXes can be
|
||||||
|
// built with libfoo.mysdk.11 and libfoo.mysdk.12, respectively depending on which sdk they are
|
||||||
|
// using.
|
||||||
|
func memberInterVersionMutator(mctx android.BottomUpMutatorContext) {
|
||||||
|
if m, ok := mctx.Module().(android.SdkAware); ok && m.IsInAnySdk() {
|
||||||
|
if !m.ContainingSdk().IsCurrentVersion() {
|
||||||
|
memberName := m.MemberName()
|
||||||
|
tag := sdkMemberVesionedDepTag{member: memberName, version: m.ContainingSdk().Version}
|
||||||
|
mctx.AddReverseDependency(mctx.Module(), tag, memberName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: transitively ripple down the SDK requirements from the root modules like APEX to its
|
||||||
|
// descendants
|
||||||
|
func sdkDepsMutator(mctx android.TopDownMutatorContext) {
|
||||||
|
if m, ok := mctx.Module().(android.SdkAware); ok {
|
||||||
|
// Module types for Mainline modules (e.g. APEX) are expected to implement RequiredSdks()
|
||||||
|
// by reading its own properties like `uses_sdks`.
|
||||||
|
requiredSdks := m.RequiredSdks()
|
||||||
|
if len(requiredSdks) > 0 {
|
||||||
|
mctx.VisitDirectDeps(func(m android.Module) {
|
||||||
|
if dep, ok := m.(android.SdkAware); ok {
|
||||||
|
dep.BuildWithSdks(requiredSdks)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5: if libfoo.mysdk.11 is in the context where version 11 of mysdk is requested, the
|
||||||
|
// versioned module is used instead of the un-versioned (in-development) module libfoo
|
||||||
|
func sdkDepsReplaceMutator(mctx android.BottomUpMutatorContext) {
|
||||||
|
if m, ok := mctx.Module().(android.SdkAware); ok && m.IsInAnySdk() {
|
||||||
|
if sdk := m.ContainingSdk(); !sdk.IsCurrentVersion() {
|
||||||
|
if m.RequiredSdks().Contains(sdk) {
|
||||||
|
// Note that this replacement is done only for the modules that have the same
|
||||||
|
// variations as the current module. Since current module is already mutated for
|
||||||
|
// apex references in other APEXes are not affected by this replacement.
|
||||||
|
memberName := m.MemberName()
|
||||||
|
mctx.ReplaceDependencies(memberName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
318
sdk/sdk_test.go
Normal file
318
sdk/sdk_test.go
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
// 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 sdk
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"android/soong/android"
|
||||||
|
"android/soong/apex"
|
||||||
|
"android/soong/cc"
|
||||||
|
"android/soong/java"
|
||||||
|
)
|
||||||
|
|
||||||
|
func testSdkContext(t *testing.T, bp string) (*android.TestContext, android.Config) {
|
||||||
|
config := android.TestArchConfig(buildDir, nil)
|
||||||
|
ctx := android.NewTestArchContext()
|
||||||
|
|
||||||
|
// from android package
|
||||||
|
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
|
||||||
|
ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
|
||||||
|
ctx.BottomUp("prebuilts", android.PrebuiltMutator).Parallel()
|
||||||
|
})
|
||||||
|
ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
|
||||||
|
ctx.TopDown("prebuilt_select", android.PrebuiltSelectModuleMutator).Parallel()
|
||||||
|
ctx.BottomUp("prebuilt_postdeps", android.PrebuiltPostDepsMutator).Parallel()
|
||||||
|
})
|
||||||
|
|
||||||
|
// from java package
|
||||||
|
ctx.RegisterModuleType("android_app_certificate", android.ModuleFactoryAdaptor(java.AndroidAppCertificateFactory))
|
||||||
|
ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(java.LibraryFactory))
|
||||||
|
ctx.RegisterModuleType("java_import", android.ModuleFactoryAdaptor(java.ImportFactory))
|
||||||
|
|
||||||
|
// from cc package
|
||||||
|
ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
|
||||||
|
ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(cc.LibrarySharedFactory))
|
||||||
|
ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory))
|
||||||
|
ctx.RegisterModuleType("cc_prebuilt_library_shared", android.ModuleFactoryAdaptor(cc.PrebuiltSharedLibraryFactory))
|
||||||
|
ctx.RegisterModuleType("cc_prebuilt_library_static", android.ModuleFactoryAdaptor(cc.PrebuiltStaticLibraryFactory))
|
||||||
|
ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(cc.LlndkLibraryFactory))
|
||||||
|
ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory))
|
||||||
|
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
|
||||||
|
ctx.BottomUp("image", cc.ImageMutator).Parallel()
|
||||||
|
ctx.BottomUp("link", cc.LinkageMutator).Parallel()
|
||||||
|
ctx.BottomUp("vndk", cc.VndkMutator).Parallel()
|
||||||
|
ctx.BottomUp("test_per_src", cc.TestPerSrcMutator).Parallel()
|
||||||
|
ctx.BottomUp("version", cc.VersionMutator).Parallel()
|
||||||
|
ctx.BottomUp("begin", cc.BeginMutator).Parallel()
|
||||||
|
})
|
||||||
|
|
||||||
|
// from apex package
|
||||||
|
ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(apex.BundleFactory))
|
||||||
|
ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(apex.ApexKeyFactory))
|
||||||
|
ctx.PostDepsMutators(apex.RegisterPostDepsMutators)
|
||||||
|
|
||||||
|
// from this package
|
||||||
|
ctx.RegisterModuleType("sdk", android.ModuleFactoryAdaptor(ModuleFactory))
|
||||||
|
ctx.PreDepsMutators(RegisterPreDepsMutators)
|
||||||
|
ctx.PostDepsMutators(RegisterPostDepsMutators)
|
||||||
|
|
||||||
|
ctx.Register()
|
||||||
|
|
||||||
|
bp = bp + `
|
||||||
|
apex_key {
|
||||||
|
name: "myapex.key",
|
||||||
|
public_key: "myapex.avbpubkey",
|
||||||
|
private_key: "myapex.pem",
|
||||||
|
}
|
||||||
|
|
||||||
|
android_app_certificate {
|
||||||
|
name: "myapex.cert",
|
||||||
|
certificate: "myapex",
|
||||||
|
}
|
||||||
|
` + cc.GatherRequiredDepsForTest(android.Android)
|
||||||
|
|
||||||
|
ctx.MockFileSystem(map[string][]byte{
|
||||||
|
"Android.bp": []byte(bp),
|
||||||
|
"build/make/target/product/security": nil,
|
||||||
|
"apex_manifest.json": nil,
|
||||||
|
"system/sepolicy/apex/myapex-file_contexts": nil,
|
||||||
|
"system/sepolicy/apex/myapex2-file_contexts": nil,
|
||||||
|
"myapex.avbpubkey": nil,
|
||||||
|
"myapex.pem": nil,
|
||||||
|
"myapex.x509.pem": nil,
|
||||||
|
"myapex.pk8": nil,
|
||||||
|
"Test.java": nil,
|
||||||
|
"Test.cpp": nil,
|
||||||
|
"libfoo.so": nil,
|
||||||
|
})
|
||||||
|
|
||||||
|
return ctx, config
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSdk(t *testing.T, bp string) (*android.TestContext, android.Config) {
|
||||||
|
ctx, config := testSdkContext(t, bp)
|
||||||
|
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
|
||||||
|
android.FailIfErrored(t, errs)
|
||||||
|
_, errs = ctx.PrepareBuildActions(config)
|
||||||
|
android.FailIfErrored(t, errs)
|
||||||
|
return ctx, config
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure that 'result' contains 'expected'
|
||||||
|
func ensureContains(t *testing.T, result string, expected string) {
|
||||||
|
t.Helper()
|
||||||
|
if !strings.Contains(result, expected) {
|
||||||
|
t.Errorf("%q is not found in %q", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensures that 'result' does not contain 'notExpected'
|
||||||
|
func ensureNotContains(t *testing.T, result string, notExpected string) {
|
||||||
|
t.Helper()
|
||||||
|
if strings.Contains(result, notExpected) {
|
||||||
|
t.Errorf("%q is found in %q", notExpected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureListContains(t *testing.T, result []string, expected string) {
|
||||||
|
t.Helper()
|
||||||
|
if !android.InList(expected, result) {
|
||||||
|
t.Errorf("%q is not found in %v", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureListNotContains(t *testing.T, result []string, notExpected string) {
|
||||||
|
t.Helper()
|
||||||
|
if android.InList(notExpected, result) {
|
||||||
|
t.Errorf("%q is found in %v", notExpected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func pathsToStrings(paths android.Paths) []string {
|
||||||
|
ret := []string{}
|
||||||
|
for _, p := range paths {
|
||||||
|
ret = append(ret, p.String())
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBasicSdkWithJava(t *testing.T) {
|
||||||
|
ctx, _ := testSdk(t, `
|
||||||
|
sdk {
|
||||||
|
name: "mysdk#1",
|
||||||
|
java_libs: ["sdkmember_mysdk_1"],
|
||||||
|
}
|
||||||
|
|
||||||
|
sdk {
|
||||||
|
name: "mysdk#2",
|
||||||
|
java_libs: ["sdkmember_mysdk_2"],
|
||||||
|
}
|
||||||
|
|
||||||
|
java_import {
|
||||||
|
name: "sdkmember",
|
||||||
|
prefer: false,
|
||||||
|
host_supported: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
java_import {
|
||||||
|
name: "sdkmember_mysdk_1",
|
||||||
|
sdk_member_name: "sdkmember",
|
||||||
|
host_supported: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
java_import {
|
||||||
|
name: "sdkmember_mysdk_2",
|
||||||
|
sdk_member_name: "sdkmember",
|
||||||
|
host_supported: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "myjavalib",
|
||||||
|
srcs: ["Test.java"],
|
||||||
|
libs: ["sdkmember"],
|
||||||
|
system_modules: "none",
|
||||||
|
sdk_version: "none",
|
||||||
|
compile_dex: true,
|
||||||
|
host_supported: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
apex {
|
||||||
|
name: "myapex",
|
||||||
|
java_libs: ["myjavalib"],
|
||||||
|
uses_sdks: ["mysdk#1"],
|
||||||
|
key: "myapex.key",
|
||||||
|
certificate: ":myapex.cert",
|
||||||
|
}
|
||||||
|
|
||||||
|
apex {
|
||||||
|
name: "myapex2",
|
||||||
|
java_libs: ["myjavalib"],
|
||||||
|
uses_sdks: ["mysdk#2"],
|
||||||
|
key: "myapex.key",
|
||||||
|
certificate: ":myapex.cert",
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
sdkMemberV1 := ctx.ModuleForTests("sdkmember_mysdk_1", "android_common_myapex").Rule("combineJar").Output
|
||||||
|
sdkMemberV2 := ctx.ModuleForTests("sdkmember_mysdk_2", "android_common_myapex2").Rule("combineJar").Output
|
||||||
|
|
||||||
|
javalibForMyApex := ctx.ModuleForTests("myjavalib", "android_common_myapex")
|
||||||
|
javalibForMyApex2 := ctx.ModuleForTests("myjavalib", "android_common_myapex2")
|
||||||
|
|
||||||
|
// Depending on the uses_sdks value, different libs are linked
|
||||||
|
ensureListContains(t, pathsToStrings(javalibForMyApex.Rule("javac").Implicits), sdkMemberV1.String())
|
||||||
|
ensureListContains(t, pathsToStrings(javalibForMyApex2.Rule("javac").Implicits), sdkMemberV2.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBasicSdkWithCc(t *testing.T) {
|
||||||
|
ctx, _ := testSdk(t, `
|
||||||
|
sdk {
|
||||||
|
name: "mysdk#1",
|
||||||
|
native_shared_libs: ["sdkmember_mysdk_1"],
|
||||||
|
}
|
||||||
|
|
||||||
|
sdk {
|
||||||
|
name: "mysdk#2",
|
||||||
|
native_shared_libs: ["sdkmember_mysdk_2"],
|
||||||
|
}
|
||||||
|
|
||||||
|
cc_prebuilt_library_shared {
|
||||||
|
name: "sdkmember",
|
||||||
|
srcs: ["libfoo.so"],
|
||||||
|
prefer: false,
|
||||||
|
system_shared_libs: [],
|
||||||
|
stl: "none",
|
||||||
|
}
|
||||||
|
|
||||||
|
cc_prebuilt_library_shared {
|
||||||
|
name: "sdkmember_mysdk_1",
|
||||||
|
sdk_member_name: "sdkmember",
|
||||||
|
srcs: ["libfoo.so"],
|
||||||
|
system_shared_libs: [],
|
||||||
|
stl: "none",
|
||||||
|
}
|
||||||
|
|
||||||
|
cc_prebuilt_library_shared {
|
||||||
|
name: "sdkmember_mysdk_2",
|
||||||
|
sdk_member_name: "sdkmember",
|
||||||
|
srcs: ["libfoo.so"],
|
||||||
|
system_shared_libs: [],
|
||||||
|
stl: "none",
|
||||||
|
}
|
||||||
|
|
||||||
|
cc_library_shared {
|
||||||
|
name: "mycpplib",
|
||||||
|
srcs: ["Test.cpp"],
|
||||||
|
shared_libs: ["sdkmember"],
|
||||||
|
system_shared_libs: [],
|
||||||
|
stl: "none",
|
||||||
|
}
|
||||||
|
|
||||||
|
apex {
|
||||||
|
name: "myapex",
|
||||||
|
native_shared_libs: ["mycpplib"],
|
||||||
|
uses_sdks: ["mysdk#1"],
|
||||||
|
key: "myapex.key",
|
||||||
|
certificate: ":myapex.cert",
|
||||||
|
}
|
||||||
|
|
||||||
|
apex {
|
||||||
|
name: "myapex2",
|
||||||
|
native_shared_libs: ["mycpplib"],
|
||||||
|
uses_sdks: ["mysdk#2"],
|
||||||
|
key: "myapex.key",
|
||||||
|
certificate: ":myapex.cert",
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
sdkMemberV1 := ctx.ModuleForTests("sdkmember_mysdk_1", "android_arm64_armv8-a_core_shared_myapex").Rule("toc").Output
|
||||||
|
sdkMemberV2 := ctx.ModuleForTests("sdkmember_mysdk_2", "android_arm64_armv8-a_core_shared_myapex2").Rule("toc").Output
|
||||||
|
|
||||||
|
cpplibForMyApex := ctx.ModuleForTests("mycpplib", "android_arm64_armv8-a_core_shared_myapex")
|
||||||
|
cpplibForMyApex2 := ctx.ModuleForTests("mycpplib", "android_arm64_armv8-a_core_shared_myapex2")
|
||||||
|
|
||||||
|
// Depending on the uses_sdks value, different libs are linked
|
||||||
|
ensureListContains(t, pathsToStrings(cpplibForMyApex.Rule("ld").Implicits), sdkMemberV1.String())
|
||||||
|
ensureListContains(t, pathsToStrings(cpplibForMyApex2.Rule("ld").Implicits), sdkMemberV2.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
var buildDir string
|
||||||
|
|
||||||
|
func setUp() {
|
||||||
|
var err error
|
||||||
|
buildDir, err = ioutil.TempDir("", "soong_sdk_test")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func tearDown() {
|
||||||
|
os.RemoveAll(buildDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
run := func() int {
|
||||||
|
setUp()
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
return m.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Exit(run())
|
||||||
|
}
|
Reference in New Issue
Block a user