Merge changes from topic "ndk_libandroid_support_late_static_libs"
* changes:
Use LateStaticLibs for ndk_libandroid_support
Move LateStaticLibs after SharedLibs in the dependency include order
Test include directory ordering
diff --git a/Android.bp b/Android.bp
index 8f7f3e2..45e661e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -92,7 +92,7 @@
}
cc_genrule {
- name: "host_bionic_linker_flags",
+ name: "host_bionic_linker_script",
host_supported: true,
device_supported: false,
target: {
@@ -107,9 +107,9 @@
},
},
tools: ["extract_linker"],
- cmd: "$(location) -f $(out) $(in)",
+ cmd: "$(location) -T $(out) $(in)",
srcs: [":linker"],
- out: ["linker.flags"],
+ out: ["linker.script"],
}
// Instantiate the dex_bootjars singleton module.
diff --git a/android/bazel.go b/android/bazel.go
index b9d7070..992d8aa 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -218,11 +218,7 @@
// Per-module denylist to opt modules out of mixed builds. Such modules will
// still be generated via bp2build.
- mixedBuildsDisabledList = []string{
- "libc", // b/190211183, missing libbionic_Slibdl_Sliblibdl_Ubp2build_Ucc_Ulibrary_Ushared.so
- "libdl", // b/190211183, missing libbionic_Slinker_Slibld-android_Ubp2build_Ucc_Ulibrary_Ushared.so
- "libdl_android", // b/190211183, missing libbionic_Slinker_Slibld-android_Ubp2build_Ucc_Ulibrary_Ushared.so
- }
+ mixedBuildsDisabledList = []string{}
// Used for quicker lookups
bp2buildModuleDoNotConvert = map[string]bool{}
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index f906c8a..b11b474 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -542,10 +542,13 @@
platform_name = build_options(target)["//command_line_option:platforms"][0].name
if platform_name == "host":
return "HOST"
- elif not platform_name.startswith("android_"):
- fail("expected platform name of the form 'android_<arch>', but was " + str(platforms))
+ elif platform_name.startswith("android_"):
+ return platform_name[len("android_"):]
+ elif platform_name.startswith("linux_"):
+ return platform_name[len("linux_"):]
+ else:
+ fail("expected platform name of the form 'android_<arch>' or 'linux_<arch>', but was " + str(platforms))
return "UNKNOWN"
- return platform_name[len("android_"):]
def format(target):
id_string = str(target.label) + "|" + get_arch(target)
@@ -742,8 +745,17 @@
}
rule := NewRuleBuilder(pctx, ctx)
cmd := rule.Command()
- cmd.Text(fmt.Sprintf("cd %s/execroot/__main__ && %s",
- ctx.Config().BazelContext.OutputBase(), buildStatement.Command))
+
+ // cd into Bazel's execution root, which is the action cwd.
+ cmd.Text(fmt.Sprintf("cd %s/execroot/__main__ && ", ctx.Config().BazelContext.OutputBase()))
+
+ for _, pair := range buildStatement.Env {
+ // Set per-action env variables, if any.
+ cmd.Flag(pair.Key + "=" + pair.Value)
+ }
+
+ // The actual Bazel action.
+ cmd.Text(" " + buildStatement.Command)
for _, outputPath := range buildStatement.OutputPaths {
cmd.ImplicitOutput(PathForBazelOut(ctx, outputPath))
@@ -756,6 +768,10 @@
cmd.ImplicitDepFile(PathForBazelOut(ctx, *depfile))
}
+ for _, symlinkPath := range buildStatement.SymlinkPaths {
+ cmd.ImplicitSymlinkOutput(PathForBazelOut(ctx, symlinkPath))
+ }
+
// This is required to silence warnings pertaining to unexpected timestamps. Particularly,
// some Bazel builtins (such as files in the bazel_tools directory) have far-future
// timestamps. Without restat, Ninja would emit warnings that the input files of a
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
index f93fe2b..f74fed1 100644
--- a/android/bazel_paths.go
+++ b/android/bazel_paths.go
@@ -83,6 +83,36 @@
// or ":<module>") and returns a Bazel-compatible label which corresponds to dependencies on the
// module within the given ctx.
func BazelLabelForModuleDeps(ctx BazelConversionPathContext, modules []string) bazel.LabelList {
+ return bazelLabelForModuleDeps(ctx, modules, false)
+}
+
+// BazelLabelForModuleWholeDeps expects a list of references to other modules, ("<module>"
+// or ":<module>") and returns a Bazel-compatible label which corresponds to dependencies on the
+// module within the given ctx, where prebuilt dependencies will be appended with _alwayslink so
+// they can be handled as whole static libraries.
+func BazelLabelForModuleWholeDeps(ctx BazelConversionPathContext, modules []string) bazel.LabelList {
+ return bazelLabelForModuleDeps(ctx, modules, true)
+}
+
+// BazelLabelForModuleDepsExcludes expects two lists: modules (containing modules to include in the
+// list), and excludes (modules to exclude from the list). Both of these should contain references
+// to other modules, ("<module>" or ":<module>"). It returns a Bazel-compatible label list which
+// corresponds to dependencies on the module within the given ctx, and the excluded dependencies.
+func BazelLabelForModuleDepsExcludes(ctx BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
+ return bazelLabelForModuleDepsExcludes(ctx, modules, excludes, false)
+}
+
+// BazelLabelForModuleWholeDepsExcludes expects two lists: modules (containing modules to include in
+// the list), and excludes (modules to exclude from the list). Both of these should contain
+// references to other modules, ("<module>" or ":<module>"). It returns a Bazel-compatible label
+// list which corresponds to dependencies on the module within the given ctx, and the excluded
+// dependencies. Prebuilt dependencies will be appended with _alwayslink so they can be handled as
+// whole static libraries.
+func BazelLabelForModuleWholeDepsExcludes(ctx BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
+ return bazelLabelForModuleDepsExcludes(ctx, modules, excludes, true)
+}
+
+func bazelLabelForModuleDeps(ctx BazelConversionPathContext, modules []string, isWholeLibs bool) bazel.LabelList {
var labels bazel.LabelList
for _, module := range modules {
bpText := module
@@ -90,7 +120,7 @@
module = ":" + module
}
if m, t := SrcIsModuleWithTag(module); m != "" {
- l := getOtherModuleLabel(ctx, m, t)
+ l := getOtherModuleLabel(ctx, m, t, isWholeLibs)
l.OriginalModuleName = bpText
labels.Includes = append(labels.Includes, l)
} else {
@@ -100,16 +130,12 @@
return labels
}
-// BazelLabelForModuleDeps expects two lists: modules (containing modules to include in the list),
-// and excludes (modules to exclude from the list). Both of these should contain references to other
-// modules, ("<module>" or ":<module>"). It returns a Bazel-compatible label list which corresponds
-// to dependencies on the module within the given ctx, and the excluded dependencies.
-func BazelLabelForModuleDepsExcludes(ctx BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
- moduleLabels := BazelLabelForModuleDeps(ctx, RemoveListFromList(modules, excludes))
+func bazelLabelForModuleDepsExcludes(ctx BazelConversionPathContext, modules, excludes []string, isWholeLibs bool) bazel.LabelList {
+ moduleLabels := bazelLabelForModuleDeps(ctx, RemoveListFromList(modules, excludes), isWholeLibs)
if len(excludes) == 0 {
return moduleLabels
}
- excludeLabels := BazelLabelForModuleDeps(ctx, excludes)
+ excludeLabels := bazelLabelForModuleDeps(ctx, excludes, isWholeLibs)
return bazel.LabelList{
Includes: moduleLabels.Includes,
Excludes: excludeLabels.Includes,
@@ -273,7 +299,7 @@
for _, p := range paths {
if m, tag := SrcIsModuleWithTag(p); m != "" {
- l := getOtherModuleLabel(ctx, m, tag)
+ l := getOtherModuleLabel(ctx, m, tag, false)
if !InList(l.Label, expandedExcludes) {
l.OriginalModuleName = fmt.Sprintf(":%s", m)
labels.Includes = append(labels.Includes, l)
@@ -304,7 +330,7 @@
// getOtherModuleLabel returns a bazel.Label for the given dependency/tag combination for the
// module. The label will be relative to the current directory if appropriate. The dependency must
// already be resolved by either deps mutator or path deps mutator.
-func getOtherModuleLabel(ctx BazelConversionPathContext, dep, tag string) bazel.Label {
+func getOtherModuleLabel(ctx BazelConversionPathContext, dep, tag string, isWholeLibs bool) bazel.Label {
m, _ := ctx.GetDirectDep(dep)
if m == nil {
panic(fmt.Errorf(`Cannot get direct dep %q of %q.
@@ -313,6 +339,11 @@
}
otherLabel := bazelModuleLabel(ctx, m, tag)
label := bazelModuleLabel(ctx, ctx.Module(), "")
+ if isWholeLibs {
+ if m, ok := m.(Module); ok && IsModulePrebuilt(m) {
+ otherLabel += "_alwayslink"
+ }
+ }
if samePackage(label, otherLabel) {
otherLabel = bazelShortLabel(otherLabel)
}
diff --git a/android/config.go b/android/config.go
index da78c7a..ed90c31 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1690,6 +1690,16 @@
return paths
}
+// BuildPathsByModule returns a map from module name to build paths based on the given directory
+// prefix.
+func (l *ConfiguredJarList) BuildPathsByModule(ctx PathContext, dir OutputPath) map[string]WritablePath {
+ paths := map[string]WritablePath{}
+ for _, jar := range l.jars {
+ paths[jar] = dir.Join(ctx, ModuleStem(jar)+".jar")
+ }
+ return paths
+}
+
// UnmarshalJSON converts JSON configuration from raw bytes into a
// ConfiguredJarList structure.
func (l *ConfiguredJarList) UnmarshalJSON(b []byte) error {
diff --git a/android/image.go b/android/image.go
index 66101be..bc6b8cd 100644
--- a/android/image.go
+++ b/android/image.go
@@ -43,10 +43,9 @@
// its variation.
ExtraImageVariations(ctx BaseModuleContext) []string
- // SetImageVariation will be passed a newly created recovery variant of the module. ModuleBase implements
- // SetImageVariation, most module types will not need to override it, and those that do must call the
- // overridden method. Implementors of SetImageVariation must be careful to modify the module argument
- // and not the receiver.
+ // SetImageVariation is called for each newly created image variant. The receiver is the original
+ // module, "variation" is the name of the newly created variant and "module" is the newly created
+ // variant itself.
SetImageVariation(ctx BaseModuleContext, variation string, module Module)
}
diff --git a/android/testing.go b/android/testing.go
index 191cb8d..b36f62c 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -713,9 +713,11 @@
func (b baseTestingComponent) maybeBuildParamsFromRule(rule string) (TestingBuildParams, []string) {
var searchedRules []string
- for _, p := range b.provider.BuildParamsForTests() {
- searchedRules = append(searchedRules, p.Rule.String())
- if strings.Contains(p.Rule.String(), rule) {
+ buildParams := b.provider.BuildParamsForTests()
+ for _, p := range buildParams {
+ ruleAsString := p.Rule.String()
+ searchedRules = append(searchedRules, ruleAsString)
+ if strings.Contains(ruleAsString, rule) {
return b.newTestingBuildParams(p), searchedRules
}
}
@@ -725,7 +727,7 @@
func (b baseTestingComponent) buildParamsFromRule(rule string) TestingBuildParams {
p, searchRules := b.maybeBuildParamsFromRule(rule)
if p.Rule == nil {
- panic(fmt.Errorf("couldn't find rule %q.\nall rules: %v", rule, searchRules))
+ panic(fmt.Errorf("couldn't find rule %q.\nall rules:\n%s", rule, strings.Join(searchRules, "\n")))
}
return p
}
diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go
index 5316d7b..08616a9 100644
--- a/androidmk/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -104,6 +104,7 @@
"LOCAL_NDK_STL_VARIANT": "stl",
"LOCAL_JAR_MANIFEST": "manifest",
"LOCAL_CERTIFICATE": "certificate",
+ "LOCAL_CERTIFICATE_LINEAGE": "lineage",
"LOCAL_PACKAGE_NAME": "name",
"LOCAL_MODULE_RELATIVE_PATH": "relative_install_path",
"LOCAL_PROTOC_OPTIMIZE_TYPE": "proto.type",
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index 439f45d..067dcba 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -1463,6 +1463,22 @@
}
`,
},
+ {
+ desc: "LOCAL_CERTIFICATE_LINEAGE",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_TAGS := tests
+LOCAL_CERTIFICATE_LINEAGE := lineage
+include $(BUILD_PACKAGE)
+`,
+ expected: `
+android_test {
+ name: "foo",
+ lineage: "lineage",
+}
+`,
+ },
}
func TestEndToEnd(t *testing.T) {
diff --git a/apex/apex.go b/apex/apex.go
index 926085b..33b83c0 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -170,9 +170,10 @@
// Default is false.
Ignore_system_library_special_case *bool
- // Whenever apex_payload.img of the APEX should include dm-verity hashtree. Should be only
- // used in tests.
- Test_only_no_hashtree *bool
+ // Whenever apex_payload.img of the APEX should include dm-verity hashtree.
+ // Default value is false.
+ // TODO(b/190621617): change default value to true.
+ Generate_hashtree *bool
// Whenever apex_payload.img of the APEX should not be dm-verity signed. Should be only
// used in tests.
@@ -1317,9 +1318,9 @@
return !a.properties.PreventInstall && (a.properties.Installable == nil || proptools.Bool(a.properties.Installable))
}
-// See the test_only_no_hashtree property
-func (a *apexBundle) testOnlyShouldSkipHashtreeGeneration() bool {
- return proptools.Bool(a.properties.Test_only_no_hashtree)
+// See the generate_hashtree property
+func (a *apexBundle) shouldGenerateHashtree() bool {
+ return proptools.BoolDefault(a.properties.Generate_hashtree, false)
}
// See the test_only_unsigned_payload property
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 6a7c35c..1bfe7e9 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -4769,7 +4769,7 @@
// prebuilt_apex module always depends on the prebuilt, and so it doesn't
// find the dex boot jar in it. We either need to disable the source libfoo
// or make the prebuilt libfoo preferred.
- testDexpreoptWithApexes(t, bp, "failed to find a dex jar path for module 'libfoo'", preparer)
+ testDexpreoptWithApexes(t, bp, "module libfoo does not provide a dex boot jar", preparer)
})
t.Run("prebuilt library preferred with source", func(t *testing.T) {
diff --git a/apex/builder.go b/apex/builder.go
index 021e499..24c049b 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -630,11 +630,7 @@
optFlags = append(optFlags, "--assets_dir "+filepath.Dir(a.mergedNotices.HtmlGzOutput.String()))
}
- if ctx.ModuleDir() != "system/apex/apexd/apexd_testdata" && ctx.ModuleDir() != "system/apex/shim/build" && a.testOnlyShouldSkipHashtreeGeneration() {
- ctx.PropertyErrorf("test_only_no_hashtree", "not available")
- return
- }
- if (moduleMinSdkVersion.GreaterThan(android.SdkVersion_Android10) || a.testOnlyShouldSkipHashtreeGeneration()) && !compressionEnabled {
+ if (moduleMinSdkVersion.GreaterThan(android.SdkVersion_Android10) && !a.shouldGenerateHashtree()) && !compressionEnabled {
// Apexes which are supposed to be installed in builtin dirs(/system, etc)
// don't need hashtree for activation. Therefore, by removing hashtree from
// apex bundle (filesystem image in it, to be specific), we can save storage.
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index ce12f46..7297926 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -15,6 +15,8 @@
package apex
import (
+ "fmt"
+ "strings"
"testing"
"android/soong/android"
@@ -31,6 +33,139 @@
PrepareForTestWithApexBuildComponents,
)
+func TestPlatformBootclasspath_Fragments(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ prepareForTestWithMyapex,
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.FixtureWithLastReleaseApis("foo"),
+ java.FixtureConfigureBootJars("myapex:bar"),
+ android.FixtureWithRootAndroidBp(`
+ platform_bootclasspath {
+ name: "platform-bootclasspath",
+ fragments: [
+ {
+ apex: "myapex",
+ module:"bar-fragment",
+ },
+ ],
+ hidden_api: {
+ unsupported: [
+ "unsupported.txt",
+ ],
+ removed: [
+ "removed.txt",
+ ],
+ max_target_r_low_priority: [
+ "max-target-r-low-priority.txt",
+ ],
+ max_target_q: [
+ "max-target-q.txt",
+ ],
+ max_target_p: [
+ "max-target-p.txt",
+ ],
+ max_target_o_low_priority: [
+ "max-target-o-low-priority.txt",
+ ],
+ blocked: [
+ "blocked.txt",
+ ],
+ unsupported_packages: [
+ "unsupported-packages.txt",
+ ],
+ },
+ }
+
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ bootclasspath_fragments: [
+ "bar-fragment",
+ ],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ bootclasspath_fragment {
+ name: "bar-fragment",
+ contents: ["bar"],
+ apex_available: ["myapex"],
+ api: {
+ stub_libs: ["foo"],
+ },
+ hidden_api: {
+ unsupported: [
+ "bar-unsupported.txt",
+ ],
+ removed: [
+ "bar-removed.txt",
+ ],
+ max_target_r_low_priority: [
+ "bar-max-target-r-low-priority.txt",
+ ],
+ max_target_q: [
+ "bar-max-target-q.txt",
+ ],
+ max_target_p: [
+ "bar-max-target-p.txt",
+ ],
+ max_target_o_low_priority: [
+ "bar-max-target-o-low-priority.txt",
+ ],
+ blocked: [
+ "bar-blocked.txt",
+ ],
+ unsupported_packages: [
+ "bar-unsupported-packages.txt",
+ ],
+ },
+ }
+
+ java_library {
+ name: "bar",
+ apex_available: ["myapex"],
+ srcs: ["a.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ permitted_packages: ["bar"],
+ }
+
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ public: {
+ enabled: true,
+ },
+ compile_dex: true,
+ }
+ `),
+ ).RunTest(t)
+
+ pbcp := result.Module("platform-bootclasspath", "android_common")
+ info := result.ModuleProvider(pbcp, java.MonolithicHiddenAPIInfoProvider).(java.MonolithicHiddenAPIInfo)
+
+ for _, category := range java.HiddenAPIFlagFileCategories {
+ name := category.PropertyName
+ message := fmt.Sprintf("category %s", name)
+ filename := strings.ReplaceAll(name, "_", "-")
+ expected := []string{fmt.Sprintf("%s.txt", filename), fmt.Sprintf("bar-%s.txt", filename)}
+ android.AssertPathsRelativeToTopEquals(t, message, expected, info.FlagsFilesByCategory[category])
+ }
+
+ android.AssertPathsRelativeToTopEquals(t, "stub flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/stub-flags.csv"}, info.StubFlagsPaths)
+ android.AssertPathsRelativeToTopEquals(t, "annotation flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/annotation-flags.csv"}, info.AnnotationFlagsPaths)
+ android.AssertPathsRelativeToTopEquals(t, "metadata flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/metadata.csv"}, info.MetadataPaths)
+ android.AssertPathsRelativeToTopEquals(t, "index flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/index.csv"}, info.IndexPaths)
+ android.AssertPathsRelativeToTopEquals(t, "all flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/all-flags.csv"}, info.AllFlagsPaths)
+}
+
func TestPlatformBootclasspathDependencies(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForTestWithPlatformBootclasspath,
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 81bfc86..4e89883 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -47,21 +47,47 @@
}
type prebuiltCommon struct {
+ android.ModuleBase
prebuilt android.Prebuilt
// Properties common to both prebuilt_apex and apex_set.
- prebuiltCommonProperties prebuiltCommonProperties
+ prebuiltCommonProperties *PrebuiltCommonProperties
+
+ installDir android.InstallPath
+ installFilename string
+ outputApex android.WritablePath
+
+ // list of commands to create symlinks for backward compatibility.
+ // these commands will be attached as LOCAL_POST_INSTALL_CMD
+ compatSymlinks []string
+
+ hostRequired []string
+ postInstallCommands []string
}
type sanitizedPrebuilt interface {
hasSanitizedSource(sanitizer string) bool
}
-type prebuiltCommonProperties struct {
+type PrebuiltCommonProperties struct {
SelectedApexProperties
ForceDisable bool `blueprint:"mutated"`
+ // whether the extracted apex file is installable.
+ Installable *bool
+
+ // optional name for the installed apex. If unspecified, name of the
+ // module is used as the file name
+ Filename *string
+
+ // names of modules to be overridden. Listed modules can only be other binaries
+ // (in Make or Soong).
+ // This does not completely prevent installation of the overridden binaries, but if both
+ // binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
+ // from PRODUCT_PACKAGES.
+ Overrides []string
+
// List of java libraries that are embedded inside this prebuilt APEX bundle and for which this
// APEX bundle will create an APEX variant and provide dex implementation jars for use by
// dexpreopt and boot jars package check.
@@ -72,6 +98,14 @@
Exported_bootclasspath_fragments []string
}
+// initPrebuiltCommon initializes the prebuiltCommon structure and performs initialization of the
+// module that is common to Prebuilt and ApexSet.
+func (p *prebuiltCommon) initPrebuiltCommon(module android.Module, properties *PrebuiltCommonProperties) {
+ p.prebuiltCommonProperties = properties
+ android.InitSingleSourcePrebuiltModule(module.(android.PrebuiltInterface), properties, "Selected_apex")
+ android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
+}
+
func (p *prebuiltCommon) Prebuilt() *android.Prebuilt {
return &p.prebuilt
}
@@ -105,6 +139,46 @@
return false
}
+func (p *prebuiltCommon) InstallFilename() string {
+ return proptools.StringDefault(p.prebuiltCommonProperties.Filename, p.BaseModuleName()+imageApexSuffix)
+}
+
+func (p *prebuiltCommon) Name() string {
+ return p.prebuilt.Name(p.ModuleBase.Name())
+}
+
+func (p *prebuiltCommon) Overrides() []string {
+ return p.prebuiltCommonProperties.Overrides
+}
+
+func (p *prebuiltCommon) installable() bool {
+ return proptools.BoolDefault(p.prebuiltCommonProperties.Installable, true)
+}
+
+func (p *prebuiltCommon) AndroidMkEntries() []android.AndroidMkEntries {
+ return []android.AndroidMkEntries{
+ {
+ Class: "ETC",
+ OutputFile: android.OptionalPathForPath(p.outputApex),
+ Include: "$(BUILD_PREBUILT)",
+ Host_required: p.hostRequired,
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_MODULE_PATH", p.installDir.ToMakePath().String())
+ entries.SetString("LOCAL_MODULE_STEM", p.installFilename)
+ entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !p.installable())
+ entries.AddStrings("LOCAL_OVERRIDES_MODULES", p.prebuiltCommonProperties.Overrides...)
+ postInstallCommands := append([]string{}, p.postInstallCommands...)
+ postInstallCommands = append(postInstallCommands, p.compatSymlinks...)
+ if len(postInstallCommands) > 0 {
+ entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(postInstallCommands, " && "))
+ }
+ },
+ },
+ },
+ }
+}
+
// prebuiltApexModuleCreator defines the methods that need to be implemented by prebuilt_apex and
// apex_set in order to create the modules needed to provide access to the prebuilt .apex file.
type prebuiltApexModuleCreator interface {
@@ -272,19 +346,11 @@
}
type Prebuilt struct {
- android.ModuleBase
prebuiltCommon
properties PrebuiltProperties
- inputApex android.Path
- installDir android.InstallPath
- installFilename string
- outputApex android.WritablePath
-
- // list of commands to create symlinks for backward compatibility.
- // these commands will be attached as LOCAL_POST_INSTALL_CMD
- compatSymlinks []string
+ inputApex android.Path
}
type ApexFileProperties struct {
@@ -349,27 +415,13 @@
type PrebuiltProperties struct {
ApexFileProperties
- Installable *bool
- // Optional name for the installed apex. If unspecified, name of the
- // module is used as the file name
- Filename *string
-
- // Names of modules to be overridden. Listed modules can only be other binaries
- // (in Make or Soong).
- // This does not completely prevent installation of the overridden binaries, but if both
- // binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
- // from PRODUCT_PACKAGES.
- Overrides []string
+ PrebuiltCommonProperties
}
func (a *Prebuilt) hasSanitizedSource(sanitizer string) bool {
return false
}
-func (p *Prebuilt) installable() bool {
- return p.properties.Installable == nil || proptools.Bool(p.properties.Installable)
-}
-
func (p *Prebuilt) OutputFiles(tag string) (android.Paths, error) {
switch tag {
case "":
@@ -379,20 +431,11 @@
}
}
-func (p *Prebuilt) InstallFilename() string {
- return proptools.StringDefault(p.properties.Filename, p.BaseModuleName()+imageApexSuffix)
-}
-
-func (p *Prebuilt) Name() string {
- return p.prebuiltCommon.prebuilt.Name(p.ModuleBase.Name())
-}
-
// prebuilt_apex imports an `.apex` file into the build graph as if it was built with apex.
func PrebuiltFactory() android.Module {
module := &Prebuilt{}
- module.AddProperties(&module.properties, &module.prebuiltCommonProperties)
- android.InitSingleSourcePrebuiltModule(module, &module.prebuiltCommonProperties, "Selected_apex")
- android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ module.AddProperties(&module.properties)
+ module.initPrebuiltCommon(module, &module.properties.PrebuiltCommonProperties)
return module
}
@@ -415,7 +458,7 @@
// A deapexer module is only needed when the prebuilt apex specifies one or more modules in either
// the `exported_java_libs` or `exported_bootclasspath_fragments` properties as that indicates that
// the listed modules need access to files from within the prebuilt .apex file.
-func createDeapexerModuleIfNeeded(ctx android.TopDownMutatorContext, deapexerName string, apexFileSource string, properties *prebuiltCommonProperties) {
+func createDeapexerModuleIfNeeded(ctx android.TopDownMutatorContext, deapexerName string, apexFileSource string, properties *PrebuiltCommonProperties) {
// Only create the deapexer module if it is needed.
if len(properties.Exported_java_libs)+len(properties.Exported_bootclasspath_fragments) == 0 {
return
@@ -556,7 +599,7 @@
createApexSelectorModule(ctx, apexSelectorModuleName, &p.properties.ApexFileProperties)
apexFileSource := ":" + apexSelectorModuleName
- createDeapexerModuleIfNeeded(ctx, deapexerModuleName(baseModuleName), apexFileSource, &p.prebuiltCommonProperties)
+ createDeapexerModuleIfNeeded(ctx, deapexerModuleName(baseModuleName), apexFileSource, p.prebuiltCommonProperties)
// Add a source reference to retrieve the selected apex from the selector module.
p.prebuiltCommonProperties.Selected_apex = proptools.StringPtr(apexFileSource)
@@ -599,30 +642,11 @@
// in case that prebuilt_apex replaces source apex (using prefer: prop)
p.compatSymlinks = makeCompatSymlinks(p.BaseModuleName(), ctx)
// or that prebuilt_apex overrides other apexes (using overrides: prop)
- for _, overridden := range p.properties.Overrides {
+ for _, overridden := range p.prebuiltCommonProperties.Overrides {
p.compatSymlinks = append(p.compatSymlinks, makeCompatSymlinks(overridden, ctx)...)
}
}
-func (p *Prebuilt) AndroidMkEntries() []android.AndroidMkEntries {
- return []android.AndroidMkEntries{android.AndroidMkEntries{
- Class: "ETC",
- OutputFile: android.OptionalPathForPath(p.inputApex),
- Include: "$(BUILD_PREBUILT)",
- ExtraEntries: []android.AndroidMkExtraEntriesFunc{
- func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_PATH", p.installDir.ToMakePath().String())
- entries.SetString("LOCAL_MODULE_STEM", p.installFilename)
- entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !p.installable())
- entries.AddStrings("LOCAL_OVERRIDES_MODULES", p.properties.Overrides...)
- if len(p.compatSymlinks) > 0 {
- entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(p.compatSymlinks, " && "))
- }
- },
- },
- }}
-}
-
// 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 {
@@ -667,21 +691,9 @@
}
type ApexSet struct {
- android.ModuleBase
prebuiltCommon
properties ApexSetProperties
-
- installDir android.InstallPath
- installFilename string
- outputApex android.WritablePath
-
- // list of commands to create symlinks for backward compatibility.
- // these commands will be attached as LOCAL_POST_INSTALL_CMD
- compatSymlinks []string
-
- hostRequired []string
- postInstallCommands []string
}
type ApexExtractorProperties struct {
@@ -731,19 +743,7 @@
type ApexSetProperties struct {
ApexExtractorProperties
- // whether the extracted apex file installable.
- Installable *bool
-
- // optional name for the installed apex. If unspecified, name of the
- // module is used as the file name
- Filename *string
-
- // names of modules to be overridden. Listed modules can only be other binaries
- // (in Make or Soong).
- // This does not completely prevent installation of the overridden binaries, but if both
- // binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
- // from PRODUCT_PACKAGES.
- Overrides []string
+ PrebuiltCommonProperties
}
func (a *ApexSet) hasSanitizedSource(sanitizer string) bool {
@@ -757,29 +757,11 @@
return false
}
-func (a *ApexSet) installable() bool {
- return a.properties.Installable == nil || proptools.Bool(a.properties.Installable)
-}
-
-func (a *ApexSet) InstallFilename() string {
- return proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+imageApexSuffix)
-}
-
-func (a *ApexSet) Name() string {
- return a.prebuiltCommon.prebuilt.Name(a.ModuleBase.Name())
-}
-
-func (a *ApexSet) Overrides() []string {
- return a.properties.Overrides
-}
-
// 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.prebuiltCommonProperties)
-
- android.InitSingleSourcePrebuiltModule(module, &module.prebuiltCommonProperties, "Selected_apex")
- android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ module.AddProperties(&module.properties)
+ module.initPrebuiltCommon(module, &module.properties.PrebuiltCommonProperties)
return module
}
@@ -817,7 +799,7 @@
createApexExtractorModule(ctx, apexExtractorModuleName, &a.properties.ApexExtractorProperties)
apexFileSource := ":" + apexExtractorModuleName
- createDeapexerModuleIfNeeded(ctx, deapexerModuleName(baseModuleName), apexFileSource, &a.prebuiltCommonProperties)
+ createDeapexerModuleIfNeeded(ctx, deapexerModuleName(baseModuleName), apexFileSource, a.prebuiltCommonProperties)
// After passing the arch specific src properties to the creating the apex selector module
a.prebuiltCommonProperties.Selected_apex = proptools.StringPtr(apexFileSource)
@@ -860,7 +842,7 @@
// in case that apex_set replaces source apex (using prefer: prop)
a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx)
// or that apex_set overrides other apexes (using overrides: prop)
- for _, overridden := range a.properties.Overrides {
+ for _, overridden := range a.prebuiltCommonProperties.Overrides {
a.compatSymlinks = append(a.compatSymlinks, makeCompatSymlinks(overridden, ctx)...)
}
@@ -883,25 +865,3 @@
func (*systemExtContext) SystemExtSpecific() bool {
return true
}
-
-func (a *ApexSet) AndroidMkEntries() []android.AndroidMkEntries {
- return []android.AndroidMkEntries{android.AndroidMkEntries{
- Class: "ETC",
- OutputFile: android.OptionalPathForPath(a.outputApex),
- Include: "$(BUILD_PREBUILT)",
- Host_required: a.hostRequired,
- ExtraEntries: []android.AndroidMkExtraEntriesFunc{
- func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_PATH", a.installDir.ToMakePath().String())
- entries.SetString("LOCAL_MODULE_STEM", a.installFilename)
- entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !a.installable())
- entries.AddStrings("LOCAL_OVERRIDES_MODULES", a.properties.Overrides...)
- postInstallCommands := append([]string{}, a.postInstallCommands...)
- postInstallCommands = append(postInstallCommands, a.compatSymlinks...)
- if len(postInstallCommands) > 0 {
- entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(postInstallCommands, " && "))
- }
- },
- },
- }}
-}
diff --git a/bazel/aquery.go b/bazel/aquery.go
index d1119cb..8741afb 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -73,12 +73,13 @@
// BuildStatement contains information to register a build statement corresponding (one to one)
// with a Bazel action from Bazel's action graph.
type BuildStatement struct {
- Command string
- Depfile *string
- OutputPaths []string
- InputPaths []string
- Env []KeyValuePair
- Mnemonic string
+ Command string
+ Depfile *string
+ OutputPaths []string
+ InputPaths []string
+ SymlinkPaths []string
+ Env []KeyValuePair
+ Mnemonic string
}
// A helper type for aquery processing which facilitates retrieval of path IDs from their
@@ -234,10 +235,21 @@
OutputPaths: outputPaths,
InputPaths: inputPaths,
Env: actionEntry.EnvironmentVariables,
- Mnemonic: actionEntry.Mnemonic}
- if len(actionEntry.Arguments) < 1 {
+ Mnemonic: actionEntry.Mnemonic,
+ }
+
+ if isSymlinkAction(actionEntry) {
+ if len(inputPaths) != 1 || len(outputPaths) != 1 {
+ return nil, fmt.Errorf("Expect 1 input and 1 output to symlink action, got: input %q, output %q", inputPaths, outputPaths)
+ }
+ out := outputPaths[0]
+ outDir := proptools.ShellEscapeIncludingSpaces(filepath.Dir(out))
+ out = proptools.ShellEscapeIncludingSpaces(out)
+ in := proptools.ShellEscapeIncludingSpaces(inputPaths[0])
+ buildStatement.Command = fmt.Sprintf("mkdir -p %[1]s && rm -f %[2]s && ln -rsf %[3]s %[2]s", outDir, out, in)
+ buildStatement.SymlinkPaths = outputPaths[:]
+ } else if len(actionEntry.Arguments) < 1 {
return nil, fmt.Errorf("received action with no command: [%v]", buildStatement)
- continue
}
buildStatements = append(buildStatements, buildStatement)
}
@@ -245,9 +257,13 @@
return buildStatements, nil
}
+func isSymlinkAction(a action) bool {
+ return a.Mnemonic == "Symlink" || a.Mnemonic == "SolibSymlink"
+}
+
func shouldSkipAction(a action) bool {
- // TODO(b/180945121): Handle symlink actions.
- if a.Mnemonic == "Symlink" || a.Mnemonic == "SourceSymlinkManifest" || a.Mnemonic == "SymlinkTree" || a.Mnemonic == "SolibSymlink" {
+ // TODO(b/180945121): Handle complex symlink actions.
+ if a.Mnemonic == "SymlinkTree" || a.Mnemonic == "SourceSymlinkManifest" {
return true
}
// Middleman actions are not handled like other actions; they are handled separately as a
@@ -278,6 +294,9 @@
return "", fmt.Errorf("undefined path fragment id %d", currId)
}
labels = append([]string{currFragment.Label}, labels...)
+ if currId == currFragment.ParentId {
+ return "", fmt.Errorf("Fragment cannot refer to itself as parent %#v", currFragment)
+ }
currId = currFragment.ParentId
}
return filepath.Join(labels...), nil
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index 7b40dcd..43e4155 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -805,17 +805,229 @@
}
}
+func TestSimpleSymlink(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [{
+ "id": 1,
+ "pathFragmentId": 3
+ }, {
+ "id": 2,
+ "pathFragmentId": 5
+ }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "Symlink",
+ "inputDepSetIds": [1],
+ "outputIds": [2],
+ "primaryOutputId": 2
+ }],
+ "depSetOfFiles": [{
+ "id": 1,
+ "directArtifactIds": [1]
+ }],
+ "pathFragments": [{
+ "id": 1,
+ "label": "one"
+ }, {
+ "id": 2,
+ "label": "file_subdir",
+ "parentId": 1
+ }, {
+ "id": 3,
+ "label": "file",
+ "parentId": 2
+ }, {
+ "id": 4,
+ "label": "symlink_subdir",
+ "parentId": 1
+ }, {
+ "id": 5,
+ "label": "symlink",
+ "parentId": 4
+ }]
+}`
+
+ actual, err := AqueryBuildStatements([]byte(inputString))
+
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
+ }
+
+ expectedBuildStatements := []BuildStatement{
+ BuildStatement{
+ Command: "mkdir -p one/symlink_subdir && " +
+ "rm -f one/symlink_subdir/symlink && " +
+ "ln -rsf one/file_subdir/file one/symlink_subdir/symlink",
+ InputPaths: []string{"one/file_subdir/file"},
+ OutputPaths: []string{"one/symlink_subdir/symlink"},
+ SymlinkPaths: []string{"one/symlink_subdir/symlink"},
+ Mnemonic: "Symlink",
+ },
+ }
+ assertBuildStatements(t, actual, expectedBuildStatements)
+}
+
+func TestSymlinkQuotesPaths(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [{
+ "id": 1,
+ "pathFragmentId": 3
+ }, {
+ "id": 2,
+ "pathFragmentId": 5
+ }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "SolibSymlink",
+ "inputDepSetIds": [1],
+ "outputIds": [2],
+ "primaryOutputId": 2
+ }],
+ "depSetOfFiles": [{
+ "id": 1,
+ "directArtifactIds": [1]
+ }],
+ "pathFragments": [{
+ "id": 1,
+ "label": "one"
+ }, {
+ "id": 2,
+ "label": "file subdir",
+ "parentId": 1
+ }, {
+ "id": 3,
+ "label": "file",
+ "parentId": 2
+ }, {
+ "id": 4,
+ "label": "symlink subdir",
+ "parentId": 1
+ }, {
+ "id": 5,
+ "label": "symlink",
+ "parentId": 4
+ }]
+}`
+
+ actual, err := AqueryBuildStatements([]byte(inputString))
+
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
+ }
+
+ expectedBuildStatements := []BuildStatement{
+ BuildStatement{
+ Command: "mkdir -p 'one/symlink subdir' && " +
+ "rm -f 'one/symlink subdir/symlink' && " +
+ "ln -rsf 'one/file subdir/file' 'one/symlink subdir/symlink'",
+ InputPaths: []string{"one/file subdir/file"},
+ OutputPaths: []string{"one/symlink subdir/symlink"},
+ SymlinkPaths: []string{"one/symlink subdir/symlink"},
+ Mnemonic: "SolibSymlink",
+ },
+ }
+ assertBuildStatements(t, actual, expectedBuildStatements)
+}
+
+func TestSymlinkMultipleInputs(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [{
+ "id": 1,
+ "pathFragmentId": 1
+ }, {
+ "id": 2,
+ "pathFragmentId": 2
+ }, {
+ "id": 3,
+ "pathFragmentId": 3
+ }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "Symlink",
+ "inputDepSetIds": [1],
+ "outputIds": [3],
+ "primaryOutputId": 3
+ }],
+ "depSetOfFiles": [{
+ "id": 1,
+ "directArtifactIds": [1,2]
+ }],
+ "pathFragments": [{
+ "id": 1,
+ "label": "file"
+ }, {
+ "id": 2,
+ "label": "other_file"
+ }, {
+ "id": 3,
+ "label": "symlink"
+ }]
+}`
+
+ _, err := AqueryBuildStatements([]byte(inputString))
+ assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file" "other_file"], output ["symlink"]`)
+}
+
+func TestSymlinkMultipleOutputs(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [{
+ "id": 1,
+ "pathFragmentId": 1
+ }, {
+ "id": 2,
+ "pathFragmentId": 2
+ }, {
+ "id": 3,
+ "pathFragmentId": 3
+ }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "Symlink",
+ "inputDepSetIds": [1],
+ "outputIds": [2,3],
+ "primaryOutputId": 2
+ }],
+ "depSetOfFiles": [{
+ "id": 1,
+ "directArtifactIds": [1]
+ }],
+ "pathFragments": [{
+ "id": 1,
+ "label": "file"
+ }, {
+ "id": 2,
+ "label": "symlink"
+ }, {
+ "id": 3,
+ "label": "other_symlink"
+ }]
+}`
+
+ _, err := AqueryBuildStatements([]byte(inputString))
+ assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file"], output ["symlink" "other_symlink"]`)
+}
+
func assertError(t *testing.T, err error, expected string) {
+ t.Helper()
if err == nil {
t.Errorf("expected error '%s', but got no error", expected)
} else if err.Error() != expected {
- t.Errorf("expected error '%s', but got: %s", expected, err.Error())
+ t.Errorf("expected error:\n\t'%s', but got:\n\t'%s'", expected, err.Error())
}
}
// Asserts that the given actual build statements match the given expected build statements.
// Build statement equivalence is determined using buildStatementEquals.
func assertBuildStatements(t *testing.T, expected []BuildStatement, actual []BuildStatement) {
+ t.Helper()
if len(expected) != len(actual) {
t.Errorf("expected %d build statements, but got %d,\n expected: %v,\n actual: %v",
len(expected), len(actual), expected, actual)
@@ -852,6 +1064,12 @@
if !reflect.DeepEqual(stringSet(first.OutputPaths), stringSet(second.OutputPaths)) {
return false
}
+ if !reflect.DeepEqual(stringSet(first.SymlinkPaths), stringSet(second.SymlinkPaths)) {
+ return false
+ }
+ if first.Depfile != second.Depfile {
+ return false
+ }
return true
}
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index 92135c6..52c6c2f 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -20,6 +20,10 @@
// be a subset of OutputFiles. (or static libraries, this will be equal to OutputFiles,
// but general cc_library will also have dynamic libraries in output files).
RootStaticArchives []string
+ // Dynamic libraries (.so files) created by the current target. These will
+ // be a subset of OutputFiles. (or shared libraries, this will be equal to OutputFiles,
+ // but general cc_library will also have dynamic libraries in output files).
+ RootDynamicLibraries []string
}
type getOutputFilesRequestType struct{}
@@ -86,13 +90,21 @@
if linker_input.owner == target.label:
rootStaticArchives.append(library.static_library.path)
+rootDynamicLibraries = []
+
+if "@rules_cc//examples:experimental_cc_shared_library.bzl%CcSharedLibraryInfo" in providers(target):
+ shared_info = providers(target)["@rules_cc//examples:experimental_cc_shared_library.bzl%CcSharedLibraryInfo"]
+ for lib in shared_info.linker_input.libraries:
+ rootDynamicLibraries += [lib.dynamic_library.path]
+
returns = [
outputFiles,
staticLibraries,
ccObjectFiles,
includes,
system_includes,
- rootStaticArchives
+ rootStaticArchives,
+ rootDynamicLibraries
]
return "|".join([", ".join(r) for r in returns])`
@@ -106,7 +118,7 @@
var ccObjects []string
splitString := strings.Split(rawString, "|")
- if expectedLen := 6; len(splitString) != expectedLen {
+ if expectedLen := 7; len(splitString) != expectedLen {
return CcInfo{}, fmt.Errorf("Expected %d items, got %q", expectedLen, splitString)
}
outputFilesString := splitString[0]
@@ -118,6 +130,7 @@
includes := splitOrEmpty(splitString[3], ", ")
systemIncludes := splitOrEmpty(splitString[4], ", ")
rootStaticArchives := splitOrEmpty(splitString[5], ", ")
+ rootDynamicLibraries := splitOrEmpty(splitString[6], ", ")
return CcInfo{
OutputFiles: outputFiles,
CcObjectFiles: ccObjects,
@@ -125,6 +138,7 @@
Includes: includes,
SystemIncludes: systemIncludes,
RootStaticArchives: rootStaticArchives,
+ RootDynamicLibraries: rootDynamicLibraries,
}, nil
}
diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go
index 602849e..035544e 100644
--- a/bazel/cquery/request_type_test.go
+++ b/bazel/cquery/request_type_test.go
@@ -46,7 +46,7 @@
}{
{
description: "no result",
- input: "|||||",
+ input: "||||||",
expectedOutput: CcInfo{
OutputFiles: []string{},
CcObjectFiles: []string{},
@@ -54,11 +54,12 @@
Includes: []string{},
SystemIncludes: []string{},
RootStaticArchives: []string{},
+ RootDynamicLibraries: []string{},
},
},
{
description: "only output",
- input: "test|||||",
+ input: "test||||||",
expectedOutput: CcInfo{
OutputFiles: []string{"test"},
CcObjectFiles: []string{},
@@ -66,11 +67,12 @@
Includes: []string{},
SystemIncludes: []string{},
RootStaticArchives: []string{},
+ RootDynamicLibraries: []string{},
},
},
{
description: "all items set",
- input: "out1, out2|static_lib1, static_lib2|object1, object2|., dir/subdir|system/dir, system/other/dir|rootstaticarchive1",
+ input: "out1, out2|static_lib1, static_lib2|object1, object2|., dir/subdir|system/dir, system/other/dir|rootstaticarchive1|rootdynamiclibrary1",
expectedOutput: CcInfo{
OutputFiles: []string{"out1", "out2"},
CcObjectFiles: []string{"object1", "object2"},
@@ -78,19 +80,20 @@
Includes: []string{".", "dir/subdir"},
SystemIncludes: []string{"system/dir", "system/other/dir"},
RootStaticArchives: []string{"rootstaticarchive1"},
+ RootDynamicLibraries: []string{"rootdynamiclibrary1"},
},
},
{
description: "too few result splits",
input: "|",
expectedOutput: CcInfo{},
- expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 6, []string{"", ""}),
+ expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 7, []string{"", ""}),
},
{
description: "too many result splits",
input: strings.Repeat("|", 8),
expectedOutput: CcInfo{},
- expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 6, make([]string, 9)),
+ expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 7, make([]string, 9)),
},
}
for _, tc := range testCases {
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index 4de5aae..a1e0424 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -488,6 +488,9 @@
ret = "{\n"
// Sort and print the struct props by the key.
structProps := extractStructProperties(propertyValue, indent)
+ if len(structProps) == 0 {
+ return "", nil
+ }
for _, k := range android.SortedStringKeys(structProps) {
ret += makeIndent(indent + 1)
ret += fmt.Sprintf("%q: %s,\n", k, structProps[k])
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index c464cec..285677a 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -49,6 +49,7 @@
cc.RegisterCCBuildComponents(ctx)
ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
ctx.RegisterModuleType("cc_library_static", cc.LibraryStaticFactory)
+ ctx.RegisterModuleType("cc_prebuilt_library_static", cc.PrebuiltStaticLibraryFactory)
ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
}
@@ -384,19 +385,69 @@
"-I$(BINDIR)/foo/bar",
],
dynamic_deps = [":shared_dep_for_both"],
- dynamic_deps_for_shared = [":shared_dep_for_shared"],
- dynamic_deps_for_static = [":shared_dep_for_static"],
implementation_deps = [":static_dep_for_both"],
- shared_copts = ["sharedflag"],
- shared_srcs = ["sharedonly.cpp"],
+ shared = {
+ "copts": ["sharedflag"],
+ "dynamic_deps": [":shared_dep_for_shared"],
+ "srcs": ["sharedonly.cpp"],
+ "static_deps": [":static_dep_for_shared"],
+ "whole_archive_deps": [":whole_static_lib_for_shared"],
+ },
srcs = ["both.cpp"],
- static_copts = ["staticflag"],
- static_deps_for_shared = [":static_dep_for_shared"],
- static_deps_for_static = [":static_dep_for_static"],
- static_srcs = ["staticonly.cpp"],
+ static = {
+ "copts": ["staticflag"],
+ "dynamic_deps": [":shared_dep_for_static"],
+ "srcs": ["staticonly.cpp"],
+ "static_deps": [":static_dep_for_static"],
+ "whole_archive_deps": [":whole_static_lib_for_static"],
+ },
whole_archive_deps = [":whole_static_lib_for_both"],
- whole_archive_deps_for_shared = [":whole_static_lib_for_shared"],
- whole_archive_deps_for_static = [":whole_static_lib_for_static"],
+)`},
+ })
+}
+
+func TestCcLibraryWholeStaticLibsAlwaysLink(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": `
+cc_library {
+ name: "a",
+ whole_static_libs: ["whole_static_lib_for_both"],
+ static: {
+ whole_static_libs: ["whole_static_lib_for_static"],
+ },
+ shared: {
+ whole_static_libs: ["whole_static_lib_for_shared"],
+ },
+ bazel_module: { bp2build_available: true },
+}
+
+cc_prebuilt_library_static { name: "whole_static_lib_for_shared" }
+
+cc_prebuilt_library_static { name: "whole_static_lib_for_static" }
+
+cc_prebuilt_library_static { name: "whole_static_lib_for_both" }
+`,
+ },
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
+ name = "a",
+ copts = [
+ "-Ifoo/bar",
+ "-I$(BINDIR)/foo/bar",
+ ],
+ shared = {
+ "whole_archive_deps": [":whole_static_lib_for_shared_alwayslink"],
+ },
+ static = {
+ "whole_archive_deps": [":whole_static_lib_for_static_alwayslink"],
+ },
+ whole_archive_deps = [":whole_static_lib_for_both_alwayslink"],
)`},
})
}
@@ -486,52 +537,56 @@
"-Ifoo/bar",
"-I$(BINDIR)/foo/bar",
],
- dynamic_deps_for_shared = select({
- "//build/bazel/platforms/arch:arm": [":arm_shared_dep_for_shared"],
- "//conditions:default": [],
- }),
implementation_deps = [":static_dep_for_both"],
- shared_copts = ["sharedflag"] + select({
- "//build/bazel/platforms/arch:arm": ["-DARM_SHARED"],
- "//conditions:default": [],
- }) + select({
- "//build/bazel/platforms/os:android": ["-DANDROID_SHARED"],
- "//conditions:default": [],
- }) + select({
- "//build/bazel/platforms/os_arch:android_arm": ["-DANDROID_ARM_SHARED"],
- "//conditions:default": [],
- }),
- shared_srcs = ["sharedonly.cpp"] + select({
- "//build/bazel/platforms/arch:arm": ["arm_shared.cpp"],
- "//conditions:default": [],
- }) + select({
- "//build/bazel/platforms/os:android": ["android_shared.cpp"],
- "//conditions:default": [],
- }),
+ shared = {
+ "copts": ["sharedflag"] + select({
+ "//build/bazel/platforms/arch:arm": ["-DARM_SHARED"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/platforms/os:android": ["-DANDROID_SHARED"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/platforms/os_arch:android_arm": ["-DANDROID_ARM_SHARED"],
+ "//conditions:default": [],
+ }),
+ "dynamic_deps": select({
+ "//build/bazel/platforms/arch:arm": [":arm_shared_dep_for_shared"],
+ "//conditions:default": [],
+ }),
+ "srcs": ["sharedonly.cpp"] + select({
+ "//build/bazel/platforms/arch:arm": ["arm_shared.cpp"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/platforms/os:android": ["android_shared.cpp"],
+ "//conditions:default": [],
+ }),
+ "static_deps": [":static_dep_for_shared"] + select({
+ "//build/bazel/platforms/arch:arm": [":arm_static_dep_for_shared"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/platforms/os:android": [":android_dep_for_shared"],
+ "//conditions:default": [],
+ }),
+ "whole_archive_deps": select({
+ "//build/bazel/platforms/arch:arm": [":arm_whole_static_dep_for_shared"],
+ "//conditions:default": [],
+ }),
+ },
srcs = ["both.cpp"],
- static_copts = ["staticflag"] + select({
- "//build/bazel/platforms/arch:x86": ["-DX86_STATIC"],
- "//conditions:default": [],
- }),
- static_deps_for_shared = [":static_dep_for_shared"] + select({
- "//build/bazel/platforms/arch:arm": [":arm_static_dep_for_shared"],
- "//conditions:default": [],
- }) + select({
- "//build/bazel/platforms/os:android": [":android_dep_for_shared"],
- "//conditions:default": [],
- }),
- static_deps_for_static = [":static_dep_for_static"] + select({
- "//build/bazel/platforms/arch:x86": [":x86_dep_for_static"],
- "//conditions:default": [],
- }),
- static_srcs = ["staticonly.cpp"] + select({
- "//build/bazel/platforms/arch:x86": ["x86_static.cpp"],
- "//conditions:default": [],
- }),
- whole_archive_deps_for_shared = select({
- "//build/bazel/platforms/arch:arm": [":arm_whole_static_dep_for_shared"],
- "//conditions:default": [],
- }),
+ static = {
+ "copts": ["staticflag"] + select({
+ "//build/bazel/platforms/arch:x86": ["-DX86_STATIC"],
+ "//conditions:default": [],
+ }),
+ "srcs": ["staticonly.cpp"] + select({
+ "//build/bazel/platforms/arch:x86": ["x86_static.cpp"],
+ "//conditions:default": [],
+ }),
+ "static_deps": [":static_dep_for_static"] + select({
+ "//build/bazel/platforms/arch:x86": [":x86_dep_for_static"],
+ "//conditions:default": [],
+ }),
+ },
)`},
})
}
@@ -623,20 +678,22 @@
"-Ifoo/bar",
"-I$(BINDIR)/foo/bar",
],
- shared_srcs = [
- ":shared_filegroup_cpp_srcs",
- "shared_source.cc",
- "shared_source.cpp",
- ],
- shared_srcs_as = [
- "shared_source.s",
- "shared_source.S",
- ":shared_filegroup_as_srcs",
- ],
- shared_srcs_c = [
- "shared_source.c",
- ":shared_filegroup_c_srcs",
- ],
+ shared = {
+ "srcs": [
+ ":shared_filegroup_cpp_srcs",
+ "shared_source.cc",
+ "shared_source.cpp",
+ ],
+ "srcs_as": [
+ "shared_source.s",
+ "shared_source.S",
+ ":shared_filegroup_as_srcs",
+ ],
+ "srcs_c": [
+ "shared_source.c",
+ ":shared_filegroup_c_srcs",
+ ],
+ },
srcs = [
":both_filegroup_cpp_srcs",
"both_source.cc",
@@ -651,20 +708,22 @@
"both_source.c",
":both_filegroup_c_srcs",
],
- static_srcs = [
- ":static_filegroup_cpp_srcs",
- "static_source.cc",
- "static_source.cpp",
- ],
- static_srcs_as = [
- "static_source.s",
- "static_source.S",
- ":static_filegroup_as_srcs",
- ],
- static_srcs_c = [
- "static_source.c",
- ":static_filegroup_c_srcs",
- ],
+ static = {
+ "srcs": [
+ ":static_filegroup_cpp_srcs",
+ "static_source.cc",
+ "static_source.cpp",
+ ],
+ "srcs_as": [
+ "static_source.s",
+ "static_source.S",
+ ":static_filegroup_as_srcs",
+ ],
+ "srcs_c": [
+ "static_source.c",
+ ":static_filegroup_c_srcs",
+ ],
+ },
)`},
})
}
@@ -1231,3 +1290,173 @@
}),
)`}})
}
+
+func TestCcLibraryStrip(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library strip args",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": `
+cc_library {
+ name: "nothing",
+ bazel_module: { bp2build_available: true },
+}
+cc_library {
+ name: "keep_symbols",
+ bazel_module: { bp2build_available: true },
+ strip: {
+ keep_symbols: true,
+ }
+}
+cc_library {
+ name: "keep_symbols_and_debug_frame",
+ bazel_module: { bp2build_available: true },
+ strip: {
+ keep_symbols_and_debug_frame: true,
+ }
+}
+cc_library {
+ name: "none",
+ bazel_module: { bp2build_available: true },
+ strip: {
+ none: true,
+ }
+}
+cc_library {
+ name: "keep_symbols_list",
+ bazel_module: { bp2build_available: true },
+ strip: {
+ keep_symbols_list: ["symbol"],
+ }
+}
+cc_library {
+ name: "all",
+ bazel_module: { bp2build_available: true },
+ strip: {
+ all: true,
+ }
+}
+`,
+ },
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
+ name = "all",
+ copts = [
+ "-Ifoo/bar",
+ "-I$(BINDIR)/foo/bar",
+ ],
+ strip = {
+ "all": True,
+ },
+)`, `cc_library(
+ name = "keep_symbols",
+ copts = [
+ "-Ifoo/bar",
+ "-I$(BINDIR)/foo/bar",
+ ],
+ strip = {
+ "keep_symbols": True,
+ },
+)`, `cc_library(
+ name = "keep_symbols_and_debug_frame",
+ copts = [
+ "-Ifoo/bar",
+ "-I$(BINDIR)/foo/bar",
+ ],
+ strip = {
+ "keep_symbols_and_debug_frame": True,
+ },
+)`, `cc_library(
+ name = "keep_symbols_list",
+ copts = [
+ "-Ifoo/bar",
+ "-I$(BINDIR)/foo/bar",
+ ],
+ strip = {
+ "keep_symbols_list": ["symbol"],
+ },
+)`, `cc_library(
+ name = "none",
+ copts = [
+ "-Ifoo/bar",
+ "-I$(BINDIR)/foo/bar",
+ ],
+ strip = {
+ "none": True,
+ },
+)`, `cc_library(
+ name = "nothing",
+ copts = [
+ "-Ifoo/bar",
+ "-I$(BINDIR)/foo/bar",
+ ],
+)`},
+ })
+}
+
+func TestCcLibraryStripWithArch(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library strip args",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": `
+cc_library {
+ name: "multi-arch",
+ bazel_module: { bp2build_available: true },
+ target: {
+ darwin: {
+ strip: {
+ keep_symbols_list: ["foo", "bar"]
+ }
+ },
+ },
+ arch: {
+ arm: {
+ strip: {
+ keep_symbols_and_debug_frame: true,
+ },
+ },
+ arm64: {
+ strip: {
+ keep_symbols: true,
+ },
+ },
+ }
+}
+`,
+ },
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
+ name = "multi-arch",
+ copts = [
+ "-Ifoo/bar",
+ "-I$(BINDIR)/foo/bar",
+ ],
+ strip = {
+ "keep_symbols": select({
+ "//build/bazel/platforms/arch:arm64": True,
+ "//conditions:default": None,
+ }),
+ "keep_symbols_and_debug_frame": select({
+ "//build/bazel/platforms/arch:arm": True,
+ "//conditions:default": None,
+ }),
+ "keep_symbols_list": select({
+ "//build/bazel/platforms/os:darwin": [
+ "foo",
+ "bar",
+ ],
+ "//conditions:default": [],
+ }),
+ },
+)`},
+ })
+}
diff --git a/cc/binary.go b/cc/binary.go
index 999b82c..3aa3fdf 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -149,11 +149,11 @@
if ctx.toolchain().Bionic() {
if !Bool(binary.baseLinker.Properties.Nocrt) {
if binary.static() {
- deps.CrtBegin = "crtbegin_static"
+ deps.CrtBegin = []string{"crtbegin_static"}
} else {
- deps.CrtBegin = "crtbegin_dynamic"
+ deps.CrtBegin = []string{"crtbegin_dynamic"}
}
- deps.CrtEnd = "crtend_android"
+ deps.CrtEnd = []string{"crtend_android"}
}
if binary.static() {
@@ -178,7 +178,7 @@
// the kernel before jumping to the embedded linker.
if ctx.Os() == android.LinuxBionic && !binary.static() {
deps.DynamicLinker = "linker"
- deps.LinkerFlagsFile = "host_bionic_linker_flags"
+ deps.CrtBegin = append(deps.CrtBegin, "host_bionic_linker_script")
}
}
@@ -345,12 +345,6 @@
var linkerDeps android.Paths
- // Add flags from linker flags file.
- if deps.LinkerFlagsFile.Valid() {
- flags.Local.LdFlags = append(flags.Local.LdFlags, "$$(cat "+deps.LinkerFlagsFile.String()+")")
- linkerDeps = append(linkerDeps, deps.LinkerFlagsFile.Path())
- }
-
if flags.DynamicLinker != "" {
flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-dynamic-linker,"+flags.DynamicLinker)
} else if ctx.toolchain().Bionic() && !binary.static() {
@@ -401,16 +395,18 @@
}
}
+ var validations android.WritablePaths
+
// Handle host bionic linker symbols.
if ctx.Os() == android.LinuxBionic && !binary.static() {
- injectedOutputFile := outputFile
- outputFile = android.PathForModuleOut(ctx, "prelinker", fileName)
+ verifyFile := android.PathForModuleOut(ctx, "host_bionic_verify.stamp")
if !deps.DynamicLinker.Valid() {
panic("Non-static host bionic modules must have a dynamic linker")
}
- binary.injectHostBionicLinkerSymbols(ctx, outputFile, deps.DynamicLinker.Path(), injectedOutputFile)
+ binary.verifyHostBionicLinker(ctx, outputFile, deps.DynamicLinker.Path(), verifyFile)
+ validations = append(validations, verifyFile)
}
var sharedLibs android.Paths
@@ -430,7 +426,7 @@
// Register link action.
transformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs, deps.StaticLibs,
deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true,
- builderFlags, outputFile, nil)
+ builderFlags, outputFile, nil, validations)
objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...)
objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...)
@@ -532,19 +528,19 @@
}
func init() {
- pctx.HostBinToolVariable("hostBionicSymbolsInjectCmd", "host_bionic_inject")
+ pctx.HostBinToolVariable("verifyHostBionicCmd", "host_bionic_verify")
}
-var injectHostBionicSymbols = pctx.AndroidStaticRule("injectHostBionicSymbols",
+var verifyHostBionic = pctx.AndroidStaticRule("verifyHostBionic",
blueprint.RuleParams{
- Command: "$hostBionicSymbolsInjectCmd -i $in -l $linker -o $out",
- CommandDeps: []string{"$hostBionicSymbolsInjectCmd"},
+ Command: "$verifyHostBionicCmd -i $in -l $linker && touch $out",
+ CommandDeps: []string{"$verifyHostBionicCmd"},
}, "linker")
-func (binary *binaryDecorator) injectHostBionicLinkerSymbols(ctx ModuleContext, in, linker android.Path, out android.WritablePath) {
+func (binary *binaryDecorator) verifyHostBionicLinker(ctx ModuleContext, in, linker android.Path, out android.WritablePath) {
ctx.Build(pctx, android.BuildParams{
- Rule: injectHostBionicSymbols,
- Description: "inject host bionic symbols",
+ Rule: verifyHostBionic,
+ Description: "verify host bionic",
Input: in,
Implicit: linker,
Output: out,
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 211fe5e..76c5f3b 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -142,15 +142,14 @@
// staticOrSharedAttributes are the Bazel-ified versions of StaticOrSharedProperties --
// properties which apply to either the shared or static version of a cc_library module.
type staticOrSharedAttributes struct {
- srcs bazel.LabelListAttribute
- srcs_c bazel.LabelListAttribute
- srcs_as bazel.LabelListAttribute
+ Srcs bazel.LabelListAttribute
+ Srcs_c bazel.LabelListAttribute
+ Srcs_as bazel.LabelListAttribute
+ Copts bazel.StringListAttribute
- copts bazel.StringListAttribute
-
- staticDeps bazel.LabelListAttribute
- dynamicDeps bazel.LabelListAttribute
- wholeArchiveDeps bazel.LabelListAttribute
+ Static_deps bazel.LabelListAttribute
+ Dynamic_deps bazel.LabelListAttribute
+ Whole_archive_deps bazel.LabelListAttribute
}
func groupSrcsByExtension(ctx android.TopDownMutatorContext, srcs bazel.LabelListAttribute) (cppSrcs, cSrcs, asSrcs bazel.LabelListAttribute) {
@@ -251,19 +250,19 @@
}
attrs := staticOrSharedAttributes{
- copts: bazel.StringListAttribute{Value: props.Cflags},
- srcs: bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, props.Srcs)),
- staticDeps: bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, props.Static_libs)),
- dynamicDeps: bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, props.Shared_libs)),
- wholeArchiveDeps: bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, props.Whole_static_libs)),
+ Copts: bazel.StringListAttribute{Value: props.Cflags},
+ Srcs: bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, props.Srcs)),
+ Static_deps: bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, props.Static_libs)),
+ Dynamic_deps: bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, props.Shared_libs)),
+ Whole_archive_deps: bazel.MakeLabelListAttribute(android.BazelLabelForModuleWholeDeps(ctx, props.Whole_static_libs)),
}
setAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) {
- attrs.copts.SetSelectValue(axis, config, props.Cflags)
- attrs.srcs.SetSelectValue(axis, config, android.BazelLabelForModuleSrc(ctx, props.Srcs))
- attrs.staticDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, props.Static_libs))
- attrs.dynamicDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, props.Shared_libs))
- attrs.wholeArchiveDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, props.Whole_static_libs))
+ attrs.Copts.SetSelectValue(axis, config, props.Cflags)
+ attrs.Srcs.SetSelectValue(axis, config, android.BazelLabelForModuleSrc(ctx, props.Srcs))
+ attrs.Static_deps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, props.Static_libs))
+ attrs.Dynamic_deps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, props.Shared_libs))
+ attrs.Whole_archive_deps.SetSelectValue(axis, config, android.BazelLabelForModuleWholeDeps(ctx, props.Whole_static_libs))
}
if isStatic {
@@ -284,10 +283,10 @@
}
}
- cppSrcs, cSrcs, asSrcs := groupSrcsByExtension(ctx, attrs.srcs)
- attrs.srcs = cppSrcs
- attrs.srcs_c = cSrcs
- attrs.srcs_as = asSrcs
+ cppSrcs, cSrcs, asSrcs := groupSrcsByExtension(ctx, attrs.Srcs)
+ attrs.Srcs = cppSrcs
+ attrs.Srcs_c = cSrcs
+ attrs.Srcs_as = asSrcs
return attrs
}
@@ -485,13 +484,18 @@
// Convenience struct to hold all attributes parsed from linker properties.
type linkerAttributes struct {
- deps bazel.LabelListAttribute
- dynamicDeps bazel.LabelListAttribute
- wholeArchiveDeps bazel.LabelListAttribute
- exportedDeps bazel.LabelListAttribute
- useLibcrt bazel.BoolAttribute
- linkopts bazel.StringListAttribute
- versionScript bazel.LabelAttribute
+ deps bazel.LabelListAttribute
+ dynamicDeps bazel.LabelListAttribute
+ wholeArchiveDeps bazel.LabelListAttribute
+ exportedDeps bazel.LabelListAttribute
+ useLibcrt bazel.BoolAttribute
+ linkopts bazel.StringListAttribute
+ versionScript bazel.LabelAttribute
+ stripKeepSymbols bazel.BoolAttribute
+ stripKeepSymbolsAndDebugFrame bazel.BoolAttribute
+ stripKeepSymbolsList bazel.StringListAttribute
+ stripAll bazel.BoolAttribute
+ stripNone bazel.BoolAttribute
}
// FIXME(b/187655838): Use the existing linkerFlags() function instead of duplicating logic here
@@ -515,6 +519,33 @@
var versionScript bazel.LabelAttribute
var useLibcrt bazel.BoolAttribute
+ var stripKeepSymbols bazel.BoolAttribute
+ var stripKeepSymbolsAndDebugFrame bazel.BoolAttribute
+ var stripKeepSymbolsList bazel.StringListAttribute
+ var stripAll bazel.BoolAttribute
+ var stripNone bazel.BoolAttribute
+
+ if libraryDecorator, ok := module.linker.(*libraryDecorator); ok {
+ stripProperties := libraryDecorator.stripper.StripProperties
+ stripKeepSymbols.Value = stripProperties.Strip.Keep_symbols
+ stripKeepSymbolsList.Value = stripProperties.Strip.Keep_symbols_list
+ stripKeepSymbolsAndDebugFrame.Value = stripProperties.Strip.Keep_symbols_and_debug_frame
+ stripAll.Value = stripProperties.Strip.All
+ stripNone.Value = stripProperties.Strip.None
+ }
+
+ for axis, configToProps := range module.GetArchVariantProperties(ctx, &StripProperties{}) {
+ for config, props := range configToProps {
+ if stripProperties, ok := props.(*StripProperties); ok {
+ stripKeepSymbols.SetSelectValue(axis, config, stripProperties.Strip.Keep_symbols)
+ stripKeepSymbolsList.SetSelectValue(axis, config, stripProperties.Strip.Keep_symbols_list)
+ stripKeepSymbolsAndDebugFrame.SetSelectValue(axis, config, stripProperties.Strip.Keep_symbols_and_debug_frame)
+ stripAll.SetSelectValue(axis, config, stripProperties.Strip.All)
+ stripNone.SetSelectValue(axis, config, stripProperties.Strip.None)
+ }
+ }
+ }
+
for _, linkerProps := range module.linker.linkerProps() {
if baseLinkerProps, ok := linkerProps.(*BaseLinkerProperties); ok {
// Excludes to parallel Soong:
@@ -522,7 +553,7 @@
staticLibs := android.FirstUniqueStrings(baseLinkerProps.Static_libs)
staticDeps.Value = android.BazelLabelForModuleDepsExcludes(ctx, staticLibs, baseLinkerProps.Exclude_static_libs)
wholeArchiveLibs := android.FirstUniqueStrings(baseLinkerProps.Whole_static_libs)
- wholeArchiveDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDepsExcludes(ctx, wholeArchiveLibs, baseLinkerProps.Exclude_static_libs))
+ wholeArchiveDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleWholeDepsExcludes(ctx, wholeArchiveLibs, baseLinkerProps.Exclude_static_libs))
sharedLibs := android.FirstUniqueStrings(baseLinkerProps.Shared_libs)
dynamicDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDepsExcludes(ctx, sharedLibs, baseLinkerProps.Exclude_shared_libs))
@@ -549,7 +580,7 @@
staticLibs := android.FirstUniqueStrings(baseLinkerProps.Static_libs)
staticDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDepsExcludes(ctx, staticLibs, baseLinkerProps.Exclude_static_libs))
wholeArchiveLibs := android.FirstUniqueStrings(baseLinkerProps.Whole_static_libs)
- wholeArchiveDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDepsExcludes(ctx, wholeArchiveLibs, baseLinkerProps.Exclude_static_libs))
+ wholeArchiveDeps.SetSelectValue(axis, config, android.BazelLabelForModuleWholeDepsExcludes(ctx, wholeArchiveLibs, baseLinkerProps.Exclude_static_libs))
sharedLibs := android.FirstUniqueStrings(baseLinkerProps.Shared_libs)
dynamicDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDepsExcludes(ctx, sharedLibs, baseLinkerProps.Exclude_shared_libs))
@@ -572,13 +603,15 @@
excludesField string
// reference to the bazel attribute that should be set for the given product variable config
attribute *bazel.LabelListAttribute
+
+ depResolutionFunc func(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList
}
productVarToDepFields := map[string]productVarDep{
// product variables do not support exclude_shared_libs
- "Shared_libs": productVarDep{attribute: &dynamicDeps},
- "Static_libs": productVarDep{"Exclude_static_libs", &staticDeps},
- "Whole_static_libs": productVarDep{"Exclude_static_libs", &wholeArchiveDeps},
+ "Shared_libs": productVarDep{attribute: &dynamicDeps, depResolutionFunc: android.BazelLabelForModuleDepsExcludes},
+ "Static_libs": productVarDep{"Exclude_static_libs", &staticDeps, android.BazelLabelForModuleDepsExcludes},
+ "Whole_static_libs": productVarDep{"Exclude_static_libs", &wholeArchiveDeps, android.BazelLabelForModuleWholeDepsExcludes},
}
productVariableProps := android.ProductVariableProperties(ctx)
@@ -612,7 +645,8 @@
if excludes, ok = excludesProp.Property.([]string); excludesExists && !ok {
ctx.ModuleErrorf("Could not convert product variable %s property", dep.excludesField)
}
- dep.attribute.SetSelectValue(bazel.ProductVariableConfigurationAxis(config), config, android.BazelLabelForModuleDepsExcludes(ctx, android.FirstUniqueStrings(includes), excludes))
+
+ dep.attribute.SetSelectValue(bazel.ProductVariableConfigurationAxis(config), config, dep.depResolutionFunc(ctx, android.FirstUniqueStrings(includes), excludes))
}
}
@@ -630,6 +664,13 @@
linkopts: linkopts,
useLibcrt: useLibcrt,
versionScript: versionScript,
+
+ // Strip properties
+ stripKeepSymbols: stripKeepSymbols,
+ stripKeepSymbolsAndDebugFrame: stripKeepSymbolsAndDebugFrame,
+ stripKeepSymbolsList: stripKeepSymbolsList,
+ stripAll: stripAll,
+ stripNone: stripNone,
}
}
diff --git a/cc/builder.go b/cc/builder.go
index fae9522..bde8c96 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -730,8 +730,9 @@
// Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries,
// and shared libraries, to a shared library (.so) or dynamic executable
func transformObjToDynamicBinary(ctx android.ModuleContext,
- objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps android.Paths,
- crtBegin, crtEnd android.OptionalPath, groupLate bool, flags builderFlags, outputFile android.WritablePath, implicitOutputs android.WritablePaths) {
+ objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps, crtBegin, crtEnd android.Paths,
+ groupLate bool, flags builderFlags, outputFile android.WritablePath,
+ implicitOutputs android.WritablePaths, validations android.WritablePaths) {
ldCmd := "${config.ClangBin}/clang++"
@@ -778,18 +779,17 @@
deps = append(deps, staticLibs...)
deps = append(deps, lateStaticLibs...)
deps = append(deps, wholeStaticLibs...)
- if crtBegin.Valid() {
- deps = append(deps, crtBegin.Path(), crtEnd.Path())
- }
+ deps = append(deps, crtBegin...)
+ deps = append(deps, crtEnd...)
rule := ld
args := map[string]string{
"ldCmd": ldCmd,
- "crtBegin": crtBegin.String(),
+ "crtBegin": strings.Join(crtBegin.Strings(), " "),
"libFlags": strings.Join(libFlagsList, " "),
"extraLibFlags": flags.extraLibFlags,
"ldFlags": flags.globalLdFlags + " " + flags.localLdFlags,
- "crtEnd": crtEnd.String(),
+ "crtEnd": strings.Join(crtEnd.Strings(), " "),
}
if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CXX_LINKS") {
rule = ldRE
@@ -805,6 +805,7 @@
Inputs: objFiles,
Implicits: deps,
OrderOnly: sharedLibs,
+ Validations: validations.Paths(),
Args: args,
})
}
diff --git a/cc/cc.go b/cc/cc.go
index 818490a..2e094d0 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -126,11 +126,10 @@
ReexportGeneratedHeaders []string
- CrtBegin, CrtEnd string
+ CrtBegin, CrtEnd []string
// Used for host bionic
- LinkerFlagsFile string
- DynamicLinker string
+ DynamicLinker string
// List of libs that need to be excluded for APEX variant
ExcludeLibsForApex []string
@@ -177,10 +176,7 @@
ReexportedDeps android.Paths
// Paths to crt*.o files
- CrtBegin, CrtEnd android.OptionalPath
-
- // Path to the file container flags to use with the linker
- LinkerFlagsFile android.OptionalPath
+ CrtBegin, CrtEnd android.Paths
// Path to the dynamic linker binary
DynamicLinker android.OptionalPath
@@ -290,9 +286,15 @@
// Set by DepsMutator.
AndroidMkSystemSharedLibs []string `blueprint:"mutated"`
+ // The name of the image this module is built for, suffixed with a '.'
ImageVariationPrefix string `blueprint:"mutated"`
- VndkVersion string `blueprint:"mutated"`
- SubName string `blueprint:"mutated"`
+
+ // The VNDK version this module is built against. If empty, the module is not
+ // build against the VNDK.
+ VndkVersion string `blueprint:"mutated"`
+
+ // Suffix for the name of Android.mk entries generated by this module
+ SubName string `blueprint:"mutated"`
// *.logtags files, to combine together in order to generate the /system/etc/event-log-tags
// file
@@ -315,12 +317,15 @@
// Make this module available when building for recovery
Recovery_available *bool
- // Set by imageMutator
- CoreVariantNeeded bool `blueprint:"mutated"`
- RamdiskVariantNeeded bool `blueprint:"mutated"`
- VendorRamdiskVariantNeeded bool `blueprint:"mutated"`
- RecoveryVariantNeeded bool `blueprint:"mutated"`
- ExtraVariants []string `blueprint:"mutated"`
+ // Used by imageMutator, set by ImageMutatorBegin()
+ CoreVariantNeeded bool `blueprint:"mutated"`
+ RamdiskVariantNeeded bool `blueprint:"mutated"`
+ VendorRamdiskVariantNeeded bool `blueprint:"mutated"`
+ RecoveryVariantNeeded bool `blueprint:"mutated"`
+
+ // A list of variations for the "image" mutator of the form
+ //<image name> '.' <version char>, for example, 'vendor.S'
+ ExtraVersionedImageVariations []string `blueprint:"mutated"`
// Allows this module to use non-APEX version of libraries. Useful
// for building binaries that are started before APEXes are activated.
@@ -717,7 +722,6 @@
genHeaderDepTag = dependencyTag{name: "gen header"}
genHeaderExportDepTag = dependencyTag{name: "gen header export"}
objDepTag = dependencyTag{name: "obj"}
- linkerFlagsDepTag = dependencyTag{name: "linker flags file"}
dynamicLinkerDepTag = installDependencyTag{name: "dynamic linker"}
reuseObjTag = dependencyTag{name: "reuse objects"}
staticVariantTag = dependencyTag{name: "static variant"}
@@ -1673,10 +1677,6 @@
c.makeLinkType = GetMakeLinkType(actx, c)
- if c.maybeGenerateBazelActions(actx) {
- return
- }
-
ctx := &moduleContext{
ModuleContext: actx,
moduleContextImpl: moduleContextImpl{
@@ -1685,6 +1685,11 @@
}
ctx.ctx = ctx
+ if c.maybeGenerateBazelActions(actx) {
+ c.maybeInstall(ctx, apexInfo)
+ return
+ }
+
deps := c.depsToPaths(ctx)
if ctx.Failed() {
return
@@ -1772,19 +1777,7 @@
}
c.outputFile = android.OptionalPathForPath(outputFile)
- // If a lib is directly included in any of the APEXes or is not available to the
- // platform (which is often the case when the stub is provided as a prebuilt),
- // unhide the stubs variant having the latest version gets visible to make. In
- // addition, the non-stubs variant is renamed to <libname>.bootstrap. This is to
- // force anything in the make world to link against the stubs library. (unless it
- // is explicitly referenced via .bootstrap suffix or the module is marked with
- // 'bootstrap: true').
- if c.HasStubsVariants() && c.NotInPlatform() && !c.InRamdisk() &&
- !c.InRecovery() && !c.UseVndk() && !c.static() && !c.isCoverageVariant() &&
- c.IsStubs() && !c.InVendorRamdisk() {
- c.Properties.HideFromMake = false // unhide
- // Note: this is still non-installable
- }
+ c.maybeUnhideFromMake()
// glob exported headers for snapshot, if BOARD_VNDK_VERSION is current or
// RECOVERY_SNAPSHOT_VERSION is current.
@@ -1795,6 +1788,26 @@
}
}
+ c.maybeInstall(ctx, apexInfo)
+}
+
+func (c *Module) maybeUnhideFromMake() {
+ // If a lib is directly included in any of the APEXes or is not available to the
+ // platform (which is often the case when the stub is provided as a prebuilt),
+ // unhide the stubs variant having the latest version gets visible to make. In
+ // addition, the non-stubs variant is renamed to <libname>.bootstrap. This is to
+ // force anything in the make world to link against the stubs library. (unless it
+ // is explicitly referenced via .bootstrap suffix or the module is marked with
+ // 'bootstrap: true').
+ if c.HasStubsVariants() && c.NotInPlatform() && !c.InRamdisk() &&
+ !c.InRecovery() && !c.UseVndk() && !c.static() && !c.isCoverageVariant() &&
+ c.IsStubs() && !c.InVendorRamdisk() {
+ c.Properties.HideFromMake = false // unhide
+ // Note: this is still non-installable
+ }
+}
+
+func (c *Module) maybeInstall(ctx ModuleContext, apexInfo android.ApexInfo) {
if !proptools.BoolDefault(c.Properties.Installable, true) {
// If the module has been specifically configure to not be installed then
// hide from make as otherwise it will break when running inside make
@@ -2246,16 +2259,13 @@
crtVariations := GetCrtVariations(ctx, c)
actx.AddVariationDependencies(crtVariations, objDepTag, deps.ObjFiles...)
- if deps.CrtBegin != "" {
+ for _, crt := range deps.CrtBegin {
actx.AddVariationDependencies(crtVariations, CrtBeginDepTag,
- RewriteSnapshotLib(deps.CrtBegin, GetSnapshot(c, &snapshotInfo, actx).Objects))
+ RewriteSnapshotLib(crt, GetSnapshot(c, &snapshotInfo, actx).Objects))
}
- if deps.CrtEnd != "" {
+ for _, crt := range deps.CrtEnd {
actx.AddVariationDependencies(crtVariations, CrtEndDepTag,
- RewriteSnapshotLib(deps.CrtEnd, GetSnapshot(c, &snapshotInfo, actx).Objects))
- }
- if deps.LinkerFlagsFile != "" {
- actx.AddDependency(c, linkerFlagsDepTag, deps.LinkerFlagsFile)
+ RewriteSnapshotLib(crt, GetSnapshot(c, &snapshotInfo, actx).Objects))
}
if deps.DynamicLinker != "" {
actx.AddDependency(c, dynamicLinkerDepTag, deps.DynamicLinker)
@@ -2555,17 +2565,10 @@
} else {
ctx.ModuleErrorf("module %q is not a genrule", depName)
}
- case linkerFlagsDepTag:
- if genRule, ok := dep.(genrule.SourceFileGenerator); ok {
- files := genRule.GeneratedSourceFiles()
- if len(files) == 1 {
- depPaths.LinkerFlagsFile = android.OptionalPathForPath(files[0])
- } else if len(files) > 1 {
- ctx.ModuleErrorf("module %q can only generate a single file if used for a linker flag file", depName)
- }
- } else {
- ctx.ModuleErrorf("module %q is not a genrule", depName)
- }
+ case CrtBeginDepTag:
+ depPaths.CrtBegin = append(depPaths.CrtBegin, android.OutputFileForModule(ctx, dep, ""))
+ case CrtEndDepTag:
+ depPaths.CrtEnd = append(depPaths.CrtEnd, android.OutputFileForModule(ctx, dep, ""))
}
return
}
@@ -2878,9 +2881,9 @@
case objDepTag:
depPaths.Objs.objFiles = append(depPaths.Objs.objFiles, linkFile.Path())
case CrtBeginDepTag:
- depPaths.CrtBegin = linkFile
+ depPaths.CrtBegin = append(depPaths.CrtBegin, linkFile.Path())
case CrtEndDepTag:
- depPaths.CrtEnd = linkFile
+ depPaths.CrtEnd = append(depPaths.CrtEnd, linkFile.Path())
case dynamicLinkerDepTag:
depPaths.DynamicLinker = linkFile
}
diff --git a/cc/image.go b/cc/image.go
index c9c0e63..15ec1c8 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -341,11 +341,11 @@
}
func (m *Module) ExtraVariants() []string {
- return m.Properties.ExtraVariants
+ return m.Properties.ExtraVersionedImageVariations
}
func (m *Module) AppendExtraVariant(extraVariant string) {
- m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, extraVariant)
+ m.Properties.ExtraVersionedImageVariations = append(m.Properties.ExtraVersionedImageVariations, extraVariant)
}
func (m *Module) SetRamdiskVariantNeeded(b bool) {
@@ -629,7 +629,7 @@
}
func (c *Module) ExtraImageVariations(ctx android.BaseModuleContext) []string {
- return c.Properties.ExtraVariants
+ return c.Properties.ExtraVersionedImageVariations
}
func squashVendorSrcs(m *Module) {
diff --git a/cc/library.go b/cc/library.go
index 93bd56c..5b6c623 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -28,6 +28,7 @@
"android/soong/android"
"android/soong/bazel"
+ "android/soong/bazel/cquery"
"android/soong/cc/config"
)
@@ -236,29 +237,22 @@
Linkopts bazel.StringListAttribute
Use_libcrt bazel.BoolAttribute
- // Attributes pertaining to shared variant.
- Shared_srcs bazel.LabelListAttribute
- Shared_srcs_c bazel.LabelListAttribute
- Shared_srcs_as bazel.LabelListAttribute
- Shared_copts bazel.StringListAttribute
+ // This is shared only.
+ Version_script bazel.LabelAttribute
- Exported_deps_for_shared bazel.LabelListAttribute
- Static_deps_for_shared bazel.LabelListAttribute
- Dynamic_deps_for_shared bazel.LabelListAttribute
- Whole_archive_deps_for_shared bazel.LabelListAttribute
- User_link_flags bazel.StringListAttribute
- Version_script bazel.LabelAttribute
+ // Common properties shared between both shared and static variants.
+ Shared staticOrSharedAttributes
+ Static staticOrSharedAttributes
- // Attributes pertaining to static variant.
- Static_srcs bazel.LabelListAttribute
- Static_srcs_c bazel.LabelListAttribute
- Static_srcs_as bazel.LabelListAttribute
- Static_copts bazel.StringListAttribute
+ Strip stripAttributes
+}
- Exported_deps_for_static bazel.LabelListAttribute
- Static_deps_for_static bazel.LabelListAttribute
- Dynamic_deps_for_static bazel.LabelListAttribute
- Whole_archive_deps_for_static bazel.LabelListAttribute
+type stripAttributes struct {
+ Keep_symbols bazel.BoolAttribute
+ Keep_symbols_and_debug_frame bazel.BoolAttribute
+ Keep_symbols_list bazel.StringListAttribute
+ All bazel.BoolAttribute
+ None bazel.BoolAttribute
}
type bazelCcLibrary struct {
@@ -323,22 +317,19 @@
Linkopts: linkerAttrs.linkopts,
Use_libcrt: linkerAttrs.useLibcrt,
- Shared_srcs: sharedAttrs.srcs,
- Shared_srcs_c: sharedAttrs.srcs_c,
- Shared_srcs_as: sharedAttrs.srcs_as,
- Shared_copts: sharedAttrs.copts,
- Static_deps_for_shared: sharedAttrs.staticDeps,
- Whole_archive_deps_for_shared: sharedAttrs.wholeArchiveDeps,
- Dynamic_deps_for_shared: sharedAttrs.dynamicDeps,
- Version_script: linkerAttrs.versionScript,
+ Version_script: linkerAttrs.versionScript,
- Static_srcs: staticAttrs.srcs,
- Static_srcs_c: staticAttrs.srcs_c,
- Static_srcs_as: staticAttrs.srcs_as,
- Static_copts: staticAttrs.copts,
- Static_deps_for_static: staticAttrs.staticDeps,
- Whole_archive_deps_for_static: staticAttrs.wholeArchiveDeps,
- Dynamic_deps_for_static: staticAttrs.dynamicDeps,
+ Strip: stripAttributes{
+ Keep_symbols: linkerAttrs.stripKeepSymbols,
+ Keep_symbols_and_debug_frame: linkerAttrs.stripKeepSymbolsAndDebugFrame,
+ Keep_symbols_list: linkerAttrs.stripKeepSymbolsList,
+ All: linkerAttrs.stripAll,
+ None: linkerAttrs.stripNone,
+ },
+
+ Shared: sharedAttrs,
+
+ Static: staticAttrs,
}
props := bazel.BazelTargetModuleProperties{
@@ -561,22 +552,10 @@
module *Module
}
-func (handler *ccLibraryBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
- if !handler.module.static() {
- // TODO(cparsons): Support shared libraries.
- return false
- }
- bazelCtx := ctx.Config().BazelContext
- ccInfo, ok, err := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType)
- if err != nil {
- ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err)
- return false
- }
- if !ok {
- return ok
- }
+// generateStaticBazelBuildActions constructs the StaticLibraryInfo Soong
+// provider from a Bazel shared library's CcInfo provider.
+func (handler *ccLibraryBazelHandler) generateStaticBazelBuildActions(ctx android.ModuleContext, label string, ccInfo cquery.CcInfo) bool {
rootStaticArchives := ccInfo.RootStaticArchives
- objPaths := ccInfo.CcObjectFiles
if len(rootStaticArchives) != 1 {
ctx.ModuleErrorf("expected exactly one root archive file for '%s', but got %s", label, rootStaticArchives)
return false
@@ -584,6 +563,7 @@
outputFilePath := android.PathForBazelOut(ctx, rootStaticArchives[0])
handler.module.outputFile = android.OptionalPathForPath(outputFilePath)
+ objPaths := ccInfo.CcObjectFiles
objFiles := make(android.Paths, len(objPaths))
for i, objPath := range objPaths {
objFiles[i] = android.PathForBazelOut(ctx, objPath)
@@ -597,26 +577,109 @@
ReuseObjects: objects,
Objects: objects,
- // TODO(cparsons): Include transitive static libraries in this provider to support
+ // TODO(b/190524881): Include transitive static libraries in this provider to support
// static libraries with deps.
TransitiveStaticLibrariesForOrdering: android.NewDepSetBuilder(android.TOPOLOGICAL).
Direct(outputFilePath).
Build(),
})
- ctx.SetProvider(FlagExporterInfoProvider, flagExporterInfoFromCcInfo(ctx, ccInfo))
+ return true
+}
+
+// generateSharedBazelBuildActions constructs the SharedLibraryInfo Soong
+// provider from a Bazel shared library's CcInfo provider.
+func (handler *ccLibraryBazelHandler) generateSharedBazelBuildActions(ctx android.ModuleContext, label string, ccInfo cquery.CcInfo) bool {
+ rootDynamicLibraries := ccInfo.RootDynamicLibraries
+
+ if len(rootDynamicLibraries) != 1 {
+ ctx.ModuleErrorf("expected exactly one root dynamic library file for '%s', but got %s", label, rootDynamicLibraries)
+ return false
+ }
+ outputFilePath := android.PathForBazelOut(ctx, rootDynamicLibraries[0])
+ handler.module.outputFile = android.OptionalPathForPath(outputFilePath)
+
+ handler.module.linker.(*libraryDecorator).unstrippedOutputFile = outputFilePath
+
+ tocFile := getTocFile(ctx, label, ccInfo.OutputFiles)
+ handler.module.linker.(*libraryDecorator).tocFile = tocFile
+
+ ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+ TableOfContents: tocFile,
+ SharedLibrary: outputFilePath,
+ Target: ctx.Target(),
+ // TODO(b/190524881): Include transitive static libraries in this provider to support
+ // static libraries with deps. The provider key for this is TransitiveStaticLibrariesForOrdering.
+ })
+ return true
+}
+
+// getTocFile looks for the .so.toc file in the target's output files, if any. The .so.toc file
+// contains the table of contents of all symbols of a shared object.
+func getTocFile(ctx android.ModuleContext, label string, outputFiles []string) android.OptionalPath {
+ var tocFile string
+ for _, file := range outputFiles {
+ if strings.HasSuffix(file, ".so.toc") {
+ if tocFile != "" {
+ ctx.ModuleErrorf("The %s target cannot produce more than 1 .toc file.", label)
+ }
+ tocFile = file
+ // Don't break to validate that there are no multiple .toc files per .so.
+ }
+ }
+ if tocFile == "" {
+ return android.OptionalPath{}
+ }
+ return android.OptionalPathForPath(android.PathForBazelOut(ctx, tocFile))
+}
+
+func (handler *ccLibraryBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
+ bazelCtx := ctx.Config().BazelContext
+ ccInfo, ok, err := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType)
+ if err != nil {
+ ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err)
+ return false
+ }
+ if !ok {
+ return ok
+ }
+
+ if handler.module.static() {
+ if ok := handler.generateStaticBazelBuildActions(ctx, label, ccInfo); !ok {
+ return false
+ }
+ } else if handler.module.Shared() {
+ if ok := handler.generateSharedBazelBuildActions(ctx, label, ccInfo); !ok {
+ return false
+ }
+ } else {
+ return false
+ }
+
+ handler.module.linker.(*libraryDecorator).setFlagExporterInfoFromCcInfo(ctx, ccInfo)
+ handler.module.maybeUnhideFromMake()
+
if i, ok := handler.module.linker.(snapshotLibraryInterface); ok {
// 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
+ // TODO(b/190533363): More closely mirror the collectHeadersForSnapshot
// implementation.
i.(*libraryDecorator).collectedSnapshotHeaders = android.Paths{}
}
-
return ok
}
+func (library *libraryDecorator) setFlagExporterInfoFromCcInfo(ctx android.ModuleContext, ccInfo cquery.CcInfo) {
+ flagExporterInfo := flagExporterInfoFromCcInfo(ctx, ccInfo)
+ // flag exporters consolidates properties like includes, flags, dependencies that should be
+ // exported from this module to other modules
+ ctx.SetProvider(FlagExporterInfoProvider, flagExporterInfo)
+ // Store flag info to be passed along to androidmk
+ // TODO(b/184387147): Androidmk should be done in Bazel, not Soong.
+ library.flagExporterInfo = &flagExporterInfo
+}
+
func GlobHeadersForSnapshot(ctx android.ModuleContext, paths android.Paths) android.Paths {
ret := android.Paths{}
@@ -1112,8 +1175,8 @@
deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, library.StaticProperties.Static.Export_static_lib_headers...)
} else if library.shared() {
if ctx.toolchain().Bionic() && !Bool(library.baseLinker.Properties.Nocrt) {
- deps.CrtBegin = "crtbegin_so"
- deps.CrtEnd = "crtend_so"
+ deps.CrtBegin = []string{"crtbegin_so"}
+ deps.CrtEnd = []string{"crtend_so"}
}
deps.WholeStaticLibs = append(deps.WholeStaticLibs, library.SharedProperties.Shared.Whole_static_libs...)
deps.StaticLibs = append(deps.StaticLibs, library.SharedProperties.Shared.Static_libs...)
@@ -1343,7 +1406,7 @@
linkerDeps = append(linkerDeps, objs.tidyFiles...)
transformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs,
deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs,
- linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile, implicitOutputs)
+ linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile, implicitOutputs, nil)
objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...)
objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...)
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 2065929..d6b4529 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -73,13 +73,7 @@
// HeaderLibraryInfo is an empty struct to indicate to dependencies that this is a header library
ctx.SetProvider(HeaderLibraryInfoProvider, HeaderLibraryInfo{})
- flagExporterInfo := flagExporterInfoFromCcInfo(ctx, ccInfo)
- // Store flag info to be passed along to androimk
- // TODO(b/184387147): Androidmk should be done in Bazel, not Soong.
- h.library.flagExporterInfo = &flagExporterInfo
- // flag exporters consolidates properties like includes, flags, dependencies that should be
- // exported from this module to other modules
- ctx.SetProvider(FlagExporterInfoProvider, flagExporterInfo)
+ h.library.setFlagExporterInfoFromCcInfo(ctx, ccInfo)
// Dependencies on this library will expect collectedSnapshotHeaders to be set, otherwise
// validation will fail. For now, set this to an empty list.
diff --git a/cc/library_test.go b/cc/library_test.go
index 7975275..ba372a8 100644
--- a/cc/library_test.go
+++ b/cc/library_test.go
@@ -19,6 +19,7 @@
"testing"
"android/soong/android"
+ "android/soong/bazel/cquery"
)
func TestLibraryReuse(t *testing.T) {
@@ -240,3 +241,48 @@
testCcError(t, `"libfoo" .*: versions: "X" could not be parsed as an integer and is not a recognized codename`, bp)
}
+
+func TestCcLibraryWithBazel(t *testing.T) {
+ bp := `
+cc_library {
+ name: "foo",
+ srcs: ["foo.cc"],
+ bazel_module: { label: "//foo/bar:bar" },
+}`
+ config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
+ config.BazelContext = android.MockBazelContext{
+ OutputBaseDir: "outputbase",
+ LabelToCcInfo: map[string]cquery.CcInfo{
+ "//foo/bar:bar": cquery.CcInfo{
+ CcObjectFiles: []string{"foo.o"},
+ Includes: []string{"include"},
+ SystemIncludes: []string{"system_include"},
+ RootStaticArchives: []string{"foo.a"},
+ RootDynamicLibraries: []string{"foo.so"},
+ },
+ },
+ }
+ ctx := testCcWithConfig(t, config)
+
+ staticFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_static").Module()
+ outputFiles, err := staticFoo.(android.OutputFileProducer).OutputFiles("")
+ if err != nil {
+ t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
+ }
+
+ expectedOutputFiles := []string{"outputbase/execroot/__main__/foo.a"}
+ android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
+
+ sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
+ outputFiles, err = sharedFoo.(android.OutputFileProducer).OutputFiles("")
+ if err != nil {
+ t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
+ }
+ expectedOutputFiles = []string{"outputbase/execroot/__main__/foo.so"}
+ android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
+
+ entries := android.AndroidMkEntriesForTest(t, ctx, sharedFoo)[0]
+ expectedFlags := []string{"-Ioutputbase/execroot/__main__/include", "-isystem outputbase/execroot/__main__/system_include"}
+ gotFlags := entries.EntryMap["LOCAL_EXPORT_CFLAGS"]
+ android.AssertDeepEquals(t, "androidmk exported cflags", expectedFlags, gotFlags)
+}
diff --git a/cc/linker.go b/cc/linker.go
index 895931a..d9ee0cf 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -122,7 +122,7 @@
// version script for vendor or product variant
Version_script *string `android:"arch_variant"`
- }
+ } `android:"arch_variant"`
Recovery struct {
// list of shared libs that only should be used to build the recovery
// variant of the C/C++ module.
@@ -182,7 +182,7 @@
// variant of the C/C++ module.
Exclude_static_libs []string
}
- }
+ } `android:"arch_variant"`
// make android::build:GetBuildNumber() available containing the build ID.
Use_version_lib *bool `android:"arch_variant"`
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index 4a9601b..2726b1a 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -144,13 +144,13 @@
Inputs: licensePaths,
})
- baseDepPaths := append(installPaths, combinedLicense,
- getNdkAbiDiffTimestampFile(ctx))
+ baseDepPaths := append(installPaths, combinedLicense)
ctx.Build(pctx, android.BuildParams{
- Rule: android.Touch,
- Output: getNdkBaseTimestampFile(ctx),
- Implicits: baseDepPaths,
+ Rule: android.Touch,
+ Output: getNdkBaseTimestampFile(ctx),
+ Implicits: baseDepPaths,
+ Validation: getNdkAbiDiffTimestampFile(ctx),
})
fullDepPaths := append(staticLibInstallPaths, getNdkBaseTimestampFile(ctx))
diff --git a/cc/ndkstubgen/__init__.py b/cc/ndkstubgen/__init__.py
index 2387e69..5e6b8f5 100755
--- a/cc/ndkstubgen/__init__.py
+++ b/cc/ndkstubgen/__init__.py
@@ -108,7 +108,14 @@
parser.add_argument(
'--llndk', action='store_true', help='Use the LLNDK variant.')
parser.add_argument(
- '--apex', action='store_true', help='Use the APEX variant.')
+ '--apex',
+ action='store_true',
+ help='Use the APEX variant. Note: equivalent to --system-api.')
+ parser.add_argument(
+ '--system-api',
+ action='store_true',
+ dest='apex',
+ help='Use the SystemAPI variant. Note: equivalent to --apex.')
parser.add_argument('--api-map',
type=resolved_path,
diff --git a/cc/ndkstubgen/test_ndkstubgen.py b/cc/ndkstubgen/test_ndkstubgen.py
index 3dbab61..09551ea 100755
--- a/cc/ndkstubgen/test_ndkstubgen.py
+++ b/cc/ndkstubgen/test_ndkstubgen.py
@@ -19,9 +19,10 @@
import textwrap
import unittest
-import ndkstubgen
import symbolfile
-from symbolfile import Arch, Tag
+from symbolfile import Arch, Tags
+
+import ndkstubgen
# pylint: disable=missing-docstring
@@ -38,23 +39,25 @@
version_file, symbol_list_file,
Arch('arm'), 9, False, False)
- version = symbolfile.Version('VERSION_PRIVATE', None, [], [
- symbolfile.Symbol('foo', []),
+ version = symbolfile.Version('VERSION_PRIVATE', None, Tags(), [
+ symbolfile.Symbol('foo', Tags()),
])
generator.write_version(version)
self.assertEqual('', src_file.getvalue())
self.assertEqual('', version_file.getvalue())
- version = symbolfile.Version('VERSION', None, [Tag('x86')], [
- symbolfile.Symbol('foo', []),
- ])
+ version = symbolfile.Version('VERSION', None, Tags.from_strs(['x86']),
+ [
+ symbolfile.Symbol('foo', Tags()),
+ ])
generator.write_version(version)
self.assertEqual('', src_file.getvalue())
self.assertEqual('', version_file.getvalue())
- version = symbolfile.Version('VERSION', None, [Tag('introduced=14')], [
- symbolfile.Symbol('foo', []),
- ])
+ version = symbolfile.Version('VERSION', None,
+ Tags.from_strs(['introduced=14']), [
+ symbolfile.Symbol('foo', Tags()),
+ ])
generator.write_version(version)
self.assertEqual('', src_file.getvalue())
self.assertEqual('', version_file.getvalue())
@@ -69,29 +72,29 @@
version_file, symbol_list_file,
Arch('arm'), 9, False, False)
- version = symbolfile.Version('VERSION_1', None, [], [
- symbolfile.Symbol('foo', [Tag('x86')]),
+ version = symbolfile.Version('VERSION_1', None, Tags(), [
+ symbolfile.Symbol('foo', Tags.from_strs(['x86'])),
])
generator.write_version(version)
self.assertEqual('', src_file.getvalue())
self.assertEqual('', version_file.getvalue())
- version = symbolfile.Version('VERSION_1', None, [], [
- symbolfile.Symbol('foo', [Tag('introduced=14')]),
+ version = symbolfile.Version('VERSION_1', None, Tags(), [
+ symbolfile.Symbol('foo', Tags.from_strs(['introduced=14'])),
])
generator.write_version(version)
self.assertEqual('', src_file.getvalue())
self.assertEqual('', version_file.getvalue())
- version = symbolfile.Version('VERSION_1', None, [], [
- symbolfile.Symbol('foo', [Tag('llndk')]),
+ version = symbolfile.Version('VERSION_1', None, Tags(), [
+ symbolfile.Symbol('foo', Tags.from_strs(['llndk'])),
])
generator.write_version(version)
self.assertEqual('', src_file.getvalue())
self.assertEqual('', version_file.getvalue())
- version = symbolfile.Version('VERSION_1', None, [], [
- symbolfile.Symbol('foo', [Tag('apex')]),
+ version = symbolfile.Version('VERSION_1', None, Tags(), [
+ symbolfile.Symbol('foo', Tags.from_strs(['apex'])),
])
generator.write_version(version)
self.assertEqual('', src_file.getvalue())
@@ -106,18 +109,17 @@
Arch('arm'), 9, False, False)
versions = [
- symbolfile.Version('VERSION_1', None, [], [
- symbolfile.Symbol('foo', []),
- symbolfile.Symbol('bar', [Tag('var')]),
- symbolfile.Symbol('woodly', [Tag('weak')]),
- symbolfile.Symbol('doodly',
- [Tag('weak'), Tag('var')]),
+ symbolfile.Version('VERSION_1', None, Tags(), [
+ symbolfile.Symbol('foo', Tags()),
+ symbolfile.Symbol('bar', Tags.from_strs(['var'])),
+ symbolfile.Symbol('woodly', Tags.from_strs(['weak'])),
+ symbolfile.Symbol('doodly', Tags.from_strs(['weak', 'var'])),
]),
- symbolfile.Version('VERSION_2', 'VERSION_1', [], [
- symbolfile.Symbol('baz', []),
+ symbolfile.Version('VERSION_2', 'VERSION_1', Tags(), [
+ symbolfile.Symbol('baz', Tags()),
]),
- symbolfile.Version('VERSION_3', 'VERSION_1', [], [
- symbolfile.Symbol('qux', [Tag('versioned=14')]),
+ symbolfile.Version('VERSION_3', 'VERSION_1', Tags(), [
+ symbolfile.Symbol('qux', Tags.from_strs(['versioned=14'])),
]),
]
diff --git a/cc/strip.go b/cc/strip.go
index b1f34bb..c60e135 100644
--- a/cc/strip.go
+++ b/cc/strip.go
@@ -59,6 +59,7 @@
return !forceDisable && (forceEnable || defaultEnable)
}
+// Keep this consistent with //build/bazel/rules/stripped_shared_library.bzl.
func (stripper *Stripper) strip(actx android.ModuleContext, in android.Path, out android.ModuleOutPath,
flags StripFlags, isStaticLib bool) {
if actx.Darwin() {
diff --git a/cc/symbolfile/__init__.py b/cc/symbolfile/__init__.py
index 5678e7d..31c4443 100644
--- a/cc/symbolfile/__init__.py
+++ b/cc/symbolfile/__init__.py
@@ -14,18 +14,22 @@
# limitations under the License.
#
"""Parser for Android's version script information."""
-from dataclasses import dataclass
+from __future__ import annotations
+
+from dataclasses import dataclass, field
import logging
import re
from typing import (
Dict,
Iterable,
+ Iterator,
List,
Mapping,
NewType,
Optional,
TextIO,
Tuple,
+ Union,
)
@@ -52,11 +56,52 @@
@dataclass
+class Tags:
+ """Container class for the tags attached to a symbol or version."""
+
+ tags: tuple[Tag, ...] = field(default_factory=tuple)
+
+ @classmethod
+ def from_strs(cls, strs: Iterable[str]) -> Tags:
+ """Constructs tags from a collection of strings.
+
+ Does not decode API levels.
+ """
+ return Tags(tuple(Tag(s) for s in strs))
+
+ def __contains__(self, tag: Union[Tag, str]) -> bool:
+ return tag in self.tags
+
+ def __iter__(self) -> Iterator[Tag]:
+ yield from self.tags
+
+ @property
+ def has_mode_tags(self) -> bool:
+ """Returns True if any mode tags (apex, llndk, etc) are set."""
+ return self.has_apex_tags or self.has_llndk_tags
+
+ @property
+ def has_apex_tags(self) -> bool:
+ """Returns True if any APEX tags are set."""
+ return 'apex' in self.tags or 'systemapi' in self.tags
+
+ @property
+ def has_llndk_tags(self) -> bool:
+ """Returns True if any LL-NDK tags are set."""
+ return 'llndk' in self.tags
+
+ @property
+ def has_platform_only_tags(self) -> bool:
+ """Returns True if any platform-only tags are set."""
+ return 'platform-only' in self.tags
+
+
+@dataclass
class Symbol:
"""A symbol definition from a symbol file."""
name: str
- tags: List[Tag]
+ tags: Tags
@dataclass
@@ -65,14 +110,22 @@
name: str
base: Optional[str]
- tags: List[Tag]
+ tags: Tags
symbols: List[Symbol]
+ @property
+ def is_private(self) -> bool:
+ """Returns True if this version block is private (platform only)."""
+ return self.name.endswith('_PRIVATE') or self.name.endswith('_PLATFORM')
-def get_tags(line: str) -> List[Tag]:
+
+def get_tags(line: str, api_map: ApiMap) -> Tags:
"""Returns a list of all tags on this line."""
_, _, all_tags = line.strip().partition('#')
- return [Tag(e) for e in re.split(r'\s+', all_tags) if e.strip()]
+ return Tags(tuple(
+ decode_api_level_tag(Tag(e), api_map)
+ for e in re.split(r'\s+', all_tags) if e.strip()
+ ))
def is_api_level_tag(tag: Tag) -> bool:
@@ -104,24 +157,21 @@
return api_map[api]
-def decode_api_level_tags(tags: Iterable[Tag], api_map: ApiMap) -> List[Tag]:
- """Decodes API level code names in a list of tags.
+def decode_api_level_tag(tag: Tag, api_map: ApiMap) -> Tag:
+ """Decodes API level code name in a tag.
Raises:
ParseError: An unknown version name was found in a tag.
"""
- decoded_tags = list(tags)
- for idx, tag in enumerate(tags):
- if not is_api_level_tag(tag):
- continue
- name, value = split_tag(tag)
+ if not is_api_level_tag(tag):
+ return tag
- try:
- decoded = str(decode_api_level(value, api_map))
- decoded_tags[idx] = Tag('='.join([name, decoded]))
- except KeyError:
- raise ParseError(f'Unknown version name in tag: {tag}')
- return decoded_tags
+ name, value = split_tag(tag)
+ try:
+ decoded = str(decode_api_level(value, api_map))
+ return Tag(f'{name}={decoded}')
+ except KeyError as ex:
+ raise ParseError(f'Unknown version name in tag: {tag}') from ex
def split_tag(tag: Tag) -> Tuple[str, str]:
@@ -149,55 +199,52 @@
return split_tag(tag)[1]
-def version_is_private(version: str) -> bool:
- """Returns True if the version name should be treated as private."""
- return version.endswith('_PRIVATE') or version.endswith('_PLATFORM')
+def _should_omit_tags(tags: Tags, arch: Arch, api: int, llndk: bool,
+ apex: bool) -> bool:
+ """Returns True if the tagged object should be omitted.
+
+ This defines the rules shared between version tagging and symbol tagging.
+ """
+ # The apex and llndk tags will only exclude APIs from other modes. If in
+ # APEX or LLNDK mode and neither tag is provided, we fall back to the
+ # default behavior because all NDK symbols are implicitly available to APEX
+ # and LLNDK.
+ if tags.has_mode_tags:
+ if not apex and not llndk:
+ return True
+ if apex and not tags.has_apex_tags:
+ return True
+ if llndk and not tags.has_llndk_tags:
+ return True
+ if not symbol_in_arch(tags, arch):
+ return True
+ if not symbol_in_api(tags, arch, api):
+ return True
+ return False
def should_omit_version(version: Version, arch: Arch, api: int, llndk: bool,
apex: bool) -> bool:
- """Returns True if the version section should be ommitted.
+ """Returns True if the version section should be omitted.
We want to omit any sections that do not have any symbols we'll have in the
stub library. Sections that contain entirely future symbols or only symbols
for certain architectures.
"""
- if version_is_private(version.name):
+ if version.is_private:
return True
- if 'platform-only' in version.tags:
+ if version.tags.has_platform_only_tags:
return True
-
- no_llndk_no_apex = ('llndk' not in version.tags
- and 'apex' not in version.tags)
- keep = no_llndk_no_apex or \
- ('llndk' in version.tags and llndk) or \
- ('apex' in version.tags and apex)
- if not keep:
- return True
- if not symbol_in_arch(version.tags, arch):
- return True
- if not symbol_in_api(version.tags, arch, api):
- return True
- return False
+ return _should_omit_tags(version.tags, arch, api, llndk, apex)
def should_omit_symbol(symbol: Symbol, arch: Arch, api: int, llndk: bool,
apex: bool) -> bool:
"""Returns True if the symbol should be omitted."""
- no_llndk_no_apex = 'llndk' not in symbol.tags and 'apex' not in symbol.tags
- keep = no_llndk_no_apex or \
- ('llndk' in symbol.tags and llndk) or \
- ('apex' in symbol.tags and apex)
- if not keep:
- return True
- if not symbol_in_arch(symbol.tags, arch):
- return True
- if not symbol_in_api(symbol.tags, arch, api):
- return True
- return False
+ return _should_omit_tags(symbol.tags, arch, api, llndk, apex)
-def symbol_in_arch(tags: Iterable[Tag], arch: Arch) -> bool:
+def symbol_in_arch(tags: Tags, arch: Arch) -> bool:
"""Returns true if the symbol is present for the given architecture."""
has_arch_tags = False
for tag in tags:
@@ -325,8 +372,7 @@
"""Parses a single version section and returns a Version object."""
assert self.current_line is not None
name = self.current_line.split('{')[0].strip()
- tags = get_tags(self.current_line)
- tags = decode_api_level_tags(tags, self.api_map)
+ tags = get_tags(self.current_line, self.api_map)
symbols: List[Symbol] = []
global_scope = True
cpp_symbols = False
@@ -373,8 +419,7 @@
'Wildcard global symbols are not permitted.')
# Line is now in the format "<symbol-name>; # tags"
name, _, _ = self.current_line.strip().partition(';')
- tags = get_tags(self.current_line)
- tags = decode_api_level_tags(tags, self.api_map)
+ tags = get_tags(self.current_line, self.api_map)
return Symbol(name, tags)
def next_line(self) -> str:
diff --git a/cc/symbolfile/test_symbolfile.py b/cc/symbolfile/test_symbolfile.py
index 92b1399..c1e8219 100644
--- a/cc/symbolfile/test_symbolfile.py
+++ b/cc/symbolfile/test_symbolfile.py
@@ -19,7 +19,7 @@
import unittest
import symbolfile
-from symbolfile import Arch, Tag
+from symbolfile import Arch, Tag, Tags, Version
# pylint: disable=missing-docstring
@@ -35,12 +35,14 @@
class TagsTest(unittest.TestCase):
def test_get_tags_no_tags(self) -> None:
- self.assertEqual([], symbolfile.get_tags(''))
- self.assertEqual([], symbolfile.get_tags('foo bar baz'))
+ self.assertEqual(Tags(), symbolfile.get_tags('', {}))
+ self.assertEqual(Tags(), symbolfile.get_tags('foo bar baz', {}))
def test_get_tags(self) -> None:
- self.assertEqual(['foo', 'bar'], symbolfile.get_tags('# foo bar'))
- self.assertEqual(['bar', 'baz'], symbolfile.get_tags('foo # bar baz'))
+ self.assertEqual(Tags.from_strs(['foo', 'bar']),
+ symbolfile.get_tags('# foo bar', {}))
+ self.assertEqual(Tags.from_strs(['bar', 'baz']),
+ symbolfile.get_tags('foo # bar baz', {}))
def test_split_tag(self) -> None:
self.assertTupleEqual(('foo', 'bar'),
@@ -77,12 +79,14 @@
}
tags = [
- Tag('introduced=9'),
- Tag('introduced-arm=14'),
- Tag('versioned=16'),
- Tag('arm'),
- Tag('introduced=O'),
- Tag('introduced=P'),
+ symbolfile.decode_api_level_tag(t, api_map) for t in (
+ Tag('introduced=9'),
+ Tag('introduced-arm=14'),
+ Tag('versioned=16'),
+ Tag('arm'),
+ Tag('introduced=O'),
+ Tag('introduced=P'),
+ )
]
expected_tags = [
Tag('introduced=9'),
@@ -92,33 +96,37 @@
Tag('introduced=9000'),
Tag('introduced=9001'),
]
- self.assertListEqual(
- expected_tags, symbolfile.decode_api_level_tags(tags, api_map))
+ self.assertListEqual(expected_tags, tags)
with self.assertRaises(symbolfile.ParseError):
- symbolfile.decode_api_level_tags([Tag('introduced=O')], {})
+ symbolfile.decode_api_level_tag(Tag('introduced=O'), {})
class PrivateVersionTest(unittest.TestCase):
def test_version_is_private(self) -> None:
- self.assertFalse(symbolfile.version_is_private('foo'))
- self.assertFalse(symbolfile.version_is_private('PRIVATE'))
- self.assertFalse(symbolfile.version_is_private('PLATFORM'))
- self.assertFalse(symbolfile.version_is_private('foo_private'))
- self.assertFalse(symbolfile.version_is_private('foo_platform'))
- self.assertFalse(symbolfile.version_is_private('foo_PRIVATE_'))
- self.assertFalse(symbolfile.version_is_private('foo_PLATFORM_'))
+ def mock_version(name: str) -> Version:
+ return Version(name, base=None, tags=Tags(), symbols=[])
- self.assertTrue(symbolfile.version_is_private('foo_PRIVATE'))
- self.assertTrue(symbolfile.version_is_private('foo_PLATFORM'))
+ self.assertFalse(mock_version('foo').is_private)
+ self.assertFalse(mock_version('PRIVATE').is_private)
+ self.assertFalse(mock_version('PLATFORM').is_private)
+ self.assertFalse(mock_version('foo_private').is_private)
+ self.assertFalse(mock_version('foo_platform').is_private)
+ self.assertFalse(mock_version('foo_PRIVATE_').is_private)
+ self.assertFalse(mock_version('foo_PLATFORM_').is_private)
+
+ self.assertTrue(mock_version('foo_PRIVATE').is_private)
+ self.assertTrue(mock_version('foo_PLATFORM').is_private)
class SymbolPresenceTest(unittest.TestCase):
def test_symbol_in_arch(self) -> None:
- self.assertTrue(symbolfile.symbol_in_arch([], Arch('arm')))
- self.assertTrue(symbolfile.symbol_in_arch([Tag('arm')], Arch('arm')))
+ self.assertTrue(symbolfile.symbol_in_arch(Tags(), Arch('arm')))
+ self.assertTrue(
+ symbolfile.symbol_in_arch(Tags.from_strs(['arm']), Arch('arm')))
- self.assertFalse(symbolfile.symbol_in_arch([Tag('x86')], Arch('arm')))
+ self.assertFalse(
+ symbolfile.symbol_in_arch(Tags.from_strs(['x86']), Arch('arm')))
def test_symbol_in_api(self) -> None:
self.assertTrue(symbolfile.symbol_in_api([], Arch('arm'), 9))
@@ -197,81 +205,99 @@
def test_omit_private(self) -> None:
self.assertFalse(
symbolfile.should_omit_version(
- symbolfile.Version('foo', None, [], []), Arch('arm'), 9, False,
- False))
+ symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9,
+ False, False))
self.assertTrue(
symbolfile.should_omit_version(
- symbolfile.Version('foo_PRIVATE', None, [], []), Arch('arm'),
- 9, False, False))
+ symbolfile.Version('foo_PRIVATE', None, Tags(), []),
+ Arch('arm'), 9, False, False))
self.assertTrue(
symbolfile.should_omit_version(
- symbolfile.Version('foo_PLATFORM', None, [], []), Arch('arm'),
- 9, False, False))
+ symbolfile.Version('foo_PLATFORM', None, Tags(), []),
+ Arch('arm'), 9, False, False))
self.assertTrue(
symbolfile.should_omit_version(
- symbolfile.Version('foo', None, [Tag('platform-only')], []),
+ symbolfile.Version('foo', None,
+ Tags.from_strs(['platform-only']), []),
Arch('arm'), 9, False, False))
def test_omit_llndk(self) -> None:
self.assertTrue(
symbolfile.should_omit_version(
- symbolfile.Version('foo', None, [Tag('llndk')], []),
+ symbolfile.Version('foo', None, Tags.from_strs(['llndk']), []),
Arch('arm'), 9, False, False))
self.assertFalse(
symbolfile.should_omit_version(
- symbolfile.Version('foo', None, [], []), Arch('arm'), 9, True,
- False))
+ symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9,
+ True, False))
self.assertFalse(
symbolfile.should_omit_version(
- symbolfile.Version('foo', None, [Tag('llndk')], []),
+ symbolfile.Version('foo', None, Tags.from_strs(['llndk']), []),
Arch('arm'), 9, True, False))
def test_omit_apex(self) -> None:
self.assertTrue(
symbolfile.should_omit_version(
- symbolfile.Version('foo', None, [Tag('apex')], []),
+ symbolfile.Version('foo', None, Tags.from_strs(['apex']), []),
Arch('arm'), 9, False, False))
self.assertFalse(
symbolfile.should_omit_version(
- symbolfile.Version('foo', None, [], []), Arch('arm'), 9, False,
- True))
+ symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9,
+ False, True))
self.assertFalse(
symbolfile.should_omit_version(
- symbolfile.Version('foo', None, [Tag('apex')], []),
+ symbolfile.Version('foo', None, Tags.from_strs(['apex']), []),
Arch('arm'), 9, False, True))
+ def test_omit_systemapi(self) -> None:
+ self.assertTrue(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo', None, Tags.from_strs(['systemapi']),
+ []), Arch('arm'), 9, False, False))
+
+ self.assertFalse(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9,
+ False, True))
+ self.assertFalse(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo', None, Tags.from_strs(['systemapi']),
+ []), Arch('arm'), 9, False, True))
+
def test_omit_arch(self) -> None:
self.assertFalse(
symbolfile.should_omit_version(
- symbolfile.Version('foo', None, [], []), Arch('arm'), 9, False,
- False))
+ symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9,
+ False, False))
self.assertFalse(
symbolfile.should_omit_version(
- symbolfile.Version('foo', None, [Tag('arm')], []), Arch('arm'),
- 9, False, False))
-
- self.assertTrue(
- symbolfile.should_omit_version(
- symbolfile.Version('foo', None, [Tag('x86')], []), Arch('arm'),
- 9, False, False))
-
- def test_omit_api(self) -> None:
- self.assertFalse(
- symbolfile.should_omit_version(
- symbolfile.Version('foo', None, [], []), Arch('arm'), 9, False,
- False))
- self.assertFalse(
- symbolfile.should_omit_version(
- symbolfile.Version('foo', None, [Tag('introduced=9')], []),
+ symbolfile.Version('foo', None, Tags.from_strs(['arm']), []),
Arch('arm'), 9, False, False))
self.assertTrue(
symbolfile.should_omit_version(
- symbolfile.Version('foo', None, [Tag('introduced=14')], []),
+ symbolfile.Version('foo', None, Tags.from_strs(['x86']), []),
+ Arch('arm'), 9, False, False))
+
+ def test_omit_api(self) -> None:
+ self.assertFalse(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9,
+ False, False))
+ self.assertFalse(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo', None,
+ Tags.from_strs(['introduced=9']), []),
+ Arch('arm'), 9, False, False))
+
+ self.assertTrue(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo', None,
+ Tags.from_strs(['introduced=14']), []),
Arch('arm'), 9, False, False))
@@ -279,58 +305,72 @@
def test_omit_llndk(self) -> None:
self.assertTrue(
symbolfile.should_omit_symbol(
- symbolfile.Symbol('foo', [Tag('llndk')]), Arch('arm'), 9,
- False, False))
+ symbolfile.Symbol('foo', Tags.from_strs(['llndk'])),
+ Arch('arm'), 9, False, False))
self.assertFalse(
- symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []),
+ symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()),
Arch('arm'), 9, True, False))
self.assertFalse(
symbolfile.should_omit_symbol(
- symbolfile.Symbol('foo', [Tag('llndk')]), Arch('arm'), 9, True,
- False))
+ symbolfile.Symbol('foo', Tags.from_strs(['llndk'])),
+ Arch('arm'), 9, True, False))
def test_omit_apex(self) -> None:
self.assertTrue(
symbolfile.should_omit_symbol(
- symbolfile.Symbol('foo', [Tag('apex')]), Arch('arm'), 9, False,
- False))
+ symbolfile.Symbol('foo', Tags.from_strs(['apex'])),
+ Arch('arm'), 9, False, False))
self.assertFalse(
- symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []),
+ symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()),
Arch('arm'), 9, False, True))
self.assertFalse(
symbolfile.should_omit_symbol(
- symbolfile.Symbol('foo', [Tag('apex')]), Arch('arm'), 9, False,
- True))
+ symbolfile.Symbol('foo', Tags.from_strs(['apex'])),
+ Arch('arm'), 9, False, True))
+
+ def test_omit_systemapi(self) -> None:
+ self.assertTrue(
+ symbolfile.should_omit_symbol(
+ symbolfile.Symbol('foo', Tags.from_strs(['systemapi'])),
+ Arch('arm'), 9, False, False))
+
+ self.assertFalse(
+ symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()),
+ Arch('arm'), 9, False, True))
+ self.assertFalse(
+ symbolfile.should_omit_symbol(
+ symbolfile.Symbol('foo', Tags.from_strs(['systemapi'])),
+ Arch('arm'), 9, False, True))
def test_omit_arch(self) -> None:
self.assertFalse(
- symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []),
+ symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()),
Arch('arm'), 9, False, False))
self.assertFalse(
symbolfile.should_omit_symbol(
- symbolfile.Symbol('foo', [Tag('arm')]), Arch('arm'), 9, False,
- False))
+ symbolfile.Symbol('foo', Tags.from_strs(['arm'])), Arch('arm'),
+ 9, False, False))
self.assertTrue(
symbolfile.should_omit_symbol(
- symbolfile.Symbol('foo', [Tag('x86')]), Arch('arm'), 9, False,
- False))
+ symbolfile.Symbol('foo', Tags.from_strs(['x86'])), Arch('arm'),
+ 9, False, False))
def test_omit_api(self) -> None:
self.assertFalse(
- symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []),
+ symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()),
Arch('arm'), 9, False, False))
self.assertFalse(
symbolfile.should_omit_symbol(
- symbolfile.Symbol('foo', [Tag('introduced=9')]), Arch('arm'),
- 9, False, False))
+ symbolfile.Symbol('foo', Tags.from_strs(['introduced=9'])),
+ Arch('arm'), 9, False, False))
self.assertTrue(
symbolfile.should_omit_symbol(
- symbolfile.Symbol('foo', [Tag('introduced=14')]), Arch('arm'),
- 9, False, False))
+ symbolfile.Symbol('foo', Tags.from_strs(['introduced=14'])),
+ Arch('arm'), 9, False, False))
class SymbolFileParseTest(unittest.TestCase):
@@ -376,11 +416,11 @@
version = parser.parse_version()
self.assertEqual('VERSION_1', version.name)
self.assertIsNone(version.base)
- self.assertEqual(['foo', 'bar'], version.tags)
+ self.assertEqual(Tags.from_strs(['foo', 'bar']), version.tags)
expected_symbols = [
- symbolfile.Symbol('baz', []),
- symbolfile.Symbol('qux', [Tag('woodly'), Tag('doodly')]),
+ symbolfile.Symbol('baz', Tags()),
+ symbolfile.Symbol('qux', Tags.from_strs(['woodly', 'doodly'])),
]
self.assertEqual(expected_symbols, version.symbols)
@@ -388,7 +428,7 @@
version = parser.parse_version()
self.assertEqual('VERSION_2', version.name)
self.assertEqual('VERSION_1', version.base)
- self.assertEqual([], version.tags)
+ self.assertEqual(Tags(), version.tags)
def test_parse_version_eof(self) -> None:
input_file = io.StringIO(textwrap.dedent("""\
@@ -423,12 +463,12 @@
parser.next_line()
symbol = parser.parse_symbol()
self.assertEqual('foo', symbol.name)
- self.assertEqual([], symbol.tags)
+ self.assertEqual(Tags(), symbol.tags)
parser.next_line()
symbol = parser.parse_symbol()
self.assertEqual('bar', symbol.name)
- self.assertEqual(['baz', 'qux'], symbol.tags)
+ self.assertEqual(Tags.from_strs(['baz', 'qux']), symbol.tags)
def test_wildcard_symbol_global(self) -> None:
input_file = io.StringIO(textwrap.dedent("""\
@@ -497,14 +537,15 @@
versions = parser.parse()
expected = [
- symbolfile.Version('VERSION_1', None, [], [
- symbolfile.Symbol('foo', []),
- symbolfile.Symbol('bar', [Tag('baz')]),
+ symbolfile.Version('VERSION_1', None, Tags(), [
+ symbolfile.Symbol('foo', Tags()),
+ symbolfile.Symbol('bar', Tags.from_strs(['baz'])),
]),
- symbolfile.Version('VERSION_2', 'VERSION_1', [Tag('wasd')], [
- symbolfile.Symbol('woodly', []),
- symbolfile.Symbol('doodly', [Tag('asdf')]),
- ]),
+ symbolfile.Version(
+ 'VERSION_2', 'VERSION_1', Tags.from_strs(['wasd']), [
+ symbolfile.Symbol('woodly', Tags()),
+ symbolfile.Symbol('doodly', Tags.from_strs(['asdf'])),
+ ]),
]
self.assertEqual(expected, versions)
@@ -527,10 +568,10 @@
self.assertIsNone(version.base)
expected_symbols = [
- symbolfile.Symbol('foo', []),
- symbolfile.Symbol('bar', [Tag('llndk')]),
- symbolfile.Symbol('baz', [Tag('llndk'), Tag('apex')]),
- symbolfile.Symbol('qux', [Tag('apex')]),
+ symbolfile.Symbol('foo', Tags()),
+ symbolfile.Symbol('bar', Tags.from_strs(['llndk'])),
+ symbolfile.Symbol('baz', Tags.from_strs(['llndk', 'apex'])),
+ symbolfile.Symbol('qux', Tags.from_strs(['apex'])),
]
self.assertEqual(expected_symbols, version.symbols)
diff --git a/cc/testing.go b/cc/testing.go
index fb9dc9c..80cc0ef 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -497,7 +497,7 @@
}
cc_genrule {
- name: "host_bionic_linker_flags",
+ name: "host_bionic_linker_script",
host_supported: true,
device_supported: false,
target: {
@@ -508,7 +508,7 @@
enabled: true,
},
},
- out: ["linker.flags"],
+ out: ["linker.script"],
}
cc_defaults {
diff --git a/cmd/extract_linker/main.go b/cmd/extract_linker/main.go
index ea0bf4e..2dcb894 100644
--- a/cmd/extract_linker/main.go
+++ b/cmd/extract_linker/main.go
@@ -13,7 +13,7 @@
// limitations under the License.
// This tool extracts ELF LOAD segments from our linker binary, and produces an
-// assembly file and linker flags which will embed those segments as sections
+// assembly file and linker script which will embed those segments as sections
// in another binary.
package main
@@ -31,10 +31,10 @@
func main() {
var asmPath string
- var flagsPath string
+ var scriptPath string
flag.StringVar(&asmPath, "s", "", "Path to save the assembly file")
- flag.StringVar(&flagsPath, "f", "", "Path to save the linker flags")
+ flag.StringVar(&scriptPath, "T", "", "Path to save the linker script")
flag.Parse()
f, err := os.Open(flag.Arg(0))
@@ -49,20 +49,30 @@
}
asm := &bytes.Buffer{}
+ script := &bytes.Buffer{}
baseLoadAddr := uint64(0x1000)
load := 0
- linkFlags := []string{}
fmt.Fprintln(asm, ".globl __dlwrap_linker_offset")
fmt.Fprintf(asm, ".set __dlwrap_linker_offset, 0x%x\n", baseLoadAddr)
+ fmt.Fprintln(script, "ENTRY(__dlwrap__start)")
+ fmt.Fprintln(script, "SECTIONS {")
+
for _, prog := range ef.Progs {
if prog.Type != elf.PT_LOAD {
continue
}
- sectionName := fmt.Sprintf(".linker.sect%d", load)
- symName := fmt.Sprintf("__dlwrap_linker_sect%d", load)
+ var progName string
+ progSection := progToFirstSection(prog, ef.Sections)
+ if progSection != nil {
+ progName = progSection.Name
+ } else {
+ progName = fmt.Sprintf(".sect%d", load)
+ }
+ sectionName := ".linker" + progName
+ symName := "__dlwrap_linker" + strings.ReplaceAll(progName, ".", "_")
flags := ""
if prog.Flags&elf.PF_W != 0 {
@@ -75,10 +85,9 @@
fmt.Fprintf(asm, ".globl %s\n%s:\n\n", symName, symName)
- linkFlags = append(linkFlags,
- fmt.Sprintf("-Wl,--undefined=%s", symName),
- fmt.Sprintf("-Wl,--section-start=%s=0x%x",
- sectionName, baseLoadAddr+prog.Vaddr))
+ fmt.Fprintf(script, " %s %d : {\n", sectionName, baseLoadAddr+prog.Vaddr)
+ fmt.Fprintf(script, " KEEP(*(%s));\n", sectionName)
+ fmt.Fprintln(script, " }")
buffer, _ := ioutil.ReadAll(prog.Open())
bytesToAsm(asm, buffer)
@@ -97,16 +106,18 @@
load += 1
}
+ fmt.Fprintln(script, "}")
+ fmt.Fprintln(script, "INSERT BEFORE .note.android.ident;")
+
if asmPath != "" {
if err := ioutil.WriteFile(asmPath, asm.Bytes(), 0777); err != nil {
log.Fatalf("Unable to write %q: %v", asmPath, err)
}
}
- if flagsPath != "" {
- flags := strings.Join(linkFlags, " ")
- if err := ioutil.WriteFile(flagsPath, []byte(flags), 0777); err != nil {
- log.Fatalf("Unable to write %q: %v", flagsPath, err)
+ if scriptPath != "" {
+ if err := ioutil.WriteFile(scriptPath, script.Bytes(), 0777); err != nil {
+ log.Fatalf("Unable to write %q: %v", scriptPath, err)
}
}
}
@@ -125,3 +136,12 @@
}
fmt.Fprintln(asm)
}
+
+func progToFirstSection(prog *elf.Prog, sections []*elf.Section) *elf.Section {
+ for _, section := range sections {
+ if section.Addr == prog.Vaddr {
+ return section
+ }
+ }
+ return nil
+}
diff --git a/cmd/host_bionic_inject/Android.bp b/cmd/host_bionic_verify/Android.bp
similarity index 82%
rename from cmd/host_bionic_inject/Android.bp
rename to cmd/host_bionic_verify/Android.bp
index 16bc179..4e7c379 100644
--- a/cmd/host_bionic_inject/Android.bp
+++ b/cmd/host_bionic_verify/Android.bp
@@ -17,8 +17,7 @@
}
blueprint_go_binary {
- name: "host_bionic_inject",
- deps: ["soong-symbol_inject"],
- srcs: ["host_bionic_inject.go"],
- testSrcs: ["host_bionic_inject_test.go"],
+ name: "host_bionic_verify",
+ srcs: ["host_bionic_verify.go"],
+ testSrcs: ["host_bionic_verify_test.go"],
}
diff --git a/cmd/host_bionic_inject/host_bionic_inject.go b/cmd/host_bionic_verify/host_bionic_verify.go
similarity index 68%
rename from cmd/host_bionic_inject/host_bionic_inject.go
rename to cmd/host_bionic_verify/host_bionic_verify.go
index ce8b062..52400a3 100644
--- a/cmd/host_bionic_inject/host_bionic_inject.go
+++ b/cmd/host_bionic_verify/host_bionic_verify.go
@@ -12,8 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// Verifies a host bionic executable with an embedded linker, then injects
-// the address of the _start function for the linker_wrapper to use.
+// Verifies a host bionic executable with an embedded linker.
package main
import (
@@ -22,19 +21,16 @@
"fmt"
"io"
"os"
-
- "android/soong/symbol_inject"
)
func main() {
- var inputFile, linkerFile, outputFile string
+ var inputFile, linkerFile string
flag.StringVar(&inputFile, "i", "", "Input file")
flag.StringVar(&linkerFile, "l", "", "Linker file")
- flag.StringVar(&outputFile, "o", "", "Output file")
flag.Parse()
- if inputFile == "" || linkerFile == "" || outputFile == "" || flag.NArg() != 0 {
+ if inputFile == "" || linkerFile == "" || flag.NArg() != 0 {
flag.Usage()
os.Exit(1)
}
@@ -46,75 +42,52 @@
}
defer r.Close()
- file, err := symbol_inject.OpenFile(r)
- if err != nil {
- fmt.Fprintln(os.Stderr, err.Error())
- os.Exit(3)
- }
-
linker, err := elf.Open(linkerFile)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(4)
}
- startAddr, err := parseElf(r, linker)
+ err = checkElf(r, linker)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(5)
}
-
- w, err := os.OpenFile(outputFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777)
- if err != nil {
- fmt.Fprintln(os.Stderr, err.Error())
- os.Exit(6)
- }
- defer w.Close()
-
- err = symbol_inject.InjectUint64Symbol(file, w, "__dlwrap_original_start", startAddr)
- if err != nil {
- fmt.Fprintln(os.Stderr, err.Error())
- os.Exit(7)
- }
}
// Check the ELF file, and return the address to the _start function
-func parseElf(r io.ReaderAt, linker *elf.File) (uint64, error) {
+func checkElf(r io.ReaderAt, linker *elf.File) error {
file, err := elf.NewFile(r)
if err != nil {
- return 0, err
+ return err
}
symbols, err := file.Symbols()
if err != nil {
- return 0, err
+ return err
}
for _, prog := range file.Progs {
if prog.Type == elf.PT_INTERP {
- return 0, fmt.Errorf("File should not have a PT_INTERP header")
+ return fmt.Errorf("File should not have a PT_INTERP header")
}
}
if dlwrap_start, err := findSymbol(symbols, "__dlwrap__start"); err != nil {
- return 0, err
+ return err
} else if dlwrap_start.Value != file.Entry {
- return 0, fmt.Errorf("Expected file entry(0x%x) to point to __dlwrap_start(0x%x)",
+ return fmt.Errorf("Expected file entry(0x%x) to point to __dlwrap_start(0x%x)",
file.Entry, dlwrap_start.Value)
}
err = checkLinker(file, linker, symbols)
if err != nil {
- return 0, fmt.Errorf("Linker executable failed verification against app embedded linker: %s\n"+
+ return fmt.Errorf("Linker executable failed verification against app embedded linker: %s\n"+
"linker might not be in sync with crtbegin_dynamic.o.",
err)
}
- start, err := findSymbol(symbols, "_start")
- if err != nil {
- return 0, fmt.Errorf("Failed to find _start symbol")
- }
- return start.Value, nil
+ return nil
}
func findSymbol(symbols []elf.Symbol, name string) (elf.Symbol, error) {
diff --git a/cmd/host_bionic_inject/host_bionic_inject_test.go b/cmd/host_bionic_verify/host_bionic_verify_test.go
similarity index 100%
rename from cmd/host_bionic_inject/host_bionic_inject_test.go
rename to cmd/host_bionic_verify/host_bionic_verify_test.go
diff --git a/docs/map_files.md b/docs/map_files.md
index 192530f..1388059 100644
--- a/docs/map_files.md
+++ b/docs/map_files.md
@@ -70,9 +70,11 @@
### apex
-Indicates that the version or symbol is to be exposed in the APEX stubs rather
-than the NDK. May be used in combination with `llndk` if the symbol is exposed
-to both APEX and the LL-NDK.
+Indicates that the version or symbol is to be exposed by an APEX rather than the
+NDK. For APIs exposed by the platform *for* APEX, use `systemapi`.
+
+May be used in combination with `llndk` if the symbol is exposed to both APEX
+and the LL-NDK.
### future
@@ -144,6 +146,12 @@
preferable to keep such APIs in an entirely separate library to protect them
from access via `dlsym`, but this is not always possible.
+### systemapi
+
+This is a synonym of the `apex` tag. It should be used to clarify that the API
+is an API exposed by the system for an APEX, whereas `apex` should be used for
+APIs exposed by an APEX to the platform or another APEX.
+
### var
Used to define a public global variable. By default all symbols are exposed as
diff --git a/java/base.go b/java/base.go
index 440b004..1daa108 100644
--- a/java/base.go
+++ b/java/base.go
@@ -155,6 +155,11 @@
// List of java_plugin modules that provide extra errorprone checks.
Extra_check_modules []string
+
+ // Whether to run errorprone on a normal build. If this is false, errorprone
+ // will still be run if the RUN_ERROR_PRONE environment variable is true.
+ // Default false.
+ Enabled *bool
}
Proto struct {
@@ -701,7 +706,7 @@
// javaVersion flag.
flags.javaVersion = getJavaVersion(ctx, String(j.properties.Java_version), android.SdkContext(j))
- if ctx.Config().RunErrorProne() {
+ if ctx.Config().RunErrorProne() || Bool(j.properties.Errorprone.Enabled) {
if config.ErrorProneClasspath == nil && ctx.Config().TestProductVariables == nil {
ctx.ModuleErrorf("cannot build with Error Prone, missing external/error_prone?")
}
@@ -972,14 +977,23 @@
}
if len(uniqueSrcFiles) > 0 || len(srcJars) > 0 {
var extraJarDeps android.Paths
- if ctx.Config().RunErrorProne() {
- // If error-prone is enabled, add an additional rule to compile the java files into
- // a separate set of classes (so that they don't overwrite the normal ones and require
- // a rebuild when error-prone is turned off).
- // TODO(ccross): Once we always compile with javac9 we may be able to conditionally
- // enable error-prone without affecting the output class files.
+ if Bool(j.properties.Errorprone.Enabled) {
+ // If error-prone is enabled, enable errorprone flags on the regular
+ // build.
+ flags = enableErrorproneFlags(flags)
+ } else if ctx.Config().RunErrorProne() {
+ // Otherwise, if the RUN_ERROR_PRONE environment variable is set, create
+ // a new jar file just for compiling with the errorprone compiler to.
+ // This is because we don't want to cause the java files to get completely
+ // rebuilt every time the state of the RUN_ERROR_PRONE variable changes.
+ // We also don't want to run this if errorprone is enabled by default for
+ // this module, or else we could have duplicated errorprone messages.
+ errorproneFlags := enableErrorproneFlags(flags)
errorprone := android.PathForModuleOut(ctx, "errorprone", jarName)
- RunErrorProne(ctx, errorprone, uniqueSrcFiles, srcJars, flags)
+
+ transformJavaToClasses(ctx, errorprone, -1, uniqueSrcFiles, srcJars, errorproneFlags, nil,
+ "errorprone", "errorprone")
+
extraJarDeps = append(extraJarDeps, errorprone)
}
@@ -1303,6 +1317,21 @@
j.outputFile = outputFile.WithoutRel()
}
+// Returns a copy of the supplied flags, but with all the errorprone-related
+// fields copied to the regular build's fields.
+func enableErrorproneFlags(flags javaBuilderFlags) javaBuilderFlags {
+ flags.processorPath = append(flags.errorProneProcessorPath, flags.processorPath...)
+
+ if len(flags.errorProneExtraJavacFlags) > 0 {
+ if len(flags.javacFlags) > 0 {
+ flags.javacFlags += " " + flags.errorProneExtraJavacFlags
+ } else {
+ flags.javacFlags = flags.errorProneExtraJavacFlags
+ }
+ }
+ return flags
+}
+
func (j *Module) compileJavaClasses(ctx android.ModuleContext, jarName string, idx int,
srcFiles, srcJars android.Paths, flags javaBuilderFlags, extraJarDeps android.Paths) android.WritablePath {
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 1c7ad78..fc8f557 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -140,7 +140,7 @@
// produceHiddenAPIAllFlagsFile produces the all-flags.csv and intermediate files.
//
// Updates the supplied hiddenAPIInfo with the paths to the generated files set.
- produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []hiddenAPIModule, input HiddenAPIFlagInput) *HiddenAPIFlagOutput
+ produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIFlagOutput
}
var _ commonBootclasspathFragment = (*BootclasspathFragmentModule)(nil)
@@ -465,7 +465,7 @@
if unencodedDex == nil {
// This is an error. Sometimes Soong will report the error directly, other times it will
// defer the error reporting to happen only when trying to use the missing file in ninja.
- // Either way it is handled by extractBootDexJarsFromHiddenAPIModules which must have been
+ // Either way it is handled by extractBootDexJarsFromModules which must have been
// called before this as it generates the flags that are used to encode these files.
continue
}
@@ -561,12 +561,9 @@
// TODO(b/179354495): Stop hidden API processing being conditional once all bootclasspath_fragment
// modules have been updated to support it.
if input.canPerformHiddenAPIProcessing(ctx, b.properties) {
- // Get the content modules that contribute to the hidden API processing.
- hiddenAPIModules := gatherHiddenAPIModuleFromContents(ctx, contents)
-
// Delegate the production of the hidden API all-flags.csv file to a module type specific method.
common := ctx.Module().(commonBootclasspathFragment)
- output = common.produceHiddenAPIAllFlagsFile(ctx, hiddenAPIModules, input)
+ output = common.produceHiddenAPIAllFlagsFile(ctx, contents, input)
}
// Initialize a HiddenAPIInfo structure.
@@ -620,7 +617,7 @@
// produceHiddenAPIAllFlagsFile produces the hidden API all-flags.csv file (and supporting files)
// for the fragment.
-func (b *BootclasspathFragmentModule) produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []hiddenAPIModule, input HiddenAPIFlagInput) *HiddenAPIFlagOutput {
+func (b *BootclasspathFragmentModule) produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIFlagOutput {
// Generate the rules to create the hidden API flags and update the supplied hiddenAPIInfo with the
// paths to the created files.
return hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx, contents, input)
@@ -648,7 +645,8 @@
}
// Copy the dex jars of this fragment's content modules to their predefined locations.
- copyBootJarsToPredefinedLocations(ctx, contents, imageConfig.modules, imageConfig.dexPaths)
+ bootDexJarByModule := extractEncodedDexJarsFromModules(ctx, contents)
+ copyBootJarsToPredefinedLocations(ctx, bootDexJarByModule, imageConfig.dexPathsByModule)
// Build a profile for the image config and then use that to build the boot image.
profile := bootImageProfileRule(ctx, imageConfig)
@@ -763,7 +761,7 @@
// Copy manually curated flag files specified on the bootclasspath_fragment.
if b.Flag_files_by_category != nil {
- for _, category := range hiddenAPIFlagFileCategories {
+ for _, category := range HiddenAPIFlagFileCategories {
paths := b.Flag_files_by_category[category]
if len(paths) > 0 {
dests := []string{}
@@ -772,7 +770,7 @@
builder.CopyToSnapshot(p, dest)
dests = append(dests, dest)
}
- hiddenAPISet.AddProperty(category.propertyName, dests)
+ hiddenAPISet.AddProperty(category.PropertyName, dests)
}
}
}
@@ -840,7 +838,7 @@
// produceHiddenAPIAllFlagsFile returns a path to the prebuilt all-flags.csv or nil if none is
// specified.
-func (module *prebuiltBootclasspathFragmentModule) produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []hiddenAPIModule, _ HiddenAPIFlagInput) *HiddenAPIFlagOutput {
+func (module *prebuiltBootclasspathFragmentModule) produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []android.Module, _ HiddenAPIFlagInput) *HiddenAPIFlagOutput {
pathForOptionalSrc := func(src *string) android.Path {
if src == nil {
// TODO(b/179354495): Fail if this is not provided once prebuilts have been updated.
diff --git a/java/builder.go b/java/builder.go
index cde8731..ea011b8 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -279,23 +279,6 @@
transformJavaToClasses(ctx, outputFile, shardIdx, srcFiles, srcJars, flags, deps, "javac", desc)
}
-func RunErrorProne(ctx android.ModuleContext, outputFile android.WritablePath,
- srcFiles, srcJars android.Paths, flags javaBuilderFlags) {
-
- flags.processorPath = append(flags.errorProneProcessorPath, flags.processorPath...)
-
- if len(flags.errorProneExtraJavacFlags) > 0 {
- if len(flags.javacFlags) > 0 {
- flags.javacFlags += " " + flags.errorProneExtraJavacFlags
- } else {
- flags.javacFlags = flags.errorProneExtraJavacFlags
- }
- }
-
- transformJavaToClasses(ctx, outputFile, -1, srcFiles, srcJars, flags, nil,
- "errorprone", "errorprone")
-}
-
// Emits the rule to generate Xref input file (.kzip file) for the given set of source files and source jars
// to compile with given set of builder flags, etc.
func emitXrefRule(ctx android.ModuleContext, xrefFile android.WritablePath, idx int,
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index e1a3650..dc8df5e 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -15,7 +15,6 @@
package java
import (
- "fmt"
"path/filepath"
"sort"
"strings"
@@ -254,6 +253,9 @@
dexPaths android.WritablePaths // for this image
dexPathsDeps android.WritablePaths // for the dependency images and in this image
+ // Map from module name (without prebuilt_ prefix) to the predefined build path.
+ dexPathsByModule map[string]android.WritablePath
+
// File path to a zip archive with all image files (or nil, if not needed).
zip android.WritablePath
@@ -276,13 +278,24 @@
dexLocationsDeps []string // for the dependency images and in this image
// Paths to image files.
- imagePathOnHost android.OutputPath // first image file path on host
- imagePathOnDevice string // first image file path on device
- imagesDeps android.OutputPaths // all files
+ imagePathOnHost android.OutputPath // first image file path on host
+ imagePathOnDevice string // first image file path on device
- // Only for extensions, paths to the primary boot images.
+ // All the files that constitute this image variant, i.e. .art, .oat and .vdex files.
+ imagesDeps android.OutputPaths
+
+ // The path to the primary image variant's imagePathOnHost field, where primary image variant
+ // means the image variant that this extends.
+ //
+ // This is only set for a variant of an image that extends another image.
primaryImages android.OutputPath
+ // The paths to the primary image variant's imagesDeps field, where primary image variant
+ // means the image variant that this extends.
+ //
+ // This is only set for a variant of an image that extends another image.
+ primaryImagesDeps android.Paths
+
// Rules which should be used in make to install the outputs.
installs android.RuleBuilderInstalls
vdexInstalls android.RuleBuilderInstalls
@@ -450,53 +463,27 @@
return true
}
-// copyBootJarsToPredefinedLocations generates commands that will copy boot jars to
-// predefined paths in the global config.
-func copyBootJarsToPredefinedLocations(ctx android.ModuleContext, bootModules []android.Module, bootjars android.ConfiguredJarList, jarPathsPredefined android.WritablePaths) {
- jarPaths := make(android.Paths, bootjars.Len())
- for i, module := range bootModules {
- if module != nil {
- bootDexJar := module.(interface{ DexJarBuildPath() android.Path }).DexJarBuildPath()
- jarPaths[i] = bootDexJar
+// copyBootJarsToPredefinedLocations generates commands that will copy boot jars to predefined
+// paths in the global config.
+func copyBootJarsToPredefinedLocations(ctx android.ModuleContext, srcBootDexJarsByModule bootDexJarByModule, dstBootJarsByModule map[string]android.WritablePath) {
+ // Create the super set of module names.
+ names := []string{}
+ names = append(names, android.SortedStringKeys(srcBootDexJarsByModule)...)
+ names = append(names, android.SortedStringKeys(dstBootJarsByModule)...)
+ names = android.SortedUniqueStrings(names)
+ for _, name := range names {
+ src := srcBootDexJarsByModule[name]
+ dst := dstBootJarsByModule[name]
- name := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(module))
- if bootjars.Jar(i) != name {
- ctx.ModuleErrorf("expected module %s at position %d but found %s", bootjars.Jar(i), i, name)
- }
- }
- }
-
- // The paths to bootclasspath DEX files need to be known at module GenerateAndroidBuildAction
- // time, before the boot images are built (these paths are used in dexpreopt rule generation for
- // Java libraries and apps). Generate rules that copy bootclasspath DEX jars to the predefined
- // paths.
- for i := range jarPaths {
- input := jarPaths[i]
- output := jarPathsPredefined[i]
- module := bootjars.Jar(i)
- if input == nil {
- if ctx.Config().AllowMissingDependencies() {
- apex := bootjars.Apex(i)
-
- // Create an error rule that pretends to create the output file but will actually fail if it
- // is run.
- ctx.Build(pctx, android.BuildParams{
- Rule: android.ErrorRule,
- Output: output,
- Args: map[string]string{
- "error": fmt.Sprintf("missing dependencies: dex jar for %s:%s", module, apex),
- },
- })
- } else {
- ctx.ModuleErrorf("failed to find a dex jar path for module '%s'"+
- ", note that some jars may be filtered out by module constraints", module)
- }
-
+ if src == nil {
+ ctx.ModuleErrorf("module %s does not provide a dex boot jar", name)
+ } else if dst == nil {
+ ctx.ModuleErrorf("module %s is not part of the boot configuration", name)
} else {
ctx.Build(pctx, android.BuildParams{
Rule: android.Cp,
- Input: input,
- Output: output,
+ Input: src,
+ Output: dst,
})
}
}
@@ -588,7 +575,15 @@
cmd.
Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
Flag("--runtime-arg").FlagWithList("-Xbootclasspath-locations:", image.dexLocationsDeps, ":").
- FlagWithArg("--boot-image=", dexpreopt.PathToLocation(artImage, arch)).Implicit(artImage)
+ // Add the path to the first file in the boot image with the arch specific directory removed,
+ // dex2oat will reconstruct the path to the actual file when it needs it. As the actual path
+ // to the file cannot be passed to the command make sure to add the actual path as an Implicit
+ // dependency to ensure that it is built before the command runs.
+ FlagWithArg("--boot-image=", dexpreopt.PathToLocation(artImage, arch)).Implicit(artImage).
+ // Similarly, the dex2oat tool will automatically find the paths to other files in the base
+ // boot image so make sure to add them as implicit dependencies to ensure that they are built
+ // before this command is run.
+ Implicits(image.primaryImagesDeps)
} else {
// It is a primary image, so it needs a base address.
cmd.FlagWithArg("--base=", ctx.Config().LibartImgDeviceBaseAddress())
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 39a3e11..b13955f 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -100,6 +100,7 @@
// TODO(b/143682396): use module dependencies instead
inputDir := deviceDir.Join(ctx, "dex_"+c.name+"jars_input")
c.dexPaths = c.modules.BuildPaths(ctx, inputDir)
+ c.dexPathsByModule = c.modules.BuildPathsByModule(ctx, inputDir)
c.dexPathsDeps = c.dexPaths
// Create target-specific variants.
@@ -125,6 +126,7 @@
frameworkCfg.dexPathsDeps = append(artCfg.dexPathsDeps, frameworkCfg.dexPathsDeps...)
for i := range targets {
frameworkCfg.variants[i].primaryImages = artCfg.variants[i].imagePathOnHost
+ frameworkCfg.variants[i].primaryImagesDeps = artCfg.variants[i].imagesDeps.Paths()
frameworkCfg.variants[i].dexLocationsDeps = append(artCfg.variants[i].dexLocations, frameworkCfg.variants[i].dexLocationsDeps...)
}
@@ -152,6 +154,9 @@
// later on a singleton adds commands to copy actual jars to the predefined paths.
dexPaths android.WritablePaths
+ // Map from module name (without prebuilt_ prefix) to the predefined build path.
+ dexPathsByModule map[string]android.WritablePath
+
// A list of dex locations (a.k.a. on-device paths) to the boot jars.
dexLocations []string
}
@@ -165,10 +170,11 @@
dir := android.PathForOutput(ctx, ctx.Config().DeviceName(), "updatable_bootjars")
dexPaths := updatableBootJars.BuildPaths(ctx, dir)
+ dexPathsByModuleName := updatableBootJars.BuildPathsByModule(ctx, dir)
dexLocations := updatableBootJars.DevicePaths(ctx.Config(), android.Android)
- return updatableBootConfig{updatableBootJars, dexPaths, dexLocations}
+ return updatableBootConfig{updatableBootJars, dexPaths, dexPathsByModuleName, dexLocations}
}).(updatableBootConfig)
}
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index e9693c6..f901434 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -219,7 +219,6 @@
BuiltTool("merge_csv").
Flag("--zip_input").
Flag("--key_field signature").
- FlagWithArg("--header=", "signature,file,startline,startcol,endline,endcol,properties").
FlagWithOutput("--output=", indexCSV).
Inputs(classesJars)
rule.Build(desc, desc)
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index f2649d3..643c5cb 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -248,8 +248,8 @@
}
type hiddenAPIFlagFileCategory struct {
- // propertyName is the name of the property for this category.
- propertyName string
+ // PropertyName is the name of the property for this category.
+ PropertyName string
// propertyValueReader retrieves the value of the property for this category from the set of
// properties.
@@ -262,12 +262,12 @@
// The flag file category for removed members of the API.
//
-// This is extracted from hiddenAPIFlagFileCategories as it is needed to add the dex signatures
+// This is extracted from HiddenAPIFlagFileCategories as it is needed to add the dex signatures
// list of removed API members that are generated automatically from the removed.txt files provided
// by API stubs.
var hiddenAPIRemovedFlagFileCategory = &hiddenAPIFlagFileCategory{
// See HiddenAPIFlagFileProperties.Removed
- propertyName: "removed",
+ PropertyName: "removed",
propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
return properties.Removed
},
@@ -276,10 +276,10 @@
},
}
-var hiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{
+var HiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{
// See HiddenAPIFlagFileProperties.Unsupported
{
- propertyName: "unsupported",
+ PropertyName: "unsupported",
propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
return properties.Unsupported
},
@@ -290,7 +290,7 @@
hiddenAPIRemovedFlagFileCategory,
// See HiddenAPIFlagFileProperties.Max_target_r_low_priority
{
- propertyName: "max_target_r_low_priority",
+ PropertyName: "max_target_r_low_priority",
propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
return properties.Max_target_r_low_priority
},
@@ -300,7 +300,7 @@
},
// See HiddenAPIFlagFileProperties.Max_target_q
{
- propertyName: "max_target_q",
+ PropertyName: "max_target_q",
propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
return properties.Max_target_q
},
@@ -310,7 +310,7 @@
},
// See HiddenAPIFlagFileProperties.Max_target_p
{
- propertyName: "max_target_p",
+ PropertyName: "max_target_p",
propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
return properties.Max_target_p
},
@@ -320,7 +320,7 @@
},
// See HiddenAPIFlagFileProperties.Max_target_o_low_priority
{
- propertyName: "max_target_o_low_priority",
+ PropertyName: "max_target_o_low_priority",
propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
return properties.Max_target_o_low_priority
},
@@ -330,7 +330,7 @@
},
// See HiddenAPIFlagFileProperties.Blocked
{
- propertyName: "blocked",
+ PropertyName: "blocked",
propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
return properties.Blocked
},
@@ -340,7 +340,7 @@
},
// See HiddenAPIFlagFileProperties.Unsupported_packages
{
- propertyName: "unsupported_packages",
+ PropertyName: "unsupported_packages",
propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
return properties.Unsupported_packages
},
@@ -355,7 +355,7 @@
// append appends the supplied flags files to the corresponding category in this map.
func (s FlagFilesByCategory) append(other FlagFilesByCategory) {
- for _, category := range hiddenAPIFlagFileCategories {
+ for _, category := range HiddenAPIFlagFileCategories {
s[category] = append(s[category], other[category]...)
}
}
@@ -540,7 +540,7 @@
// extractFlagFilesFromProperties extracts the paths to flag files that are specified in the
// supplied properties and stores them in this struct.
func (i *HiddenAPIFlagInput) extractFlagFilesFromProperties(ctx android.ModuleContext, p *HiddenAPIFlagFileProperties) {
- for _, category := range hiddenAPIFlagFileCategories {
+ for _, category := range HiddenAPIFlagFileCategories {
paths := android.PathsForModuleSrc(ctx, category.propertyValueReader(p))
i.FlagFilesByCategory[category] = paths
}
@@ -571,6 +571,15 @@
AllFlagsPath android.Path
}
+// bootDexJarByModule is a map from base module name (without prebuilt_ prefix) to the boot dex
+// path.
+type bootDexJarByModule map[string]android.Path
+
+// addPath adds the path for a module to the map.
+func (b bootDexJarByModule) addPath(module android.Module, path android.Path) {
+ b[android.RemoveOptionalPrebuiltPrefix(module.Name())] = path
+}
+
// pathForValidation creates a path of the same type as the supplied type but with a name of
// <path>.valid.
//
@@ -630,7 +639,7 @@
FlagWithOutput("--output ", tempPath)
// Add the options for the different categories of flag files.
- for _, category := range hiddenAPIFlagFileCategories {
+ for _, category := range HiddenAPIFlagFileCategories {
paths := flagFilesByCategory[category]
for _, path := range paths {
category.commandMutator(command, path)
@@ -670,11 +679,11 @@
// * metadata.csv
// * index.csv
// * all-flags.csv
-func hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx android.ModuleContext, contents []hiddenAPIModule, input HiddenAPIFlagInput) *HiddenAPIFlagOutput {
+func hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIFlagOutput {
hiddenApiSubDir := "modular-hiddenapi"
// Gather the dex files for the boot libraries provided by this fragment.
- bootDexJars := extractBootDexJarsFromHiddenAPIModules(ctx, contents)
+ bootDexJars := extractBootDexJarsFromModules(ctx, contents)
// Generate the stub-flags.csv.
stubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "stub-flags.csv")
@@ -682,7 +691,7 @@
rule.Build("modularHiddenAPIStubFlagsFile", "modular hiddenapi stub flags")
// Extract the classes jars from the contents.
- classesJars := extractClassJarsFromHiddenAPIModules(ctx, contents)
+ classesJars := extractClassesJarsFromModules(contents)
// Generate the set of flags from the annotations in the source code.
annotationFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "annotation-flags.csv")
@@ -737,29 +746,18 @@
return android.OptionalPathForPath(output)
}
-// gatherHiddenAPIModuleFromContents gathers the hiddenAPIModule from the supplied contents.
-func gatherHiddenAPIModuleFromContents(ctx android.ModuleContext, contents []android.Module) []hiddenAPIModule {
- hiddenAPIModules := []hiddenAPIModule{}
- for _, module := range contents {
- if hiddenAPI, ok := module.(hiddenAPIModule); ok {
- hiddenAPIModules = append(hiddenAPIModules, hiddenAPI)
- } else if _, ok := module.(*DexImport); ok {
- // Ignore this for the purposes of hidden API processing
- } else {
- ctx.ModuleErrorf("module %s does not implement hiddenAPIModule", module)
- }
- }
- return hiddenAPIModules
-}
-
-// extractBootDexJarsFromHiddenAPIModules extracts the boot dex jars from the supplied modules.
-func extractBootDexJarsFromHiddenAPIModules(ctx android.ModuleContext, contents []hiddenAPIModule) android.Paths {
+// extractBootDexJarsFromModules extracts the boot dex jars from the supplied modules.
+func extractBootDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) android.Paths {
bootDexJars := android.Paths{}
for _, module := range contents {
- bootDexJar := module.bootDexJar()
+ hiddenAPIModule := hiddenAPIModuleFromModule(ctx, module)
+ if hiddenAPIModule == nil {
+ continue
+ }
+ bootDexJar := hiddenAPIModule.bootDexJar()
if bootDexJar == nil {
if ctx.Config().AlwaysUsePrebuiltSdks() {
- // TODO(b/179354495): Remove this work around when it is unnecessary.
+ // TODO(b/179354495): Remove this workaround when it is unnecessary.
// Prebuilt modules like framework-wifi do not yet provide dex implementation jars. So,
// create a fake one that will cause a build error only if it is used.
fake := android.PathForModuleOut(ctx, "fake/boot-dex/%s.jar", module.Name())
@@ -784,11 +782,142 @@
return bootDexJars
}
-// extractClassJarsFromHiddenAPIModules extracts the class jars from the supplied modules.
-func extractClassJarsFromHiddenAPIModules(ctx android.ModuleContext, contents []hiddenAPIModule) android.Paths {
+func hiddenAPIModuleFromModule(ctx android.BaseModuleContext, module android.Module) hiddenAPIModule {
+ if hiddenAPIModule, ok := module.(hiddenAPIModule); ok {
+ return hiddenAPIModule
+ } else if _, ok := module.(*DexImport); ok {
+ // Ignore this for the purposes of hidden API processing
+ } else {
+ ctx.ModuleErrorf("module %s does not implement hiddenAPIModule", module)
+ }
+
+ return nil
+}
+
+// extractClassesJarsFromModules extracts the class jars from the supplied modules.
+func extractClassesJarsFromModules(contents []android.Module) android.Paths {
classesJars := android.Paths{}
for _, module := range contents {
- classesJars = append(classesJars, module.classesJars()...)
+ classesJars = append(classesJars, retrieveClassesJarsFromModule(module)...)
}
return classesJars
}
+
+// retrieveClassesJarsFromModule retrieves the classes jars from the supplied module.
+func retrieveClassesJarsFromModule(module android.Module) android.Paths {
+ if hiddenAPIModule, ok := module.(hiddenAPIModule); ok {
+ return hiddenAPIModule.classesJars()
+ }
+
+ return nil
+}
+
+// deferReportingMissingBootDexJar returns true if a missing boot dex jar should not be reported by
+// Soong but should instead only be reported in ninja if the file is actually built.
+func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.Module) bool {
+ // TODO(b/179354495): Remove this workaround when it is unnecessary.
+ // Prebuilt modules like framework-wifi do not yet provide dex implementation jars. So,
+ // create a fake one that will cause a build error only if it is used.
+ if ctx.Config().AlwaysUsePrebuiltSdks() {
+ return true
+ }
+
+ // This is called for both platform_bootclasspath and bootclasspath_fragment modules.
+ //
+ // A bootclasspath_fragment module should only use the APEX variant of source or prebuilt modules.
+ // Ideally, a bootclasspath_fragment module should never have a platform variant created for it
+ // but unfortunately, due to b/187910671 it does.
+ //
+ // That causes issues when obtaining a boot dex jar for a prebuilt module as a prebuilt module
+ // used by a bootclasspath_fragment can only provide a boot dex jar when it is part of APEX, i.e.
+ // has an APEX variant not a platform variant.
+ //
+ // There are some other situations when a prebuilt module used by a bootclasspath_fragment cannot
+ // provide a boot dex jar:
+ // 1. If the bootclasspath_fragment is not exported by the prebuilt_apex/apex_set module then it
+ // does not have an APEX variant and only has a platform variant and neither do its content
+ // modules.
+ // 2. Some build configurations, e.g. setting TARGET_BUILD_USE_PREBUILT_SDKS causes all
+ // java_sdk_library_import modules to be treated as preferred and as many of them are not part
+ // of an apex they cannot provide a boot dex jar.
+ //
+ // The first case causes problems when the affected prebuilt modules are preferred but that is an
+ // invalid configuration and it is ok for it to fail as the work to enable that is not yet
+ // complete. The second case is used for building targets that do not use boot dex jars and so
+ // deferring error reporting to ninja is fine as the affected ninja targets should never be built.
+ // That is handled above.
+ //
+ // A platform_bootclasspath module can use libraries from both platform and APEX variants. Unlike
+ // the bootclasspath_fragment it supports dex_import modules which provides the dex file. So, it
+ // can obtain a boot dex jar from a prebuilt that is not part of an APEX. However, it is assumed
+ // that if the library can be part of an APEX then it is the APEX variant that is used.
+ //
+ // This check handles the slightly different requirements of the bootclasspath_fragment and
+ // platform_bootclasspath modules by only deferring error reporting for the platform variant of
+ // a prebuilt modules that has other variants which are part of an APEX.
+ //
+ // TODO(b/187910671): Remove this once platform variants are no longer created unnecessarily.
+ if android.IsModulePrebuilt(module) {
+ if am, ok := module.(android.ApexModule); ok && am.InAnyApex() {
+ apexInfo := ctx.OtherModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+ if apexInfo.IsForPlatform() {
+ return true
+ }
+ }
+ }
+
+ // A bootclasspath module that is part of a versioned sdk never provides a boot dex jar as there
+ // is no equivalently versioned prebuilt APEX file from which it can be obtained. However,
+ // versioned bootclasspath modules are processed by Soong so in order to avoid them causing build
+ // failures missing boot dex jars need to be deferred.
+ if android.IsModuleInVersionedSdk(ctx.Module()) {
+ return true
+ }
+
+ return false
+}
+
+// handleMissingDexBootFile will either log a warning or create an error rule to create the fake
+// file depending on the value returned from deferReportingMissingBootDexJar.
+func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, fake android.WritablePath) {
+ if deferReportingMissingBootDexJar(ctx, module) {
+ // Create an error rule that pretends to create the output file but will actually fail if it
+ // is run.
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.ErrorRule,
+ Output: fake,
+ Args: map[string]string{
+ "error": fmt.Sprintf("missing dependencies: boot dex jar for %s", module),
+ },
+ })
+ } else {
+ ctx.ModuleErrorf("module %s does not provide a dex jar", module)
+ }
+}
+
+// retrieveEncodedBootDexJarFromModule returns a path to the boot dex jar from the supplied module's
+// DexJarBuildPath() method.
+//
+// The returned path will usually be to a dex jar file that has been encoded with hidden API flags.
+// However, under certain conditions, e.g. errors, or special build configurations it will return
+// a path to a fake file.
+func retrieveEncodedBootDexJarFromModule(ctx android.ModuleContext, module android.Module) android.Path {
+ bootDexJar := module.(interface{ DexJarBuildPath() android.Path }).DexJarBuildPath()
+ if bootDexJar == nil {
+ fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/encoded-dex/%s.jar", module.Name()))
+ bootDexJar = fake
+
+ handleMissingDexBootFile(ctx, module, fake)
+ }
+ return bootDexJar
+}
+
+// extractEncodedDexJarsFromModules extracts the encoded dex jars from the supplied modules.
+func extractEncodedDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
+ encodedDexJarsByModuleName := bootDexJarByModule{}
+ for _, module := range contents {
+ path := retrieveEncodedBootDexJarFromModule(ctx, module)
+ encodedDexJarsByModuleName.addPath(module, path)
+ }
+ return encodedDexJarsByModuleName
+}
diff --git a/java/hiddenapi_monolithic.go b/java/hiddenapi_monolithic.go
index a6bf8c7..edf4235 100644
--- a/java/hiddenapi_monolithic.go
+++ b/java/hiddenapi_monolithic.go
@@ -99,4 +99,4 @@
i.AllFlagsPaths = android.FirstUniquePaths(i.AllFlagsPaths)
}
-var monolithicHiddenAPIInfoProvider = blueprint.NewProvider(MonolithicHiddenAPIInfo{})
+var MonolithicHiddenAPIInfoProvider = blueprint.NewProvider(MonolithicHiddenAPIInfo{})
diff --git a/java/java_test.go b/java/java_test.go
index bd373c1..78d9ab4 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1392,3 +1392,31 @@
assertDeepEquals(t, "Default installable value should be true.", proptools.BoolPtr(true),
module.properties.Installable)
}
+
+func TestErrorproneEnabled(t *testing.T) {
+ ctx, _ := testJava(t, `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ errorprone: {
+ enabled: true,
+ },
+ }
+ `)
+
+ javac := ctx.ModuleForTests("foo", "android_common").Description("javac")
+
+ // Test that the errorprone plugins are passed to javac
+ expectedSubstring := "-Xplugin:ErrorProne"
+ if !strings.Contains(javac.Args["javacFlags"], expectedSubstring) {
+ t.Errorf("expected javacFlags to conain %q, got %q", expectedSubstring, javac.Args["javacFlags"])
+ }
+
+ // Modules with errorprone { enabled: true } will include errorprone checks
+ // in the main javac build rule. Only when RUN_ERROR_PRONE is true will
+ // the explicit errorprone build rule be created.
+ errorprone := ctx.ModuleForTests("foo", "android_common").MaybeDescription("errorprone")
+ if errorprone.RuleParams.Description != "" {
+ t.Errorf("expected errorprone build rule to not exist, but it did")
+ }
+}
diff --git a/java/kotlin_test.go b/java/kotlin_test.go
index 1c146a1..fd2f3ca 100644
--- a/java/kotlin_test.go
+++ b/java/kotlin_test.go
@@ -185,7 +185,6 @@
buildOS := android.BuildOs.String()
kapt := result.ModuleForTests("foo", "android_common").Rule("kapt")
- //kotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc")
javac := result.ModuleForTests("foo", "android_common").Description("javac")
errorprone := result.ModuleForTests("foo", "android_common").Description("errorprone")
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 87c695c..fba73d0 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -280,7 +280,6 @@
}
monolithicInfo := b.createAndProvideMonolithicHiddenAPIInfo(ctx, fragments)
-
// Create the input to pass to ruleToGenerateHiddenAPIStubFlagsFile
input := newHiddenAPIFlagInput()
@@ -291,16 +290,14 @@
// Use the flag files from this module and all the fragments.
input.FlagFilesByCategory = monolithicInfo.FlagsFilesByCategory
- hiddenAPIModules := gatherHiddenAPIModuleFromContents(ctx, modules)
-
// Generate the monolithic stub-flags.csv file.
- bootDexJars := extractBootDexJarsFromHiddenAPIModules(ctx, hiddenAPIModules)
+ bootDexJars := extractBootDexJarsFromModules(ctx, modules)
stubFlags := hiddenAPISingletonPaths(ctx).stubFlags
rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlags, bootDexJars, input)
rule.Build("platform-bootclasspath-monolithic-hiddenapi-stub-flags", "monolithic hidden API stub flags")
// Extract the classes jars from the contents.
- classesJars := extractClassJarsFromHiddenAPIModules(ctx, hiddenAPIModules)
+ classesJars := extractClassesJarsFromModules(modules)
// Generate the annotation-flags.csv file from all the module annotations.
annotationFlags := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "annotation-flags.csv")
@@ -342,7 +339,7 @@
monolithicInfo := newMonolithicHiddenAPIInfo(ctx, temporaryInput.FlagFilesByCategory, fragments)
// Store the information for testing.
- ctx.SetProvider(monolithicHiddenAPIInfoProvider, monolithicInfo)
+ ctx.SetProvider(MonolithicHiddenAPIInfoProvider, monolithicInfo)
return monolithicInfo
}
@@ -390,11 +387,13 @@
generateUpdatableBcpPackagesRule(ctx, imageConfig, updatableModules)
// Copy non-updatable module dex jars to their predefined locations.
- copyBootJarsToPredefinedLocations(ctx, nonUpdatableModules, imageConfig.modules, imageConfig.dexPaths)
+ nonUpdatableBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, nonUpdatableModules)
+ copyBootJarsToPredefinedLocations(ctx, nonUpdatableBootDexJarsByModule, imageConfig.dexPathsByModule)
// Copy updatable module dex jars to their predefined locations.
config := GetUpdatableBootConfig(ctx)
- copyBootJarsToPredefinedLocations(ctx, updatableModules, config.modules, config.dexPaths)
+ updatableBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, updatableModules)
+ copyBootJarsToPredefinedLocations(ctx, updatableBootDexJarsByModule, config.dexPathsByModule)
// Build a profile for the image config and then use that to build the boot image.
profile := bootImageProfileRule(ctx, imageConfig)
diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go
index ed5549d..0318a07 100644
--- a/java/platform_bootclasspath_test.go
+++ b/java/platform_bootclasspath_test.go
@@ -15,8 +15,6 @@
package java
import (
- "fmt"
- "strings"
"testing"
"android/soong/android"
@@ -152,116 +150,6 @@
})
}
-func TestPlatformBootclasspath_Fragments(t *testing.T) {
- result := android.GroupFixturePreparers(
- prepareForTestWithPlatformBootclasspath,
- PrepareForTestWithJavaSdkLibraryFiles,
- FixtureWithLastReleaseApis("foo"),
- android.FixtureWithRootAndroidBp(`
- platform_bootclasspath {
- name: "platform-bootclasspath",
- fragments: [
- {module:"bar-fragment"},
- ],
- hidden_api: {
- unsupported: [
- "unsupported.txt",
- ],
- removed: [
- "removed.txt",
- ],
- max_target_r_low_priority: [
- "max-target-r-low-priority.txt",
- ],
- max_target_q: [
- "max-target-q.txt",
- ],
- max_target_p: [
- "max-target-p.txt",
- ],
- max_target_o_low_priority: [
- "max-target-o-low-priority.txt",
- ],
- blocked: [
- "blocked.txt",
- ],
- unsupported_packages: [
- "unsupported-packages.txt",
- ],
- },
- }
-
- bootclasspath_fragment {
- name: "bar-fragment",
- contents: ["bar"],
- api: {
- stub_libs: ["foo"],
- },
- hidden_api: {
- unsupported: [
- "bar-unsupported.txt",
- ],
- removed: [
- "bar-removed.txt",
- ],
- max_target_r_low_priority: [
- "bar-max-target-r-low-priority.txt",
- ],
- max_target_q: [
- "bar-max-target-q.txt",
- ],
- max_target_p: [
- "bar-max-target-p.txt",
- ],
- max_target_o_low_priority: [
- "bar-max-target-o-low-priority.txt",
- ],
- blocked: [
- "bar-blocked.txt",
- ],
- unsupported_packages: [
- "bar-unsupported-packages.txt",
- ],
- },
- }
-
- java_library {
- name: "bar",
- srcs: ["a.java"],
- system_modules: "none",
- sdk_version: "none",
- compile_dex: true,
- }
-
- java_sdk_library {
- name: "foo",
- srcs: ["a.java"],
- public: {
- enabled: true,
- },
- compile_dex: true,
- }
- `),
- ).RunTest(t)
-
- pbcp := result.Module("platform-bootclasspath", "android_common")
- info := result.ModuleProvider(pbcp, monolithicHiddenAPIInfoProvider).(MonolithicHiddenAPIInfo)
-
- for _, category := range hiddenAPIFlagFileCategories {
- name := category.propertyName
- message := fmt.Sprintf("category %s", name)
- filename := strings.ReplaceAll(name, "_", "-")
- expected := []string{fmt.Sprintf("%s.txt", filename), fmt.Sprintf("bar-%s.txt", filename)}
- android.AssertPathsRelativeToTopEquals(t, message, expected, info.FlagsFilesByCategory[category])
- }
-
- android.AssertPathsRelativeToTopEquals(t, "stub flags", []string{"out/soong/.intermediates/bar-fragment/android_common/modular-hiddenapi/stub-flags.csv"}, info.StubFlagsPaths)
- android.AssertPathsRelativeToTopEquals(t, "annotation flags", []string{"out/soong/.intermediates/bar-fragment/android_common/modular-hiddenapi/annotation-flags.csv"}, info.AnnotationFlagsPaths)
- android.AssertPathsRelativeToTopEquals(t, "metadata flags", []string{"out/soong/.intermediates/bar-fragment/android_common/modular-hiddenapi/metadata.csv"}, info.MetadataPaths)
- android.AssertPathsRelativeToTopEquals(t, "index flags", []string{"out/soong/.intermediates/bar-fragment/android_common/modular-hiddenapi/index.csv"}, info.IndexPaths)
- android.AssertPathsRelativeToTopEquals(t, "all flags", []string{"out/soong/.intermediates/bar-fragment/android_common/modular-hiddenapi/all-flags.csv"}, info.AllFlagsPaths)
-}
-
func TestPlatformBootclasspathVariant(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForTestWithPlatformBootclasspath,
diff --git a/scripts/hiddenapi/merge_csv.py b/scripts/hiddenapi/merge_csv.py
index b047aab..a65326c 100755
--- a/scripts/hiddenapi/merge_csv.py
+++ b/scripts/hiddenapi/merge_csv.py
@@ -55,14 +55,15 @@
if entry.endswith('.uau'):
csv_readers.append(dict_reader(io.TextIOWrapper(zip.open(entry, 'r'))))
-headers = set()
if args.header:
fieldnames = args.header.split(',')
else:
+ headers = {}
# Build union of all columns from source files:
for reader in csv_readers:
- headers = headers.union(reader.fieldnames)
- fieldnames = sorted(headers)
+ for fieldname in reader.fieldnames:
+ headers[fieldname] = ""
+ fieldnames = list(headers.keys())
# By default chain the csv readers together so that the resulting output is
# the concatenation of the rows from each of them:
diff --git a/scripts/rbc-run b/scripts/rbc-run
new file mode 100755
index 0000000..e2fa6d1
--- /dev/null
+++ b/scripts/rbc-run
@@ -0,0 +1,16 @@
+#! /bin/bash
+# Convert and run one configuration
+# Args: <product>-<variant>
+[[ $# -eq 1 && "$1" =~ ^(.*)-(.*)$ ]] || { echo Usage: ${0##*/} PRODUCT-VARIANT >&2; exit 1; }
+declare -r product="${BASH_REMATCH[1]:-aosp_arm}"
+declare -r variant="${BASH_REMATCH[2]:-eng}"
+set -eu
+declare -r output_root=${OUT_DIR:-out}
+declare -r runner="$output_root/soong/.bootstrap/bin/rbcrun"
+declare -r converter="$output_root/soong/.bootstrap/bin/mk2rbc"
+declare -r launcher=$output_root/launchers/run.rbc
+$converter -mode=write -r --outdir $output_root --launcher=$launcher $product
+printf "#TARGET_PRODUCT=$product TARGET_BUILD_VARIANT=$variant\n"
+env TARGET_PRODUCT=$product TARGET_BUILD_VARIANT=$variant \
+ $runner RBC_OUT="make,global" RBC_DEBUG="${RBC_DEBUG:-}" $launcher
+
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index d9fe281..f2ab6a1 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -15,12 +15,53 @@
package sdk
import (
+ "fmt"
+ "path/filepath"
"testing"
"android/soong/android"
"android/soong/java"
)
+// fixtureAddPlatformBootclasspathForBootclasspathFragment adds a platform_bootclasspath module that
+// references the bootclasspath fragment.
+func fixtureAddPlatformBootclasspathForBootclasspathFragment(apex, fragment string) android.FixturePreparer {
+ return android.GroupFixturePreparers(
+ // Add a platform_bootclasspath module.
+ android.FixtureAddTextFile("frameworks/base/boot/Android.bp", fmt.Sprintf(`
+ platform_bootclasspath {
+ name: "platform-bootclasspath",
+ fragments: [
+ {
+ apex: "%s",
+ module: "%s",
+ },
+ ],
+ }
+ `, apex, fragment)),
+ android.FixtureAddFile("frameworks/base/config/boot-profile.txt", nil),
+ )
+}
+
+// fixtureAddPrebuiltApexForBootclasspathFragment adds a prebuilt_apex that exports the fragment.
+func fixtureAddPrebuiltApexForBootclasspathFragment(apex, fragment string) android.FixturePreparer {
+ apexFile := fmt.Sprintf("%s.apex", apex)
+ dir := "prebuilts/apex"
+ return android.GroupFixturePreparers(
+ // A preparer to add a prebuilt apex to the test fixture.
+ android.FixtureAddTextFile(filepath.Join(dir, "Android.bp"), fmt.Sprintf(`
+ prebuilt_apex {
+ name: "%s",
+ src: "%s",
+ exported_bootclasspath_fragments: [
+ "%s",
+ ],
+ }
+ `, apex, apexFile, fragment)),
+ android.FixtureAddFile(filepath.Join(dir, apexFile), nil),
+ )
+}
+
func TestSnapshotWithBootclasspathFragment_ImageName(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForSdkTestWithJava,
@@ -34,20 +75,8 @@
"system/sepolicy/apex/com.android.art-file_contexts": nil,
}),
- // platform_bootclasspath that depends on the fragment.
- android.FixtureAddTextFile("frameworks/base/boot/Android.bp", `
- platform_bootclasspath {
- name: "platform-bootclasspath",
- fragments: [
- {
- apex: "com.android.art",
- module: "mybootclasspathfragment",
- },
- ],
- }
- `),
- // Needed for platform_bootclasspath
- android.FixtureAddFile("frameworks/base/config/boot-profile.txt", nil),
+ // Add a platform_bootclasspath that depends on the fragment.
+ fixtureAddPlatformBootclasspathForBootclasspathFragment("com.android.art", "mybootclasspathfragment"),
java.FixtureConfigureBootJars("com.android.art:mybootlib"),
android.FixtureWithRootAndroidBp(`
@@ -89,19 +118,8 @@
`),
).RunTest(t)
- // A preparer to add a prebuilt apex to the test fixture.
- prepareWithPrebuiltApex := android.GroupFixturePreparers(
- android.FixtureAddTextFile("prebuilts/apex/Android.bp", `
- prebuilt_apex {
- name: "com.android.art",
- src: "art.apex",
- exported_bootclasspath_fragments: [
- "mybootclasspathfragment",
- ],
- }
- `),
- android.FixtureAddFile("prebuilts/apex/art.apex", nil),
- )
+ // A preparer to update the test fixture used when processing an unpackage snapshot.
+ preparerForSnapshot := fixtureAddPrebuiltApexForBootclasspathFragment("com.android.art", "mybootclasspathfragment")
CheckSnapshot(t, result, "mysdk", "",
checkUnversionedAndroidBpContents(`
@@ -154,9 +172,9 @@
checkAllCopyRules(`
.intermediates/mybootlib/android_common/javac/mybootlib.jar -> java/mybootlib.jar
`),
- snapshotTestPreparer(checkSnapshotWithoutSource, prepareWithPrebuiltApex),
- snapshotTestPreparer(checkSnapshotWithSourcePreferred, prepareWithPrebuiltApex),
- snapshotTestPreparer(checkSnapshotPreferredWithSource, prepareWithPrebuiltApex),
+ snapshotTestPreparer(checkSnapshotWithoutSource, preparerForSnapshot),
+ snapshotTestPreparer(checkSnapshotWithSourcePreferred, preparerForSnapshot),
+ snapshotTestPreparer(checkSnapshotPreferredWithSource, preparerForSnapshot),
)
}
@@ -166,6 +184,12 @@
java.PrepareForTestWithJavaDefaultModules,
java.PrepareForTestWithJavaSdkLibraryFiles,
java.FixtureWithLastReleaseApis("mysdklibrary", "myothersdklibrary", "mycoreplatform"),
+ java.FixtureConfigureUpdatableBootJars("myapex:mybootlib", "myapex:myothersdklibrary"),
+ prepareForSdkTestWithApex,
+
+ // Add a platform_bootclasspath that depends on the fragment.
+ fixtureAddPlatformBootclasspathForBootclasspathFragment("myapex", "mybootclasspathfragment"),
+
android.FixtureWithRootAndroidBp(`
sdk {
name: "mysdk",
@@ -179,8 +203,16 @@
],
}
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ min_sdk_version: "2",
+ bootclasspath_fragments: ["mybootclasspathfragment"],
+ }
+
bootclasspath_fragment {
name: "mybootclasspathfragment",
+ apex_available: ["myapex"],
contents: [
// This should be automatically added to the sdk_snapshot as a java_boot_libs module.
"mybootlib",
@@ -198,35 +230,48 @@
java_library {
name: "mybootlib",
+ apex_available: ["myapex"],
srcs: ["Test.java"],
system_modules: "none",
sdk_version: "none",
+ min_sdk_version: "2",
compile_dex: true,
+ permitted_packages: ["mybootlib"],
}
java_sdk_library {
name: "mysdklibrary",
+ apex_available: ["myapex"],
srcs: ["Test.java"],
shared_library: false,
public: {enabled: true},
+ min_sdk_version: "2",
}
java_sdk_library {
name: "myothersdklibrary",
+ apex_available: ["myapex"],
srcs: ["Test.java"],
shared_library: false,
public: {enabled: true},
+ min_sdk_version: "2",
+ permitted_packages: ["myothersdklibrary"],
}
java_sdk_library {
name: "mycoreplatform",
+ apex_available: ["myapex"],
srcs: ["Test.java"],
shared_library: false,
public: {enabled: true},
+ min_sdk_version: "2",
}
`),
).RunTest(t)
+ // A preparer to update the test fixture used when processing an unpackage snapshot.
+ preparerForSnapshot := fixtureAddPrebuiltApexForBootclasspathFragment("myapex", "mybootclasspathfragment")
+
CheckSnapshot(t, result, "mysdk", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -235,7 +280,7 @@
name: "mybootclasspathfragment",
prefer: false,
visibility: ["//visibility:public"],
- apex_available: ["//apex_available:platform"],
+ apex_available: ["myapex"],
contents: [
"mybootlib",
"myothersdklibrary",
@@ -259,7 +304,7 @@
name: "mybootlib",
prefer: false,
visibility: ["//visibility:public"],
- apex_available: ["//apex_available:platform"],
+ apex_available: ["myapex"],
jars: ["java/mybootlib.jar"],
}
@@ -267,7 +312,7 @@
name: "myothersdklibrary",
prefer: false,
visibility: ["//visibility:public"],
- apex_available: ["//apex_available:platform"],
+ apex_available: ["myapex"],
shared_library: false,
public: {
jars: ["sdk_library/public/myothersdklibrary-stubs.jar"],
@@ -282,7 +327,7 @@
name: "mysdklibrary",
prefer: false,
visibility: ["//visibility:public"],
- apex_available: ["//apex_available:platform"],
+ apex_available: ["myapex"],
shared_library: false,
public: {
jars: ["sdk_library/public/mysdklibrary-stubs.jar"],
@@ -297,7 +342,7 @@
name: "mycoreplatform",
prefer: false,
visibility: ["//visibility:public"],
- apex_available: ["//apex_available:platform"],
+ apex_available: ["myapex"],
shared_library: false,
public: {
jars: ["sdk_library/public/mycoreplatform-stubs.jar"],
@@ -315,7 +360,7 @@
name: "mysdk_mybootclasspathfragment@current",
sdk_member_name: "mybootclasspathfragment",
visibility: ["//visibility:public"],
- apex_available: ["//apex_available:platform"],
+ apex_available: ["myapex"],
contents: [
"mysdk_mybootlib@current",
"mysdk_myothersdklibrary@current",
@@ -339,7 +384,7 @@
name: "mysdk_mybootlib@current",
sdk_member_name: "mybootlib",
visibility: ["//visibility:public"],
- apex_available: ["//apex_available:platform"],
+ apex_available: ["myapex"],
jars: ["java/mybootlib.jar"],
}
@@ -347,7 +392,7 @@
name: "mysdk_myothersdklibrary@current",
sdk_member_name: "myothersdklibrary",
visibility: ["//visibility:public"],
- apex_available: ["//apex_available:platform"],
+ apex_available: ["myapex"],
shared_library: false,
public: {
jars: ["sdk_library/public/myothersdklibrary-stubs.jar"],
@@ -362,7 +407,7 @@
name: "mysdk_mysdklibrary@current",
sdk_member_name: "mysdklibrary",
visibility: ["//visibility:public"],
- apex_available: ["//apex_available:platform"],
+ apex_available: ["myapex"],
shared_library: false,
public: {
jars: ["sdk_library/public/mysdklibrary-stubs.jar"],
@@ -377,7 +422,7 @@
name: "mysdk_mycoreplatform@current",
sdk_member_name: "mycoreplatform",
visibility: ["//visibility:public"],
- apex_available: ["//apex_available:platform"],
+ apex_available: ["myapex"],
shared_library: false,
public: {
jars: ["sdk_library/public/mycoreplatform-stubs.jar"],
@@ -416,7 +461,11 @@
.intermediates/mycoreplatform.stubs/android_common/javac/mycoreplatform.stubs.jar -> sdk_library/public/mycoreplatform-stubs.jar
.intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_api.txt -> sdk_library/public/mycoreplatform.txt
.intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_removed.txt -> sdk_library/public/mycoreplatform-removed.txt
-`))
+`),
+ snapshotTestPreparer(checkSnapshotWithoutSource, preparerForSnapshot),
+ snapshotTestPreparer(checkSnapshotWithSourcePreferred, preparerForSnapshot),
+ snapshotTestPreparer(checkSnapshotPreferredWithSource, preparerForSnapshot),
+ )
}
// Test that bootclasspath_fragment works with sdk.
@@ -482,7 +531,12 @@
java.PrepareForTestWithJavaDefaultModules,
java.PrepareForTestWithJavaSdkLibraryFiles,
java.FixtureWithLastReleaseApis("mysdklibrary"),
+ java.FixtureConfigureUpdatableBootJars("myapex:mybootlib"),
prepareForSdkTestWithApex,
+
+ // Add a platform_bootclasspath that depends on the fragment.
+ fixtureAddPlatformBootclasspathForBootclasspathFragment("myapex", "mybootclasspathfragment"),
+
android.MockFS{
"my-blocked.txt": nil,
"my-max-target-o-low-priority.txt": nil,
@@ -549,6 +603,7 @@
sdk_version: "none",
min_sdk_version: "1",
compile_dex: true,
+ permitted_packages: ["mybootlib"],
}
java_sdk_library {
@@ -560,6 +615,9 @@
`),
).RunTest(t)
+ // A preparer to update the test fixture used when processing an unpackage snapshot.
+ preparerForSnapshot := fixtureAddPrebuiltApexForBootclasspathFragment("myapex", "mybootclasspathfragment")
+
CheckSnapshot(t, result, "mysdk", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -633,5 +691,8 @@
.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
`),
+ snapshotTestPreparer(checkSnapshotWithoutSource, preparerForSnapshot),
+ snapshotTestPreparer(checkSnapshotWithSourcePreferred, preparerForSnapshot),
+ snapshotTestPreparer(checkSnapshotPreferredWithSource, preparerForSnapshot),
)
}
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 7128414..19a47ae 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -99,6 +99,21 @@
"--used_env", shared.JoinPath(config.SoongOutDir(), usedEnvFile+suffix),
}
}
+
+func writeEmptyGlobFile(ctx Context, path string) {
+ err := os.MkdirAll(filepath.Dir(path), 0777)
+ if err != nil {
+ ctx.Fatalf("Failed to create parent directories of empty ninja glob file '%s': %s", path, err)
+ }
+
+ if _, err := os.Stat(path); os.IsNotExist(err) {
+ err = ioutil.WriteFile(path, nil, 0666)
+ if err != nil {
+ ctx.Fatalf("Failed to create empty ninja glob file '%s': %s", path, err)
+ }
+ }
+}
+
func bootstrapBlueprint(ctx Context, config Config, integratedBp2Build bool) {
ctx.BeginTrace(metrics.RunSoong, "blueprint bootstrap")
defer ctx.EndTrace()
@@ -106,8 +121,10 @@
var args bootstrap.Args
mainNinjaFile := shared.JoinPath(config.SoongOutDir(), "build.ninja")
- globFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/soong-build-globs.ninja")
bootstrapGlobFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/build-globs.ninja")
+ // .bootstrap/build.ninja "includes" .bootstrap/build-globs.ninja for incremental builds
+ // generate an empty glob before running any rule in .bootstrap/build.ninja
+ writeEmptyGlobFile(ctx, bootstrapGlobFile)
bootstrapDepFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja.d")
args.RunGoTests = !config.skipSoongTests
@@ -117,7 +134,10 @@
args.TopFile = "Android.bp"
args.ModuleListFile = filepath.Join(config.FileListDir(), "Android.bp.list")
args.OutFile = shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja")
- args.GlobFile = globFile
+ // The primary builder (aka soong_build) will use bootstrapGlobFile as the globFile to generate build.ninja(.d)
+ // Building soong_build does not require a glob file
+ // Using "" instead of "<soong_build_glob>.ninja" will ensure that an unused glob file is not written to out/soong/.bootstrap during StagePrimary
+ args.GlobFile = ""
args.GeneratingPrimaryBuilder = true
args.EmptyNinjaFile = config.EmptyNinjaFile()