Merge "Support paths for init_rc from Soong."
diff --git a/android/bazel.go b/android/bazel.go
index b2170be..b54ae64 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -174,6 +174,18 @@
"liblinker_debuggerd_stub", // ruperts@, cc_library_static, depends on //system/libbase
"libbionic_tests_headers_posix", // ruperts@, cc_library_static
"libc_dns", // ruperts@, cc_library_static
+
+ "note_memtag_heap_async", // jingwen@, b/185079815, features.h includes not found
+ "note_memtag_heap_sync", // jingwen@, b/185079815, features.h includes not found
+
+ // List of all full_cc_libraries in //bionic, with their immediate failures
+ "libc", // jingwen@, cc_library, depends on //external/gwp_asan
+ "libc_malloc_debug", // jingwen@, cc_library, fatal error: 'assert.h' file not found
+ "libc_malloc_hooks", // jingwen@, cc_library, fatal error: 'errno.h' file not found
+ "libdl", // jingwen@, cc_library, ld.lld: error: no input files
+ "libm", // jingwen@, cc_library, fatal error: 'freebsd-compat.h' file not found
+ "libseccomp_policy", // jingwen@, cc_library, fatal error: 'seccomp_policy.h' file not found
+ "libstdc++", // jingwen@, cc_library, depends on //external/gwp_asan
}
// Used for quicker lookups
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 5b9d3bf..97eec30 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -34,10 +34,26 @@
"android/soong/shared"
)
+type cqueryRequest interface {
+ // Name returns a string name for this request type. Such request type names must be unique,
+ // and must only consist of alphanumeric characters.
+ Name() string
+
+ // StarlarkFunctionBody returns a starlark function body to process this request type.
+ // The returned string is the body of a Starlark function which obtains
+ // all request-relevant information about a target and returns a string containing
+ // this information.
+ // The function should have the following properties:
+ // - `target` is the only parameter to this function (a configured target).
+ // - The return value must be a string.
+ // - The function body should not be indented outside of its own scope.
+ StarlarkFunctionBody() string
+}
+
// Map key to describe bazel cquery requests.
type cqueryKey struct {
label string
- requestType cquery.RequestType
+ requestType cqueryRequest
archType ArchType
}
@@ -53,6 +69,10 @@
// Returns the results of GetOutputFiles and GetCcObjectFiles in a single query (in that order).
GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool)
+ // GetPrebuiltCcStaticLibraryFiles returns paths to prebuilt cc static libraries, and whether the
+ // results were available
+ GetPrebuiltCcStaticLibraryFiles(label string, archType ArchType) ([]string, bool)
+
// ** End cquery methods
// Issues commands to Bazel to receive results for all cquery requests
@@ -97,17 +117,26 @@
// A bazel context to use for tests.
type MockBazelContext struct {
- AllFiles map[string][]string
+ OutputBaseDir string
+
+ LabelToOutputFiles map[string][]string
+ LabelToOutputFilesAndCcObjectFiles map[string]cquery.GetOutputFilesAndCcObjectFiles_Result
+ LabelToCcStaticLibraryFiles map[string][]string
}
func (m MockBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
- result, ok := m.AllFiles[label]
+ result, ok := m.LabelToOutputFiles[label]
return result, ok
}
func (m MockBazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
- result, ok := m.AllFiles[label]
- return result, result, ok
+ result, ok := m.LabelToOutputFilesAndCcObjectFiles[label]
+ return result.OutputFiles, result.CcObjectFiles, ok
+}
+
+func (m MockBazelContext) GetPrebuiltCcStaticLibraryFiles(label string, archType ArchType) ([]string, bool) {
+ result, ok := m.LabelToCcStaticLibraryFiles[label]
+ return result, ok
}
func (m MockBazelContext) InvokeBazel() error {
@@ -118,9 +147,7 @@
return true
}
-func (m MockBazelContext) OutputBase() string {
- return "outputbase"
-}
+func (m MockBazelContext) OutputBase() string { return m.OutputBaseDir }
func (m MockBazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
return []bazel.BuildStatement{}
@@ -133,7 +160,7 @@
var ret []string
if ok {
bazelOutput := strings.TrimSpace(rawString)
- ret = cquery.GetOutputFiles.ParseResult(bazelOutput).([]string)
+ ret = cquery.GetOutputFiles.ParseResult(bazelOutput)
}
return ret, ok
}
@@ -145,7 +172,7 @@
result, ok := bazelCtx.cquery(label, cquery.GetOutputFilesAndCcObjectFiles, archType)
if ok {
bazelOutput := strings.TrimSpace(result)
- returnResult := cquery.GetOutputFilesAndCcObjectFiles.ParseResult(bazelOutput).(cquery.GetOutputFilesAndCcObjectFiles_Result)
+ returnResult := cquery.GetOutputFilesAndCcObjectFiles.ParseResult(bazelOutput)
outputFiles = returnResult.OutputFiles
ccObjects = returnResult.CcObjectFiles
}
@@ -153,6 +180,19 @@
return outputFiles, ccObjects, ok
}
+// GetPrebuiltCcStaticLibraryFiles returns a slice of prebuilt static libraries for the given
+// label/archType if there are query results; otherwise, it enqueues the query and returns false.
+func (bazelCtx *bazelContext) GetPrebuiltCcStaticLibraryFiles(label string, archType ArchType) ([]string, bool) {
+ result, ok := bazelCtx.cquery(label, cquery.GetPrebuiltCcStaticLibraryFiles, archType)
+ if !ok {
+ return nil, false
+ }
+
+ bazelOutput := strings.TrimSpace(result)
+ ret := cquery.GetPrebuiltCcStaticLibraryFiles.ParseResult(bazelOutput)
+ return ret, ok
+}
+
func (n noopBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
panic("unimplemented")
}
@@ -161,6 +201,10 @@
panic("unimplemented")
}
+func (n noopBazelContext) GetPrebuiltCcStaticLibraryFiles(label string, archType ArchType) ([]string, bool) {
+ panic("unimplemented")
+}
+
func (n noopBazelContext) InvokeBazel() error {
panic("unimplemented")
}
@@ -231,7 +275,7 @@
// If the given request was already made (and the results are available), then
// returns (result, true). If the request is queued but no results are available,
// then returns ("", false).
-func (context *bazelContext) cquery(label string, requestType cquery.RequestType,
+func (context *bazelContext) cquery(label string, requestType cqueryRequest,
archType ArchType) (string, bool) {
key := cqueryKey{label, requestType, archType}
if result, ok := context.results[key]; ok {
@@ -310,15 +354,20 @@
# This file is generated by soong_build. Do not edit.
local_repository(
name = "sourceroot",
- path = "%s",
+ path = "%[1]s",
)
local_repository(
name = "rules_cc",
- path = "%s/build/bazel/rules_cc",
+ path = "%[1]s/build/bazel/rules_cc",
+)
+
+local_repository(
+ name = "bazel_skylib",
+ path = "%[1]s/build/bazel/bazel_skylib",
)
`
- return []byte(fmt.Sprintf(formatString, context.workspaceDir, context.workspaceDir))
+ return []byte(fmt.Sprintf(formatString, context.workspaceDir))
}
func (context *bazelContext) mainBzlFileContents() []byte {
@@ -449,7 +498,7 @@
// and grouped by their request type. The data retrieved for each label depends on its
// request type.
func (context *bazelContext) cqueryStarlarkFileContents() []byte {
- requestTypeToCqueryIdEntries := map[cquery.RequestType][]string{}
+ requestTypeToCqueryIdEntries := map[cqueryRequest][]string{}
for val, _ := range context.requests {
cqueryId := getCqueryId(val)
mapEntryString := fmt.Sprintf("%q : True", cqueryId)
diff --git a/android/config.go b/android/config.go
index cfbc37f..80651bb 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1498,6 +1498,10 @@
return c.config.productVariables.BuildBrokenTrebleSyspropNeverallow
}
+func (c *deviceConfig) BuildDebugfsRestrictionsEnabled() bool {
+ return c.config.productVariables.BuildDebugfsRestrictionsEnabled
+}
+
func (c *deviceConfig) BuildBrokenVendorPropertyNamespace() bool {
return c.config.productVariables.BuildBrokenVendorPropertyNamespace
}
diff --git a/android/paths.go b/android/paths.go
index ba1ab11..37b04dd 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -421,6 +421,9 @@
// bazel-compatible labels. Properties passed as the paths or excludes argument must have been
// annotated with struct tag `android:"path"` so that dependencies on other modules will have
// already been handled by the path_properties mutator.
+//
+// With expanded globs, we can catch package boundaries problem instead of
+// silently failing to potentially missing files from Bazel's globs.
func BazelLabelForModuleSrc(ctx BazelConversionPathContext, paths []string) bazel.LabelList {
return BazelLabelForModuleSrcExcludes(ctx, paths, []string(nil))
}
@@ -431,6 +434,9 @@
// passed as the paths or excludes argument must have been annotated with struct tag
// `android:"path"` so that dependencies on other modules will have already been handled by the
// path_properties mutator.
+//
+// With expanded globs, we can catch package boundaries problem instead of
+// silently failing to potentially missing files from Bazel's globs.
func BazelLabelForModuleSrcExcludes(ctx BazelConversionPathContext, paths, excludes []string) bazel.LabelList {
excludeLabels := expandSrcsForBazel(ctx, excludes, []string(nil))
excluded := make([]string, 0, len(excludeLabels.Includes))
diff --git a/android/variable.go b/android/variable.go
index dff48c2..f25143d 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -385,6 +385,8 @@
BuildBrokenTrebleSyspropNeverallow bool `json:",omitempty"`
BuildBrokenVendorPropertyNamespace bool `json:",omitempty"`
+ BuildDebugfsRestrictionsEnabled bool `json:",omitempty"`
+
RequiresInsecureExecmemForSwiftshader bool `json:",omitempty"`
SelinuxIgnoreNeverallows bool `json:",omitempty"`
diff --git a/apex/Android.bp b/apex/Android.bp
index 1890b89..7b52402 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -31,6 +31,7 @@
testSrcs: [
"apex_test.go",
"boot_image_test.go",
+ "platform_bootclasspath_test.go",
"vndk_test.go",
],
pluginFor: ["soong_build"],
diff --git a/apex/apex.go b/apex/apex.go
index bad382a..880028f 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1927,6 +1927,10 @@
filesInfo = append(filesInfo, af)
return true // track transitive dependencies
}
+ } else if rust.IsRlibDepTag(depTag) {
+ // Rlib is statically linked, but it might have shared lib
+ // dependencies. Track them.
+ return true
} else if java.IsbootImageContentDepTag(depTag) {
// Add the contents of the boot image to the apex.
switch child.(type) {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 54aead7..ee4255e 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -392,6 +392,15 @@
srcs: ["foo.rs"],
crate_name: "foo",
apex_available: ["myapex"],
+ shared_libs: ["libfoo.shared_from_rust"],
+ }
+
+ cc_library_shared {
+ name: "libfoo.shared_from_rust",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: ["myapex"],
}
rust_library_dylib {
@@ -539,6 +548,7 @@
ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.rlib.rust"), "android_arm64_armv8-a_rlib_dylib-std_apex10000")
ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.dylib.rust"), "android_arm64_armv8-a_dylib_apex10000")
ensureListContains(t, ctx.ModuleVariantsForTests("libbar.ffi"), "android_arm64_armv8-a_shared_apex10000")
+ ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.shared_from_rust"), "android_arm64_armv8-a_shared_apex10000")
// Ensure that both direct and indirect deps are copied into apex
ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
@@ -548,6 +558,7 @@
ensureContains(t, copyCmds, "image.apex/lib64/libfoo.dylib.rust.dylib.so")
ensureContains(t, copyCmds, "image.apex/lib64/libfoo.ffi.so")
ensureContains(t, copyCmds, "image.apex/lib64/libbar.ffi.so")
+ ensureContains(t, copyCmds, "image.apex/lib64/libfoo.shared_from_rust.so")
// .. but not for java libs
ensureNotContains(t, copyCmds, "image.apex/javalib/myotherjar.jar")
ensureNotContains(t, copyCmds, "image.apex/javalib/msharedjar.jar")
@@ -4605,6 +4616,40 @@
`)
})
+ t.Run("apex_set only", func(t *testing.T) {
+ bp := `
+ apex_set {
+ name: "myapex",
+ set: "myapex.apks",
+ exported_java_libs: ["libfoo", "libbar"],
+ }
+
+ java_import {
+ name: "libfoo",
+ jars: ["libfoo.jar"],
+ apex_available: ["myapex"],
+ }
+
+ java_sdk_library_import {
+ name: "libbar",
+ public: {
+ jars: ["libbar.jar"],
+ },
+ apex_available: ["myapex"],
+ }
+ `
+
+ ctx := testDexpreoptWithApexes(t, bp, "", transform)
+ checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
+ checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
+
+ // Make sure that the dex file from the apex_set contributes to the hiddenapi index file.
+ checkHiddenAPIIndexInputs(t, ctx, `
+.intermediates/libbar/android_common_myapex/hiddenapi/index.csv
+.intermediates/libfoo/android_common_myapex/hiddenapi/index.csv
+`)
+ })
+
t.Run("prebuilt with source library preferred", func(t *testing.T) {
bp := `
prebuilt_apex {
@@ -6368,8 +6413,7 @@
}
func TestAppSetBundlePrebuilt(t *testing.T) {
- ctx := testApex(t, "", android.FixtureModifyMockFS(func(fs android.MockFS) {
- bp := `
+ bp := `
apex_set {
name: "myapex",
filename: "foo_v2.apex",
@@ -6377,24 +6421,23 @@
none: { set: "myapex.apks", },
hwaddress: { set: "myapex.hwasan.apks", },
},
- }`
- fs["Android.bp"] = []byte(bp)
- }),
- prepareForTestWithSantitizeHwaddress,
- )
+ }
+ `
+ ctx := testApex(t, bp, prepareForTestWithSantitizeHwaddress)
- m := ctx.ModuleForTests("myapex", "android_common")
- extractedApex := m.Output("out/soong/.intermediates/myapex/android_common/foo_v2.apex")
+ // Check that the extractor produces the correct output file from the correct input file.
+ extractorOutput := "out/soong/.intermediates/myapex.apex.extractor/android_common/extracted/myapex.hwasan.apks"
- actual := extractedApex.Inputs
- if len(actual) != 1 {
- t.Errorf("expected a single input")
- }
+ m := ctx.ModuleForTests("myapex.apex.extractor", "android_common")
+ extractedApex := m.Output(extractorOutput)
- expected := "myapex.hwasan.apks"
- if actual[0].String() != expected {
- t.Errorf("expected %s, got %s", expected, actual[0].String())
- }
+ android.AssertArrayString(t, "extractor input", []string{"myapex.hwasan.apks"}, extractedApex.Inputs.Strings())
+
+ // Ditto for the apex.
+ m = ctx.ModuleForTests("myapex", "android_common")
+ copiedApex := m.Output("out/soong/.intermediates/myapex/android_common/foo_v2.apex")
+
+ android.AssertStringEquals(t, "myapex input", extractorOutput, copiedApex.Input.String())
}
func testNoUpdatableJarsInBootImage(t *testing.T, errmsg string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) {
@@ -7030,10 +7073,10 @@
}),
)
- m := ctx.ModuleForTests("myapex", "android_common")
+ m := ctx.ModuleForTests("myapex.apex.extractor", "android_common")
// Check extract_apks tool parameters.
- extractedApex := m.Output("out/soong/.intermediates/myapex/android_common/foo_v2.apex")
+ extractedApex := m.Output("extracted/myapex.apks")
actual := extractedApex.Args["abis"]
expected := "ARMEABI_V7A,ARM64_V8A"
if actual != expected {
@@ -7045,6 +7088,7 @@
t.Errorf("Unexpected abis parameter - expected %q vs actual %q", expected, actual)
}
+ m = ctx.ModuleForTests("myapex", "android_common")
a := m.Module().(*ApexSet)
expectedOverrides := []string{"foo"}
actualOverrides := android.AndroidMkEntriesForTest(t, ctx, a)[0].EntryMap["LOCAL_OVERRIDES_MODULES"]
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
new file mode 100644
index 0000000..2ea6401
--- /dev/null
+++ b/apex/platform_bootclasspath_test.go
@@ -0,0 +1,177 @@
+// 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 (
+ "testing"
+
+ "android/soong/android"
+ "android/soong/dexpreopt"
+ "android/soong/java"
+ "github.com/google/blueprint"
+)
+
+// Contains tests for platform_bootclasspath logic from java/platform_bootclasspath.go that requires
+// apexes.
+
+var prepareForTestWithPlatformBootclasspath = android.GroupFixturePreparers(
+ java.PrepareForTestWithDexpreopt,
+ PrepareForTestWithApexBuildComponents,
+)
+
+func TestPlatformBootclasspathDependencies(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ prepareForTestWithArtApex,
+ prepareForTestWithMyapex,
+ // Configure some libraries in the art and framework boot images.
+ dexpreopt.FixtureSetArtBootJars("com.android.art:baz", "com.android.art:quuz"),
+ dexpreopt.FixtureSetBootJars("platform:foo"),
+ dexpreopt.FixtureSetUpdatableBootJars("myapex:bar"),
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.FixtureWithLastReleaseApis("foo"),
+ ).RunTestWithBp(t, `
+ apex {
+ name: "com.android.art",
+ key: "com.android.art.key",
+ bootclasspath_fragments: [
+ "art-bootclasspath-fragment",
+ ],
+ 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,
+ }
+
+ // Add a java_import that is not preferred and so won't have an appropriate apex variant created
+ // for it to make sure that the platform_bootclasspath doesn't try and add a dependency onto it.
+ java_import {
+ name: "baz",
+ apex_available: [
+ "com.android.art",
+ ],
+ jars: ["b.jar"],
+ }
+
+ java_library {
+ name: "quuz",
+ apex_available: [
+ "com.android.art",
+ ],
+ srcs: ["b.java"],
+ installable: true,
+ }
+
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ java_libs: [
+ "bar",
+ ],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_sdk_library {
+ name: "foo",
+ srcs: ["b.java"],
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java"],
+ installable: true,
+ apex_available: ["myapex"],
+ permitted_packages: ["bar"],
+ }
+
+ platform_bootclasspath {
+ name: "myplatform-bootclasspath",
+
+ fragments: [
+ {
+ apex: "com.android.art",
+ module: "art-bootclasspath-fragment",
+ },
+ ],
+ }
+`,
+ )
+
+ java.CheckPlatformBootclasspathModules(t, result, "myplatform-bootclasspath", []string{
+ "com.android.art:baz",
+ "com.android.art:quuz",
+ "platform:foo",
+ "myapex:bar",
+ })
+
+ java.CheckPlatformBootclasspathFragments(t, result, "myplatform-bootclasspath", []string{
+ `com.android.art:art-bootclasspath-fragment`,
+ })
+
+ // Make sure that the myplatform-bootclasspath has the correct dependencies.
+ CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{
+ `platform:dex2oatd`,
+ `com.android.art:baz`,
+ `com.android.art:quuz`,
+ `platform:foo`,
+ `myapex:bar`,
+ `com.android.art:art-bootclasspath-fragment`,
+ })
+}
+
+// CheckModuleDependencies checks the dependencies of the selected module against the expected list.
+//
+// The expected list must be a list of strings of the form "<apex>:<module>", where <apex> is the
+// name of the apex, or platform is it is not part of an apex and <module> is the module name.
+func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) {
+ t.Helper()
+ module := ctx.ModuleForTests(name, variant).Module()
+ modules := []android.Module{}
+ ctx.VisitDirectDeps(module, func(m blueprint.Module) {
+ modules = append(modules, m.(android.Module))
+ })
+
+ pairs := java.ApexNamePairsFromModules(ctx, modules)
+ android.AssertDeepEquals(t, "module dependencies", expected, pairs)
+}
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 9d84281..10a70a3 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -48,6 +48,9 @@
type prebuiltCommon struct {
prebuilt android.Prebuilt
properties prebuiltCommonProperties
+
+ deapexerProperties DeapexerProperties
+ selectedApexProperties SelectedApexProperties
}
type sanitizedPrebuilt interface {
@@ -91,6 +94,96 @@
return false
}
+func (p *prebuiltCommon) deapexerDeps(ctx android.BottomUpMutatorContext) {
+ // Add dependencies onto the java modules that represent the java libraries that are provided by
+ // and exported from this prebuilt apex.
+ for _, lib := range p.deapexerProperties.Exported_java_libs {
+ dep := prebuiltApexExportedModuleName(ctx, lib)
+ ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), exportedJavaLibTag, dep)
+ }
+}
+
+// apexInfoMutator marks any modules for which this apex exports a file as requiring an apex
+// specific variant and checks that they are supported.
+//
+// The apexMutator will ensure that the ApexInfo objects passed to BuildForApex(ApexInfo) are
+// associated with the apex specific variant using the ApexInfoProvider for later retrieval.
+//
+// Unlike the source apex module type the prebuilt_apex module type cannot share compatible variants
+// across prebuilt_apex modules. That is because there is no way to determine whether two
+// prebuilt_apex modules that export files for the same module are compatible. e.g. they could have
+// been built from different source at different times or they could have been built with different
+// build options that affect the libraries.
+//
+// While it may be possible to provide sufficient information to determine whether two prebuilt_apex
+// modules were compatible it would be a lot of work and would not provide much benefit for a couple
+// of reasons:
+// * The number of prebuilt_apex modules that will be exporting files for the same module will be
+// low as the prebuilt_apex only exports files for the direct dependencies that require it and
+// very few modules are direct dependencies of multiple prebuilt_apex modules, e.g. there are a
+// few com.android.art* apex files that contain the same contents and could export files for the
+// same modules but only one of them needs to do so. Contrast that with source apex modules which
+// need apex specific variants for every module that contributes code to the apex, whether direct
+// or indirect.
+// * The build cost of a prebuilt_apex variant is generally low as at worst it will involve some
+// extra copying of files. Contrast that with source apex modules that has to build each variant
+// from source.
+func (p *prebuiltCommon) apexInfoMutator(mctx android.TopDownMutatorContext) {
+
+ // Collect direct dependencies into contents.
+ contents := make(map[string]android.ApexMembership)
+
+ // Collect the list of dependencies.
+ var dependencies []android.ApexModule
+ mctx.VisitDirectDeps(func(m android.Module) {
+ tag := mctx.OtherModuleDependencyTag(m)
+ if tag == exportedJavaLibTag {
+ depName := mctx.OtherModuleName(m)
+
+ // It is an error if the other module is not a prebuilt.
+ if _, ok := m.(android.PrebuiltInterface); !ok {
+ mctx.PropertyErrorf("exported_java_libs", "%q is not a prebuilt module", depName)
+ return
+ }
+
+ // It is an error if the other module is not an ApexModule.
+ if _, ok := m.(android.ApexModule); !ok {
+ mctx.PropertyErrorf("exported_java_libs", "%q is not usable within an apex", depName)
+ return
+ }
+
+ // Strip off the prebuilt_ prefix if present before storing content to ensure consistent
+ // behavior whether there is a corresponding source module present or not.
+ depName = android.RemoveOptionalPrebuiltPrefix(depName)
+
+ // Remember that this module was added as a direct dependency.
+ contents[depName] = contents[depName].Add(true)
+
+ // Add the module to the list of dependencies that need to have an APEX variant.
+ dependencies = append(dependencies, m.(android.ApexModule))
+ }
+ })
+
+ // Create contents for the prebuilt_apex and store it away for later use.
+ apexContents := android.NewApexContents(contents)
+ mctx.SetProvider(ApexBundleInfoProvider, ApexBundleInfo{
+ Contents: apexContents,
+ })
+
+ // Create an ApexInfo for the prebuilt_apex.
+ apexInfo := android.ApexInfo{
+ ApexVariationName: mctx.ModuleName(),
+ InApexes: []string{mctx.ModuleName()},
+ ApexContents: []*android.ApexContents{apexContents},
+ ForPrebuiltApex: true,
+ }
+
+ // Mark the dependencies of this module as requiring a variant for this module.
+ for _, am := range dependencies {
+ am.BuildForApex(apexInfo)
+ }
+}
+
// prebuiltApexSelectorModule is a private module type that is only created by the prebuilt_apex
// module. It selects the apex to use and makes it available for use by prebuilt_apex and the
// deapexer.
@@ -197,7 +290,6 @@
type PrebuiltProperties struct {
ApexFileProperties
- DeapexerProperties
Installable *bool
// Optional name for the installed apex. If unspecified, name of the
@@ -267,7 +359,7 @@
//
func PrebuiltFactory() android.Module {
module := &Prebuilt{}
- module.AddProperties(&module.properties, &module.selectedApexProperties)
+ module.AddProperties(&module.properties, &module.deapexerProperties, &module.selectedApexProperties)
android.InitSingleSourcePrebuiltModule(module, &module.selectedApexProperties, "Selected_apex")
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
@@ -278,8 +370,8 @@
createApexSelectorModule(ctx, apexSelectorModuleName, &module.properties.ApexFileProperties)
apexFileSource := ":" + apexSelectorModuleName
- if len(module.properties.Exported_java_libs) != 0 {
- createDeapexerModule(ctx, deapexerModuleName(baseModuleName), apexFileSource, &module.properties.DeapexerProperties)
+ if len(module.deapexerProperties.Exported_java_libs) != 0 {
+ createDeapexerModule(ctx, deapexerModuleName(baseModuleName), apexFileSource, &module.deapexerProperties)
}
// Add a source reference to retrieve the selected apex from the selector module.
@@ -363,95 +455,13 @@
)
func (p *Prebuilt) DepsMutator(ctx android.BottomUpMutatorContext) {
- // Add dependencies onto the java modules that represent the java libraries that are provided by
- // and exported from this prebuilt apex.
- for _, lib := range p.properties.Exported_java_libs {
- dep := prebuiltApexExportedModuleName(ctx, lib)
- ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), exportedJavaLibTag, dep)
- }
+ p.deapexerDeps(ctx)
}
var _ ApexInfoMutator = (*Prebuilt)(nil)
-// ApexInfoMutator marks any modules for which this apex exports a file as requiring an apex
-// specific variant and checks that they are supported.
-//
-// The apexMutator will ensure that the ApexInfo objects passed to BuildForApex(ApexInfo) are
-// associated with the apex specific variant using the ApexInfoProvider for later retrieval.
-//
-// Unlike the source apex module type the prebuilt_apex module type cannot share compatible variants
-// across prebuilt_apex modules. That is because there is no way to determine whether two
-// prebuilt_apex modules that export files for the same module are compatible. e.g. they could have
-// been built from different source at different times or they could have been built with different
-// build options that affect the libraries.
-//
-// While it may be possible to provide sufficient information to determine whether two prebuilt_apex
-// modules were compatible it would be a lot of work and would not provide much benefit for a couple
-// of reasons:
-// * The number of prebuilt_apex modules that will be exporting files for the same module will be
-// low as the prebuilt_apex only exports files for the direct dependencies that require it and
-// very few modules are direct dependencies of multiple prebuilt_apex modules, e.g. there are a
-// few com.android.art* apex files that contain the same contents and could export files for the
-// same modules but only one of them needs to do so. Contrast that with source apex modules which
-// need apex specific variants for every module that contributes code to the apex, whether direct
-// or indirect.
-// * The build cost of a prebuilt_apex variant is generally low as at worst it will involve some
-// extra copying of files. Contrast that with source apex modules that has to build each variant
-// from source.
func (p *Prebuilt) ApexInfoMutator(mctx android.TopDownMutatorContext) {
-
- // Collect direct dependencies into contents.
- contents := make(map[string]android.ApexMembership)
-
- // Collect the list of dependencies.
- var dependencies []android.ApexModule
- mctx.VisitDirectDeps(func(m android.Module) {
- tag := mctx.OtherModuleDependencyTag(m)
- if tag == exportedJavaLibTag {
- depName := mctx.OtherModuleName(m)
-
- // It is an error if the other module is not a prebuilt.
- if _, ok := m.(android.PrebuiltInterface); !ok {
- mctx.PropertyErrorf("exported_java_libs", "%q is not a prebuilt module", depName)
- return
- }
-
- // It is an error if the other module is not an ApexModule.
- if _, ok := m.(android.ApexModule); !ok {
- mctx.PropertyErrorf("exported_java_libs", "%q is not usable within an apex", depName)
- return
- }
-
- // Strip off the prebuilt_ prefix if present before storing content to ensure consistent
- // behavior whether there is a corresponding source module present or not.
- depName = android.RemoveOptionalPrebuiltPrefix(depName)
-
- // Remember that this module was added as a direct dependency.
- contents[depName] = contents[depName].Add(true)
-
- // Add the module to the list of dependencies that need to have an APEX variant.
- dependencies = append(dependencies, m.(android.ApexModule))
- }
- })
-
- // Create contents for the prebuilt_apex and store it away for later use.
- apexContents := android.NewApexContents(contents)
- mctx.SetProvider(ApexBundleInfoProvider, ApexBundleInfo{
- Contents: apexContents,
- })
-
- // Create an ApexInfo for the prebuilt_apex.
- apexInfo := android.ApexInfo{
- ApexVariationName: mctx.ModuleName(),
- InApexes: []string{mctx.ModuleName()},
- ApexContents: []*android.ApexContents{apexContents},
- ForPrebuiltApex: true,
- }
-
- // Mark the dependencies of this module as requiring a variant for this module.
- for _, am := range dependencies {
- am.BuildForApex(apexInfo)
- }
+ p.apexInfoMutator(mctx)
}
func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -505,6 +515,49 @@
}}
}
+// prebuiltApexExtractorModule is a private module type that is only created by the prebuilt_apex
+// module. It extracts the correct apex to use and makes it available for use by apex_set.
+type prebuiltApexExtractorModule struct {
+ android.ModuleBase
+
+ properties ApexExtractorProperties
+
+ extractedApex android.WritablePath
+}
+
+func privateApexExtractorModuleFactory() android.Module {
+ module := &prebuiltApexExtractorModule{}
+ module.AddProperties(
+ &module.properties,
+ )
+ android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ return module
+}
+
+func (p *prebuiltApexExtractorModule) Srcs() android.Paths {
+ return android.Paths{p.extractedApex}
+}
+
+func (p *prebuiltApexExtractorModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ srcsSupplier := func(ctx android.BaseModuleContext, prebuilt android.Module) []string {
+ return p.properties.prebuiltSrcs(ctx)
+ }
+ apexSet := android.SingleSourcePathFromSupplier(ctx, srcsSupplier, "set")
+ p.extractedApex = android.PathForModuleOut(ctx, "extracted", apexSet.Base())
+ ctx.Build(pctx,
+ android.BuildParams{
+ Rule: extractMatchingApex,
+ Description: "Extract an apex from an apex set",
+ Inputs: android.Paths{apexSet},
+ Output: p.extractedApex,
+ Args: map[string]string{
+ "abis": strings.Join(java.SupportedAbis(ctx), ","),
+ "allow-prereleased": strconv.FormatBool(proptools.Bool(p.properties.Prerelease)),
+ "sdk-version": ctx.Config().PlatformSdkVersion().String(),
+ },
+ })
+}
+
type ApexSet struct {
android.ModuleBase
prebuiltCommon
@@ -523,7 +576,7 @@
postInstallCommands []string
}
-type ApexSetProperties struct {
+type ApexExtractorProperties struct {
// the .apks file path that contains prebuilt apex files to be extracted.
Set *string
@@ -539,6 +592,37 @@
}
}
+ // apexes in this set use prerelease SDK version
+ Prerelease *bool
+}
+
+func (e *ApexExtractorProperties) prebuiltSrcs(ctx android.BaseModuleContext) []string {
+ var srcs []string
+ if e.Set != nil {
+ srcs = append(srcs, *e.Set)
+ }
+
+ var sanitizers []string
+ if ctx.Host() {
+ sanitizers = ctx.Config().SanitizeHost()
+ } else {
+ sanitizers = ctx.Config().SanitizeDevice()
+ }
+
+ if android.InList("address", sanitizers) && e.Sanitized.Address.Set != nil {
+ srcs = append(srcs, *e.Sanitized.Address.Set)
+ } else if android.InList("hwaddress", sanitizers) && e.Sanitized.Hwaddress.Set != nil {
+ srcs = append(srcs, *e.Sanitized.Hwaddress.Set)
+ } else if e.Sanitized.None.Set != nil {
+ srcs = append(srcs, *e.Sanitized.None.Set)
+ }
+
+ return srcs
+}
+
+type ApexSetProperties struct {
+ ApexExtractorProperties
+
// whether the extracted apex file installable.
Installable *bool
@@ -552,33 +636,6 @@
// binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
// from PRODUCT_PACKAGES.
Overrides []string
-
- // apexes in this set use prerelease SDK version
- Prerelease *bool
-}
-
-func (a *ApexSet) prebuiltSrcs(ctx android.BaseModuleContext) []string {
- var srcs []string
- if a.properties.Set != nil {
- srcs = append(srcs, *a.properties.Set)
- }
-
- var sanitizers []string
- if ctx.Host() {
- sanitizers = ctx.Config().SanitizeHost()
- } else {
- sanitizers = ctx.Config().SanitizeDevice()
- }
-
- if android.InList("address", sanitizers) && a.properties.Sanitized.Address.Set != nil {
- srcs = append(srcs, *a.properties.Sanitized.Address.Set)
- } else if android.InList("hwaddress", sanitizers) && a.properties.Sanitized.Hwaddress.Set != nil {
- srcs = append(srcs, *a.properties.Sanitized.Hwaddress.Set)
- } else if a.properties.Sanitized.None.Set != nil {
- srcs = append(srcs, *a.properties.Sanitized.None.Set)
- }
-
- return srcs
}
func (a *ApexSet) hasSanitizedSource(sanitizer string) bool {
@@ -611,15 +668,54 @@
// prebuilt_apex imports an `.apex` file into the build graph as if it was built with apex.
func apexSetFactory() android.Module {
module := &ApexSet{}
- module.AddProperties(&module.properties)
+ module.AddProperties(&module.properties, &module.selectedApexProperties, &module.deapexerProperties)
- srcsSupplier := func(ctx android.BaseModuleContext, _ android.Module) []string {
- return module.prebuiltSrcs(ctx)
+ android.InitSingleSourcePrebuiltModule(module, &module.selectedApexProperties, "Selected_apex")
+ android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
+
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+ baseModuleName := module.BaseModuleName()
+
+ apexExtractorModuleName := apexExtractorModuleName(baseModuleName)
+ createApexExtractorModule(ctx, apexExtractorModuleName, &module.properties.ApexExtractorProperties)
+
+ apexFileSource := ":" + apexExtractorModuleName
+ if len(module.deapexerProperties.Exported_java_libs) != 0 {
+ createDeapexerModule(ctx, deapexerModuleName(baseModuleName), apexFileSource, &module.deapexerProperties)
+ }
+
+ // After passing the arch specific src properties to the creating the apex selector module
+ module.selectedApexProperties.Selected_apex = proptools.StringPtr(apexFileSource)
+ })
+
+ return module
+}
+
+func createApexExtractorModule(ctx android.LoadHookContext, name string, apexExtractorProperties *ApexExtractorProperties) {
+ props := struct {
+ Name *string
+ }{
+ Name: proptools.StringPtr(name),
}
- android.InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "set")
- android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
- return module
+ ctx.CreateModule(privateApexExtractorModuleFactory,
+ &props,
+ apexExtractorProperties,
+ )
+}
+
+func apexExtractorModuleName(baseModuleName string) string {
+ return baseModuleName + ".apex.extractor"
+}
+
+func (a *ApexSet) DepsMutator(ctx android.BottomUpMutatorContext) {
+ a.deapexerDeps(ctx)
+}
+
+var _ ApexInfoMutator = (*ApexSet)(nil)
+
+func (a *ApexSet) ApexInfoMutator(mctx android.TopDownMutatorContext) {
+ a.apexInfoMutator(mctx)
}
func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -628,20 +724,13 @@
ctx.ModuleErrorf("filename should end in %s for apex_set", imageApexSuffix)
}
- apexSet := a.prebuiltCommon.prebuilt.SingleSourcePath(ctx)
+ inputApex := android.OptionalPathForModuleSrc(ctx, a.selectedApexProperties.Selected_apex).Path()
a.outputApex = android.PathForModuleOut(ctx, a.installFilename)
- ctx.Build(pctx,
- android.BuildParams{
- Rule: extractMatchingApex,
- Description: "Extract an apex from an apex set",
- Inputs: android.Paths{apexSet},
- Output: a.outputApex,
- Args: map[string]string{
- "abis": strings.Join(java.SupportedAbis(ctx), ","),
- "allow-prereleased": strconv.FormatBool(proptools.Bool(a.properties.Prerelease)),
- "sdk-version": ctx.Config().PlatformSdkVersion().String(),
- },
- })
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: inputApex,
+ Output: a.outputApex,
+ })
if a.prebuiltCommon.checkForceDisable(ctx) {
a.HideFromMake()
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index affb5ce..b88da2f 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -5,8 +5,9 @@
)
var (
- GetOutputFiles RequestType = &getOutputFilesRequestType{}
- GetOutputFilesAndCcObjectFiles RequestType = &getOutputFilesAndCcObjectFilesType{}
+ GetOutputFiles = &getOutputFilesRequestType{}
+ GetOutputFilesAndCcObjectFiles = &getOutputFilesAndCcObjectFilesType{}
+ GetPrebuiltCcStaticLibraryFiles = &getPrebuiltCcStaticLibraryFiles{}
)
type GetOutputFilesAndCcObjectFiles_Result struct {
@@ -14,49 +15,49 @@
CcObjectFiles []string
}
-type RequestType interface {
- // Name returns a string name for this request type. Such request type names must be unique,
- // and must only consist of alphanumeric characters.
- Name() string
-
- // StarlarkFunctionBody returns a straark function body to process this request type.
- // The returned string is the body of a Starlark function which obtains
- // all request-relevant information about a target and returns a string containing
- // this information.
- // The function should have the following properties:
- // - `target` is the only parameter to this function (a configured target).
- // - The return value must be a string.
- // - The function body should not be indented outside of its own scope.
- StarlarkFunctionBody() string
-
- // ParseResult returns a value obtained by parsing the result of the request's Starlark function.
- // The given rawString must correspond to the string output which was created by evaluating the
- // Starlark given in StarlarkFunctionBody.
- // The type of this value depends on the request type; it is up to the caller to
- // cast to the correct type.
- ParseResult(rawString string) interface{}
-}
-
type getOutputFilesRequestType struct{}
+// Name returns a string name for this request type. Such request type names must be unique,
+// and must only consist of alphanumeric characters.
func (g getOutputFilesRequestType) Name() string {
return "getOutputFiles"
}
+// StarlarkFunctionBody returns a starlark function body to process this request type.
+// The returned string is the body of a Starlark function which obtains
+// all request-relevant information about a target and returns a string containing
+// this information.
+// The function should have the following properties:
+// - `target` is the only parameter to this function (a configured target).
+// - The return value must be a string.
+// - The function body should not be indented outside of its own scope.
func (g getOutputFilesRequestType) StarlarkFunctionBody() string {
return "return ', '.join([f.path for f in target.files.to_list()])"
}
-func (g getOutputFilesRequestType) ParseResult(rawString string) interface{} {
+// ParseResult returns a value obtained by parsing the result of the request's Starlark function.
+// The given rawString must correspond to the string output which was created by evaluating the
+// Starlark given in StarlarkFunctionBody.
+func (g getOutputFilesRequestType) ParseResult(rawString string) []string {
return strings.Split(rawString, ", ")
}
type getOutputFilesAndCcObjectFilesType struct{}
+// Name returns a string name for this request type. Such request type names must be unique,
+// and must only consist of alphanumeric characters.
func (g getOutputFilesAndCcObjectFilesType) Name() string {
return "getOutputFilesAndCcObjectFiles"
}
+// StarlarkFunctionBody returns a starlark function body to process this request type.
+// The returned string is the body of a Starlark function which obtains
+// all request-relevant information about a target and returns a string containing
+// this information.
+// The function should have the following properties:
+// - `target` is the only parameter to this function (a configured target).
+// - The return value must be a string.
+// - The function body should not be indented outside of its own scope.
func (g getOutputFilesAndCcObjectFilesType) StarlarkFunctionBody() string {
return `
outputFiles = [f.path for f in target.files.to_list()]
@@ -71,7 +72,10 @@
return ', '.join(outputFiles) + "|" + ', '.join(ccObjectFiles)`
}
-func (g getOutputFilesAndCcObjectFilesType) ParseResult(rawString string) interface{} {
+// ParseResult returns a value obtained by parsing the result of the request's Starlark function.
+// The given rawString must correspond to the string output which was created by evaluating the
+// Starlark given in StarlarkFunctionBody.
+func (g getOutputFilesAndCcObjectFilesType) ParseResult(rawString string) GetOutputFilesAndCcObjectFiles_Result {
var outputFiles []string
var ccObjects []string
@@ -83,6 +87,34 @@
return GetOutputFilesAndCcObjectFiles_Result{outputFiles, ccObjects}
}
+type getPrebuiltCcStaticLibraryFiles struct{}
+
+// Name returns the name of the starlark function to get prebuilt cc static library files
+func (g getPrebuiltCcStaticLibraryFiles) Name() string {
+ return "getPrebuiltCcStaticLibraryFiles"
+}
+
+// StarlarkFunctionBody returns the unindented body of a starlark function for extracting the static
+// library paths from a cc_import module.
+func (g getPrebuiltCcStaticLibraryFiles) StarlarkFunctionBody() string {
+ return `
+linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list()
+
+static_libraries = []
+for linker_input in linker_inputs:
+ for library in linker_input.libraries:
+ static_libraries.append(library.static_library.path)
+
+return ', '.join(static_libraries)`
+}
+
+// ParseResult returns a slice of bazel output paths to static libraries if any exist for the given
+// rawString corresponding to the string output which was created by evaluating the
+// StarlarkFunctionBody.
+func (g getPrebuiltCcStaticLibraryFiles) ParseResult(rawString string) []string {
+ return strings.Split(rawString, ", ")
+}
+
// splitOrEmpty is a modification of strings.Split() that returns an empty list
// if the given string is empty.
func splitOrEmpty(s string, sep string) []string {
diff --git a/bazel/properties.go b/bazel/properties.go
index 2440ca1..4bb2391 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -16,6 +16,7 @@
import (
"fmt"
+ "path/filepath"
"regexp"
"sort"
)
@@ -47,6 +48,57 @@
Excludes []Label
}
+// GlobsInDir returns a list of glob expressions for a list of extensions
+// (optionally recursive) within a directory.
+func GlobsInDir(dir string, recursive bool, extensions []string) []string {
+ globs := []string{}
+
+ globInfix := ""
+ if dir == "." {
+ if recursive {
+ // e.g "**/*.h"
+ globInfix = "**/"
+ } // else e.g. "*.h"
+ for _, ext := range extensions {
+ globs = append(globs, globInfix+"*"+ext)
+ }
+ } else {
+ if recursive {
+ // e.g. "foo/bar/**/*.h"
+ dir += "/**"
+ } // else e.g. "foo/bar/*.h"
+ for _, ext := range extensions {
+ globs = append(globs, dir+"/*"+ext)
+ }
+ }
+ return globs
+}
+
+// LooseHdrsGlobs returns the list of non-recursive header globs for each parent directory of
+// each source file in this LabelList's Includes.
+func (ll *LabelList) LooseHdrsGlobs(exts []string) []string {
+ var globs []string
+ for _, parentDir := range ll.uniqueParentDirectories() {
+ globs = append(globs,
+ GlobsInDir(parentDir, false, exts)...)
+ }
+ return globs
+}
+
+// uniqueParentDirectories returns a list of the unique parent directories for
+// all files in ll.Includes.
+func (ll *LabelList) uniqueParentDirectories() []string {
+ dirMap := map[string]bool{}
+ for _, label := range ll.Includes {
+ dirMap[filepath.Dir(label.Label)] = true
+ }
+ dirs := []string{}
+ for dir := range dirMap {
+ dirs = append(dirs, dir)
+ }
+ return dirs
+}
+
// Append appends the fields of other labelList to the corresponding fields of ll.
func (ll *LabelList) Append(other LabelList) {
if len(ll.Includes) > 0 || len(other.Includes) > 0 {
@@ -79,6 +131,63 @@
return uniqueLabelList
}
+// Subtract needle from haystack
+func SubtractStrings(haystack []string, needle []string) []string {
+ // This is really a set
+ remainder := make(map[string]bool)
+
+ for _, s := range haystack {
+ remainder[s] = true
+ }
+ for _, s := range needle {
+ delete(remainder, s)
+ }
+
+ var strings []string
+ for s, _ := range remainder {
+ strings = append(strings, s)
+ }
+
+ sort.SliceStable(strings, func(i, j int) bool {
+ return strings[i] < strings[j]
+ })
+
+ return strings
+}
+
+// Subtract needle from haystack
+func SubtractBazelLabels(haystack []Label, needle []Label) []Label {
+ // This is really a set
+ remainder := make(map[Label]bool)
+
+ for _, label := range haystack {
+ remainder[label] = true
+ }
+ for _, label := range needle {
+ delete(remainder, label)
+ }
+
+ var labels []Label
+ for label, _ := range remainder {
+ labels = append(labels, label)
+ }
+
+ sort.SliceStable(labels, func(i, j int) bool {
+ return labels[i].Label < labels[j].Label
+ })
+
+ return labels
+}
+
+// Subtract needle from haystack
+func SubtractBazelLabelList(haystack LabelList, needle LabelList) LabelList {
+ var result LabelList
+ result.Includes = SubtractBazelLabels(haystack.Includes, needle.Includes)
+ // NOTE: Excludes are intentionally not subtracted
+ result.Excludes = haystack.Excludes
+ return result
+}
+
const (
// ArchType names in arch.go
ARCH_ARM = "arm"
@@ -167,6 +276,26 @@
return LabelListAttribute{Value: UniqueBazelLabelList(value)}
}
+// Append appends all values, including os and arch specific ones, from another
+// LabelListAttribute to this LabelListAttribute.
+func (attrs *LabelListAttribute) Append(other LabelListAttribute) {
+ for arch := range PlatformArchMap {
+ this := attrs.GetValueForArch(arch)
+ that := other.GetValueForArch(arch)
+ this.Append(that)
+ attrs.SetValueForArch(arch, this)
+ }
+
+ for os := range PlatformOsMap {
+ this := attrs.GetValueForOS(os)
+ that := other.GetValueForOS(os)
+ this.Append(that)
+ attrs.SetValueForOS(os, this)
+ }
+
+ attrs.Value.Append(other.Value)
+}
+
// HasArchSpecificValues returns true if the attribute contains
// architecture-specific label_list values.
func (attrs LabelListAttribute) HasConfigurableValues() bool {
@@ -257,6 +386,12 @@
OsValues stringListOsValues
}
+// MakeStringListAttribute initializes a StringListAttribute with the non-arch specific value.
+func MakeStringListAttribute(value []string) StringListAttribute {
+ // NOTE: These strings are not necessarily unique or sorted.
+ return StringListAttribute{Value: value}
+}
+
// Arch-specific string_list typed Bazel attribute values. This should correspond
// to the types of architectures supported for compilation in arch.go.
type stringListArchValues struct {
diff --git a/bazel/properties_test.go b/bazel/properties_test.go
index 0fcb904..56840ef 100644
--- a/bazel/properties_test.go
+++ b/bazel/properties_test.go
@@ -46,6 +46,82 @@
}
}
+func TestSubtractStrings(t *testing.T) {
+ testCases := []struct {
+ haystack []string
+ needle []string
+ expectedResult []string
+ }{
+ {
+ haystack: []string{
+ "a",
+ "b",
+ "c",
+ },
+ needle: []string{
+ "a",
+ },
+ expectedResult: []string{
+ "b", "c",
+ },
+ },
+ }
+ for _, tc := range testCases {
+ actualResult := SubtractStrings(tc.haystack, tc.needle)
+ if !reflect.DeepEqual(tc.expectedResult, actualResult) {
+ t.Fatalf("Expected %v, got %v", tc.expectedResult, actualResult)
+ }
+ }
+}
+
+func TestSubtractBazelLabelList(t *testing.T) {
+ testCases := []struct {
+ haystack LabelList
+ needle LabelList
+ expectedResult LabelList
+ }{
+ {
+ haystack: LabelList{
+ Includes: []Label{
+ {Label: "a"},
+ {Label: "b"},
+ {Label: "c"},
+ },
+ Excludes: []Label{
+ {Label: "x"},
+ {Label: "y"},
+ {Label: "z"},
+ },
+ },
+ needle: LabelList{
+ Includes: []Label{
+ {Label: "a"},
+ },
+ Excludes: []Label{
+ {Label: "z"},
+ },
+ },
+ // NOTE: Excludes are intentionally not subtracted
+ expectedResult: LabelList{
+ Includes: []Label{
+ {Label: "b"},
+ {Label: "c"},
+ },
+ Excludes: []Label{
+ {Label: "x"},
+ {Label: "y"},
+ {Label: "z"},
+ },
+ },
+ },
+ }
+ for _, tc := range testCases {
+ actualResult := SubtractBazelLabelList(tc.haystack, tc.needle)
+ if !reflect.DeepEqual(tc.expectedResult, actualResult) {
+ t.Fatalf("Expected %v, got %v", tc.expectedResult, actualResult)
+ }
+ }
+}
func TestUniqueBazelLabelList(t *testing.T) {
testCases := []struct {
originalLabelList LabelList
diff --git a/bloaty/bloaty.go b/bloaty/bloaty.go
index 653c489..764cded 100644
--- a/bloaty/bloaty.go
+++ b/bloaty/bloaty.go
@@ -23,7 +23,7 @@
)
const bloatyDescriptorExt = ".bloaty.csv"
-const protoFilename = "binary_sizes.pb"
+const protoFilename = "binary_sizes.pb.gz"
var (
fileSizeMeasurerKey blueprint.ProviderKey
diff --git a/bloaty/bloaty_merger.py b/bloaty/bloaty_merger.py
index c873fb8..1034462 100644
--- a/bloaty/bloaty_merger.py
+++ b/bloaty/bloaty_merger.py
@@ -16,12 +16,13 @@
Merges a list of .csv files from Bloaty into a protobuf. It takes the list as
a first argument and the output as second. For instance:
- $ bloaty_merger binary_sizes.lst binary_sizes.pb
+ $ bloaty_merger binary_sizes.lst binary_sizes.pb.gz
"""
import argparse
import csv
+import gzip
import ninja_rsp
@@ -57,7 +58,8 @@
Args:
input_list: The path to the file which contains the list of CSV files. Each
filepath is separated by a space.
- output_proto: The path for the output protobuf.
+ output_proto: The path for the output protobuf. It will be compressed using
+ gzip.
"""
metrics = file_sections_pb2.FileSizeMetrics()
reader = ninja_rsp.NinjaRspFileReader(input_list)
@@ -65,7 +67,7 @@
file_proto = parse_csv(csv_path)
if file_proto:
metrics.files.append(file_proto)
- with open(output_proto, "wb") as output:
+ with gzip.open(output_proto, "wb") as output:
output.write(metrics.SerializeToString())
def main():
diff --git a/bloaty/bloaty_merger_test.py b/bloaty/bloaty_merger_test.py
index 0e3641d..9de049a 100644
--- a/bloaty/bloaty_merger_test.py
+++ b/bloaty/bloaty_merger_test.py
@@ -11,6 +11,7 @@
# 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.
+import gzip
import unittest
from pyfakefs import fake_filesystem_unittest
@@ -53,10 +54,10 @@
self.fs.create_file("file1.bloaty.csv", contents=file1_content)
self.fs.create_file("file2.bloaty.csv", contents=file2_content)
- bloaty_merger.create_file_size_metrics("files.lst", "output.pb")
+ bloaty_merger.create_file_size_metrics("files.lst", "output.pb.gz")
metrics = file_sections_pb2.FileSizeMetrics()
- with open("output.pb", "rb") as output:
+ with gzip.open("output.pb.gz", "rb") as output:
metrics.ParseFromString(output.read())
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index cc616f2..d2a8729 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -26,6 +26,7 @@
testSrcs: [
"build_conversion_test.go",
"bzl_conversion_test.go",
+ "cc_library_conversion_test.go",
"cc_library_headers_conversion_test.go",
"cc_library_static_conversion_test.go",
"cc_object_conversion_test.go",
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index dd14c7d..b7a2810 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -374,16 +374,9 @@
// value>)" to set the default value of unset attributes. In the cases
// where the bp2build converter didn't set the default value within the
// mutator when creating the BazelTargetModule, this would be a zero
- // value. For those cases, we return a non-surprising default value so
- // generated BUILD files are syntactically correct.
- switch propertyValue.Kind() {
- case reflect.Slice:
- return "[]", nil
- case reflect.Map:
- return "{}", nil
- default:
- return "", nil
- }
+ // value. For those cases, we return an empty string so we don't
+ // unnecessarily generate empty values.
+ return "", nil
}
var ret string
@@ -397,21 +390,38 @@
case reflect.Ptr:
return prettyPrint(propertyValue.Elem(), indent)
case reflect.Slice:
- ret = "[\n"
- for i := 0; i < propertyValue.Len(); i++ {
- indexedValue, err := prettyPrint(propertyValue.Index(i), indent+1)
+ if propertyValue.Len() == 0 {
+ return "", nil
+ }
+
+ if propertyValue.Len() == 1 {
+ // Single-line list for list with only 1 element
+ ret += "["
+ indexedValue, err := prettyPrint(propertyValue.Index(0), indent)
if err != nil {
return "", err
}
+ ret += indexedValue
+ ret += "]"
+ } else {
+ // otherwise, use a multiline list.
+ ret += "[\n"
+ for i := 0; i < propertyValue.Len(); i++ {
+ indexedValue, err := prettyPrint(propertyValue.Index(i), indent+1)
+ if err != nil {
+ return "", err
+ }
- if indexedValue != "" {
- ret += makeIndent(indent + 1)
- ret += indexedValue
- ret += ",\n"
+ if indexedValue != "" {
+ ret += makeIndent(indent + 1)
+ ret += indexedValue
+ ret += ",\n"
+ }
}
+ ret += makeIndent(indent)
+ ret += "]"
}
- ret += makeIndent(indent)
- ret += "]"
+
case reflect.Struct:
// Special cases where the bp2build sends additional information to the codegenerator
// by wrapping the attributes in a custom struct type.
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 49897b3..1ede442 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -27,9 +27,7 @@
expectedBazelTarget string
}{
{
- bp: `custom {
- name: "foo",
-}
+ bp: `custom { name: "foo" }
`,
expectedBazelTarget: `soong_module(
name = "foo",
@@ -85,9 +83,7 @@
soong_module_variant = "",
soong_module_deps = [
],
- required = [
- "bar",
- ],
+ required = ["bar"],
)`,
},
{
@@ -116,12 +112,10 @@
targets: ["goal_foo"],
tag: ".foo",
},
- dists: [
- {
- targets: ["goal_bar"],
- tag: ".bar",
- },
- ],
+ dists: [{
+ targets: ["goal_bar"],
+ tag: ".bar",
+ }],
}
`,
expectedBazelTarget: `soong_module(
@@ -133,18 +127,12 @@
],
dist = {
"tag": ".foo",
- "targets": [
- "goal_foo",
- ],
+ "targets": ["goal_foo"],
},
- dists = [
- {
- "tag": ".bar",
- "targets": [
- "goal_bar",
- ],
- },
- ],
+ dists = [{
+ "tag": ".bar",
+ "targets": ["goal_bar"],
+ }],
)`,
},
{
@@ -169,19 +157,13 @@
soong_module_variant = "",
soong_module_deps = [
],
- dists = [
- {
- "tag": ".tag",
- "targets": [
- "my_goal",
- ],
- },
- ],
+ dists = [{
+ "tag": ".tag",
+ "targets": ["my_goal"],
+ }],
owner = "custom_owner",
ramdisk = True,
- required = [
- "bar",
- ],
+ required = ["bar"],
target_required = [
"qux",
"bazqux",
@@ -553,9 +535,7 @@
}`,
expectedBazelTargets: []string{`filegroup(
name = "fg_foo",
- srcs = [
- "b",
- ],
+ srcs = ["b"],
)`,
},
},
@@ -625,7 +605,7 @@
bp: `filegroup {
name: "foobar",
srcs: [
- ":foo",
+ ":foo",
"c",
],
bazel_module: { bp2build_available: true },
@@ -671,25 +651,15 @@
`genrule(
name = "foo",
cmd = "$(location :foo.tool) --genDir=$(GENDIR) arg $(SRCS) $(OUTS)",
- outs = [
- "foo.out",
- ],
- srcs = [
- "foo.in",
- ],
- tools = [
- ":foo.tool",
- ],
+ outs = ["foo.out"],
+ srcs = ["foo.in"],
+ tools = [":foo.tool"],
)`,
`genrule(
name = "foo.tool",
cmd = "cp $(SRCS) $(OUTS)",
- outs = [
- "foo_tool.out",
- ],
- srcs = [
- "foo_tool.in",
- ],
+ outs = ["foo_tool.out"],
+ srcs = ["foo_tool.in"],
)`,
},
},
@@ -718,15 +688,9 @@
expectedBazelTargets: []string{`genrule(
name = "foo",
cmd = "$(locations :foo.tools) -s $(OUTS) $(SRCS)",
- outs = [
- "foo.out",
- ],
- srcs = [
- "foo.in",
- ],
- tools = [
- ":foo.tools",
- ],
+ outs = ["foo.out"],
+ srcs = ["foo.in"],
+ tools = [":foo.tools"],
)`,
`genrule(
name = "foo.tools",
@@ -735,9 +699,7 @@
"foo_tool.out",
"foo_tool2.out",
],
- srcs = [
- "foo_tool.in",
- ],
+ srcs = ["foo_tool.in"],
)`,
},
},
@@ -758,15 +720,9 @@
expectedBazelTargets: []string{`genrule(
name = "foo",
cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)",
- outs = [
- "foo.out",
- ],
- srcs = [
- "foo.in",
- ],
- tools = [
- "//other:foo.tool",
- ],
+ outs = ["foo.out"],
+ srcs = ["foo.in"],
+ tools = ["//other:foo.tool"],
)`,
},
fs: otherGenruleBp,
@@ -788,15 +744,9 @@
expectedBazelTargets: []string{`genrule(
name = "foo",
cmd = "$(locations //other:foo.tool) -s $(OUTS) $(location //other:other.tool)",
- outs = [
- "foo.out",
- ],
- srcs = [
- "//other:other.tool",
- ],
- tools = [
- "//other:foo.tool",
- ],
+ outs = ["foo.out"],
+ srcs = ["//other:other.tool"],
+ tools = ["//other:foo.tool"],
)`,
},
fs: otherGenruleBp,
@@ -818,12 +768,8 @@
expectedBazelTargets: []string{`genrule(
name = "foo",
cmd = "$(location //other:foo.tool) -s $(OUTS) $(SRCS)",
- outs = [
- "foo.out",
- ],
- srcs = [
- "foo.in",
- ],
+ outs = ["foo.out"],
+ srcs = ["foo.in"],
tools = [
"//other:foo.tool",
"//other:other.tool",
@@ -849,12 +795,8 @@
expectedBazelTargets: []string{`genrule(
name = "foo",
cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)",
- outs = [
- "foo.out",
- ],
- srcs = [
- "foo.in",
- ],
+ outs = ["foo.out"],
+ srcs = ["foo.in"],
tools = [
"//other:foo.tool",
"//other:other.tool",
@@ -879,12 +821,8 @@
expectedBazelTargets: []string{`genrule(
name = "foo",
cmd = "cp $(SRCS) $(OUTS)",
- outs = [
- "foo.out",
- ],
- srcs = [
- "foo.in",
- ],
+ outs = ["foo.out"],
+ srcs = ["foo.in"],
)`,
},
},
@@ -988,12 +926,8 @@
expectedBazelTarget: `genrule(
name = "gen",
cmd = "do-something $(SRCS) $(OUTS)",
- outs = [
- "out",
- ],
- srcs = [
- "in1",
- ],
+ outs = ["out"],
+ srcs = ["in1"],
)`,
description: "genrule applies properties from a genrule_defaults dependency if not specified",
},
@@ -1062,12 +996,8 @@
expectedBazelTarget: `genrule(
name = "gen",
cmd = "cp $(SRCS) $(OUTS)",
- outs = [
- "out",
- ],
- srcs = [
- "in1",
- ],
+ outs = ["out"],
+ srcs = ["in1"],
)`,
description: "genrule applies properties from list of genrule_defaults",
},
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
new file mode 100644
index 0000000..783af2e
--- /dev/null
+++ b/bp2build/cc_library_conversion_test.go
@@ -0,0 +1,271 @@
+// Copyright 2021 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 bp2build
+
+import (
+ "android/soong/android"
+ "android/soong/cc"
+ "strings"
+ "testing"
+)
+
+const (
+ // See cc/testing.go for more context
+ soongCcLibraryPreamble = `
+cc_defaults {
+ name: "linux_bionic_supported",
+}
+
+toolchain_library {
+ name: "libclang_rt.builtins-x86_64-android",
+ defaults: ["linux_bionic_supported"],
+ vendor_available: true,
+ vendor_ramdisk_available: true,
+ product_available: true,
+ recovery_available: true,
+ native_bridge_supported: true,
+ src: "",
+}`
+)
+
+func TestCcLibraryBp2Build(t *testing.T) {
+ testCases := []struct {
+ description string
+ moduleTypeUnderTest string
+ moduleTypeUnderTestFactory android.ModuleFactory
+ moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
+ bp string
+ expectedBazelTargets []string
+ filesystem map[string]string
+ dir string
+ }{
+ {
+ description: "cc_library - simple example",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ filesystem: map[string]string{
+ "android.cpp": "",
+ "darwin.cpp": "",
+ // Refer to cc.headerExts for the supported header extensions in Soong.
+ "header.h": "",
+ "header.hh": "",
+ "header.hpp": "",
+ "header.hxx": "",
+ "header.h++": "",
+ "header.inl": "",
+ "header.inc": "",
+ "header.ipp": "",
+ "header.h.generic": "",
+ "impl.cpp": "",
+ "linux.cpp": "",
+ "x86.cpp": "",
+ "x86_64.cpp": "",
+ "foo-dir/a.h": "",
+ },
+ bp: soongCcLibraryPreamble + `
+cc_library_headers { name: "some-headers" }
+cc_library {
+ name: "foo-lib",
+ srcs: ["impl.cpp"],
+ cflags: ["-Wall"],
+ header_libs: ["some-headers"],
+ export_include_dirs: ["foo-dir"],
+ ldflags: ["-Wl,--exclude-libs=bar.a"],
+ arch: {
+ x86: {
+ ldflags: ["-Wl,--exclude-libs=baz.a"],
+ srcs: ["x86.cpp"],
+ },
+ x86_64: {
+ ldflags: ["-Wl,--exclude-libs=qux.a"],
+ srcs: ["x86_64.cpp"],
+ },
+ },
+ target: {
+ android: {
+ srcs: ["android.cpp"],
+ },
+ linux_glibc: {
+ srcs: ["linux.cpp"],
+ },
+ darwin: {
+ srcs: ["darwin.cpp"],
+ },
+ },
+}
+`,
+ expectedBazelTargets: []string{`cc_library(
+ name = "foo-lib",
+ copts = ["-Wall"],
+ deps = [":some-headers"],
+ hdrs = [
+ "header.h",
+ "header.hh",
+ "header.hpp",
+ "header.hxx",
+ "header.h++",
+ "header.inl",
+ "header.inc",
+ "header.ipp",
+ "header.h.generic",
+ "foo-dir/a.h",
+ ],
+ includes = ["foo-dir"],
+ linkopts = ["-Wl,--exclude-libs=bar.a"] + select({
+ "//build/bazel/platforms/arch:x86": ["-Wl,--exclude-libs=baz.a"],
+ "//build/bazel/platforms/arch:x86_64": ["-Wl,--exclude-libs=qux.a"],
+ "//conditions:default": [],
+ }),
+ srcs = ["impl.cpp"] + select({
+ "//build/bazel/platforms/arch:x86": ["x86.cpp"],
+ "//build/bazel/platforms/arch:x86_64": ["x86_64.cpp"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/platforms/os:android": ["android.cpp"],
+ "//build/bazel/platforms/os:darwin": ["darwin.cpp"],
+ "//build/bazel/platforms/os:linux": ["linux.cpp"],
+ "//conditions:default": [],
+ }),
+)`},
+ },
+ {
+ description: "cc_library - trimmed example of //bionic/linker:ld-android",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ filesystem: map[string]string{
+ "ld-android.cpp": "",
+ "linked_list.h": "",
+ "linker.h": "",
+ "linker_block_allocator.h": "",
+ "linker_cfi.h": "",
+ },
+ bp: soongCcLibraryPreamble + `
+cc_library_headers { name: "libc_headers" }
+cc_library {
+ name: "fake-ld-android",
+ srcs: ["ld_android.cpp"],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Wunused",
+ "-Werror",
+ ],
+ header_libs: ["libc_headers"],
+ ldflags: [
+ "-Wl,--exclude-libs=libgcc.a",
+ "-Wl,--exclude-libs=libgcc_stripped.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-arm-android.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-aarch64-android.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-i686-android.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-x86_64-android.a",
+ ],
+ arch: {
+ x86: {
+ ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
+ },
+ x86_64: {
+ ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
+ },
+ },
+}
+`,
+ expectedBazelTargets: []string{`cc_library(
+ name = "fake-ld-android",
+ copts = [
+ "-Wall",
+ "-Wextra",
+ "-Wunused",
+ "-Werror",
+ ],
+ deps = [":libc_headers"],
+ hdrs = [
+ "linked_list.h",
+ "linker.h",
+ "linker_block_allocator.h",
+ "linker_cfi.h",
+ ],
+ linkopts = [
+ "-Wl,--exclude-libs=libgcc.a",
+ "-Wl,--exclude-libs=libgcc_stripped.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-arm-android.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-aarch64-android.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-i686-android.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-x86_64-android.a",
+ ] + select({
+ "//build/bazel/platforms/arch:x86": ["-Wl,--exclude-libs=libgcc_eh.a"],
+ "//build/bazel/platforms/arch:x86_64": ["-Wl,--exclude-libs=libgcc_eh.a"],
+ "//conditions:default": [],
+ }),
+ srcs = ["ld_android.cpp"],
+)`},
+ },
+ }
+
+ dir := "."
+ for _, testCase := range testCases {
+ filesystem := make(map[string][]byte)
+ toParse := []string{
+ "Android.bp",
+ }
+ for f, content := range testCase.filesystem {
+ if strings.HasSuffix(f, "Android.bp") {
+ toParse = append(toParse, f)
+ }
+ filesystem[f] = []byte(content)
+ }
+ config := android.TestConfig(buildDir, nil, testCase.bp, filesystem)
+ ctx := android.NewTestContext(config)
+
+ cc.RegisterCCBuildComponents(ctx)
+ ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
+ ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
+ ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
+ ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
+ ctx.RegisterBp2BuildConfig(bp2buildConfig) // TODO(jingwen): make this the default for all tests
+ ctx.RegisterForBazelConversion()
+
+ _, errs := ctx.ParseFileList(dir, toParse)
+ if Errored(t, testCase.description, errs) {
+ continue
+ }
+ _, errs = ctx.ResolveDependencies(config)
+ if Errored(t, testCase.description, errs) {
+ continue
+ }
+
+ checkDir := dir
+ if testCase.dir != "" {
+ checkDir = testCase.dir
+ }
+ codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+ bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir)
+ if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
+ t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount)
+ } else {
+ for i, target := range bazelTargets {
+ if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
+ t.Errorf(
+ "%s: Expected generated Bazel target to be '%s', got '%s'",
+ testCase.description,
+ w,
+ g,
+ )
+ }
+ }
+ }
+ }
+}
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index dbea37a..c59241f 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -23,7 +23,7 @@
const (
// See cc/testing.go for more context
- soongCcLibraryPreamble = `
+ soongCcLibraryHeadersPreamble = `
cc_defaults {
name: "linux_bionic_supported",
}
@@ -86,16 +86,19 @@
moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build,
filesystem: map[string]string{
- "lib-1/lib1a.h": "",
- "lib-1/lib1b.h": "",
- "lib-2/lib2a.h": "",
- "lib-2/lib2b.h": "",
- "dir-1/dir1a.h": "",
- "dir-1/dir1b.h": "",
- "dir-2/dir2a.h": "",
- "dir-2/dir2b.h": "",
+ "lib-1/lib1a.h": "",
+ "lib-1/lib1b.h": "",
+ "lib-2/lib2a.h": "",
+ "lib-2/lib2b.h": "",
+ "dir-1/dir1a.h": "",
+ "dir-1/dir1b.h": "",
+ "dir-2/dir2a.h": "",
+ "dir-2/dir2b.h": "",
+ "arch_arm64_exported_include_dir/a.h": "",
+ "arch_x86_exported_include_dir/b.h": "",
+ "arch_x86_64_exported_include_dir/c.h": "",
},
- bp: soongCcLibraryPreamble + `
+ bp: soongCcLibraryHeadersPreamble + `
cc_library_headers {
name: "lib-1",
export_include_dirs: ["lib-1"],
@@ -111,6 +114,19 @@
export_include_dirs: ["dir-1", "dir-2"],
header_libs: ["lib-1", "lib-2"],
+ arch: {
+ arm64: {
+ // We expect dir-1 headers to be dropped, because dir-1 is already in export_include_dirs
+ export_include_dirs: ["arch_arm64_exported_include_dir", "dir-1"],
+ },
+ x86: {
+ export_include_dirs: ["arch_x86_exported_include_dir"],
+ },
+ x86_64: {
+ export_include_dirs: ["arch_x86_64_exported_include_dir"],
+ },
+ },
+
// TODO: Also support export_header_lib_headers
}`,
expectedBazelTargets: []string{`cc_library_headers(
@@ -124,29 +140,35 @@
"dir-1/dir1b.h",
"dir-2/dir2a.h",
"dir-2/dir2b.h",
- ],
+ ] + select({
+ "//build/bazel/platforms/arch:arm64": ["arch_arm64_exported_include_dir/a.h"],
+ "//build/bazel/platforms/arch:x86": ["arch_x86_exported_include_dir/b.h"],
+ "//build/bazel/platforms/arch:x86_64": ["arch_x86_64_exported_include_dir/c.h"],
+ "//conditions:default": [],
+ }),
includes = [
"dir-1",
"dir-2",
- ],
+ ] + select({
+ "//build/bazel/platforms/arch:arm64": ["arch_arm64_exported_include_dir"],
+ "//build/bazel/platforms/arch:x86": ["arch_x86_exported_include_dir"],
+ "//build/bazel/platforms/arch:x86_64": ["arch_x86_64_exported_include_dir"],
+ "//conditions:default": [],
+ }),
)`, `cc_library_headers(
name = "lib-1",
hdrs = [
"lib-1/lib1a.h",
"lib-1/lib1b.h",
],
- includes = [
- "lib-1",
- ],
+ includes = ["lib-1"],
)`, `cc_library_headers(
name = "lib-2",
hdrs = [
"lib-2/lib2a.h",
"lib-2/lib2b.h",
],
- includes = [
- "lib-2",
- ],
+ includes = ["lib-2"],
)`},
},
{
@@ -185,27 +207,13 @@
name = "darwin-lib",
)`, `cc_library_headers(
name = "foo_headers",
- deps = [
- ":base-lib",
- ] + select({
- "//build/bazel/platforms/os:android": [
- ":android-lib",
- ],
- "//build/bazel/platforms/os:darwin": [
- ":darwin-lib",
- ],
- "//build/bazel/platforms/os:fuchsia": [
- ":fuchsia-lib",
- ],
- "//build/bazel/platforms/os:linux": [
- ":linux-lib",
- ],
- "//build/bazel/platforms/os:linux_bionic": [
- ":linux_bionic-lib",
- ],
- "//build/bazel/platforms/os:windows": [
- ":windows-lib",
- ],
+ deps = [":base-lib"] + select({
+ "//build/bazel/platforms/os:android": [":android-lib"],
+ "//build/bazel/platforms/os:darwin": [":darwin-lib"],
+ "//build/bazel/platforms/os:fuchsia": [":fuchsia-lib"],
+ "//build/bazel/platforms/os:linux": [":linux-lib"],
+ "//build/bazel/platforms/os:linux_bionic": [":linux_bionic-lib"],
+ "//build/bazel/platforms/os:windows": [":windows-lib"],
"//conditions:default": [],
}),
)`, `cc_library_headers(
@@ -240,7 +248,7 @@
name = "exported-lib",
)`, `cc_library_headers(
name = "foo_headers",
- deps = [] + select({
+ deps = select({
"//build/bazel/platforms/os:android": [
":android-lib",
":exported-lib",
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 467b0b2..427aed3 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -101,6 +101,9 @@
"export_include_dir_1/export_include_dir_1_b.h": "",
"export_include_dir_2/export_include_dir_2_a.h": "",
"export_include_dir_2/export_include_dir_2_b.h": "",
+ // NOTE: Soong implicitly includes headers in the current directory
+ "implicit_include_1.h": "",
+ "implicit_include_2.h": "",
},
bp: soongCcLibraryStaticPreamble + `
cc_library_headers {
@@ -191,6 +194,8 @@
":whole_static_lib_2",
],
hdrs = [
+ "implicit_include_1.h",
+ "implicit_include_2.h",
"export_include_dir_1/export_include_dir_1_a.h",
"export_include_dir_1/export_include_dir_1_b.h",
"export_include_dir_2/export_include_dir_2_a.h",
@@ -203,35 +208,74 @@
"include_dir_2",
"local_include_dir_1",
"local_include_dir_2",
+ ".",
],
linkstatic = True,
srcs = [
"foo_static1.cc",
"foo_static2.cc",
+ "include_dir_1/include_dir_1_a.h",
+ "include_dir_1/include_dir_1_b.h",
+ "include_dir_2/include_dir_2_a.h",
+ "include_dir_2/include_dir_2_b.h",
+ "local_include_dir_1/local_include_dir_1_a.h",
+ "local_include_dir_1/local_include_dir_1_b.h",
+ "local_include_dir_2/local_include_dir_2_a.h",
+ "local_include_dir_2/local_include_dir_2_b.h",
+ "implicit_include_1.h",
+ "implicit_include_2.h",
],
)`, `cc_library_static(
name = "static_lib_1",
+ hdrs = [
+ "implicit_include_1.h",
+ "implicit_include_2.h",
+ ],
+ includes = ["."],
linkstatic = True,
srcs = [
"static_lib_1.cc",
+ "implicit_include_1.h",
+ "implicit_include_2.h",
],
)`, `cc_library_static(
name = "static_lib_2",
+ hdrs = [
+ "implicit_include_1.h",
+ "implicit_include_2.h",
+ ],
+ includes = ["."],
linkstatic = True,
srcs = [
"static_lib_2.cc",
+ "implicit_include_1.h",
+ "implicit_include_2.h",
],
)`, `cc_library_static(
name = "whole_static_lib_1",
+ hdrs = [
+ "implicit_include_1.h",
+ "implicit_include_2.h",
+ ],
+ includes = ["."],
linkstatic = True,
srcs = [
"whole_static_lib_1.cc",
+ "implicit_include_1.h",
+ "implicit_include_2.h",
],
)`, `cc_library_static(
name = "whole_static_lib_2",
+ hdrs = [
+ "implicit_include_1.h",
+ "implicit_include_2.h",
+ ],
+ includes = ["."],
linkstatic = True,
srcs = [
"whole_static_lib_2.cc",
+ "implicit_include_1.h",
+ "implicit_include_2.h",
],
)`},
},
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
index 4f3babe..a9d24ac 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -52,7 +52,6 @@
"-Werror",
],
srcs: [
- "a/b/*.h",
"a/b/*.c"
],
exclude_srcs: ["a/b/exclude.c"],
@@ -68,15 +67,15 @@
"-Wall",
"-Werror",
],
+ hdrs = [
+ "a/b/bar.h",
+ "a/b/foo.h",
+ ],
local_include_dirs = [
"include",
".",
],
- srcs = [
- "a/b/bar.h",
- "a/b/c.c",
- "a/b/foo.h",
- ],
+ srcs = ["a/b/c.c"],
)`,
},
},
@@ -123,9 +122,7 @@
"include",
".",
],
- srcs = [
- "a/b/c.c",
- ],
+ srcs = ["a/b/c.c"],
)`,
},
},
@@ -155,29 +152,15 @@
`,
expectedBazelTargets: []string{`cc_object(
name = "bar",
- copts = [
- "-fno-addrsig",
- ],
- local_include_dirs = [
- ".",
- ],
- srcs = [
- "x/y/z.c",
- ],
+ copts = ["-fno-addrsig"],
+ local_include_dirs = ["."],
+ srcs = ["x/y/z.c"],
)`, `cc_object(
name = "foo",
- copts = [
- "-fno-addrsig",
- ],
- deps = [
- ":bar",
- ],
- local_include_dirs = [
- ".",
- ],
- srcs = [
- "a/b/c.c",
- ],
+ copts = ["-fno-addrsig"],
+ deps = [":bar"],
+ local_include_dirs = ["."],
+ srcs = ["a/b/c.c"],
)`,
},
},
@@ -200,12 +183,8 @@
`,
expectedBazelTargets: []string{`cc_object(
name = "foo",
- copts = [
- "-fno-addrsig",
- ],
- srcs = [
- "a/b/c.c",
- ],
+ copts = ["-fno-addrsig"],
+ srcs = ["a/b/c.c"],
)`,
},
},
@@ -228,12 +207,8 @@
`,
expectedBazelTargets: []string{`cc_object(
name = "foo",
- asflags = [
- "-DPLATFORM_SDK_VERSION={Platform_sdk_version}",
- ],
- copts = [
- "-fno-addrsig",
- ],
+ asflags = ["-DPLATFORM_SDK_VERSION={Platform_sdk_version}"],
+ copts = ["-fno-addrsig"],
)`,
},
},
@@ -321,23 +296,13 @@
expectedBazelTargets: []string{
`cc_object(
name = "foo",
- copts = [
- "-fno-addrsig",
- ] + select({
- "//build/bazel/platforms/arch:x86": [
- "-fPIC",
- ],
+ copts = ["-fno-addrsig"] + select({
+ "//build/bazel/platforms/arch:x86": ["-fPIC"],
"//conditions:default": [],
}),
- local_include_dirs = [
- ".",
- ],
- srcs = [
- "a.cpp",
- ] + select({
- "//build/bazel/platforms/arch:arm": [
- "arch/arm/file.S",
- ],
+ local_include_dirs = ["."],
+ srcs = ["a.cpp"] + select({
+ "//build/bazel/platforms/arch:arm": ["arch/arm/file.S"],
"//conditions:default": [],
}),
)`,
@@ -375,41 +340,19 @@
expectedBazelTargets: []string{
`cc_object(
name = "foo",
- copts = [
- "-fno-addrsig",
- ] + select({
- "//build/bazel/platforms/arch:arm": [
- "-Wall",
- ],
- "//build/bazel/platforms/arch:arm64": [
- "-Wall",
- ],
- "//build/bazel/platforms/arch:x86": [
- "-fPIC",
- ],
- "//build/bazel/platforms/arch:x86_64": [
- "-fPIC",
- ],
+ copts = ["-fno-addrsig"] + select({
+ "//build/bazel/platforms/arch:arm": ["-Wall"],
+ "//build/bazel/platforms/arch:arm64": ["-Wall"],
+ "//build/bazel/platforms/arch:x86": ["-fPIC"],
+ "//build/bazel/platforms/arch:x86_64": ["-fPIC"],
"//conditions:default": [],
}),
- local_include_dirs = [
- ".",
- ],
- srcs = [
- "base.cpp",
- ] + select({
- "//build/bazel/platforms/arch:arm": [
- "arm.cpp",
- ],
- "//build/bazel/platforms/arch:arm64": [
- "arm64.cpp",
- ],
- "//build/bazel/platforms/arch:x86": [
- "x86.cpp",
- ],
- "//build/bazel/platforms/arch:x86_64": [
- "x86_64.cpp",
- ],
+ local_include_dirs = ["."],
+ srcs = ["base.cpp"] + select({
+ "//build/bazel/platforms/arch:arm": ["arm.cpp"],
+ "//build/bazel/platforms/arch:arm64": ["arm64.cpp"],
+ "//build/bazel/platforms/arch:x86": ["x86.cpp"],
+ "//build/bazel/platforms/arch:x86_64": ["x86_64.cpp"],
"//conditions:default": [],
}),
)`,
@@ -440,26 +383,14 @@
expectedBazelTargets: []string{
`cc_object(
name = "foo",
- copts = [
- "-fno-addrsig",
- ] + select({
- "//build/bazel/platforms/os:android": [
- "-fPIC",
- ],
- "//build/bazel/platforms/os:darwin": [
- "-Wall",
- ],
- "//build/bazel/platforms/os:windows": [
- "-fPIC",
- ],
+ copts = ["-fno-addrsig"] + select({
+ "//build/bazel/platforms/os:android": ["-fPIC"],
+ "//build/bazel/platforms/os:darwin": ["-Wall"],
+ "//build/bazel/platforms/os:windows": ["-fPIC"],
"//conditions:default": [],
}),
- local_include_dirs = [
- ".",
- ],
- srcs = [
- "base.cpp",
- ],
+ local_include_dirs = ["."],
+ srcs = ["base.cpp"],
)`,
},
},
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
index b2b3379..97729df 100644
--- a/bp2build/configurability.go
+++ b/bp2build/configurability.go
@@ -69,20 +69,26 @@
return ret, err
}
- // Create the selects for arch specific values.
- selectMap, err := prettyPrintSelectMap(archSelects, "[]", indent)
+ // Convenience function to append selects components to an attribute value.
+ appendSelects := func(selectsData selects, defaultValue, s string) (string, error) {
+ selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent)
+ if err != nil {
+ return "", err
+ }
+ if s != "" && selectMap != "" {
+ s += " + "
+ }
+ s += selectMap
+
+ return s, nil
+ }
+
+ ret, err = appendSelects(archSelects, "[]", ret)
if err != nil {
return "", err
}
- ret += selectMap
- // Create the selects for target os specific values.
- selectMap, err = prettyPrintSelectMap(osSelects, "[]", indent)
- if err != nil {
- return "", err
- }
- ret += selectMap
-
+ ret, err = appendSelects(osSelects, "[]", ret)
return ret, err
}
@@ -113,7 +119,7 @@
}
// Create the map.
- ret := " + select({\n"
+ ret := "select({\n"
ret += selects
// default condition comes last.
ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), "//conditions:default", defaultValue)
diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go
index 7600e36..2054e06 100644
--- a/bp2build/python_binary_conversion_test.go
+++ b/bp2build/python_binary_conversion_test.go
@@ -33,24 +33,15 @@
blueprint: `python_binary_host {
name: "foo",
main: "a.py",
- srcs: [
- "**/*.py"
- ],
- exclude_srcs: [
- "b/e.py"
- ],
- data: [
- "files/data.txt",
- ],
-
+ srcs: ["**/*.py"],
+ exclude_srcs: ["b/e.py"],
+ data: ["files/data.txt",],
bazel_module: { bp2build_available: true },
}
`,
expectedBazelTargets: []string{`py_binary(
name = "foo",
- data = [
- "files/data.txt",
- ],
+ data = ["files/data.txt"],
main = "a.py",
srcs = [
"a.py",
@@ -83,9 +74,7 @@
expectedBazelTargets: []string{`py_binary(
name = "foo",
python_version = "PY2",
- srcs = [
- "a.py",
- ],
+ srcs = ["a.py"],
)`,
},
},
@@ -113,9 +102,7 @@
// python_version is PY3 by default.
`py_binary(
name = "foo",
- srcs = [
- "a.py",
- ],
+ srcs = ["a.py"],
)`,
},
},
diff --git a/bp2build/sh_conversion_test.go b/bp2build/sh_conversion_test.go
index 2aa373c..37f542e 100644
--- a/bp2build/sh_conversion_test.go
+++ b/bp2build/sh_conversion_test.go
@@ -74,9 +74,7 @@
}`,
expectedBazelTargets: []string{`sh_binary(
name = "foo",
- srcs = [
- "foo.sh",
- ],
+ srcs = ["foo.sh"],
)`},
},
}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 497d227..0bca30a 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -16,6 +16,7 @@
import (
"android/soong/android"
"android/soong/bazel"
+ "strings"
)
// bp2build functions and helpers for converting cc_* modules to Bazel.
@@ -58,74 +59,168 @@
ctx.AddDependency(module, nil, android.SortedUniqueStrings(allDeps)...)
}
-// bp2buildParseCflags creates a label list attribute containing the cflags of a module, including
-func bp2BuildParseCflags(ctx android.TopDownMutatorContext, module *Module) bazel.StringListAttribute {
- var ret bazel.StringListAttribute
+// Convenience struct to hold all attributes parsed from compiler properties.
+type compilerAttributes struct {
+ copts bazel.StringListAttribute
+ srcs bazel.LabelListAttribute
+ hdrs bazel.LabelListAttribute
+}
+
+// bp2BuildParseCompilerProps returns copts, srcs and hdrs and other attributes.
+func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Module) compilerAttributes {
+ var hdrs, srcs bazel.LabelListAttribute
+ var copts bazel.StringListAttribute
+
+ hdrsAndSrcs := func(baseCompilerProps *BaseCompilerProperties) (bazel.LabelList, bazel.LabelList) {
+ srcsList := android.BazelLabelForModuleSrcExcludes(
+ ctx, baseCompilerProps.Srcs, baseCompilerProps.Exclude_srcs)
+ hdrsList := android.BazelLabelForModuleSrc(ctx, srcsList.LooseHdrsGlobs(headerExts))
+ return hdrsList, srcsList
+ }
+
for _, props := range module.compiler.compilerProps() {
if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
- ret.Value = baseCompilerProps.Cflags
+ hdrs.Value, srcs.Value = hdrsAndSrcs(baseCompilerProps)
+ copts.Value = baseCompilerProps.Cflags
break
}
}
for arch, props := range module.GetArchProperties(&BaseCompilerProperties{}) {
if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
- ret.SetValueForArch(arch.Name, baseCompilerProps.Cflags)
+ hdrsList, srcsList := hdrsAndSrcs(baseCompilerProps)
+ hdrs.SetValueForArch(arch.Name, bazel.SubtractBazelLabelList(hdrsList, hdrs.Value))
+ srcs.SetValueForArch(arch.Name, srcsList)
+ copts.SetValueForArch(arch.Name, baseCompilerProps.Cflags)
}
}
for os, props := range module.GetTargetProperties(&BaseCompilerProperties{}) {
if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
- ret.SetValueForOS(os.Name, baseCompilerProps.Cflags)
+ hdrsList, srcsList := hdrsAndSrcs(baseCompilerProps)
+ hdrs.SetValueForOS(os.Name, bazel.SubtractBazelLabelList(hdrsList, hdrs.Value))
+ srcs.SetValueForOS(os.Name, srcsList)
+ copts.SetValueForOS(os.Name, baseCompilerProps.Cflags)
}
}
- return ret
+ return compilerAttributes{
+ hdrs: hdrs,
+ srcs: srcs,
+ copts: copts,
+ }
}
-// bp2BuildParseHeaderLibs creates a label list attribute containing the header library deps of a module, including
+// Convenience struct to hold all attributes parsed from linker properties.
+type linkerAttributes struct {
+ deps bazel.LabelListAttribute
+ linkopts bazel.StringListAttribute
+}
+
+// bp2BuildParseLinkerProps creates a label list attribute containing the header library deps of a module, including
// configurable attribute values.
-func bp2BuildParseHeaderLibs(ctx android.TopDownMutatorContext, module *Module) bazel.LabelListAttribute {
- var ret bazel.LabelListAttribute
+func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module) linkerAttributes {
+
+ var deps bazel.LabelListAttribute
+ var linkopts bazel.StringListAttribute
+
for _, linkerProps := range module.linker.linkerProps() {
if baseLinkerProps, ok := linkerProps.(*BaseLinkerProperties); ok {
libs := baseLinkerProps.Header_libs
libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
- ret = bazel.MakeLabelListAttribute(
+ deps = bazel.MakeLabelListAttribute(
android.BazelLabelForModuleDeps(ctx, android.SortedUniqueStrings(libs)))
+ linkopts.Value = baseLinkerProps.Ldflags
break
}
}
+ for arch, p := range module.GetArchProperties(&BaseLinkerProperties{}) {
+ if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok {
+ libs := baseLinkerProps.Header_libs
+ libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
+ libs = android.SortedUniqueStrings(libs)
+ deps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, libs))
+ linkopts.SetValueForArch(arch.Name, baseLinkerProps.Ldflags)
+ }
+ }
+
for os, p := range module.GetTargetProperties(&BaseLinkerProperties{}) {
if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok {
libs := baseLinkerProps.Header_libs
libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
libs = android.SortedUniqueStrings(libs)
- ret.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, libs))
+ deps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, libs))
+ linkopts.SetValueForOS(os.Name, baseLinkerProps.Ldflags)
}
}
- return ret
+ return linkerAttributes{
+ deps: deps,
+ linkopts: linkopts,
+ }
+}
+
+func bp2BuildListHeadersInDir(ctx android.TopDownMutatorContext, includeDir string) bazel.LabelList {
+ globs := bazel.GlobsInDir(includeDir, includeDir != ".", headerExts)
+ return android.BazelLabelForModuleSrc(ctx, globs)
+}
+
+// Bazel wants include paths to be relative to the module
+func bp2BuildMakePathsRelativeToModule(ctx android.TopDownMutatorContext, paths []string) []string {
+ var relativePaths []string
+ for _, path := range paths {
+ relativePath := strings.TrimPrefix(path, ctx.ModuleDir()+"/")
+ relativePaths = append(relativePaths, relativePath)
+ }
+ return relativePaths
}
// bp2BuildParseExportedIncludes creates a label list attribute contains the
// exported included directories of a module.
-func bp2BuildParseExportedIncludes(ctx android.TopDownMutatorContext, module *Module) (bazel.LabelListAttribute, bazel.LabelListAttribute) {
+func bp2BuildParseExportedIncludes(ctx android.TopDownMutatorContext, module *Module) (bazel.StringListAttribute, bazel.LabelListAttribute) {
libraryDecorator := module.linker.(*libraryDecorator)
includeDirs := libraryDecorator.flagExporter.Properties.Export_system_include_dirs
includeDirs = append(includeDirs, libraryDecorator.flagExporter.Properties.Export_include_dirs...)
+ includeDirs = bp2BuildMakePathsRelativeToModule(ctx, includeDirs)
+ includeDirsAttribute := bazel.MakeStringListAttribute(includeDirs)
- includeDirsLabels := android.BazelLabelForModuleSrc(ctx, includeDirs)
-
- var includeDirGlobs []string
+ var headersAttribute bazel.LabelListAttribute
+ var headers bazel.LabelList
for _, includeDir := range includeDirs {
- includeDirGlobs = append(includeDirGlobs, includeDir+"/**/*.h")
- includeDirGlobs = append(includeDirGlobs, includeDir+"/**/*.inc")
- includeDirGlobs = append(includeDirGlobs, includeDir+"/**/*.hpp")
+ headers.Append(bp2BuildListHeadersInDir(ctx, includeDir))
+ }
+ headers = bazel.UniqueBazelLabelList(headers)
+ headersAttribute.Value = headers
+
+ for arch, props := range module.GetArchProperties(&FlagExporterProperties{}) {
+ if flagExporterProperties, ok := props.(*FlagExporterProperties); ok {
+ archIncludeDirs := flagExporterProperties.Export_system_include_dirs
+ archIncludeDirs = append(archIncludeDirs, flagExporterProperties.Export_include_dirs...)
+ archIncludeDirs = bp2BuildMakePathsRelativeToModule(ctx, archIncludeDirs)
+
+ // To avoid duplicate includes when base includes + arch includes are combined
+ archIncludeDirs = bazel.SubtractStrings(archIncludeDirs, includeDirs)
+
+ if len(archIncludeDirs) > 0 {
+ includeDirsAttribute.SetValueForArch(arch.Name, archIncludeDirs)
+ }
+
+ var archHeaders bazel.LabelList
+ for _, archIncludeDir := range archIncludeDirs {
+ archHeaders.Append(bp2BuildListHeadersInDir(ctx, archIncludeDir))
+ }
+ archHeaders = bazel.UniqueBazelLabelList(archHeaders)
+
+ // To avoid duplicate headers when base headers + arch headers are combined
+ archHeaders = bazel.SubtractBazelLabelList(archHeaders, headers)
+
+ if len(archHeaders.Includes) > 0 || len(archHeaders.Excludes) > 0 {
+ headersAttribute.SetValueForArch(arch.Name, archHeaders)
+ }
+ }
}
- headersLabels := android.BazelLabelForModuleSrc(ctx, includeDirGlobs)
- return bazel.MakeLabelListAttribute(includeDirsLabels), bazel.MakeLabelListAttribute(headersLabels)
+ return includeDirsAttribute, headersAttribute
}
diff --git a/cc/builder.go b/cc/builder.go
index 8c9743f..da8501c 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -132,7 +132,7 @@
blueprint.RuleParams{
Depfile: "${out}.d",
Deps: blueprint.DepsGCC,
- Command: "CROSS_COMPILE=$crossCompile XZ=$xzCmd CLANG_BIN=${config.ClangBin} $stripPath ${args} -i ${in} -o ${out} -d ${out}.d",
+ Command: "XZ=$xzCmd CLANG_BIN=${config.ClangBin} $stripPath ${args} -i ${in} -o ${out} -d ${out}.d",
CommandDeps: []string{"$stripPath", "$xzCmd"},
Pool: darwinStripPool,
},
diff --git a/cc/cc.go b/cc/cc.go
index 1ce83a9..9176bc3 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -56,8 +56,8 @@
ctx.TopDown("asan_deps", sanitizerDepsMutator(Asan))
ctx.BottomUp("asan", sanitizerMutator(Asan)).Parallel()
- ctx.TopDown("hwasan_deps", sanitizerDepsMutator(hwasan))
- ctx.BottomUp("hwasan", sanitizerMutator(hwasan)).Parallel()
+ ctx.TopDown("hwasan_deps", sanitizerDepsMutator(Hwasan))
+ ctx.BottomUp("hwasan", sanitizerMutator(Hwasan)).Parallel()
ctx.TopDown("fuzzer_deps", sanitizerDepsMutator(Fuzzer))
ctx.BottomUp("fuzzer", sanitizerMutator(Fuzzer)).Parallel()
diff --git a/cc/library.go b/cc/library.go
index 11b6737..738b45f 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -206,6 +206,7 @@
RegisterLibraryBuildComponents(android.InitRegistrationContext)
android.RegisterBp2BuildMutator("cc_library_static", CcLibraryStaticBp2Build)
+ android.RegisterBp2BuildMutator("cc_library", CcLibraryBp2Build)
}
func RegisterLibraryBuildComponents(ctx android.RegistrationContext) {
@@ -216,6 +217,67 @@
ctx.RegisterModuleType("cc_library_host_shared", LibraryHostSharedFactory)
}
+// For bp2build conversion.
+type bazelCcLibraryAttributes struct {
+ Srcs bazel.LabelListAttribute
+ Hdrs bazel.LabelListAttribute
+ Copts bazel.StringListAttribute
+ Linkopts bazel.StringListAttribute
+ Deps bazel.LabelListAttribute
+ User_link_flags bazel.StringListAttribute
+ Includes bazel.StringListAttribute
+}
+
+type bazelCcLibrary struct {
+ android.BazelTargetModuleBase
+ bazelCcLibraryAttributes
+}
+
+func (m *bazelCcLibrary) Name() string {
+ return m.BaseModuleName()
+}
+
+func (m *bazelCcLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {}
+
+func BazelCcLibraryFactory() android.Module {
+ module := &bazelCcLibrary{}
+ module.AddProperties(&module.bazelCcLibraryAttributes)
+ android.InitBazelTargetModule(module)
+ return module
+}
+
+func CcLibraryBp2Build(ctx android.TopDownMutatorContext) {
+ m, ok := ctx.Module().(*Module)
+ if !ok || !m.ConvertWithBp2build(ctx) {
+ return
+ }
+
+ if ctx.ModuleType() != "cc_library" {
+ return
+ }
+
+ compilerAttrs := bp2BuildParseCompilerProps(ctx, m)
+ linkerAttrs := bp2BuildParseLinkerProps(ctx, m)
+ exportedIncludes, exportedIncludesHeaders := bp2BuildParseExportedIncludes(ctx, m)
+ compilerAttrs.hdrs.Append(exportedIncludesHeaders)
+
+ attrs := &bazelCcLibraryAttributes{
+ Srcs: compilerAttrs.srcs,
+ Hdrs: compilerAttrs.hdrs,
+ Copts: compilerAttrs.copts,
+ Linkopts: linkerAttrs.linkopts,
+ Deps: linkerAttrs.deps,
+ Includes: exportedIncludes,
+ }
+
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "cc_library",
+ Bzl_load_location: "//build/bazel/rules:full_cc_library.bzl",
+ }
+
+ ctx.CreateBazelTargetModule(BazelCcLibraryFactory, m.Name(), props, attrs)
+}
+
// cc_library creates both static and/or shared libraries for a device and/or
// host. By default, a cc_library has a single variant that targets the device.
// Specifying `host_supported: true` also creates a library that targets the
@@ -2058,11 +2120,12 @@
}
type bazelCcLibraryStaticAttributes struct {
- Copts []string
+ Copts bazel.StringListAttribute
Srcs bazel.LabelListAttribute
Deps bazel.LabelListAttribute
+ Linkopts bazel.StringListAttribute
Linkstatic bool
- Includes bazel.LabelListAttribute
+ Includes bazel.StringListAttribute
Hdrs bazel.LabelListAttribute
}
@@ -2091,24 +2154,37 @@
return
}
- var copts []string
- var srcs []string
+ compilerAttrs := bp2BuildParseCompilerProps(ctx, module)
+
var includeDirs []string
var localIncludeDirs []string
for _, props := range module.compiler.compilerProps() {
if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
- copts = baseCompilerProps.Cflags
- srcs = baseCompilerProps.Srcs
- includeDirs = baseCompilerProps.Include_dirs
- localIncludeDirs = baseCompilerProps.Local_include_dirs
+ // TODO: these should be arch and os specific.
+ includeDirs = bp2BuildMakePathsRelativeToModule(ctx, baseCompilerProps.Include_dirs)
+ localIncludeDirs = bp2BuildMakePathsRelativeToModule(ctx, baseCompilerProps.Local_include_dirs)
break
}
}
- srcsLabels := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, srcs))
+
+ // Soong implicitly includes headers from the module's directory.
+ // For Bazel builds to work we have to make these header includes explicit.
+ if module.compiler.(*libraryDecorator).includeBuildDirectory() {
+ localIncludeDirs = append(localIncludeDirs, ".")
+ }
+
+ // For Bazel, be more explicit about headers - list all header files in include dirs as srcs
+ for _, includeDir := range includeDirs {
+ compilerAttrs.srcs.Value.Append(bp2BuildListHeadersInDir(ctx, includeDir))
+ }
+ for _, localIncludeDir := range localIncludeDirs {
+ compilerAttrs.srcs.Value.Append(bp2BuildListHeadersInDir(ctx, localIncludeDir))
+ }
var staticLibs []string
var wholeStaticLibs []string
for _, props := range module.linker.linkerProps() {
+ // TODO: move this into bp2buildParseLinkerProps
if baseLinkerProperties, ok := props.(*BaseLinkerProperties); ok {
staticLibs = baseLinkerProperties.Static_libs
wholeStaticLibs = baseLinkerProperties.Whole_static_libs
@@ -2122,25 +2198,26 @@
depsLabels := android.BazelLabelForModuleDeps(ctx, allDeps)
+ exportedIncludes, exportedIncludesHeaders := bp2BuildParseExportedIncludes(ctx, module)
+
// FIXME: Unify absolute vs relative paths
// FIXME: Use -I copts instead of setting includes= ?
- allIncludes := includeDirs
- allIncludes = append(allIncludes, localIncludeDirs...)
- includesLabels := android.BazelLabelForModuleSrc(ctx, allIncludes)
+ allIncludes := exportedIncludes
+ allIncludes.Value = append(allIncludes.Value, includeDirs...)
+ allIncludes.Value = append(allIncludes.Value, localIncludeDirs...)
- exportedIncludesLabels, exportedIncludesHeadersLabels := bp2BuildParseExportedIncludes(ctx, module)
- includesLabels.Append(exportedIncludesLabels.Value)
+ compilerAttrs.hdrs.Append(exportedIncludesHeaders)
- headerLibsLabels := bp2BuildParseHeaderLibs(ctx, module)
- depsLabels.Append(headerLibsLabels.Value)
+ linkerAttrs := bp2BuildParseLinkerProps(ctx, module)
+ depsLabels.Append(linkerAttrs.deps.Value)
attrs := &bazelCcLibraryStaticAttributes{
- Copts: copts,
- Srcs: srcsLabels,
+ Copts: compilerAttrs.copts,
+ Srcs: compilerAttrs.srcs,
Deps: bazel.MakeLabelListAttribute(depsLabels),
Linkstatic: true,
- Includes: bazel.MakeLabelListAttribute(includesLabels),
- Hdrs: exportedIncludesHeadersLabels,
+ Includes: allIncludes,
+ Hdrs: compilerAttrs.hdrs,
}
props := bazel.BazelTargetModuleProperties{
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 82af16a..076ce80 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -64,7 +64,7 @@
type bazelCcLibraryHeadersAttributes struct {
Copts bazel.StringListAttribute
Hdrs bazel.LabelListAttribute
- Includes bazel.LabelListAttribute
+ Includes bazel.StringListAttribute
Deps bazel.LabelListAttribute
}
@@ -95,15 +95,15 @@
return
}
- exportedIncludesLabels, exportedIncludesHeadersLabels := bp2BuildParseExportedIncludes(ctx, module)
-
- headerLibsLabels := bp2BuildParseHeaderLibs(ctx, module)
+ exportedIncludes, exportedIncludesHeaders := bp2BuildParseExportedIncludes(ctx, module)
+ compilerAttrs := bp2BuildParseCompilerProps(ctx, module)
+ linkerAttrs := bp2BuildParseLinkerProps(ctx, module)
attrs := &bazelCcLibraryHeadersAttributes{
- Copts: bp2BuildParseCflags(ctx, module),
- Includes: exportedIncludesLabels,
- Hdrs: exportedIncludesHeadersLabels,
- Deps: headerLibsLabels,
+ Copts: compilerAttrs.copts,
+ Includes: exportedIncludes,
+ Hdrs: exportedIncludesHeaders,
+ Deps: linkerAttrs.deps,
}
props := bazel.BazelTargetModuleProperties{
diff --git a/cc/object.go b/cc/object.go
index 4f8797d..9bb279a 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -113,6 +113,7 @@
// For bp2build conversion.
type bazelObjectAttributes struct {
Srcs bazel.LabelListAttribute
+ Hdrs bazel.LabelListAttribute
Deps bazel.LabelListAttribute
Copts bazel.StringListAttribute
Asflags []string
@@ -156,16 +157,11 @@
}
// Set arch-specific configurable attributes
- var srcs bazel.LabelListAttribute
+ compilerAttrs := bp2BuildParseCompilerProps(ctx, m)
var localIncludeDirs []string
var asFlags []string
for _, props := range m.compiler.compilerProps() {
if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
- srcs = bazel.MakeLabelListAttribute(
- android.BazelLabelForModuleSrcExcludes(
- ctx,
- baseCompilerProps.Srcs,
- baseCompilerProps.Exclude_srcs))
localIncludeDirs = baseCompilerProps.Local_include_dirs
break
}
@@ -200,16 +196,11 @@
}
// TODO(b/183595872) warn/error if we're not handling product variables
- for arch, p := range m.GetArchProperties(&BaseCompilerProperties{}) {
- if cProps, ok := p.(*BaseCompilerProperties); ok {
- srcs.SetValueForArch(arch.Name, android.BazelLabelForModuleSrcExcludes(ctx, cProps.Srcs, cProps.Exclude_srcs))
- }
- }
-
attrs := &bazelObjectAttributes{
- Srcs: srcs,
+ Srcs: compilerAttrs.srcs,
+ Hdrs: compilerAttrs.hdrs,
Deps: deps,
- Copts: bp2BuildParseCflags(ctx, m),
+ Copts: compilerAttrs.copts,
Asflags: asFlags,
Local_include_dirs: localIncludeDirs,
}
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 6b9a3d5..3829b1e 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -305,6 +305,7 @@
func NewPrebuiltStaticLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
module, library := NewPrebuiltLibrary(hod)
library.BuildOnlyStatic()
+ module.bazelHandler = &prebuiltStaticLibraryBazelHandler{module: module, library: library}
return module, library
}
@@ -319,6 +320,52 @@
properties prebuiltObjectProperties
}
+type prebuiltStaticLibraryBazelHandler struct {
+ bazelHandler
+
+ module *Module
+ library *libraryDecorator
+}
+
+func (h *prebuiltStaticLibraryBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
+ bazelCtx := ctx.Config().BazelContext
+ staticLibs, ok := bazelCtx.GetPrebuiltCcStaticLibraryFiles(label, ctx.Arch().ArchType)
+ if !ok {
+ return false
+ }
+ if len(staticLibs) > 1 {
+ ctx.ModuleErrorf("expected 1 static library from bazel target %q, got %s", label, staticLibs)
+ return false
+ }
+
+ // TODO(b/184543518): cc_prebuilt_library_static may have properties for re-exporting flags
+
+ // TODO(eakammer):Add stub-related flags if this library is a stub library.
+ // h.library.exportVersioningMacroIfNeeded(ctx)
+
+ // Dependencies on this library will expect collectedSnapshotHeaders to be set, otherwise
+ // validation will fail. For now, set this to an empty list.
+ // TODO(cparsons): More closely mirror the collectHeadersForSnapshot implementation.
+ h.library.collectedSnapshotHeaders = android.Paths{}
+
+ if len(staticLibs) == 0 {
+ h.module.outputFile = android.OptionalPath{}
+ return true
+ }
+
+ out := android.PathForBazelOut(ctx, staticLibs[0])
+ h.module.outputFile = android.OptionalPathForPath(out)
+
+ depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(out).Build()
+ ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+ StaticLibrary: out,
+
+ TransitiveStaticLibrariesForOrdering: depSet,
+ })
+
+ return true
+}
+
func (p *prebuiltObjectLinker) prebuilt() *android.Prebuilt {
return &p.Prebuilt
}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index e1ac9f0..397121e 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -83,7 +83,7 @@
const (
Asan SanitizerType = iota + 1
- hwasan
+ Hwasan
tsan
intOverflow
cfi
@@ -97,7 +97,7 @@
switch t {
case Asan:
return "asan"
- case hwasan:
+ case Hwasan:
return "hwasan"
case tsan:
return "tsan"
@@ -121,7 +121,7 @@
switch t {
case Asan:
return "address"
- case hwasan:
+ case Hwasan:
return "hwaddress"
case memtag_heap:
return "memtag_heap"
@@ -144,7 +144,7 @@
switch t {
case Asan:
return true
- case hwasan:
+ case Hwasan:
return true
case tsan:
return true
@@ -163,7 +163,7 @@
// incompatibleWithCfi returns true if a sanitizer is incompatible with CFI.
func (t SanitizerType) incompatibleWithCfi() bool {
- return t == Asan || t == Fuzzer || t == hwasan
+ return t == Asan || t == Fuzzer || t == Hwasan
}
type SanitizeUserProps struct {
@@ -745,7 +745,7 @@
switch t {
case Asan:
return sanitize.Properties.Sanitize.Address
- case hwasan:
+ case Hwasan:
return sanitize.Properties.Sanitize.Hwaddress
case tsan:
return sanitize.Properties.Sanitize.Thread
@@ -767,7 +767,7 @@
// isUnsanitizedVariant returns true if no sanitizers are enabled.
func (sanitize *sanitize) isUnsanitizedVariant() bool {
return !sanitize.isSanitizerEnabled(Asan) &&
- !sanitize.isSanitizerEnabled(hwasan) &&
+ !sanitize.isSanitizerEnabled(Hwasan) &&
!sanitize.isSanitizerEnabled(tsan) &&
!sanitize.isSanitizerEnabled(cfi) &&
!sanitize.isSanitizerEnabled(scs) &&
@@ -778,7 +778,7 @@
// isVariantOnProductionDevice returns true if variant is for production devices (no non-production sanitizers enabled).
func (sanitize *sanitize) isVariantOnProductionDevice() bool {
return !sanitize.isSanitizerEnabled(Asan) &&
- !sanitize.isSanitizerEnabled(hwasan) &&
+ !sanitize.isSanitizerEnabled(Hwasan) &&
!sanitize.isSanitizerEnabled(tsan) &&
!sanitize.isSanitizerEnabled(Fuzzer)
}
@@ -787,7 +787,7 @@
switch t {
case Asan:
sanitize.Properties.Sanitize.Address = boolPtr(b)
- case hwasan:
+ case Hwasan:
sanitize.Properties.Sanitize.Hwaddress = boolPtr(b)
case tsan:
sanitize.Properties.Sanitize.Thread = boolPtr(b)
@@ -902,7 +902,7 @@
if d, ok := child.(PlatformSanitizeable); ok && d.SanitizePropDefined() &&
!d.SanitizeNever() &&
!d.IsSanitizerExplicitlyDisabled(t) {
- if t == cfi || t == hwasan || t == scs {
+ if t == cfi || t == Hwasan || t == scs {
if d.StaticallyLinked() && d.SanitizerSupported(t) {
// Rust does not support some of these sanitizers, so we need to check if it's
// supported before setting this true.
@@ -1080,6 +1080,12 @@
if Bool(c.sanitize.Properties.Sanitize.Diag.Memtag_heap) {
noteDep = "note_memtag_heap_sync"
}
+ // If we're using snapshots, redirect to snapshot whenever possible
+ // TODO(b/178470649): clean manual snapshot redirections
+ snapshot := mctx.Provider(SnapshotInfoProvider).(SnapshotInfo)
+ if lib, ok := snapshot.StaticLibs[noteDep]; ok {
+ noteDep = lib
+ }
depTag := libraryDependencyTag{Kind: staticLibraryDependency, wholeStatic: true}
variations := append(mctx.Target().Variations(),
blueprint.Variation{Mutator: "link", Variation: "static"})
@@ -1280,7 +1286,7 @@
// For cfi/scs/hwasan, we can export both sanitized and un-sanitized variants
// to Make, because the sanitized version has a different suffix in name.
// For other types of sanitizers, suppress the variation that is disabled.
- if t != cfi && t != scs && t != hwasan {
+ if t != cfi && t != scs && t != Hwasan {
if isSanitizerEnabled {
modules[0].(PlatformSanitizeable).SetPreventInstall()
modules[0].(PlatformSanitizeable).SetHideFromMake()
@@ -1294,7 +1300,7 @@
if c.StaticallyLinked() && c.ExportedToMake() {
if t == cfi {
cfiStaticLibs(mctx.Config()).add(c, c.Module().Name())
- } else if t == hwasan {
+ } else if t == Hwasan {
hwasanStaticLibs(mctx.Config()).add(c, c.Module().Name())
}
}
@@ -1411,7 +1417,7 @@
func hwasanStaticLibs(config android.Config) *sanitizerStaticLibsMap {
return config.Once(hwasanStaticLibsKey, func() interface{} {
- return newSanitizerStaticLibsMap(hwasan)
+ return newSanitizerStaticLibsMap(Hwasan)
}).(*sanitizerStaticLibsMap)
}
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index bbb8896..af05102 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -337,7 +337,8 @@
for _, name := range names {
snapshotMap[name] = name +
getSnapshotNameSuffix(snapshotSuffix+moduleSuffix,
- s.baseSnapshot.version(), ctx.Arch().ArchType.Name)
+ s.baseSnapshot.version(),
+ ctx.DeviceConfig().Arches()[0].ArchType.String())
}
return snapshotMap
}
@@ -396,7 +397,7 @@
Target_arch string
// Suffix to be added to the module name when exporting to Android.mk, e.g. ".vendor".
- Androidmk_suffix string
+ Androidmk_suffix string `blueprint:"mutated"`
// Suffix to be added to the module name, e.g., vendor_shared,
// recovery_shared, etc.
@@ -417,6 +418,7 @@
// will be seen as "libbase.vendor_static.30.arm64" by Soong.
type baseSnapshotDecorator struct {
baseProperties baseSnapshotDecoratorProperties
+ image snapshotImage
}
func (p *baseSnapshotDecorator) Name(name string) string {
@@ -447,10 +449,21 @@
return p.baseProperties.Androidmk_suffix
}
+func (p *baseSnapshotDecorator) setSnapshotAndroidMkSuffix(ctx android.ModuleContext) {
+ if ctx.OtherModuleDependencyVariantExists([]blueprint.Variation{
+ {Mutator: "image", Variation: android.CoreVariation},
+ }, ctx.Module().(*Module).BaseModuleName()) {
+ p.baseProperties.Androidmk_suffix = p.image.moduleNameSuffix()
+ } else {
+ p.baseProperties.Androidmk_suffix = ""
+ }
+}
+
// Call this with a module suffix after creating a snapshot module, such as
// vendorSnapshotSharedSuffix, recoverySnapshotBinarySuffix, etc.
-func (p *baseSnapshotDecorator) init(m *Module, snapshotSuffix, moduleSuffix string) {
- p.baseProperties.ModuleSuffix = snapshotSuffix + moduleSuffix
+func (p *baseSnapshotDecorator) init(m *Module, image snapshotImage, moduleSuffix string) {
+ p.image = image
+ p.baseProperties.ModuleSuffix = image.moduleNameSuffix() + moduleSuffix
m.AddProperties(&p.baseProperties)
android.AddLoadHook(m, func(ctx android.LoadHookContext) {
vendorSnapshotLoadHook(ctx, p)
@@ -532,6 +545,8 @@
// As snapshots are prebuilts, this just returns the prebuilt binary after doing things which are
// done by normal library decorator, e.g. exporting flags.
func (p *snapshotLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path {
+ p.setSnapshotAndroidMkSuffix(ctx)
+
if p.header() {
return p.libraryDecorator.link(ctx, flags, deps, objs)
}
@@ -614,7 +629,7 @@
}
}
-func snapshotLibraryFactory(snapshotSuffix, moduleSuffix string) (*Module, *snapshotLibraryDecorator) {
+func snapshotLibraryFactory(image snapshotImage, moduleSuffix string) (*Module, *snapshotLibraryDecorator) {
module, library := NewLibrary(android.DeviceSupported)
module.stl = nil
@@ -637,7 +652,7 @@
module.linker = prebuilt
module.installer = prebuilt
- prebuilt.init(module, snapshotSuffix, moduleSuffix)
+ prebuilt.init(module, image, moduleSuffix)
module.AddProperties(
&prebuilt.properties,
&prebuilt.sanitizerProperties,
@@ -651,7 +666,7 @@
// overrides the vendor variant of the cc shared library with the same name, if BOARD_VNDK_VERSION
// is set.
func VendorSnapshotSharedFactory() android.Module {
- module, prebuilt := snapshotLibraryFactory(vendorSnapshotImageSingleton.moduleNameSuffix(), snapshotSharedSuffix)
+ module, prebuilt := snapshotLibraryFactory(vendorSnapshotImageSingleton, snapshotSharedSuffix)
prebuilt.libraryDecorator.BuildOnlyShared()
return module.Init()
}
@@ -661,7 +676,7 @@
// overrides the recovery variant of the cc shared library with the same name, if BOARD_VNDK_VERSION
// is set.
func RecoverySnapshotSharedFactory() android.Module {
- module, prebuilt := snapshotLibraryFactory(recoverySnapshotImageSingleton.moduleNameSuffix(), snapshotSharedSuffix)
+ module, prebuilt := snapshotLibraryFactory(recoverySnapshotImageSingleton, snapshotSharedSuffix)
prebuilt.libraryDecorator.BuildOnlyShared()
return module.Init()
}
@@ -671,7 +686,7 @@
// overrides the vendor variant of the cc static library with the same name, if BOARD_VNDK_VERSION
// is set.
func VendorSnapshotStaticFactory() android.Module {
- module, prebuilt := snapshotLibraryFactory(vendorSnapshotImageSingleton.moduleNameSuffix(), snapshotStaticSuffix)
+ module, prebuilt := snapshotLibraryFactory(vendorSnapshotImageSingleton, snapshotStaticSuffix)
prebuilt.libraryDecorator.BuildOnlyStatic()
return module.Init()
}
@@ -681,7 +696,7 @@
// overrides the recovery variant of the cc static library with the same name, if BOARD_VNDK_VERSION
// is set.
func RecoverySnapshotStaticFactory() android.Module {
- module, prebuilt := snapshotLibraryFactory(recoverySnapshotImageSingleton.moduleNameSuffix(), snapshotStaticSuffix)
+ module, prebuilt := snapshotLibraryFactory(recoverySnapshotImageSingleton, snapshotStaticSuffix)
prebuilt.libraryDecorator.BuildOnlyStatic()
return module.Init()
}
@@ -691,7 +706,7 @@
// overrides the vendor variant of the cc header library with the same name, if BOARD_VNDK_VERSION
// is set.
func VendorSnapshotHeaderFactory() android.Module {
- module, prebuilt := snapshotLibraryFactory(vendorSnapshotImageSingleton.moduleNameSuffix(), snapshotHeaderSuffix)
+ module, prebuilt := snapshotLibraryFactory(vendorSnapshotImageSingleton, snapshotHeaderSuffix)
prebuilt.libraryDecorator.HeaderOnly()
return module.Init()
}
@@ -701,7 +716,7 @@
// overrides the recovery variant of the cc header library with the same name, if BOARD_VNDK_VERSION
// is set.
func RecoverySnapshotHeaderFactory() android.Module {
- module, prebuilt := snapshotLibraryFactory(recoverySnapshotImageSingleton.moduleNameSuffix(), snapshotHeaderSuffix)
+ module, prebuilt := snapshotLibraryFactory(recoverySnapshotImageSingleton, snapshotHeaderSuffix)
prebuilt.libraryDecorator.HeaderOnly()
return module.Init()
}
@@ -739,6 +754,8 @@
// cc modules' link functions are to link compiled objects into final binaries.
// As snapshots are prebuilts, this just returns the prebuilt binary
func (p *snapshotBinaryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path {
+ p.setSnapshotAndroidMkSuffix(ctx)
+
if !p.matchesWithDevice(ctx.DeviceConfig()) {
return nil
}
@@ -767,17 +784,17 @@
// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_binary
// overrides the vendor variant of the cc binary with the same name, if BOARD_VNDK_VERSION is set.
func VendorSnapshotBinaryFactory() android.Module {
- return snapshotBinaryFactory(vendorSnapshotImageSingleton.moduleNameSuffix(), snapshotBinarySuffix)
+ return snapshotBinaryFactory(vendorSnapshotImageSingleton, snapshotBinarySuffix)
}
// recovery_snapshot_binary is a special prebuilt executable binary which is auto-generated by
// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_binary
// overrides the recovery variant of the cc binary with the same name, if BOARD_VNDK_VERSION is set.
func RecoverySnapshotBinaryFactory() android.Module {
- return snapshotBinaryFactory(recoverySnapshotImageSingleton.moduleNameSuffix(), snapshotBinarySuffix)
+ return snapshotBinaryFactory(recoverySnapshotImageSingleton, snapshotBinarySuffix)
}
-func snapshotBinaryFactory(snapshotSuffix, moduleSuffix string) android.Module {
+func snapshotBinaryFactory(image snapshotImage, moduleSuffix string) android.Module {
module, binary := NewBinary(android.DeviceSupported)
binary.baseLinker.Properties.No_libcrt = BoolPtr(true)
binary.baseLinker.Properties.Nocrt = BoolPtr(true)
@@ -796,7 +813,7 @@
module.stl = nil
module.linker = prebuilt
- prebuilt.init(module, snapshotSuffix, moduleSuffix)
+ prebuilt.init(module, image, moduleSuffix)
module.AddProperties(&prebuilt.properties)
return module.Init()
}
@@ -832,6 +849,8 @@
// cc modules' link functions are to link compiled objects into final binaries.
// As snapshots are prebuilts, this just returns the prebuilt binary
func (p *snapshotObjectLinker) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path {
+ p.setSnapshotAndroidMkSuffix(ctx)
+
if !p.matchesWithDevice(ctx.DeviceConfig()) {
return nil
}
@@ -856,7 +875,7 @@
}
module.linker = prebuilt
- prebuilt.init(module, vendorSnapshotImageSingleton.moduleNameSuffix(), snapshotObjectSuffix)
+ prebuilt.init(module, vendorSnapshotImageSingleton, snapshotObjectSuffix)
module.AddProperties(&prebuilt.properties)
return module.Init()
}
@@ -874,7 +893,7 @@
}
module.linker = prebuilt
- prebuilt.init(module, recoverySnapshotImageSingleton.moduleNameSuffix(), snapshotObjectSuffix)
+ prebuilt.init(module, recoverySnapshotImageSingleton, snapshotObjectSuffix)
module.AddProperties(&prebuilt.properties)
return module.Init()
}
diff --git a/cc/stl.go b/cc/stl.go
index 594231d..4f8865f 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -140,6 +140,17 @@
}
func staticUnwinder(ctx android.BaseModuleContext) string {
+ vndkVersion := ctx.Module().(*Module).VndkVersion()
+
+ // Modules using R vndk use different unwinder
+ if vndkVersion == "30" {
+ if ctx.Arch().ArchType == android.Arm {
+ return "libunwind_llvm"
+ } else {
+ return "libgcc_stripped"
+ }
+ }
+
return "libunwind"
}
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 4014fe0..3437d77 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -196,7 +196,7 @@
if m.sanitize != nil {
// scs and hwasan export both sanitized and unsanitized variants for static and header
// Always use unsanitized variants of them.
- for _, t := range []SanitizerType{scs, hwasan} {
+ for _, t := range []SanitizerType{scs, Hwasan} {
if !l.shared() && m.sanitize.isSanitizerEnabled(t) {
return false
}
@@ -238,7 +238,6 @@
type snapshotJsonFlags struct {
ModuleName string `json:",omitempty"`
RelativeInstallPath string `json:",omitempty"`
- AndroidMkSuffix string `json:",omitempty"`
// library flags
ExportedDirs []string `json:",omitempty"`
@@ -352,7 +351,6 @@
} else {
prop.RelativeInstallPath = m.RelativeInstallPath()
}
- prop.AndroidMkSuffix = m.Properties.SubName
prop.RuntimeLibs = m.Properties.SnapshotRuntimeLibs
prop.Required = m.RequiredModuleNames()
for _, path := range m.InitRc() {
diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go
index 20cd031..1c3f1b4 100644
--- a/cc/vendor_snapshot_test.go
+++ b/cc/vendor_snapshot_test.go
@@ -271,7 +271,6 @@
enabled: true,
},
nocrt: true,
- compile_multilib: "64",
}
cc_library {
@@ -281,7 +280,6 @@
no_libcrt: true,
stl: "none",
system_shared_libs: [],
- compile_multilib: "64",
}
cc_library {
@@ -291,6 +289,25 @@
no_libcrt: true,
stl: "none",
system_shared_libs: [],
+ }
+
+ cc_library {
+ name: "lib32",
+ vendor: true,
+ nocrt: true,
+ no_libcrt: true,
+ stl: "none",
+ system_shared_libs: [],
+ compile_multilib: "32",
+ }
+
+ cc_library {
+ name: "lib64",
+ vendor: true,
+ nocrt: true,
+ no_libcrt: true,
+ stl: "none",
+ system_shared_libs: [],
compile_multilib: "64",
}
@@ -301,14 +318,23 @@
no_libcrt: true,
stl: "none",
system_shared_libs: [],
- compile_multilib: "64",
+ }
+
+ cc_binary {
+ name: "bin32",
+ vendor: true,
+ nocrt: true,
+ no_libcrt: true,
+ stl: "none",
+ system_shared_libs: [],
+ compile_multilib: "32",
}
`
vndkBp := `
vndk_prebuilt_shared {
name: "libvndk",
- version: "28",
+ version: "30",
target_arch: "arm64",
vendor_available: true,
product_available: true,
@@ -320,6 +346,10 @@
srcs: ["libvndk.so"],
export_include_dirs: ["include/libvndk"],
},
+ arm: {
+ srcs: ["libvndk.so"],
+ export_include_dirs: ["include/libvndk"],
+ },
},
}
@@ -338,6 +368,28 @@
srcs: ["libvndk.so"],
export_include_dirs: ["include/libvndk"],
},
+ arm: {
+ srcs: ["libvndk.so"],
+ export_include_dirs: ["include/libvndk"],
+ },
+ },
+ }
+
+ // different arch snapshot which has to be ignored
+ vndk_prebuilt_shared {
+ name: "libvndk",
+ version: "30",
+ target_arch: "arm",
+ vendor_available: true,
+ product_available: true,
+ vndk: {
+ enabled: true,
+ },
+ arch: {
+ arm: {
+ srcs: ["libvndk.so"],
+ export_include_dirs: ["include/libvndk"],
+ },
},
}
`
@@ -350,7 +402,6 @@
no_libcrt: true,
stl: "none",
system_shared_libs: [],
- compile_multilib: "64",
}
cc_library_shared {
@@ -362,7 +413,14 @@
system_shared_libs: [],
shared_libs: ["libvndk", "libvendor_available"],
static_libs: ["libvendor", "libvendor_without_snapshot"],
- compile_multilib: "64",
+ arch: {
+ arm64: {
+ shared_libs: ["lib64"],
+ },
+ arm: {
+ shared_libs: ["lib32"],
+ },
+ },
srcs: ["client.cpp"],
}
@@ -371,52 +429,83 @@
vendor: true,
nocrt: true,
no_libcrt: true,
- stl: "none",
+ stl: "libc++_static",
system_shared_libs: [],
static_libs: ["libvndk"],
- compile_multilib: "64",
srcs: ["bin.cpp"],
}
vendor_snapshot {
name: "vendor_snapshot",
- compile_multilib: "first",
- version: "28",
- vndk_libs: [
- "libvndk",
- ],
- static_libs: [
- "libvendor",
- "libvendor_available",
- "libvndk",
- ],
- shared_libs: [
- "libvendor",
- "libvendor_available",
- ],
- binaries: [
- "bin",
- ],
+ version: "30",
+ arch: {
+ arm64: {
+ vndk_libs: [
+ "libvndk",
+ ],
+ static_libs: [
+ "libc++_static",
+ "libc++demangle",
+ "libgcc_stripped",
+ "libvendor",
+ "libvendor_available",
+ "libvndk",
+ "lib64",
+ ],
+ shared_libs: [
+ "libvendor",
+ "libvendor_available",
+ "lib64",
+ ],
+ binaries: [
+ "bin",
+ ],
+ },
+ arm: {
+ vndk_libs: [
+ "libvndk",
+ ],
+ static_libs: [
+ "libvendor",
+ "libvendor_available",
+ "libvndk",
+ "lib32",
+ ],
+ shared_libs: [
+ "libvendor",
+ "libvendor_available",
+ "lib32",
+ ],
+ binaries: [
+ "bin32",
+ ],
+ },
+ }
}
vendor_snapshot_static {
name: "libvndk",
- version: "28",
+ version: "30",
target_arch: "arm64",
+ compile_multilib: "both",
vendor: true,
arch: {
arm64: {
src: "libvndk.a",
export_include_dirs: ["include/libvndk"],
},
+ arm: {
+ src: "libvndk.a",
+ export_include_dirs: ["include/libvndk"],
+ },
},
}
vendor_snapshot_shared {
name: "libvendor",
- version: "28",
+ version: "30",
target_arch: "arm64",
- compile_multilib: "64",
+ compile_multilib: "both",
vendor: true,
shared_libs: [
"libvendor_without_snapshot",
@@ -428,54 +517,163 @@
src: "libvendor.so",
export_include_dirs: ["include/libvendor"],
},
+ arm: {
+ src: "libvendor.so",
+ export_include_dirs: ["include/libvendor"],
+ },
+ },
+ }
+
+ vendor_snapshot_static {
+ name: "lib32",
+ version: "30",
+ target_arch: "arm64",
+ compile_multilib: "32",
+ vendor: true,
+ arch: {
+ arm: {
+ src: "lib32.a",
+ },
+ },
+ }
+
+ vendor_snapshot_shared {
+ name: "lib32",
+ version: "30",
+ target_arch: "arm64",
+ compile_multilib: "32",
+ vendor: true,
+ arch: {
+ arm: {
+ src: "lib32.so",
+ },
+ },
+ }
+
+ vendor_snapshot_static {
+ name: "lib64",
+ version: "30",
+ target_arch: "arm64",
+ compile_multilib: "64",
+ vendor: true,
+ arch: {
+ arm64: {
+ src: "lib64.a",
+ },
+ },
+ }
+
+ vendor_snapshot_shared {
+ name: "lib64",
+ version: "30",
+ target_arch: "arm64",
+ compile_multilib: "64",
+ vendor: true,
+ arch: {
+ arm64: {
+ src: "lib64.so",
+ },
},
}
vendor_snapshot_static {
name: "libvendor",
- version: "28",
+ version: "30",
target_arch: "arm64",
+ compile_multilib: "both",
vendor: true,
arch: {
arm64: {
src: "libvendor.a",
export_include_dirs: ["include/libvendor"],
},
+ arm: {
+ src: "libvendor.a",
+ export_include_dirs: ["include/libvendor"],
+ },
},
}
vendor_snapshot_shared {
name: "libvendor_available",
- androidmk_suffix: ".vendor",
- version: "28",
+ version: "30",
target_arch: "arm64",
+ compile_multilib: "both",
vendor: true,
arch: {
arm64: {
src: "libvendor_available.so",
export_include_dirs: ["include/libvendor"],
},
+ arm: {
+ src: "libvendor_available.so",
+ export_include_dirs: ["include/libvendor"],
+ },
},
}
vendor_snapshot_static {
name: "libvendor_available",
- androidmk_suffix: ".vendor",
- version: "28",
+ version: "30",
target_arch: "arm64",
+ compile_multilib: "both",
vendor: true,
arch: {
arm64: {
src: "libvendor_available.a",
export_include_dirs: ["include/libvendor"],
},
+ arm: {
+ src: "libvendor_available.so",
+ export_include_dirs: ["include/libvendor"],
+ },
+ },
+ }
+
+ vendor_snapshot_static {
+ name: "libc++_static",
+ version: "30",
+ target_arch: "arm64",
+ compile_multilib: "64",
+ vendor: true,
+ arch: {
+ arm64: {
+ src: "libc++_static.a",
+ },
+ },
+ }
+
+ vendor_snapshot_static {
+ name: "libc++demangle",
+ version: "30",
+ target_arch: "arm64",
+ compile_multilib: "64",
+ vendor: true,
+ arch: {
+ arm64: {
+ src: "libc++demangle.a",
+ },
+ },
+ }
+
+ vendor_snapshot_static {
+ name: "libgcc_stripped",
+ version: "30",
+ target_arch: "arm64",
+ compile_multilib: "64",
+ vendor: true,
+ arch: {
+ arm64: {
+ src: "libgcc_stripped.a",
+ },
},
}
vendor_snapshot_binary {
name: "bin",
- version: "28",
+ version: "30",
target_arch: "arm64",
+ compile_multilib: "64",
vendor: true,
arch: {
arm64: {
@@ -484,11 +682,39 @@
},
}
+ vendor_snapshot_binary {
+ name: "bin32",
+ version: "30",
+ target_arch: "arm64",
+ compile_multilib: "32",
+ vendor: true,
+ arch: {
+ arm: {
+ src: "bin32",
+ },
+ },
+ }
+
// old snapshot module which has to be ignored
vendor_snapshot_binary {
name: "bin",
version: "26",
target_arch: "arm64",
+ compile_multilib: "first",
+ vendor: true,
+ arch: {
+ arm64: {
+ src: "bin",
+ },
+ },
+ }
+
+ // different arch snapshot which has to be ignored
+ vendor_snapshot_binary {
+ name: "bin",
+ version: "30",
+ target_arch: "arm",
+ compile_multilib: "first",
vendor: true,
arch: {
arm64: {
@@ -502,23 +728,32 @@
mockFS := map[string][]byte{
"deps/Android.bp": []byte(depsBp),
"framework/Android.bp": []byte(frameworkBp),
+ "framework/symbol.txt": nil,
"vendor/Android.bp": []byte(vendorProprietaryBp),
"vendor/bin": nil,
+ "vendor/bin32": nil,
"vendor/bin.cpp": nil,
"vendor/client.cpp": nil,
"vendor/include/libvndk/a.h": nil,
"vendor/include/libvendor/b.h": nil,
+ "vendor/libc++_static.a": nil,
+ "vendor/libc++demangle.a": nil,
+ "vendor/libgcc_striped.a": nil,
"vendor/libvndk.a": nil,
"vendor/libvendor.a": nil,
"vendor/libvendor.so": nil,
+ "vendor/lib32.a": nil,
+ "vendor/lib32.so": nil,
+ "vendor/lib64.a": nil,
+ "vendor/lib64.so": nil,
"vndk/Android.bp": []byte(vndkBp),
"vndk/include/libvndk/a.h": nil,
"vndk/libvndk.so": nil,
}
config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
- config.TestProductVariables.DeviceVndkVersion = StringPtr("28")
- config.TestProductVariables.Platform_vndk_version = StringPtr("29")
+ config.TestProductVariables.DeviceVndkVersion = StringPtr("30")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("31")
ctx := CreateTestContext(config)
ctx.Register()
@@ -527,11 +762,14 @@
_, errs = ctx.PrepareBuildActions(config)
android.FailIfErrored(t, errs)
- sharedVariant := "android_vendor.28_arm64_armv8-a_shared"
- staticVariant := "android_vendor.28_arm64_armv8-a_static"
- binaryVariant := "android_vendor.28_arm64_armv8-a"
+ sharedVariant := "android_vendor.30_arm64_armv8-a_shared"
+ staticVariant := "android_vendor.30_arm64_armv8-a_static"
+ binaryVariant := "android_vendor.30_arm64_armv8-a"
- // libclient uses libvndk.vndk.28.arm64, libvendor.vendor_static.28.arm64, libvendor_without_snapshot
+ shared32Variant := "android_vendor.30_arm_armv7-a-neon_shared"
+ binary32Variant := "android_vendor.30_arm_armv7-a-neon"
+
+ // libclient uses libvndk.vndk.30.arm64, libvendor.vendor_static.30.arm64, libvendor_without_snapshot
libclientCcFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("cc").Args["cFlags"]
for _, includeFlags := range []string{
"-Ivndk/include/libvndk", // libvndk
@@ -545,8 +783,8 @@
libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("ld").Args["libFlags"]
for _, input := range [][]string{
- []string{sharedVariant, "libvndk.vndk.28.arm64"},
- []string{staticVariant, "libvendor.vendor_static.28.arm64"},
+ []string{sharedVariant, "libvndk.vndk.30.arm64"},
+ []string{staticVariant, "libvendor.vendor_static.30.arm64"},
[]string{staticVariant, "libvendor_without_snapshot"},
} {
outputPaths := getOutputPaths(ctx, input[0] /* variant */, []string{input[1]} /* module name */)
@@ -556,7 +794,7 @@
}
libclientAndroidMkSharedLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkSharedLibs
- if g, w := libclientAndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor"}; !reflect.DeepEqual(g, w) {
+ if g, w := libclientAndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "lib64"}; !reflect.DeepEqual(g, w) {
t.Errorf("wanted libclient AndroidMkSharedLibs %q, got %q", w, g)
}
@@ -565,7 +803,12 @@
t.Errorf("wanted libclient AndroidMkStaticLibs %q, got %q", w, g)
}
- // bin_without_snapshot uses libvndk.vendor_static.28.arm64
+ libclient32AndroidMkSharedLibs := ctx.ModuleForTests("libclient", shared32Variant).Module().(*Module).Properties.AndroidMkSharedLibs
+ if g, w := libclient32AndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "lib32"}; !reflect.DeepEqual(g, w) {
+ t.Errorf("wanted libclient32 AndroidMkSharedLibs %q, got %q", w, g)
+ }
+
+ // bin_without_snapshot uses libvndk.vendor_static.30.arm64
binWithoutSnapshotCcFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("cc").Args["cFlags"]
if !strings.Contains(binWithoutSnapshotCcFlags, "-Ivendor/include/libvndk") {
t.Errorf("flags for bin_without_snapshot must contain %#v, but was %#v.",
@@ -573,28 +816,37 @@
}
binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("ld").Args["libFlags"]
- libVndkStaticOutputPaths := getOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.28.arm64"})
+ libVndkStaticOutputPaths := getOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.30.arm64"})
if !strings.Contains(binWithoutSnapshotLdFlags, libVndkStaticOutputPaths[0].String()) {
t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v",
libVndkStaticOutputPaths[0], binWithoutSnapshotLdFlags)
}
- // libvendor.so is installed by libvendor.vendor_shared.28.arm64
- ctx.ModuleForTests("libvendor.vendor_shared.28.arm64", sharedVariant).Output("libvendor.so")
+ // libvendor.so is installed by libvendor.vendor_shared.30.arm64
+ ctx.ModuleForTests("libvendor.vendor_shared.30.arm64", sharedVariant).Output("libvendor.so")
- // libvendor_available.so is installed by libvendor_available.vendor_shared.28.arm64
- ctx.ModuleForTests("libvendor_available.vendor_shared.28.arm64", sharedVariant).Output("libvendor_available.so")
+ // lib64.so is installed by lib64.vendor_shared.30.arm64
+ ctx.ModuleForTests("lib64.vendor_shared.30.arm64", sharedVariant).Output("lib64.so")
+
+ // lib32.so is installed by lib32.vendor_shared.30.arm64
+ ctx.ModuleForTests("lib32.vendor_shared.30.arm64", shared32Variant).Output("lib32.so")
+
+ // libvendor_available.so is installed by libvendor_available.vendor_shared.30.arm64
+ ctx.ModuleForTests("libvendor_available.vendor_shared.30.arm64", sharedVariant).Output("libvendor_available.so")
// libvendor_without_snapshot.so is installed by libvendor_without_snapshot
ctx.ModuleForTests("libvendor_without_snapshot", sharedVariant).Output("libvendor_without_snapshot.so")
- // bin is installed by bin.vendor_binary.28.arm64
- ctx.ModuleForTests("bin.vendor_binary.28.arm64", binaryVariant).Output("bin")
+ // bin is installed by bin.vendor_binary.30.arm64
+ ctx.ModuleForTests("bin.vendor_binary.30.arm64", binaryVariant).Output("bin")
+
+ // bin32 is installed by bin32.vendor_binary.30.arm64
+ ctx.ModuleForTests("bin32.vendor_binary.30.arm64", binary32Variant).Output("bin32")
// bin_without_snapshot is installed by bin_without_snapshot
ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Output("bin_without_snapshot")
- // libvendor, libvendor_available and bin don't have vendor.28 variant
+ // libvendor, libvendor_available and bin don't have vendor.30 variant
libvendorVariants := ctx.ModuleVariantsForTests("libvendor")
if inList(sharedVariant, libvendorVariants) {
t.Errorf("libvendor must not have variant %#v, but it does", sharedVariant)
@@ -613,6 +865,18 @@
func TestVendorSnapshotSanitizer(t *testing.T) {
bp := `
+ vendor_snapshot {
+ name: "vendor_snapshot",
+ version: "28",
+ arch: {
+ arm64: {
+ static_libs: [
+ "libsnapshot",
+ "note_memtag_heap_sync",
+ ],
+ },
+ },
+ }
vendor_snapshot_static {
name: "libsnapshot",
vendor: true,
@@ -627,8 +891,41 @@
},
},
}
+
+ vendor_snapshot_static {
+ name: "note_memtag_heap_sync",
+ vendor: true,
+ target_arch: "arm64",
+ version: "28",
+ arch: {
+ arm64: {
+ src: "note_memtag_heap_sync.a",
+ },
+ },
+ }
+
+ cc_test {
+ name: "vstest",
+ gtest: false,
+ vendor: true,
+ compile_multilib: "64",
+ nocrt: true,
+ no_libcrt: true,
+ stl: "none",
+ static_libs: ["libsnapshot"],
+ system_shared_libs: [],
+ }
`
- config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
+
+ mockFS := map[string][]byte{
+ "vendor/Android.bp": []byte(bp),
+ "vendor/libc++demangle.a": nil,
+ "vendor/libsnapshot.a": nil,
+ "vendor/libsnapshot.cfi.a": nil,
+ "vendor/note_memtag_heap_sync.a": nil,
+ }
+
+ config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
config.TestProductVariables.DeviceVndkVersion = StringPtr("28")
config.TestProductVariables.Platform_vndk_version = StringPtr("29")
ctx := testCcWithConfig(t, config)
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 3f1e9f3..3ce4f85 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -696,7 +696,8 @@
result := android.GroupFixturePreparers(
prepareForGenRuleTest, android.FixtureModifyConfig(func(config android.Config) {
config.BazelContext = android.MockBazelContext{
- AllFiles: map[string][]string{
+ OutputBaseDir: "outputbase",
+ LabelToOutputFiles: map[string][]string{
"//foo/bar:bar": []string{"bazelone.txt", "bazeltwo.txt"}}}
})).RunTestWithBp(t, testGenruleBp()+bp)
diff --git a/java/Android.bp b/java/Android.bp
index 8334b85..f8ba1b6 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -42,6 +42,7 @@
"gen.go",
"genrule.go",
"hiddenapi.go",
+ "hiddenapi_modular.go",
"hiddenapi_singleton.go",
"jacoco.go",
"java.go",
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
new file mode 100644
index 0000000..bed11fe
--- /dev/null
+++ b/java/hiddenapi_modular.go
@@ -0,0 +1,172 @@
+// 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 (
+ "android/soong/android"
+)
+
+// Contains support for processing hiddenAPI in a modular fashion.
+
+// HiddenAPIAugmentationProperties contains paths to the files that can be used to augment the information
+// obtained from annotations within the source code in order to create the complete set of flags
+// that should be applied to the dex implementation jars on the bootclasspath.
+//
+// Each property contains a list of paths. With the exception of the Unsupported_packages the paths
+// of each property reference a plain text file that contains a java signature per line. The flags
+// for each of those signatures will be updated in a property specific way.
+//
+// The Unsupported_packages property contains a list of paths, each of which is a plain text file
+// with one Java package per line. All members of all classes within that package (but not nested
+// packages) will be updated in a property specific way.
+type HiddenAPIAugmentationProperties struct {
+ // Marks each signature in the referenced files as being unsupported.
+ Unsupported []string `android:"path"`
+
+ // Marks each signature in the referenced files as being unsupported because it has been removed.
+ // Any conflicts with other flags are ignored.
+ Removed []string `android:"path"`
+
+ // Marks each signature in the referenced files as being supported only for targetSdkVersion <= R
+ // and low priority.
+ Max_target_r_low_priority []string `android:"path"`
+
+ // Marks each signature in the referenced files as being supported only for targetSdkVersion <= Q.
+ Max_target_q []string `android:"path"`
+
+ // Marks each signature in the referenced files as being supported only for targetSdkVersion <= P.
+ Max_target_p []string `android:"path"`
+
+ // Marks each signature in the referenced files as being supported only for targetSdkVersion <= O
+ // and low priority. Any conflicts with other flags are ignored.
+ Max_target_o_low_priority []string `android:"path"`
+
+ // Marks each signature in the referenced files as being blocked.
+ Blocked []string `android:"path"`
+
+ // Marks each signature in every package in the referenced files as being unsupported.
+ Unsupported_packages []string `android:"path"`
+}
+
+func (p *HiddenAPIAugmentationProperties) hiddenAPIAugmentationInfo(ctx android.ModuleContext) hiddenAPIAugmentationInfo {
+ paths := func(paths []string) android.Paths { return android.PathsForModuleSrc(ctx, paths) }
+ return hiddenAPIAugmentationInfo{
+ Unsupported: paths(p.Unsupported),
+ Removed: paths(p.Removed),
+ Max_target_r_low_priority: paths(p.Max_target_r_low_priority),
+ Max_target_q: paths(p.Max_target_q),
+ Max_target_p: paths(p.Max_target_p),
+ Max_target_o_low_priority: paths(p.Max_target_o_low_priority),
+ Blocked: paths(p.Blocked),
+ Unsupported_packages: paths(p.Unsupported_packages),
+ }
+}
+
+// hiddenAPIAugmentationInfo contains paths resolved from HiddenAPIAugmentationProperties
+type hiddenAPIAugmentationInfo struct {
+ // See HiddenAPIAugmentationProperties.Unsupported
+ Unsupported android.Paths
+
+ // See HiddenAPIAugmentationProperties.Removed
+ Removed android.Paths
+
+ // See HiddenAPIAugmentationProperties.Max_target_r_low_priority
+ Max_target_r_low_priority android.Paths
+
+ // See HiddenAPIAugmentationProperties.Max_target_q
+ Max_target_q android.Paths
+
+ // See HiddenAPIAugmentationProperties.Max_target_p
+ Max_target_p android.Paths
+
+ // See HiddenAPIAugmentationProperties.Max_target_o_low_priority
+ Max_target_o_low_priority android.Paths
+
+ // See HiddenAPIAugmentationProperties.Blocked
+ Blocked android.Paths
+
+ // See HiddenAPIAugmentationProperties.Unsupported_packages
+ Unsupported_packages android.Paths
+}
+
+// ruleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from the
+// flags from all the modules, the stub flags, augmented with some additional configuration files.
+//
+// baseFlagsPath is the path to the flags file containing all the information from the stubs plus
+// an entry for every single member in the dex implementation jars of the individual modules. Every
+// signature in any of the other files MUST be included in this file.
+//
+// moduleSpecificFlagsPaths are the paths to the flags files generated by each module using
+// information from the baseFlagsPath as well as from annotations within the source.
+//
+// augmentationInfo is a struct containing paths to files that augment the information provided by
+// the moduleSpecificFlagsPaths.
+// ruleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from the
+// flags from all the modules, the stub flags, augmented with some additional configuration files.
+//
+// baseFlagsPath is the path to the flags file containing all the information from the stubs plus
+// an entry for every single member in the dex implementation jars of the individual modules. Every
+// signature in any of the other files MUST be included in this file.
+//
+// moduleSpecificFlagsPaths are the paths to the flags files generated by each module using
+// information from the baseFlagsPath as well as from annotations within the source.
+//
+// augmentationInfo is a struct containing paths to files that augment the information provided by
+// the moduleSpecificFlagsPaths.
+func ruleToGenerateHiddenApiFlags(ctx android.BuilderContext, outputPath android.WritablePath, baseFlagsPath android.Path, moduleSpecificFlagsPaths android.Paths, augmentationInfo hiddenAPIAugmentationInfo) {
+ tempPath := android.PathForOutput(ctx, outputPath.Rel()+".tmp")
+ rule := android.NewRuleBuilder(pctx, ctx)
+ command := rule.Command().
+ BuiltTool("generate_hiddenapi_lists").
+ FlagWithInput("--csv ", baseFlagsPath).
+ Inputs(moduleSpecificFlagsPaths).
+ FlagWithOutput("--output ", tempPath)
+
+ for _, path := range augmentationInfo.Unsupported {
+ command.FlagWithInput("--unsupported ", path)
+ }
+
+ for _, path := range augmentationInfo.Removed {
+ command.FlagWithInput("--unsupported ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed")
+ }
+
+ for _, path := range augmentationInfo.Max_target_r_low_priority {
+ command.FlagWithInput("--max-target-r ", path).FlagWithArg("--tag ", "lo-prio")
+ }
+
+ for _, path := range augmentationInfo.Max_target_q {
+ command.FlagWithInput("--max-target-q ", path)
+ }
+
+ for _, path := range augmentationInfo.Max_target_p {
+ command.FlagWithInput("--max-target-p ", path)
+ }
+
+ for _, path := range augmentationInfo.Max_target_o_low_priority {
+ command.FlagWithInput("--max-target-o ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio")
+ }
+
+ for _, path := range augmentationInfo.Blocked {
+ command.FlagWithInput("--blocked ", path)
+ }
+
+ for _, path := range augmentationInfo.Unsupported_packages {
+ command.FlagWithInput("--unsupported ", path).Flag("--packages ")
+ }
+
+ commitChangeForRestat(rule, tempPath, outputPath)
+
+ rule.Build("hiddenAPIFlagsFile", "hiddenapi flags")
+}
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 7e9477b..641e19f 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -18,7 +18,6 @@
"fmt"
"android/soong/android"
- "android/soong/genrule"
)
func init() {
@@ -321,63 +320,10 @@
return outputPath
}
-// flagsRule creates a rule to build hiddenapi-flags.csv out of flags.csv files generated for boot image modules and
-// the unsupported API.
+// flagsRule is a placeholder that simply returns the location of the file, the generation of the
+// ninja rules is done in generateHiddenAPIBuildActions.
func flagsRule(ctx android.SingletonContext) android.Path {
- var flagsCSV android.Paths
- var combinedRemovedApis android.Path
-
- ctx.VisitAllModules(func(module android.Module) {
- if h, ok := module.(hiddenAPIIntf); ok {
- if csv := h.flagsCSV(); csv != nil {
- flagsCSV = append(flagsCSV, csv)
- }
- } else if g, ok := module.(*genrule.Module); ok {
- if ctx.ModuleName(module) == "combined-removed-dex" {
- if len(g.GeneratedSourceFiles()) != 1 || combinedRemovedApis != nil {
- ctx.Errorf("Expected 1 combined-removed-dex module that generates 1 output file.")
- }
- combinedRemovedApis = g.GeneratedSourceFiles()[0]
- }
- }
- })
-
- if combinedRemovedApis == nil {
- ctx.Errorf("Failed to find combined-removed-dex.")
- }
-
- rule := android.NewRuleBuilder(pctx, ctx)
-
outputPath := hiddenAPISingletonPaths(ctx).flags
- tempPath := android.PathForOutput(ctx, outputPath.Rel()+".tmp")
-
- stubFlags := hiddenAPISingletonPaths(ctx).stubFlags
-
- rule.Command().
- BuiltTool("generate_hiddenapi_lists").
- FlagWithInput("--csv ", stubFlags).
- Inputs(flagsCSV).
- FlagWithInput("--unsupported ",
- android.PathForSource(ctx, "frameworks/base/boot/hiddenapi/hiddenapi-unsupported.txt")).
- FlagWithInput("--unsupported ", combinedRemovedApis).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed").
- FlagWithInput("--max-target-r ",
- android.PathForSource(ctx, "frameworks/base/boot/hiddenapi/hiddenapi-max-target-r-loprio.txt")).FlagWithArg("--tag ", "lo-prio").
- FlagWithInput("--max-target-q ",
- android.PathForSource(ctx, "frameworks/base/boot/hiddenapi/hiddenapi-max-target-q.txt")).
- FlagWithInput("--max-target-p ",
- android.PathForSource(ctx, "frameworks/base/boot/hiddenapi/hiddenapi-max-target-p.txt")).
- FlagWithInput("--max-target-o ", android.PathForSource(
- ctx, "frameworks/base/boot/hiddenapi/hiddenapi-max-target-o.txt")).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio").
- FlagWithInput("--blocked ",
- android.PathForSource(ctx, "frameworks/base/boot/hiddenapi/hiddenapi-force-blocked.txt")).
- FlagWithInput("--unsupported ", android.PathForSource(
- ctx, "frameworks/base/boot/hiddenapi/hiddenapi-unsupported-packages.txt")).Flag("--packages ").
- FlagWithOutput("--output ", tempPath)
-
- commitChangeForRestat(rule, tempPath, outputPath)
-
- rule.Build("hiddenAPIFlagsFile", "hiddenapi flags")
-
return outputPath
}
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 5507077..e292d80 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -17,6 +17,8 @@
import (
"android/soong/android"
"android/soong/dexpreopt"
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
)
func init() {
@@ -25,14 +27,73 @@
func registerPlatformBootclasspathBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("platform_bootclasspath", platformBootclasspathFactory)
+
+ ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("platform_bootclasspath_deps", platformBootclasspathDepsMutator)
+ })
}
+type platformBootclasspathDependencyTag struct {
+ blueprint.BaseDependencyTag
+
+ name string
+}
+
+// Avoid having to make platform bootclasspath content visible to the platform bootclasspath.
+//
+// This is a temporary workaround to make it easier to migrate to platform bootclasspath with proper
+// dependencies.
+// TODO(b/177892522): Remove this and add needed visibility.
+func (t platformBootclasspathDependencyTag) ExcludeFromVisibilityEnforcement() {
+}
+
+// The tag used for the dependency between the platform bootclasspath and any configured boot jars.
+var platformBootclasspathModuleDepTag = platformBootclasspathDependencyTag{name: "module"}
+
+// The tag used for the dependency between the platform bootclasspath and bootclasspath_fragments.
+var platformBootclasspathFragmentDepTag = platformBootclasspathDependencyTag{name: "fragment"}
+
+var _ android.ExcludeFromVisibilityEnforcementTag = platformBootclasspathDependencyTag{}
+
type platformBootclasspathModule struct {
android.ModuleBase
+
+ properties platformBootclasspathProperties
+
+ // The apex:module pairs obtained from the configured modules.
+ //
+ // Currently only for testing.
+ configuredModules []android.Module
+
+ // The apex:module pairs obtained from the fragments.
+ //
+ // Currently only for testing.
+ fragments []android.Module
+}
+
+// ApexVariantReference specifies a particular apex variant of a module.
+type ApexVariantReference struct {
+ // The name of the module apex variant, i.e. the apex containing the module variant.
+ //
+ // If this is not specified then it defaults to "platform" which will cause a dependency to be
+ // added to the module's platform variant.
+ Apex *string
+
+ // The name of the module.
+ Module *string
+}
+
+type platformBootclasspathProperties struct {
+ // The names of the bootclasspath_fragment modules that form part of this
+ // platform_bootclasspath.
+ Fragments []ApexVariantReference
+
+ Hidden_api HiddenAPIAugmentationProperties
}
func platformBootclasspathFactory() android.Module {
m := &platformBootclasspathModule{}
+ m.AddProperties(&m.properties)
android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
return m
}
@@ -47,7 +108,92 @@
dexpreopt.RegisterToolDeps(ctx)
}
+func platformBootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
+ m := ctx.Module()
+ if p, ok := m.(*platformBootclasspathModule); ok {
+ // Add dependencies on all the modules configured in the "art" boot image.
+ artImageConfig := genBootImageConfigs(ctx)[artBootImageName]
+ addDependenciesOntoBootImageModules(ctx, artImageConfig.modules)
+
+ // Add dependencies on all the modules configured in the "boot" boot image. That does not
+ // include modules configured in the "art" boot image.
+ bootImageConfig := p.getImageConfig(ctx)
+ addDependenciesOntoBootImageModules(ctx, bootImageConfig.modules)
+
+ // Add dependencies on all the updatable modules.
+ updatableModules := dexpreopt.GetGlobalConfig(ctx).UpdatableBootJars
+ addDependenciesOntoBootImageModules(ctx, updatableModules)
+
+ // Add dependencies on all the fragments.
+ addDependencyOntoApexVariants(ctx, "fragments", p.properties.Fragments, platformBootclasspathFragmentDepTag)
+ }
+}
+
+func addDependencyOntoApexVariants(ctx android.BottomUpMutatorContext, propertyName string, refs []ApexVariantReference, tag blueprint.DependencyTag) {
+ for i, ref := range refs {
+ apex := proptools.StringDefault(ref.Apex, "platform")
+
+ if ref.Module == nil {
+ ctx.PropertyErrorf(propertyName, "missing module name at position %d", i)
+ continue
+ }
+ name := proptools.String(ref.Module)
+
+ addDependencyOntoApexModulePair(ctx, apex, name, tag)
+ }
+}
+
+func addDependencyOntoApexModulePair(ctx android.BottomUpMutatorContext, apex string, name string, tag blueprint.DependencyTag) {
+ var variations []blueprint.Variation
+ if apex != "platform" {
+ // Pick the correct apex variant.
+ variations = []blueprint.Variation{
+ {Mutator: "apex", Variation: apex},
+ }
+ }
+
+ addedDep := false
+ if ctx.OtherModuleDependencyVariantExists(variations, name) {
+ ctx.AddFarVariationDependencies(variations, tag, name)
+ addedDep = true
+ }
+
+ // Add a dependency on the prebuilt module if it exists.
+ prebuiltName := android.PrebuiltNameFromSource(name)
+ if ctx.OtherModuleDependencyVariantExists(variations, prebuiltName) {
+ ctx.AddVariationDependencies(variations, tag, prebuiltName)
+ addedDep = true
+ }
+
+ // If no appropriate variant existing for this, so no dependency could be added, then it is an
+ // error, unless missing dependencies are allowed. The simplest way to handle that is to add a
+ // dependency that will not be satisfied and the default behavior will handle it.
+ if !addedDep {
+ ctx.AddFarVariationDependencies(variations, tag, name)
+ }
+}
+
+func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, modules android.ConfiguredJarList) {
+ for i := 0; i < modules.Len(); i++ {
+ apex := modules.Apex(i)
+ name := modules.Jar(i)
+
+ addDependencyOntoApexModulePair(ctx, apex, name, platformBootclasspathModuleDepTag)
+ }
+}
+
func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ ctx.VisitDirectDepsIf(isActiveModule, func(module android.Module) {
+ tag := ctx.OtherModuleDependencyTag(module)
+ if tag == platformBootclasspathModuleDepTag {
+ b.configuredModules = append(b.configuredModules, module)
+ } else if tag == platformBootclasspathFragmentDepTag {
+ b.fragments = append(b.fragments, module)
+ }
+ })
+
+ b.generateHiddenAPIBuildActions(ctx, b.configuredModules)
+
// Nothing to do if skipping the dexpreopt of boot image jars.
if SkipDexpreoptBootJars(ctx) {
return
@@ -72,3 +218,24 @@
func (b *platformBootclasspathModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig {
return defaultBootImageConfig(ctx)
}
+
+// generateHiddenAPIBuildActions generates all the hidden API related build rules.
+func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module) {
+
+ moduleSpecificFlagsPaths := android.Paths{}
+ for _, module := range modules {
+ if h, ok := module.(hiddenAPIIntf); ok {
+ if csv := h.flagsCSV(); csv != nil {
+ moduleSpecificFlagsPaths = append(moduleSpecificFlagsPaths, csv)
+ }
+ } else {
+ ctx.ModuleErrorf("module %s of type %s does not implement hiddenAPIIntf", module, ctx.OtherModuleType(module))
+ }
+ }
+
+ augmentationInfo := b.properties.Hidden_api.hiddenAPIAugmentationInfo(ctx)
+
+ outputPath := hiddenAPISingletonPaths(ctx).flags
+ baseFlagsPath := hiddenAPISingletonPaths(ctx).stubFlags
+ ruleToGenerateHiddenApiFlags(ctx, outputPath, baseFlagsPath, moduleSpecificFlagsPaths, augmentationInfo)
+}
diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go
index 1c81cfd..ebbe3a5 100644
--- a/java/platform_bootclasspath_test.go
+++ b/java/platform_bootclasspath_test.go
@@ -29,10 +29,105 @@
)
func TestPlatformBootclasspath(t *testing.T) {
- prepareForTestWithPlatformBootclasspath.
- RunTestWithBp(t, `
+ preparer := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ dexpreopt.FixtureSetBootJars("platform:foo", "platform:bar"),
+ android.FixtureWithRootAndroidBp(`
platform_bootclasspath {
name: "platform-bootclasspath",
}
- `)
+
+ java_library {
+ name: "bar",
+ srcs: ["a.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ }
+ `),
+ )
+
+ var addSourceBootclassPathModule = android.FixtureAddTextFile("source/Android.bp", `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ }
+ `)
+
+ var addPrebuiltBootclassPathModule = android.FixtureAddTextFile("prebuilt/Android.bp", `
+ java_import {
+ name: "foo",
+ jars: ["a.jar"],
+ compile_dex: true,
+ prefer: false,
+ }
+ `)
+
+ var addPrebuiltPreferredBootclassPathModule = android.FixtureAddTextFile("prebuilt/Android.bp", `
+ java_import {
+ name: "foo",
+ jars: ["a.jar"],
+ compile_dex: true,
+ prefer: true,
+ }
+ `)
+
+ t.Run("missing", func(t *testing.T) {
+ preparer.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`"platform-bootclasspath" depends on undefined module "foo"`)).
+ RunTest(t)
+ })
+
+ t.Run("source", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ preparer,
+ addSourceBootclassPathModule,
+ ).RunTest(t)
+
+ CheckPlatformBootclasspathModules(t, result, "platform-bootclasspath", []string{
+ "platform:foo",
+ "platform:bar",
+ })
+ })
+
+ t.Run("prebuilt", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ preparer,
+ addPrebuiltBootclassPathModule,
+ ).RunTest(t)
+
+ CheckPlatformBootclasspathModules(t, result, "platform-bootclasspath", []string{
+ "platform:prebuilt_foo",
+ "platform:bar",
+ })
+ })
+
+ t.Run("source+prebuilt - source preferred", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ preparer,
+ addSourceBootclassPathModule,
+ addPrebuiltBootclassPathModule,
+ ).RunTest(t)
+
+ CheckPlatformBootclasspathModules(t, result, "platform-bootclasspath", []string{
+ "platform:foo",
+ "platform:bar",
+ })
+ })
+
+ t.Run("source+prebuilt - prebuilt preferred", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ preparer,
+ addSourceBootclassPathModule,
+ addPrebuiltPreferredBootclassPathModule,
+ ).RunTest(t)
+
+ CheckPlatformBootclasspathModules(t, result, "platform-bootclasspath", []string{
+ "platform:prebuilt_foo",
+ "platform:bar",
+ })
+ })
}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index eb9ba9b..96135c3 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -201,8 +201,12 @@
return scope
}
+func (scope *apiScope) stubsLibraryModuleNameSuffix() string {
+ return ".stubs" + scope.moduleSuffix
+}
+
func (scope *apiScope) stubsLibraryModuleName(baseName string) string {
- return baseName + ".stubs" + scope.moduleSuffix
+ return baseName + scope.stubsLibraryModuleNameSuffix()
}
func (scope *apiScope) stubsSourceModuleName(baseName string) string {
@@ -1684,16 +1688,20 @@
func moduleStubLinkType(name string) (stub bool, ret sdkLinkType) {
// This suffix-based approach is fragile and could potentially mis-trigger.
// TODO(b/155164730): Clean this up when modules no longer reference sdk_lib stubs directly.
- if strings.HasSuffix(name, ".stubs.public") || strings.HasSuffix(name, "-stubs-publicapi") {
+ if strings.HasSuffix(name, apiScopePublic.stubsLibraryModuleNameSuffix()) {
+ if name == "hwbinder.stubs" || name == "libcore_private.stubs" {
+ // Due to a previous bug, these modules were not considered stubs, so we retain that.
+ return false, javaPlatform
+ }
return true, javaSdk
}
- if strings.HasSuffix(name, ".stubs.system") || strings.HasSuffix(name, "-stubs-systemapi") {
+ if strings.HasSuffix(name, apiScopeSystem.stubsLibraryModuleNameSuffix()) {
return true, javaSystem
}
- if strings.HasSuffix(name, ".stubs.module_lib") || strings.HasSuffix(name, "-stubs-module_libs_api") {
+ if strings.HasSuffix(name, apiScopeModuleLib.stubsLibraryModuleNameSuffix()) {
return true, javaModule
}
- if strings.HasSuffix(name, ".stubs.test") {
+ if strings.HasSuffix(name, apiScopeTest.stubsLibraryModuleNameSuffix()) {
return true, javaSystem
}
return false, javaPlatform
diff --git a/java/testing.go b/java/testing.go
index 80c107d..6ebc747 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -300,6 +300,46 @@
}
}
+// CheckPlatformBootclasspathModules returns the apex:module pair for the modules depended upon by
+// the platform-bootclasspath module.
+func CheckPlatformBootclasspathModules(t *testing.T, result *android.TestResult, name string, expected []string) {
+ t.Helper()
+ platformBootclasspath := result.Module(name, "android_common").(*platformBootclasspathModule)
+ pairs := ApexNamePairsFromModules(result.TestContext, platformBootclasspath.configuredModules)
+ android.AssertDeepEquals(t, fmt.Sprintf("%s modules", "platform-bootclasspath"), expected, pairs)
+}
+
+// ApexNamePairsFromModules returns the apex:module pair for the supplied modules.
+func ApexNamePairsFromModules(ctx *android.TestContext, modules []android.Module) []string {
+ pairs := []string{}
+ for _, module := range modules {
+ pairs = append(pairs, apexNamePairFromModule(ctx, module))
+ }
+ return pairs
+}
+
+func apexNamePairFromModule(ctx *android.TestContext, module android.Module) string {
+ name := module.Name()
+ var apex string
+ apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+ if apexInfo.IsForPlatform() {
+ apex = "platform"
+ } else {
+ apex = apexInfo.InApexes[0]
+ }
+
+ return fmt.Sprintf("%s:%s", apex, name)
+}
+
+// CheckPlatformBootclasspathFragments returns the apex:module pair for the fragments depended upon
+// by the platform-bootclasspath module.
+func CheckPlatformBootclasspathFragments(t *testing.T, result *android.TestResult, name string, expected []string) {
+ t.Helper()
+ platformBootclasspath := result.Module(name, "android_common").(*platformBootclasspathModule)
+ pairs := ApexNamePairsFromModules(result.TestContext, platformBootclasspath.fragments)
+ android.AssertDeepEquals(t, fmt.Sprintf("%s fragments", "platform-bootclasspath"), expected, pairs)
+}
+
func CheckHiddenAPIRuleInputs(t *testing.T, expected string, hiddenAPIRule android.TestingBuildParams) {
t.Helper()
actual := strings.TrimSpace(strings.Join(android.NormalizePathsForTesting(hiddenAPIRule.Implicits), "\n"))
diff --git a/rust/androidmk.go b/rust/androidmk.go
index b0e6967..dea32a3 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -70,6 +70,11 @@
// If the compiler is disabled, this is a SourceProvider.
mod.SubAndroidMk(&ret, mod.sourceProvider)
}
+
+ if mod.sanitize != nil {
+ mod.SubAndroidMk(&ret, mod.sanitize)
+ }
+
ret.SubName += mod.Properties.SubName
return []android.AndroidMkEntries{ret}
diff --git a/rust/builder.go b/rust/builder.go
index 9d462d4..197c703 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -51,9 +51,12 @@
Command: "$envVars $clippyCmd " +
// Because clippy-driver uses rustc as backend, we need to have some output even during the linting.
// Use the metadata output as it has the smallest footprint.
- "--emit metadata -o $out $in ${libFlags} " +
- "$rustcFlags $clippyFlags",
+ "--emit metadata -o $out --emit dep-info=$out.d.raw $in ${libFlags} " +
+ "$rustcFlags $clippyFlags" +
+ " && grep \"^$out:\" $out.d.raw > $out.d",
CommandDeps: []string{"$clippyCmd"},
+ Deps: blueprint.DepsGCC,
+ Depfile: "$out.d",
},
"rustcFlags", "libFlags", "clippyFlags", "envVars")
diff --git a/rust/compiler.go b/rust/compiler.go
index 2e85f5a..aaa1924 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -76,7 +76,7 @@
// errors). The default value is "default".
Lints *string
- // flags to pass to rustc
+ // flags to pass to rustc. To enable configuration options or features, use the "cfgs" or "features" properties.
Flags []string `android:"path,arch_variant"`
// flags to pass to the linker
@@ -125,6 +125,9 @@
// list of features to enable for this crate
Features []string `android:"arch_variant"`
+ // list of configuration options to enable for this crate. To enable features, use the "features" property.
+ Cfgs []string `android:"arch_variant"`
+
// specific rust edition that should be used if the default version is not desired
Edition *string `android:"arch_variant"`
@@ -210,9 +213,17 @@
return []interface{}{&compiler.Properties}
}
-func (compiler *baseCompiler) featuresToFlags(features []string) []string {
+func (compiler *baseCompiler) cfgsToFlags() []string {
flags := []string{}
- for _, feature := range features {
+ for _, cfg := range compiler.Properties.Cfgs {
+ flags = append(flags, "--cfg '"+cfg+"'")
+ }
+ return flags
+}
+
+func (compiler *baseCompiler) featuresToFlags() []string {
+ flags := []string{}
+ for _, feature := range compiler.Properties.Features {
flags = append(flags, "--cfg 'feature=\""+feature+"\"'")
}
return flags
@@ -226,7 +237,8 @@
}
flags.RustFlags = append(flags.RustFlags, lintFlags)
flags.RustFlags = append(flags.RustFlags, compiler.Properties.Flags...)
- flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags(compiler.Properties.Features)...)
+ flags.RustFlags = append(flags.RustFlags, compiler.cfgsToFlags()...)
+ flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags()...)
flags.RustFlags = append(flags.RustFlags, "--edition="+compiler.edition())
flags.LinkFlags = append(flags.LinkFlags, compiler.Properties.Ld_flags...)
flags.GlobalRustFlags = append(flags.GlobalRustFlags, config.GlobalRustFlags...)
diff --git a/rust/compiler_test.go b/rust/compiler_test.go
index c752762..5ca9e7f 100644
--- a/rust/compiler_test.go
+++ b/rust/compiler_test.go
@@ -42,6 +42,27 @@
}
}
+// Test that cfgs flags are being correctly generated.
+func TestCfgsToFlags(t *testing.T) {
+ ctx := testRust(t, `
+ rust_library_host {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ cfgs: [
+ "std",
+ "cfg1=\"one\""
+ ],
+ }`)
+
+ libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
+
+ if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'std'") ||
+ !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'cfg1=\"one\"'") {
+ t.Fatalf("missing std and cfg1 flags for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
+ }
+}
+
// Test that we reject multiple source files.
func TestEnforceSingleSourceFile(t *testing.T) {
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index 1c8e43e..394fcc5 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -23,6 +23,7 @@
"system/extras/profcollectd",
"system/extras/simpleperf",
"system/hardware/interfaces/keystore2",
+ "system/logging/rust",
"system/security",
"system/tools/aidl",
}
diff --git a/rust/config/global.go b/rust/config/global.go
index 9208ddb..18776ab 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
var pctx = android.NewPackageContext("android/soong/rust/config")
var (
- RustDefaultVersion = "1.50.0"
+ RustDefaultVersion = "1.51.0"
RustDefaultBase = "prebuilts/rust/"
DefaultEdition = "2018"
Stdlibs = []string{
diff --git a/rust/config/lints.go b/rust/config/lints.go
index 7c05e4f..ef6b315 100644
--- a/rust/config/lints.go
+++ b/rust/config/lints.go
@@ -54,6 +54,7 @@
"-A clippy::type-complexity",
"-A clippy::unnecessary-wraps",
"-A clippy::unusual-byte-groupings",
+ "-A clippy::upper-case-acronyms",
}
// Rust lints for vendor code.
diff --git a/rust/rust.go b/rust/rust.go
index 566ad37..34e197a 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -798,6 +798,11 @@
return ok && tag == dylibDepTag
}
+func IsRlibDepTag(depTag blueprint.DependencyTag) bool {
+ tag, ok := depTag.(dependencyTag)
+ return ok && tag == rlibDepTag
+}
+
type autoDep struct {
variation string
depTag dependencyTag
diff --git a/rust/sanitize.go b/rust/sanitize.go
index 2498aa1..ae3eff0 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -23,11 +23,12 @@
)
type SanitizeProperties struct {
- // enable AddressSanitizer, ThreadSanitizer, or UndefinedBehaviorSanitizer
+ // enable AddressSanitizer, HWAddressSanitizer, and others.
Sanitize struct {
- Address *bool `android:"arch_variant"`
- Fuzzer *bool `android:"arch_variant"`
- Never *bool `android:"arch_variant"`
+ Address *bool `android:"arch_variant"`
+ Hwaddress *bool `android:"arch_variant"`
+ Fuzzer *bool `android:"arch_variant"`
+ Never *bool `android:"arch_variant"`
}
SanitizerEnabled bool `blueprint:"mutated"`
SanitizeDep bool `blueprint:"mutated"`
@@ -43,7 +44,6 @@
"-C llvm-args=-sanitizer-coverage-level=3",
"-C llvm-args=-sanitizer-coverage-trace-compares",
"-C llvm-args=-sanitizer-coverage-inline-8bit-counters",
- "-C llvm-args=-sanitizer-coverage-stack-depth",
"-C llvm-args=-sanitizer-coverage-trace-geps",
"-C llvm-args=-sanitizer-coverage-prune-blocks=0",
"-Z sanitizer=address",
@@ -57,6 +57,11 @@
"-Z sanitizer=address",
}
+var hwasanFlags = []string{
+ "-Z sanitizer=hwaddress",
+ "-C target-feature=+tagged-globals",
+}
+
func boolPtr(v bool) *bool {
if v {
return &v
@@ -83,6 +88,15 @@
if ctx.Os() == android.Android && Bool(s.Address) {
sanitize.Properties.SanitizerEnabled = true
}
+
+ // HWASan requires AArch64 hardware feature (top-byte-ignore).
+ if ctx.Arch().ArchType != android.Arm64 {
+ s.Hwaddress = nil
+ }
+
+ if ctx.Os() == android.Android && Bool(s.Hwaddress) {
+ sanitize.Properties.SanitizerEnabled = true
+ }
}
type sanitize struct {
@@ -99,6 +113,9 @@
if Bool(sanitize.Properties.Sanitize.Address) {
flags.RustFlags = append(flags.RustFlags, asanFlags...)
}
+ if Bool(sanitize.Properties.Sanitize.Hwaddress) {
+ flags.RustFlags = append(flags.RustFlags, hwasanFlags...)
+ }
return flags, deps
}
@@ -111,11 +128,38 @@
if !mod.Enabled() {
return
}
+
+ variations := mctx.Target().Variations()
+ var depTag blueprint.DependencyTag
+ var deps []string
+
if Bool(mod.sanitize.Properties.Sanitize.Fuzzer) || Bool(mod.sanitize.Properties.Sanitize.Address) {
- mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
- {Mutator: "link", Variation: "shared"},
- }...), cc.SharedDepTag(), config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan"))
+ variations = append(variations,
+ blueprint.Variation{Mutator: "link", Variation: "shared"})
+ depTag = cc.SharedDepTag()
+ deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan")}
+ } else if mod.IsSanitizerEnabled(cc.Hwasan) {
+ // TODO(b/180495975): HWASan for static Rust binaries isn't supported yet.
+ if binary, ok := mod.compiler.(*binaryDecorator); ok {
+ if Bool(binary.Properties.Static_executable) {
+ mctx.ModuleErrorf("HWASan is not supported for static Rust executables yet.")
+ }
+ }
+
+ if mod.StaticallyLinked() {
+ variations = append(variations,
+ blueprint.Variation{Mutator: "link", Variation: "static"})
+ depTag = cc.StaticDepTag(false)
+ deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan_static")}
+ } else {
+ variations = append(variations,
+ blueprint.Variation{Mutator: "link", Variation: "shared"})
+ depTag = cc.SharedDepTag()
+ deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan")}
+ }
}
+
+ mctx.AddFarVariationDependencies(variations, depTag, deps...)
}
}
@@ -128,6 +172,9 @@
case cc.Asan:
sanitize.Properties.Sanitize.Address = boolPtr(b)
sanitizerSet = true
+ case cc.Hwasan:
+ sanitize.Properties.Sanitize.Hwaddress = boolPtr(b)
+ sanitizerSet = true
default:
panic(fmt.Errorf("setting unsupported sanitizerType %d", t))
}
@@ -169,11 +216,23 @@
return sanitize.Properties.Sanitize.Fuzzer
case cc.Asan:
return sanitize.Properties.Sanitize.Address
+ case cc.Hwasan:
+ return sanitize.Properties.Sanitize.Hwaddress
default:
return nil
}
}
+func (sanitize *sanitize) AndroidMk(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ // Add a suffix for hwasan rlib libraries to allow surfacing both the sanitized and
+ // non-sanitized variants to make without a name conflict.
+ if entries.Class == "RLIB_LIBRARIES" || entries.Class == "STATIC_LIBRARIES" {
+ if sanitize.isSanitizerEnabled(cc.Hwasan) {
+ entries.SubName += ".hwasan"
+ }
+ }
+}
+
func (mod *Module) SanitizerSupported(t cc.SanitizerType) bool {
if mod.Host() {
return false
@@ -183,6 +242,8 @@
return true
case cc.Asan:
return true
+ case cc.Hwasan:
+ return true
default:
return false
}
diff --git a/scripts/strip.sh b/scripts/strip.sh
index 43e6cbf..e3e5273 100755
--- a/scripts/strip.sh
+++ b/scripts/strip.sh
@@ -18,7 +18,6 @@
# Inputs:
# Environment:
# CLANG_BIN: path to the clang bin directory
-# CROSS_COMPILE: prefix added to readelf, objcopy tools
# XZ: path to the xz binary
# Arguments:
# -i ${file}: input file (required)
@@ -69,7 +68,7 @@
KEEP_SYMBOLS="--strip-unneeded-symbol=* --keep-symbols="
KEEP_SYMBOLS+="${outfile}.symbolList"
- "${CROSS_COMPILE}objcopy" -w "${infile}" "${outfile}.tmp" ${KEEP_SYMBOLS}
+ "${CLANG_BIN}/llvm-objcopy" -w "${infile}" "${outfile}.tmp" ${KEEP_SYMBOLS}
}
do_strip_keep_mini_debug_info() {
@@ -78,18 +77,13 @@
"${CLANG_BIN}/llvm-strip" --strip-all --keep-section=.ARM.attributes --remove-section=.comment "${infile}" -o "${outfile}.tmp" || fail=true
if [ -z $fail ]; then
- # Current prebult llvm-objcopy does not support --only-keep-debug flag,
- # and cannot process object files that are produced with the flag. Use
- # GNU objcopy instead for now. (b/141010852)
- "${CROSS_COMPILE}objcopy" --only-keep-debug "${infile}" "${outfile}.debug"
+ "${CLANG_BIN}/llvm-objcopy" --only-keep-debug "${infile}" "${outfile}.debug"
"${CLANG_BIN}/llvm-nm" -D "${infile}" --format=posix --defined-only 2> /dev/null | awk '{ print $1 }' | sort >"${outfile}.dynsyms"
"${CLANG_BIN}/llvm-nm" "${infile}" --format=posix --defined-only | awk '{ if ($2 == "T" || $2 == "t" || $2 == "D") print $1 }' | sort > "${outfile}.funcsyms"
comm -13 "${outfile}.dynsyms" "${outfile}.funcsyms" > "${outfile}.keep_symbols"
echo >> "${outfile}.keep_symbols" # Ensure that the keep_symbols file is not empty.
- "${CROSS_COMPILE}objcopy" --rename-section .debug_frame=saved_debug_frame "${outfile}.debug" "${outfile}.mini_debuginfo"
- "${CROSS_COMPILE}objcopy" -S --remove-section .gdb_index --remove-section .comment --remove-section .rustc --keep-symbols="${outfile}.keep_symbols" "${outfile}.mini_debuginfo"
- "${CROSS_COMPILE}objcopy" --rename-section saved_debug_frame=.debug_frame "${outfile}.mini_debuginfo"
- "${XZ}" --block-size=64k --threads=0 "${outfile}.mini_debuginfo"
+ "${CLANG_BIN}/llvm-objcopy" -S --keep-section .debug_frame --keep-symbols="${outfile}.keep_symbols" "${outfile}.debug" "${outfile}.mini_debuginfo"
+ "${XZ}" --keep --block-size=64k --threads=0 "${outfile}.mini_debuginfo"
"${CLANG_BIN}/llvm-objcopy" --add-section .gnu_debugdata="${outfile}.mini_debuginfo.xz" "${outfile}.tmp"
rm -f "${outfile}.dynsyms" "${outfile}.funcsyms" "${outfile}.keep_symbols" "${outfile}.debug" "${outfile}.mini_debuginfo" "${outfile}.mini_debuginfo.xz"
@@ -196,7 +190,6 @@
cat <<EOF > "${depsfile}"
${outfile}: \
${infile} \
- ${CROSS_COMPILE}objcopy \
${CLANG_BIN}/llvm-nm \
${CLANG_BIN}/llvm-objcopy \
${CLANG_BIN}/llvm-readelf \
diff --git a/bootstrap_test.sh b/tests/bootstrap_test.sh
similarity index 77%
rename from bootstrap_test.sh
rename to tests/bootstrap_test.sh
index 9d87697..b2f7b2b 100755
--- a/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -3,106 +3,13 @@
# This test exercises the bootstrapping process of the build system
# in a source tree that only contains enough files for Bazel and Soong to work.
-HARDWIRED_MOCK_TOP=
-# Uncomment this to be able to view the source tree after a test is run
-# HARDWIRED_MOCK_TOP=/tmp/td
-
-REAL_TOP="$(readlink -f "$(dirname "$0")"/../..)"
-
-function fail {
- echo ERROR: $1
- exit 1
-}
-
-function copy_directory() {
- local dir="$1"
- local parent="$(dirname "$dir")"
-
- mkdir -p "$MOCK_TOP/$parent"
- cp -R "$REAL_TOP/$dir" "$MOCK_TOP/$parent"
-}
-
-function symlink_file() {
- local file="$1"
-
- mkdir -p "$MOCK_TOP/$(dirname "$file")"
- ln -s "$REAL_TOP/$file" "$MOCK_TOP/$file"
-}
-
-function symlink_directory() {
- local dir="$1"
-
- mkdir -p "$MOCK_TOP/$dir"
- # We need to symlink the contents of the directory individually instead of
- # using one symlink for the whole directory because finder.go doesn't follow
- # symlinks when looking for Android.bp files
- for i in $(ls "$REAL_TOP/$dir"); do
- local target="$MOCK_TOP/$dir/$i"
- local source="$REAL_TOP/$dir/$i"
-
- if [[ -e "$target" ]]; then
- if [[ ! -d "$source" || ! -d "$target" ]]; then
- fail "Trying to symlink $dir twice"
- fi
- else
- ln -s "$REAL_TOP/$dir/$i" "$MOCK_TOP/$dir/$i";
- fi
- done
-}
-
-function setup_bazel() {
- copy_directory build/bazel
-
- symlink_directory prebuilts/bazel
- symlink_directory prebuilts/jdk
-
- symlink_file WORKSPACE
- symlink_file tools/bazel
-}
-
-function setup() {
- if [[ ! -z "$HARDWIRED_MOCK_TOP" ]]; then
- MOCK_TOP="$HARDWIRED_MOCK_TOP"
- rm -fr "$MOCK_TOP"
- mkdir -p "$MOCK_TOP"
- else
- MOCK_TOP=$(mktemp -t -d st.XXXXX)
- trap 'echo cd / && echo rm -fr "$MOCK_TOP"' EXIT
- fi
-
- echo "Test case: ${FUNCNAME[1]}, mock top path: $MOCK_TOP"
- cd "$MOCK_TOP"
-
- copy_directory build/blueprint
- copy_directory build/soong
-
- symlink_directory prebuilts/go
- symlink_directory prebuilts/build-tools
- symlink_directory external/golang-protobuf
-
- touch "$MOCK_TOP/Android.bp"
-
- export ALLOW_MISSING_DEPENDENCIES=true
-
- mkdir -p out/soong
-}
-
-function run_soong() {
- build/soong/soong_ui.bash --make-mode --skip-ninja --skip-make --skip-soong-tests
-}
+source "$(dirname "$0")/lib.sh"
function test_smoke {
setup
run_soong
}
-function test_bazel_smoke {
- setup
- setup_bazel
-
- tools/bazel info
-
-}
function test_null_build() {
setup
run_soong
@@ -410,7 +317,6 @@
fi
}
-test_bazel_smoke
test_smoke
test_null_build
test_null_build_after_docs
diff --git a/tests/lib.sh b/tests/lib.sh
new file mode 100644
index 0000000..3c97e14
--- /dev/null
+++ b/tests/lib.sh
@@ -0,0 +1,79 @@
+#!/bin/bash -eu
+
+HARDWIRED_MOCK_TOP=
+# Uncomment this to be able to view the source tree after a test is run
+# HARDWIRED_MOCK_TOP=/tmp/td
+
+REAL_TOP="$(readlink -f "$(dirname "$0")"/../../..)"
+
+function fail {
+ echo ERROR: $1
+ exit 1
+}
+
+function copy_directory() {
+ local dir="$1"
+ local parent="$(dirname "$dir")"
+
+ mkdir -p "$MOCK_TOP/$parent"
+ cp -R "$REAL_TOP/$dir" "$MOCK_TOP/$parent"
+}
+
+function symlink_file() {
+ local file="$1"
+
+ mkdir -p "$MOCK_TOP/$(dirname "$file")"
+ ln -s "$REAL_TOP/$file" "$MOCK_TOP/$file"
+}
+
+function symlink_directory() {
+ local dir="$1"
+
+ mkdir -p "$MOCK_TOP/$dir"
+ # We need to symlink the contents of the directory individually instead of
+ # using one symlink for the whole directory because finder.go doesn't follow
+ # symlinks when looking for Android.bp files
+ for i in $(ls "$REAL_TOP/$dir"); do
+ local target="$MOCK_TOP/$dir/$i"
+ local source="$REAL_TOP/$dir/$i"
+
+ if [[ -e "$target" ]]; then
+ if [[ ! -d "$source" || ! -d "$target" ]]; then
+ fail "Trying to symlink $dir twice"
+ fi
+ else
+ ln -s "$REAL_TOP/$dir/$i" "$MOCK_TOP/$dir/$i";
+ fi
+ done
+}
+
+function setup() {
+ if [[ ! -z "$HARDWIRED_MOCK_TOP" ]]; then
+ MOCK_TOP="$HARDWIRED_MOCK_TOP"
+ rm -fr "$MOCK_TOP"
+ mkdir -p "$MOCK_TOP"
+ else
+ MOCK_TOP=$(mktemp -t -d st.XXXXX)
+ trap 'echo cd / && echo rm -fr "$MOCK_TOP"' EXIT
+ fi
+
+ echo "Test case: ${FUNCNAME[1]}, mock top path: $MOCK_TOP"
+ cd "$MOCK_TOP"
+
+ copy_directory build/blueprint
+ copy_directory build/soong
+
+ symlink_directory prebuilts/go
+ symlink_directory prebuilts/build-tools
+ symlink_directory external/golang-protobuf
+
+ touch "$MOCK_TOP/Android.bp"
+
+ export ALLOW_MISSING_DEPENDENCIES=true
+
+ mkdir -p out/soong
+}
+
+function run_soong() {
+ build/soong/soong_ui.bash --make-mode --skip-ninja --skip-make --skip-soong-tests
+}
diff --git a/tests/mixed_mode_test.sh b/tests/mixed_mode_test.sh
new file mode 100755
index 0000000..54f0689
--- /dev/null
+++ b/tests/mixed_mode_test.sh
@@ -0,0 +1,28 @@
+#!/bin/bash -eu
+
+# This test exercises mixed builds where Soong and Bazel cooperate in building
+# Android.
+#
+# When the execroot is deleted, the Bazel server process will automatically
+# terminate itself.
+
+source "$(dirname "$0")/lib.sh"
+
+function setup_bazel() {
+ copy_directory build/bazel
+
+ symlink_directory prebuilts/bazel
+ symlink_directory prebuilts/jdk
+
+ symlink_file WORKSPACE
+ symlink_file tools/bazel
+}
+
+function test_bazel_smoke {
+ setup
+ setup_bazel
+
+ tools/bazel info
+}
+
+test_bazel_smoke
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
new file mode 100755
index 0000000..db24037
--- /dev/null
+++ b/tests/run_integration_tests.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+TOP="$(readlink -f "$(dirname "$0")"/../../..)"
+"$TOP/build/soong/tests/bootstrap_test.sh"
+"$TOP/build/soong/tests/mixed_mode_test.sh"
+