Merge "Add ClasspathElement support"
This commit is contained in:
commit
e6aefedeba
4 changed files with 548 additions and 0 deletions
|
@ -31,6 +31,7 @@ bootstrap_go_package {
|
|||
testSrcs: [
|
||||
"apex_test.go",
|
||||
"bootclasspath_fragment_test.go",
|
||||
"classpath_element_test.go",
|
||||
"platform_bootclasspath_test.go",
|
||||
"systemserver_classpath_fragment_test.go",
|
||||
"vndk_test.go",
|
||||
|
|
317
apex/classpath_element_test.go
Normal file
317
apex/classpath_element_test.go
Normal file
|
@ -0,0 +1,317 @@
|
|||
// Copyright (C) 2021 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 apex
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"android/soong/android"
|
||||
"android/soong/java"
|
||||
"github.com/google/blueprint"
|
||||
)
|
||||
|
||||
// Contains tests for java.CreateClasspathElements logic from java/classpath_element.go that
|
||||
// requires apexes.
|
||||
|
||||
// testClasspathElementContext is a ClasspathElementContext suitable for use in tests.
|
||||
type testClasspathElementContext struct {
|
||||
testContext *android.TestContext
|
||||
module android.Module
|
||||
errs []error
|
||||
}
|
||||
|
||||
func (t *testClasspathElementContext) OtherModuleHasProvider(module blueprint.Module, provider blueprint.ProviderKey) bool {
|
||||
return t.testContext.ModuleHasProvider(module, provider)
|
||||
}
|
||||
|
||||
func (t *testClasspathElementContext) OtherModuleProvider(module blueprint.Module, provider blueprint.ProviderKey) interface{} {
|
||||
return t.testContext.ModuleProvider(module, provider)
|
||||
}
|
||||
|
||||
func (t *testClasspathElementContext) ModuleErrorf(fmt string, args ...interface{}) {
|
||||
t.errs = append(t.errs, t.testContext.ModuleErrorf(t.module, fmt, args...))
|
||||
}
|
||||
|
||||
var _ java.ClasspathElementContext = (*testClasspathElementContext)(nil)
|
||||
|
||||
func TestCreateClasspathElements(t *testing.T) {
|
||||
preparer := android.GroupFixturePreparers(
|
||||
prepareForTestWithPlatformBootclasspath,
|
||||
prepareForTestWithArtApex,
|
||||
prepareForTestWithMyapex,
|
||||
// For otherapex.
|
||||
android.FixtureMergeMockFs(android.MockFS{
|
||||
"system/sepolicy/apex/otherapex-file_contexts": nil,
|
||||
}),
|
||||
java.PrepareForTestWithJavaSdkLibraryFiles,
|
||||
java.FixtureWithLastReleaseApis("foo", "othersdklibrary"),
|
||||
android.FixtureWithRootAndroidBp(`
|
||||
apex {
|
||||
name: "com.android.art",
|
||||
key: "com.android.art.key",
|
||||
bootclasspath_fragments: [
|
||||
"art-bootclasspath-fragment",
|
||||
],
|
||||
java_libs: [
|
||||
"othersdklibrary",
|
||||
],
|
||||
updatable: false,
|
||||
}
|
||||
|
||||
apex_key {
|
||||
name: "com.android.art.key",
|
||||
public_key: "com.android.art.avbpubkey",
|
||||
private_key: "com.android.art.pem",
|
||||
}
|
||||
|
||||
bootclasspath_fragment {
|
||||
name: "art-bootclasspath-fragment",
|
||||
apex_available: [
|
||||
"com.android.art",
|
||||
],
|
||||
contents: [
|
||||
"baz",
|
||||
"quuz",
|
||||
],
|
||||
}
|
||||
|
||||
java_library {
|
||||
name: "baz",
|
||||
apex_available: [
|
||||
"com.android.art",
|
||||
],
|
||||
srcs: ["b.java"],
|
||||
installable: true,
|
||||
}
|
||||
|
||||
java_library {
|
||||
name: "quuz",
|
||||
apex_available: [
|
||||
"com.android.art",
|
||||
],
|
||||
srcs: ["b.java"],
|
||||
installable: true,
|
||||
}
|
||||
|
||||
apex {
|
||||
name: "myapex",
|
||||
key: "myapex.key",
|
||||
bootclasspath_fragments: [
|
||||
"mybootclasspath-fragment",
|
||||
],
|
||||
java_libs: [
|
||||
"othersdklibrary",
|
||||
],
|
||||
updatable: false,
|
||||
}
|
||||
|
||||
apex_key {
|
||||
name: "myapex.key",
|
||||
public_key: "testkey.avbpubkey",
|
||||
private_key: "testkey.pem",
|
||||
}
|
||||
|
||||
bootclasspath_fragment {
|
||||
name: "mybootclasspath-fragment",
|
||||
apex_available: [
|
||||
"myapex",
|
||||
],
|
||||
contents: [
|
||||
"bar",
|
||||
],
|
||||
}
|
||||
|
||||
java_library {
|
||||
name: "bar",
|
||||
srcs: ["b.java"],
|
||||
installable: true,
|
||||
apex_available: ["myapex"],
|
||||
permitted_packages: ["bar"],
|
||||
}
|
||||
|
||||
java_sdk_library {
|
||||
name: "foo",
|
||||
srcs: ["b.java"],
|
||||
}
|
||||
|
||||
java_sdk_library {
|
||||
name: "othersdklibrary",
|
||||
srcs: ["b.java"],
|
||||
shared_library: false,
|
||||
apex_available: [
|
||||
"com.android.art",
|
||||
"myapex",
|
||||
],
|
||||
}
|
||||
|
||||
bootclasspath_fragment {
|
||||
name: "non-apex-fragment",
|
||||
contents: ["othersdklibrary"],
|
||||
}
|
||||
|
||||
apex {
|
||||
name: "otherapex",
|
||||
key: "otherapex.key",
|
||||
java_libs: [
|
||||
"otherapexlibrary",
|
||||
],
|
||||
updatable: false,
|
||||
}
|
||||
|
||||
apex_key {
|
||||
name: "otherapex.key",
|
||||
public_key: "testkey.avbpubkey",
|
||||
private_key: "testkey.pem",
|
||||
}
|
||||
|
||||
java_library {
|
||||
name: "otherapexlibrary",
|
||||
srcs: ["b.java"],
|
||||
installable: true,
|
||||
apex_available: ["otherapex"],
|
||||
permitted_packages: ["otherapexlibrary"],
|
||||
}
|
||||
|
||||
platform_bootclasspath {
|
||||
name: "myplatform-bootclasspath",
|
||||
|
||||
fragments: [
|
||||
{
|
||||
apex: "com.android.art",
|
||||
module: "art-bootclasspath-fragment",
|
||||
},
|
||||
],
|
||||
}
|
||||
`),
|
||||
)
|
||||
|
||||
result := preparer.RunTest(t)
|
||||
|
||||
artFragment := result.Module("art-bootclasspath-fragment", "android_common_apex10000")
|
||||
artBaz := result.Module("baz", "android_common_apex10000")
|
||||
artQuuz := result.Module("quuz", "android_common_apex10000")
|
||||
|
||||
myFragment := result.Module("mybootclasspath-fragment", "android_common_apex10000")
|
||||
myBar := result.Module("bar", "android_common_apex10000")
|
||||
|
||||
nonApexFragment := result.Module("non-apex-fragment", "android_common")
|
||||
other := result.Module("othersdklibrary", "android_common_apex10000")
|
||||
|
||||
otherApexLibrary := result.Module("otherapexlibrary", "android_common_apex10000")
|
||||
|
||||
platformFoo := result.Module("quuz", "android_common")
|
||||
|
||||
bootclasspath := result.Module("myplatform-bootclasspath", "android_common")
|
||||
|
||||
// Use a custom assertion method instead of AssertDeepEquals as the latter formats the output
|
||||
// using %#v which results in meaningless output as ClasspathElements are pointers.
|
||||
assertElementsEquals := func(t *testing.T, message string, expected, actual java.ClasspathElements) {
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("%s: expected:\n %s\n got:\n %s", message, expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
expectFragmentElement := func(module android.Module, contents ...android.Module) java.ClasspathElement {
|
||||
return &java.ClasspathFragmentElement{module, contents}
|
||||
}
|
||||
expectLibraryElement := func(module android.Module) java.ClasspathElement {
|
||||
return &java.ClasspathLibraryElement{module}
|
||||
}
|
||||
|
||||
newCtx := func() *testClasspathElementContext {
|
||||
return &testClasspathElementContext{testContext: result.TestContext, module: bootclasspath}
|
||||
}
|
||||
|
||||
// Verify that CreateClasspathElements works when given valid input.
|
||||
t.Run("art:baz, art:quuz, my:bar, foo", func(t *testing.T) {
|
||||
ctx := newCtx()
|
||||
elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, artQuuz, myBar, platformFoo}, []android.Module{artFragment, myFragment})
|
||||
expectedElements := java.ClasspathElements{
|
||||
expectFragmentElement(artFragment, artBaz, artQuuz),
|
||||
expectFragmentElement(myFragment, myBar),
|
||||
expectLibraryElement(platformFoo),
|
||||
}
|
||||
assertElementsEquals(t, "elements", expectedElements, elements)
|
||||
})
|
||||
|
||||
// Verify that CreateClasspathElements detects when a fragment does not have an associated apex.
|
||||
t.Run("non apex fragment", func(t *testing.T) {
|
||||
ctx := newCtx()
|
||||
elements := java.CreateClasspathElements(ctx, []android.Module{}, []android.Module{nonApexFragment})
|
||||
android.FailIfNoMatchingErrors(t, "fragment non-apex-fragment{.*} is not part of an apex", ctx.errs)
|
||||
expectedElements := java.ClasspathElements{}
|
||||
assertElementsEquals(t, "elements", expectedElements, elements)
|
||||
})
|
||||
|
||||
// Verify that CreateClasspathElements detects when an apex has multiple fragments.
|
||||
t.Run("multiple fragments for same apex", func(t *testing.T) {
|
||||
ctx := newCtx()
|
||||
elements := java.CreateClasspathElements(ctx, []android.Module{}, []android.Module{artFragment, artFragment})
|
||||
android.FailIfNoMatchingErrors(t, "apex com.android.art has multiple fragments, art-bootclasspath-fragment{.*} and art-bootclasspath-fragment{.*}", ctx.errs)
|
||||
expectedElements := java.ClasspathElements{}
|
||||
assertElementsEquals(t, "elements", expectedElements, elements)
|
||||
})
|
||||
|
||||
// Verify that CreateClasspathElements detects when a library is in multiple fragments.
|
||||
t.Run("library from multiple fragments", func(t *testing.T) {
|
||||
ctx := newCtx()
|
||||
elements := java.CreateClasspathElements(ctx, []android.Module{other}, []android.Module{artFragment, myFragment})
|
||||
android.FailIfNoMatchingErrors(t, "library othersdklibrary{.*} is in two separate fragments, art-bootclasspath-fragment{.*} and mybootclasspath-fragment{.*}", ctx.errs)
|
||||
expectedElements := java.ClasspathElements{}
|
||||
assertElementsEquals(t, "elements", expectedElements, elements)
|
||||
})
|
||||
|
||||
// Verify that CreateClasspathElements detects when a fragment's contents are not contiguous and
|
||||
// are separated by a library from another fragment.
|
||||
t.Run("discontiguous separated by fragment", func(t *testing.T) {
|
||||
ctx := newCtx()
|
||||
elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, myBar, artQuuz, platformFoo}, []android.Module{artFragment, myFragment})
|
||||
expectedElements := java.ClasspathElements{
|
||||
expectFragmentElement(artFragment, artBaz, artQuuz),
|
||||
expectFragmentElement(myFragment, myBar),
|
||||
expectLibraryElement(platformFoo),
|
||||
}
|
||||
assertElementsEquals(t, "elements", expectedElements, elements)
|
||||
android.FailIfNoMatchingErrors(t, "libraries from the same fragment must be contiguous, however baz{.*} and quuz{os:android,arch:common,apex:apex10000} from fragment art-bootclasspath-fragment{.*} are separated by libraries from fragment mybootclasspath-fragment{.*} like bar{.*}", ctx.errs)
|
||||
})
|
||||
|
||||
// Verify that CreateClasspathElements detects when a fragment's contents are not contiguous and
|
||||
// are separated by a standalone library.
|
||||
t.Run("discontiguous separated by library", func(t *testing.T) {
|
||||
ctx := newCtx()
|
||||
elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, platformFoo, artQuuz, myBar}, []android.Module{artFragment, myFragment})
|
||||
expectedElements := java.ClasspathElements{
|
||||
expectFragmentElement(artFragment, artBaz, artQuuz),
|
||||
expectLibraryElement(platformFoo),
|
||||
expectFragmentElement(myFragment, myBar),
|
||||
}
|
||||
assertElementsEquals(t, "elements", expectedElements, elements)
|
||||
android.FailIfNoMatchingErrors(t, "libraries from the same fragment must be contiguous, however baz{.*} and quuz{os:android,arch:common,apex:apex10000} from fragment art-bootclasspath-fragment{.*} are separated by library quuz{.*}", ctx.errs)
|
||||
})
|
||||
|
||||
// Verify that CreateClasspathElements detects when there a library on the classpath that
|
||||
// indicates it is from an apex the supplied fragments list does not contain a fragment for that
|
||||
// apex.
|
||||
t.Run("no fragment for apex", func(t *testing.T) {
|
||||
ctx := newCtx()
|
||||
elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, otherApexLibrary}, []android.Module{artFragment})
|
||||
expectedElements := java.ClasspathElements{
|
||||
expectFragmentElement(artFragment, artBaz),
|
||||
}
|
||||
assertElementsEquals(t, "elements", expectedElements, elements)
|
||||
android.FailIfNoMatchingErrors(t, `library otherapexlibrary{.*} is from apexes \[otherapex\] which have no corresponding fragment in \[art-bootclasspath-fragment{.*}\]`, ctx.errs)
|
||||
})
|
||||
}
|
|
@ -33,6 +33,7 @@ bootstrap_go_package {
|
|||
"bootclasspath.go",
|
||||
"bootclasspath_fragment.go",
|
||||
"builder.go",
|
||||
"classpath_element.go",
|
||||
"classpath_fragment.go",
|
||||
"device_host_converter.go",
|
||||
"dex.go",
|
||||
|
|
229
java/classpath_element.go
Normal file
229
java/classpath_element.go
Normal file
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
* Copyright (C) 2021 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 java
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"android/soong/android"
|
||||
"github.com/google/blueprint"
|
||||
)
|
||||
|
||||
// Supports constructing a list of ClasspathElement from a set of fragments and modules.
|
||||
|
||||
// ClasspathElement represents a component that contributes to a classpath. That can be
|
||||
// either a java module or a classpath fragment module.
|
||||
type ClasspathElement interface {
|
||||
Module() android.Module
|
||||
String() string
|
||||
}
|
||||
|
||||
type ClasspathElements []ClasspathElement
|
||||
|
||||
// ClasspathFragmentElement is a ClasspathElement that encapsulates a classpath fragment module.
|
||||
type ClasspathFragmentElement struct {
|
||||
Fragment android.Module
|
||||
Contents []android.Module
|
||||
}
|
||||
|
||||
func (b *ClasspathFragmentElement) Module() android.Module {
|
||||
return b.Fragment
|
||||
}
|
||||
|
||||
func (b *ClasspathFragmentElement) String() string {
|
||||
contents := []string{}
|
||||
for _, module := range b.Contents {
|
||||
contents = append(contents, module.String())
|
||||
}
|
||||
return fmt.Sprintf("fragment(%s, %s)", b.Fragment, strings.Join(contents, ", "))
|
||||
}
|
||||
|
||||
var _ ClasspathElement = (*ClasspathFragmentElement)(nil)
|
||||
|
||||
// ClasspathLibraryElement is a ClasspathElement that encapsulates a java library.
|
||||
type ClasspathLibraryElement struct {
|
||||
Library android.Module
|
||||
}
|
||||
|
||||
func (b *ClasspathLibraryElement) Module() android.Module {
|
||||
return b.Library
|
||||
}
|
||||
|
||||
func (b *ClasspathLibraryElement) String() string {
|
||||
return fmt.Sprintf("library{%s}", b.Library)
|
||||
}
|
||||
|
||||
var _ ClasspathElement = (*ClasspathLibraryElement)(nil)
|
||||
|
||||
// ClasspathElementContext defines the context methods needed by CreateClasspathElements
|
||||
type ClasspathElementContext interface {
|
||||
OtherModuleHasProvider(m blueprint.Module, provider blueprint.ProviderKey) bool
|
||||
OtherModuleProvider(m blueprint.Module, provider blueprint.ProviderKey) interface{}
|
||||
ModuleErrorf(fmt string, args ...interface{})
|
||||
}
|
||||
|
||||
// CreateClasspathElements creates a list of ClasspathElement objects from a list of libraries and
|
||||
// a list of fragments.
|
||||
//
|
||||
// The libraries parameter contains the set of libraries from which the classpath is constructed.
|
||||
// The fragments parameter contains the classpath fragment modules whose contents are libraries that
|
||||
// are part of the classpath. Each library in the libraries parameter may be part of a fragment. The
|
||||
// determination as to which libraries belong to fragments and which do not is based on the apex to
|
||||
// which they belong, if any.
|
||||
//
|
||||
// Every fragment in the fragments list must be part of one or more apexes and each apex is assumed
|
||||
// to contain only a single fragment from the fragments list. A library in the libraries parameter
|
||||
// that is part of an apex must be provided by a classpath fragment in the corresponding apex.
|
||||
//
|
||||
// This will return a ClasspathElements list that contains a ClasspathElement for each standalone
|
||||
// library and each fragment. The order of the elements in the list is such that if the list was
|
||||
// flattened into a list of library modules that it would result in the same list or modules as the
|
||||
// input libraries. Flattening the list can be done by replacing each ClasspathFragmentElement in
|
||||
// the list with its Contents field.
|
||||
//
|
||||
// Requirements/Assumptions:
|
||||
// * A fragment can be associated with more than one apex but each apex must only be associated with
|
||||
// a single fragment from the fragments list.
|
||||
// * All of a fragment's contents must appear as a contiguous block in the same order in the
|
||||
// libraries list.
|
||||
// * Each library must only appear in a single fragment.
|
||||
//
|
||||
// The apex is used to identify which libraries belong to which fragment. First a mapping is created
|
||||
// from apex to fragment. Then the libraries are iterated over and any library in an apex is
|
||||
// associated with an element for the fragment to which it belongs. Otherwise, the libraries are
|
||||
// standalone and have their own element.
|
||||
//
|
||||
// e.g. Given the following input:
|
||||
// libraries: com.android.art:core-oj, com.android.art:core-libart, framework, ext
|
||||
// fragments: com.android.art:art-bootclasspath-fragment
|
||||
//
|
||||
// Then this will return:
|
||||
// ClasspathFragmentElement(art-bootclasspath-fragment, [core-oj, core-libart]),
|
||||
// ClasspathLibraryElement(framework),
|
||||
// ClasspathLibraryElement(ext),
|
||||
func CreateClasspathElements(ctx ClasspathElementContext, libraries []android.Module, fragments []android.Module) ClasspathElements {
|
||||
// Create a map from apex name to the fragment module. This makes it easy to find the fragment
|
||||
// associated with a particular apex.
|
||||
apexToFragment := map[string]android.Module{}
|
||||
for _, fragment := range fragments {
|
||||
if !ctx.OtherModuleHasProvider(fragment, android.ApexInfoProvider) {
|
||||
ctx.ModuleErrorf("fragment %s is not part of an apex", fragment)
|
||||
continue
|
||||
}
|
||||
|
||||
apexInfo := ctx.OtherModuleProvider(fragment, android.ApexInfoProvider).(android.ApexInfo)
|
||||
for _, apex := range apexInfo.InApexVariants {
|
||||
if existing, ok := apexToFragment[apex]; ok {
|
||||
ctx.ModuleErrorf("apex %s has multiple fragments, %s and %s", apex, fragment, existing)
|
||||
continue
|
||||
}
|
||||
apexToFragment[apex] = fragment
|
||||
}
|
||||
}
|
||||
|
||||
fragmentToElement := map[android.Module]*ClasspathFragmentElement{}
|
||||
elements := []ClasspathElement{}
|
||||
var currentElement ClasspathElement
|
||||
|
||||
skipLibrary:
|
||||
// Iterate over the libraries to construct the ClasspathElements list.
|
||||
for _, library := range libraries {
|
||||
var element ClasspathElement
|
||||
if ctx.OtherModuleHasProvider(library, android.ApexInfoProvider) {
|
||||
apexInfo := ctx.OtherModuleProvider(library, android.ApexInfoProvider).(android.ApexInfo)
|
||||
|
||||
var fragment android.Module
|
||||
|
||||
// Make sure that the library is in only one fragment of the classpath.
|
||||
for _, apex := range apexInfo.InApexVariants {
|
||||
if f, ok := apexToFragment[apex]; ok {
|
||||
if fragment == nil {
|
||||
// This is the first fragment so just save it away.
|
||||
fragment = f
|
||||
} else if f != fragment {
|
||||
// This apex variant of the library is in a different fragment.
|
||||
ctx.ModuleErrorf("library %s is in two separate fragments, %s and %s", library, fragment, f)
|
||||
// Skip over this library entirely as otherwise the resulting classpath elements would
|
||||
// be invalid.
|
||||
continue skipLibrary
|
||||
}
|
||||
} else {
|
||||
// There is no fragment associated with the library's apex.
|
||||
}
|
||||
}
|
||||
|
||||
if fragment == nil {
|
||||
ctx.ModuleErrorf("library %s is from apexes %s which have no corresponding fragment in %s",
|
||||
library, apexInfo.InApexVariants, fragments)
|
||||
// Skip over this library entirely as otherwise the resulting classpath elements would
|
||||
// be invalid.
|
||||
continue skipLibrary
|
||||
} else if existingFragmentElement, ok := fragmentToElement[fragment]; ok {
|
||||
// This library is in a fragment element that has already been added.
|
||||
|
||||
// If the existing fragment element is still the current element then this library is
|
||||
// contiguous with other libraries in that fragment so there is nothing more to do.
|
||||
// Otherwise this library is not contiguous with other libraries in the same fragment which
|
||||
// is an error.
|
||||
if existingFragmentElement != currentElement {
|
||||
separator := ""
|
||||
if fragmentElement, ok := currentElement.(*ClasspathFragmentElement); ok {
|
||||
separator = fmt.Sprintf("libraries from fragment %s like %s", fragmentElement.Fragment, fragmentElement.Contents[0])
|
||||
} else {
|
||||
libraryElement := currentElement.(*ClasspathLibraryElement)
|
||||
separator = fmt.Sprintf("library %s", libraryElement.Library)
|
||||
}
|
||||
|
||||
// Get the library that precedes this library in the fragment. That is the last library as
|
||||
// this library has not yet been added.
|
||||
precedingLibraryInFragment := existingFragmentElement.Contents[len(existingFragmentElement.Contents)-1]
|
||||
ctx.ModuleErrorf("libraries from the same fragment must be contiguous, however %s and %s from fragment %s are separated by %s",
|
||||
precedingLibraryInFragment, library, fragment, separator)
|
||||
}
|
||||
|
||||
// Add this library to the fragment element's contents.
|
||||
existingFragmentElement.Contents = append(existingFragmentElement.Contents, library)
|
||||
} else {
|
||||
// This is the first library in this fragment so add a new element for the fragment,
|
||||
// including the library.
|
||||
fragmentElement := &ClasspathFragmentElement{
|
||||
Fragment: fragment,
|
||||
Contents: []android.Module{library},
|
||||
}
|
||||
|
||||
// Store it away so we can detect when attempting to create another element for the same
|
||||
// fragment.
|
||||
fragmentToElement[fragment] = fragmentElement
|
||||
element = fragmentElement
|
||||
}
|
||||
} else {
|
||||
// The library is from the platform so just add an element for it.
|
||||
element = &ClasspathLibraryElement{Library: library}
|
||||
}
|
||||
|
||||
// If no element was created then it means that the library has been added to an existing
|
||||
// fragment element so the list of elements and current element are unaffected.
|
||||
if element != nil {
|
||||
// Add the element to the list and make it the current element for the next iteration.
|
||||
elements = append(elements, element)
|
||||
currentElement = element
|
||||
}
|
||||
}
|
||||
|
||||
return elements
|
||||
}
|
Loading…
Reference in a new issue