Merge "Remove obsolete notice property."
diff --git a/android/Android.bp b/android/Android.bp
index cbd3459..f58a472 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -88,6 +88,7 @@
"test_asserts.go",
"test_suites.go",
"testing.go",
+ "updatable_modules.go",
"util.go",
"variable.go",
"visibility.go",
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index ab71d99..aa4363c 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -366,6 +366,7 @@
}
Bp2buildModuleTypeAlwaysConvertList = []string{
+ "linker_config",
"java_import",
"java_import_host",
}
@@ -440,7 +441,6 @@
"art-script", // depends on unconverted modules: dalvikvm, dex2oat
"bin2c_fastdeployagent", // depends on unconverted modules: deployagent
"com.android.runtime", // depends on unconverted modules: bionic-linker-config, linkerconfig
- "conv_linker_config", // depends on unconverted modules: linker_config_proto
"currysrc", // depends on unconverted modules: currysrc_org.eclipse, guavalib, jopt-simple-4.9
"dex2oat-script", // depends on unconverted modules: dex2oat
"generated_android_icu4j_resources", // depends on unconverted modules: android_icu4j_srcgen_binary, soong_zip
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 5e8a183..5804a46 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -91,6 +91,10 @@
osType OsType
}
+func (c configKey) String() string {
+ return fmt.Sprintf("%s::%s", c.arch, c.osType)
+}
+
// Map key to describe bazel cquery requests.
type cqueryKey struct {
label string
@@ -98,6 +102,11 @@
configKey configKey
}
+func (c cqueryKey) String() string {
+ return fmt.Sprintf("cquery(%s,%s,%s)", c.label, c.requestType.Name(), c.configKey)
+
+}
+
// BazelContext is a context object useful for interacting with Bazel during
// the course of a build. Use of Bazel to evaluate part of the build graph
// is referred to as a "mixed build". (Some modules are managed by Soong,
@@ -123,6 +132,9 @@
// TODO(b/232976601): Remove.
GetPythonBinary(label string, cfgKey configKey) (string, error)
+ // Returns the results of the GetApexInfo query (including output files)
+ GetApexInfo(label string, cfgkey configKey) (cquery.ApexCqueryInfo, error)
+
// ** end Cquery Results Retrieval Functions
// Issues commands to Bazel to receive results for all cquery requests
@@ -186,6 +198,7 @@
LabelToOutputFiles map[string][]string
LabelToCcInfo map[string]cquery.CcInfo
LabelToPythonBinary map[string]string
+ LabelToApexInfo map[string]cquery.ApexCqueryInfo
}
func (m MockBazelContext) QueueBazelRequest(_ string, _ cqueryRequest, _ configKey) {
@@ -207,6 +220,10 @@
return result, nil
}
+func (n MockBazelContext) GetApexInfo(_ string, _ configKey) (cquery.ApexCqueryInfo, error) {
+ panic("unimplemented")
+}
+
func (m MockBazelContext) InvokeBazel(_ Config) error {
panic("unimplemented")
}
@@ -261,6 +278,14 @@
return "", fmt.Errorf("no bazel response found for %v", key)
}
+func (bazelCtx *bazelContext) GetApexInfo(label string, cfgKey configKey) (cquery.ApexCqueryInfo, error) {
+ key := cqueryKey{label, cquery.GetApexInfo, cfgKey}
+ if rawString, ok := bazelCtx.results[key]; ok {
+ return cquery.GetApexInfo.ParseResult(strings.TrimSpace(rawString)), nil
+ }
+ return cquery.ApexCqueryInfo{}, fmt.Errorf("no bazel response found for %v", key)
+}
+
func (n noopBazelContext) QueueBazelRequest(_ string, _ cqueryRequest, _ configKey) {
panic("unimplemented")
}
@@ -277,6 +302,10 @@
panic("unimplemented")
}
+func (n noopBazelContext) GetApexInfo(_ string, _ configKey) (cquery.ApexCqueryInfo, error) {
+ panic("unimplemented")
+}
+
func (n noopBazelContext) InvokeBazel(_ Config) error {
panic("unimplemented")
}
@@ -401,11 +430,9 @@
cmdFlags := []string{
"--output_base=" + absolutePath(paths.outputBase),
command.command,
- }
- cmdFlags = append(cmdFlags, command.expression)
- cmdFlags = append(cmdFlags,
+ command.expression,
// TODO(asmundak): is it needed in every build?
- "--profile="+shared.BazelMetricsFilename(paths, runName),
+ "--profile=" + shared.BazelMetricsFilename(paths, runName),
// Set default platforms to canonicalized values for mixed builds requests.
// If these are set in the bazelrc, they will have values that are
@@ -426,21 +453,23 @@
// Suppress noise
"--ui_event_filters=-INFO",
- "--noshow_progress")
+ "--noshow_progress"}
cmdFlags = append(cmdFlags, extraFlags...)
bazelCmd := exec.Command(paths.bazelPath, cmdFlags...)
bazelCmd.Dir = absolutePath(paths.syntheticWorkspaceDir())
- bazelCmd.Env = append(os.Environ(),
- "HOME="+paths.homeDir,
+ extraEnv := []string{
+ "HOME=" + paths.homeDir,
pwdPrefix(),
- "BUILD_DIR="+absolutePath(paths.soongOutDir),
+ "BUILD_DIR=" + absolutePath(paths.soongOutDir),
// Make OUT_DIR absolute here so tools/bazel.sh uses the correct
// OUT_DIR at <root>/out, instead of <root>/out/soong/workspace/out.
- "OUT_DIR="+absolutePath(paths.outDir()),
+ "OUT_DIR=" + absolutePath(paths.outDir()),
// Disables local host detection of gcc; toolchain information is defined
// explicitly in BUILD files.
- "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1")
+ "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1",
+ }
+ bazelCmd.Env = append(os.Environ(), extraEnv...)
stderr := &bytes.Buffer{}
bazelCmd.Stderr = stderr
@@ -651,6 +680,15 @@
fail("expected platform name of the form 'android_<arch>' or 'linux_<arch>', but was " + str(platforms))
return "UNKNOWN"
+def json_for_file(key, file):
+ return '"' + key + '":"' + file.path + '"'
+
+def json_for_files(key, files):
+ return '"' + key + '":[' + ",".join(['"' + f.path + '"' for f in files]) + ']'
+
+def json_for_labels(key, ll):
+ return '"' + key + '":[' + ",".join(['"' + str(x) + '"' for x in ll]) + ']'
+
def format(target):
id_string = str(target.label) + "|" + get_arch(target)
@@ -728,7 +766,7 @@
cqueryOutput, cqueryErr, err := context.issueBazelCommand(context.paths, bazel.CqueryBuildRootRunName, cqueryCmd,
"--output=starlark", "--starlark:file="+absolutePath(cqueryFileRelpath))
if err != nil {
- err = ioutil.WriteFile(filepath.Join(soongInjectionPath, "cquery.out"), []byte(cqueryOutput), 0666)
+ _ = ioutil.WriteFile(filepath.Join(soongInjectionPath, "cquery.out"), []byte(cqueryOutput), 0666)
}
if err != nil {
return err
diff --git a/android/config.go b/android/config.go
index a5337d0..8c7d789 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1446,8 +1446,8 @@
return Bool(c.productVariables.ForceApexSymlinkOptimization)
}
-func (c *config) CompressedApex() bool {
- return Bool(c.productVariables.CompressedApex)
+func (c *config) ApexCompressionEnabled() bool {
+ return Bool(c.productVariables.CompressedApex) && !c.UnbundledBuildApps()
}
func (c *config) EnforceSystemCertificate() bool {
diff --git a/apex/constants.go b/android/updatable_modules.go
similarity index 82%
rename from apex/constants.go
rename to android/updatable_modules.go
index c68edb7..71c76c5 100644
--- a/apex/constants.go
+++ b/android/updatable_modules.go
@@ -12,11 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package apex
+package android
-// This file contains branch specific constants. They are stored in a separate
-// file to minimise the potential of merge conflicts between branches when
-// the code from the package is changed.
+// This file contains branch specific constants for building updatable modules.
+// They are stored in a separate file to minimise the potential of merge
+// conflicts between branches when the code from the package is changed.
// The default manifest version for all the modules on this branch.
// This version code will be used only if there is no version field in the
@@ -33,4 +33,4 @@
// * AOSP - xx9990000
// * x-mainline-prod - xx9990000
// * master - 990090000
-const defaultManifestVersion = "339990000"
+const DefaultUpdatableModuleVersion = "339990000"
diff --git a/apex/Android.bp b/apex/Android.bp
index 6533c61..018d030 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -26,7 +26,7 @@
"apex_sdk_member.go",
"apex_singleton.go",
"builder.go",
- "constants.go",
+ "bp2build.go",
"deapexer.go",
"key.go",
"prebuilt.go",
diff --git a/apex/apex.go b/apex/apex.go
index 6313d20..09a5784 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -17,6 +17,7 @@
package apex
import (
+ "android/soong/bazel/cquery"
"fmt"
"path/filepath"
"regexp"
@@ -1803,6 +1804,184 @@
}
}
+var _ android.MixedBuildBuildable = (*apexBundle)(nil)
+
+func (a *apexBundle) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
+ return ctx.ModuleType() == "apex" && a.properties.ApexType == imageApex
+}
+
+func (a *apexBundle) QueueBazelCall(ctx android.BaseModuleContext) {
+ bazelCtx := ctx.Config().BazelContext
+ bazelCtx.QueueBazelRequest(a.GetBazelLabel(ctx, a), cquery.GetApexInfo, android.GetConfigKey(ctx))
+}
+
+func (a *apexBundle) ProcessBazelQueryResponse(ctx android.ModuleContext) {
+ if !a.commonBuildActions(ctx) {
+ return
+ }
+
+ a.setApexTypeAndSuffix(ctx)
+ a.setPayloadFsType(ctx)
+ a.setSystemLibLink(ctx)
+
+ if a.properties.ApexType != zipApex {
+ a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx, a.primaryApexType)
+ }
+
+ bazelCtx := ctx.Config().BazelContext
+ outputs, err := bazelCtx.GetApexInfo(a.GetBazelLabel(ctx, a), android.GetConfigKey(ctx))
+ if err != nil {
+ ctx.ModuleErrorf(err.Error())
+ return
+ }
+ a.installDir = android.PathForModuleInstall(ctx, "apex")
+ a.outputApexFile = android.PathForBazelOut(ctx, outputs.SignedOutput)
+ a.outputFile = a.outputApexFile
+ a.setCompression(ctx)
+
+ a.publicKeyFile = android.PathForBazelOut(ctx, outputs.BundleKeyPair[0])
+ a.privateKeyFile = android.PathForBazelOut(ctx, outputs.BundleKeyPair[1])
+ a.containerCertificateFile = android.PathForBazelOut(ctx, outputs.ContainerKeyPair[0])
+ a.containerPrivateKeyFile = android.PathForBazelOut(ctx, outputs.ContainerKeyPair[1])
+ apexType := a.properties.ApexType
+ switch apexType {
+ case imageApex:
+ // TODO(asmundak): Bazel does not create these files yet.
+ // b/190817312
+ a.htmlGzNotice = android.PathForBazelOut(ctx, "NOTICE.html.gz")
+ // b/239081457
+ a.bundleModuleFile = android.PathForBazelOut(ctx, a.Name()+apexType.suffix()+"-base.zip")
+ // b/239081455
+ a.nativeApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, a.Name()+"_using.txt"))
+ // b/239081456
+ a.nativeApisBackedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, a.Name()+"_backing.txt"))
+ // b/239084755
+ a.javaApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, a.Name()+"_using.xml"))
+ installSuffix := imageApexSuffix
+ if a.isCompressed {
+ installSuffix = imageCapexSuffix
+ }
+ a.installedFile = ctx.InstallFile(a.installDir, a.Name()+installSuffix, a.outputFile,
+ a.compatSymlinks.Paths()...)
+ default:
+ panic(fmt.Errorf("unexpected apex_type for the ProcessBazelQuery: %v", a.properties.ApexType))
+ }
+
+ /*
+ TODO(asmundak): compared to building an APEX with Soong, building it with Bazel does not
+ return filesInfo and requiredDeps fields (in the Soong build the latter is updated).
+ Fix this, as these fields are subsequently used in apex/androidmk.go and in apex/builder/go
+ To find out what Soong build puts there, run:
+ vctx := visitorContext{handleSpecialLibs: !android.Bool(a.properties.Ignore_system_library_special_case)}
+ ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
+ return a.depVisitor(&vctx, ctx, child, parent)
+ })
+ vctx.normalizeFileInfo()
+ */
+
+}
+
+func (a *apexBundle) setCompression(ctx android.ModuleContext) {
+ if a.properties.ApexType != imageApex {
+ a.isCompressed = false
+ } else if a.testOnlyShouldForceCompression() {
+ a.isCompressed = true
+ } else {
+ a.isCompressed = ctx.Config().ApexCompressionEnabled() && a.isCompressable()
+ }
+}
+
+func (a *apexBundle) setSystemLibLink(ctx android.ModuleContext) {
+ // Optimization. If we are building bundled APEX, for the files that are gathered due to the
+ // transitive dependencies, don't place them inside the APEX, but place a symlink pointing
+ // the same library in the system partition, thus effectively sharing the same libraries
+ // across the APEX boundary. For unbundled APEX, all the gathered files are actually placed
+ // in the APEX.
+ a.linkToSystemLib = !ctx.Config().UnbundledBuild() && a.installable()
+
+ // APEXes targeting other than system/system_ext partitions use vendor/product variants.
+ // So we can't link them to /system/lib libs which are core variants.
+ if a.SocSpecific() || a.DeviceSpecific() || (a.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
+ a.linkToSystemLib = false
+ }
+
+ forced := ctx.Config().ForceApexSymlinkOptimization()
+ updatable := a.Updatable() || a.FutureUpdatable()
+
+ // We don't need the optimization for updatable APEXes, as it might give false signal
+ // to the system health when the APEXes are still bundled (b/149805758).
+ if !forced && updatable && a.properties.ApexType == imageApex {
+ a.linkToSystemLib = false
+ }
+
+ // We also don't want the optimization for host APEXes, because it doesn't make sense.
+ if ctx.Host() {
+ a.linkToSystemLib = false
+ }
+}
+
+func (a *apexBundle) setPayloadFsType(ctx android.ModuleContext) {
+ switch proptools.StringDefault(a.properties.Payload_fs_type, ext4FsType) {
+ case ext4FsType:
+ a.payloadFsType = ext4
+ case f2fsFsType:
+ a.payloadFsType = f2fs
+ case erofsFsType:
+ a.payloadFsType = erofs
+ default:
+ ctx.PropertyErrorf("payload_fs_type", "%q is not a valid filesystem for apex [ext4, f2fs, erofs]", *a.properties.Payload_fs_type)
+ }
+}
+
+func (a *apexBundle) setApexTypeAndSuffix(ctx android.ModuleContext) {
+ // Set suffix and primaryApexType depending on the ApexType
+ buildFlattenedAsDefault := ctx.Config().FlattenApex()
+ switch a.properties.ApexType {
+ case imageApex:
+ if buildFlattenedAsDefault {
+ a.suffix = imageApexSuffix
+ } else {
+ a.suffix = ""
+ a.primaryApexType = true
+
+ if ctx.Config().InstallExtraFlattenedApexes() {
+ a.requiredDeps = append(a.requiredDeps, a.Name()+flattenedSuffix)
+ }
+ }
+ case zipApex:
+ if proptools.String(a.properties.Payload_type) == "zip" {
+ a.suffix = ""
+ a.primaryApexType = true
+ } else {
+ a.suffix = zipApexSuffix
+ }
+ case flattenedApex:
+ if buildFlattenedAsDefault {
+ a.suffix = ""
+ a.primaryApexType = true
+ } else {
+ a.suffix = flattenedSuffix
+ }
+ }
+}
+
+func (a apexBundle) isCompressable() bool {
+ return proptools.BoolDefault(a.overridableProperties.Compressible, false) && !a.testApex
+}
+
+func (a *apexBundle) commonBuildActions(ctx android.ModuleContext) bool {
+ a.checkApexAvailability(ctx)
+ a.checkUpdatable(ctx)
+ a.CheckMinSdkVersion(ctx)
+ a.checkStaticLinkingToStubLibraries(ctx)
+ a.checkStaticExecutables(ctx)
+ if len(a.properties.Tests) > 0 && !a.testApex {
+ ctx.PropertyErrorf("tests", "property allowed only in apex_test module type")
+ return false
+ }
+ return true
+}
+
type visitorContext struct {
// all the files that will be included in this APEX
filesInfo []apexFile
@@ -2188,16 +2367,9 @@
func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
////////////////////////////////////////////////////////////////////////////////////////////
// 1) do some validity checks such as apex_available, min_sdk_version, etc.
- a.checkApexAvailability(ctx)
- a.checkUpdatable(ctx)
- a.CheckMinSdkVersion(ctx)
- a.checkStaticLinkingToStubLibraries(ctx)
- a.checkStaticExecutables(ctx)
- if len(a.properties.Tests) > 0 && !a.testApex {
- ctx.PropertyErrorf("tests", "property allowed only in apex_test module type")
+ if !a.commonBuildActions(ctx) {
return
}
-
////////////////////////////////////////////////////////////////////////////////////////////
// 2) traverse the dependency tree to collect apexFile structs from them.
@@ -2219,74 +2391,9 @@
a.installDir = android.PathForModuleInstall(ctx, "apex")
a.filesInfo = vctx.filesInfo
- // Set suffix and primaryApexType depending on the ApexType
- buildFlattenedAsDefault := ctx.Config().FlattenApex()
- switch a.properties.ApexType {
- case imageApex:
- if buildFlattenedAsDefault {
- a.suffix = imageApexSuffix
- } else {
- a.suffix = ""
- a.primaryApexType = true
-
- if ctx.Config().InstallExtraFlattenedApexes() {
- a.requiredDeps = append(a.requiredDeps, a.Name()+flattenedSuffix)
- }
- }
- case zipApex:
- if proptools.String(a.properties.Payload_type) == "zip" {
- a.suffix = ""
- a.primaryApexType = true
- } else {
- a.suffix = zipApexSuffix
- }
- case flattenedApex:
- if buildFlattenedAsDefault {
- a.suffix = ""
- a.primaryApexType = true
- } else {
- a.suffix = flattenedSuffix
- }
- }
-
- switch proptools.StringDefault(a.properties.Payload_fs_type, ext4FsType) {
- case ext4FsType:
- a.payloadFsType = ext4
- case f2fsFsType:
- a.payloadFsType = f2fs
- case erofsFsType:
- a.payloadFsType = erofs
- default:
- ctx.PropertyErrorf("payload_fs_type", "%q is not a valid filesystem for apex [ext4, f2fs, erofs]", *a.properties.Payload_fs_type)
- }
-
- // Optimization. If we are building bundled APEX, for the files that are gathered due to the
- // transitive dependencies, don't place them inside the APEX, but place a symlink pointing
- // the same library in the system partition, thus effectively sharing the same libraries
- // across the APEX boundary. For unbundled APEX, all the gathered files are actually placed
- // in the APEX.
- a.linkToSystemLib = !ctx.Config().UnbundledBuild() && a.installable()
-
- // APEXes targeting other than system/system_ext partitions use vendor/product variants.
- // So we can't link them to /system/lib libs which are core variants.
- if a.SocSpecific() || a.DeviceSpecific() || (a.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
- a.linkToSystemLib = false
- }
-
- forced := ctx.Config().ForceApexSymlinkOptimization()
- updatable := a.Updatable() || a.FutureUpdatable()
-
- // We don't need the optimization for updatable APEXes, as it might give false signal
- // to the system health when the APEXes are still bundled (b/149805758).
- if !forced && updatable && a.properties.ApexType == imageApex {
- a.linkToSystemLib = false
- }
-
- // We also don't want the optimization for host APEXes, because it doesn't make sense.
- if ctx.Host() {
- a.linkToSystemLib = false
- }
-
+ a.setApexTypeAndSuffix(ctx)
+ a.setPayloadFsType(ctx)
+ a.setSystemLibLink(ctx)
if a.properties.ApexType != zipApex {
a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx, a.primaryApexType)
}
diff --git a/apex/bp2build.go b/apex/bp2build.go
new file mode 100644
index 0000000..221ab13
--- /dev/null
+++ b/apex/bp2build.go
@@ -0,0 +1,30 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package apex
+
+import (
+ "android/soong/android"
+ "strings"
+)
+
+// This file contains the bp2build integration for the apex package.
+
+// Export constants as Starlark using bp2build to Bazel.
+func BazelApexToolchainVars() string {
+ content := []string{
+ "# GENERATED BY SOONG. DO NOT EDIT.",
+ "default_manifest_version = " + android.DefaultUpdatableModuleVersion, // constants.go is different in every branch.
+ }
+ return strings.Join(content, "\n")
+}
diff --git a/apex/builder.go b/apex/builder.go
index 1956b44..f1b1448 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -214,7 +214,7 @@
Args: map[string]string{
"provideNativeLibs": strings.Join(provideNativeLibs, " "),
"requireNativeLibs": strings.Join(requireNativeLibs, " "),
- "default_version": defaultManifestVersion,
+ "default_version": android.DefaultUpdatableModuleVersion,
"opt": strings.Join(optCommands, " "),
},
})
@@ -549,8 +549,6 @@
outHostBinDir := ctx.Config().HostToolPath(ctx, "").String()
prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
- // Figure out if we need to compress the apex.
- compressionEnabled := ctx.Config().CompressedApex() && proptools.BoolDefault(a.overridableProperties.Compressible, false) && !a.testApex && !ctx.Config().UnbundledBuildApps()
if apexType == imageApex {
////////////////////////////////////////////////////////////////////////////////////
@@ -635,10 +633,15 @@
implicitInputs = append(implicitInputs, noticeAssetPath)
optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeAssetPath.String()))
- 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.
+ // 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.
+ needHashTree := moduleMinSdkVersion.LessThanOrEqualTo(android.SdkVersion_Android10) ||
+ a.shouldGenerateHashtree()
+ if ctx.Config().ApexCompressionEnabled() && a.isCompressable() {
+ needHashTree = true
+ }
+ if !needHashTree {
optFlags = append(optFlags, "--no_hashtree")
}
@@ -806,8 +809,9 @@
return
}
- if apexType == imageApex && (compressionEnabled || a.testOnlyShouldForceCompression()) {
- a.isCompressed = true
+ installSuffix := suffix
+ a.setCompression(ctx)
+ if a.isCompressed {
unsignedCompressedOutputFile := android.PathForModuleOut(ctx, a.Name()+imageCapexSuffix+".unsigned")
compressRule := android.NewRuleBuilder(pctx, ctx)
@@ -835,10 +839,6 @@
Args: args,
})
a.outputFile = signedCompressedOutputFile
- }
-
- installSuffix := suffix
- if a.isCompressed {
installSuffix = imageCapexSuffix
}
diff --git a/bazel/aquery.go b/bazel/aquery.go
index ae2b107..418b143 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -574,7 +574,7 @@
// expandTemplateContent substitutes the tokens in a template.
func expandTemplateContent(actionEntry action) string {
- replacerString := []string{}
+ var replacerString []string
for _, pair := range actionEntry.Substitutions {
value := pair.Value
if val, ok := templateActionOverriddenTokens[pair.Key]; ok {
@@ -647,7 +647,7 @@
}
labels = append([]string{currFragment.Label}, labels...)
if currId == currFragment.ParentId {
- return "", fmt.Errorf("Fragment cannot refer to itself as parent %#v", currFragment)
+ return "", fmt.Errorf("fragment cannot refer to itself as parent %#v", currFragment)
}
currId = currFragment.ParentId
}
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index f5435f2..d32e619 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -1,6 +1,7 @@
package cquery
import (
+ "encoding/json"
"fmt"
"strings"
)
@@ -9,6 +10,7 @@
GetOutputFiles = &getOutputFilesRequestType{}
GetPythonBinary = &getPythonBinaryRequestType{}
GetCcInfo = &getCcInfoType{}
+ GetApexInfo = &getApexInfoType{}
)
type CcInfo struct {
@@ -179,7 +181,7 @@
const expectedLen = 10
splitString := strings.Split(rawString, "|")
if len(splitString) != expectedLen {
- return CcInfo{}, fmt.Errorf("Expected %d items, got %q", expectedLen, splitString)
+ return CcInfo{}, fmt.Errorf("expected %d items, got %q", expectedLen, splitString)
}
outputFilesString := splitString[0]
ccObjectsString := splitString[1]
@@ -215,6 +217,54 @@
}, nil
}
+// Query Bazel for the artifacts generated by the apex modules.
+type getApexInfoType struct{}
+
+// Name returns a string name for this request type. Such request type names must be unique,
+// and must only consist of alphanumeric characters.
+func (g getApexInfoType) Name() string {
+ return "getApexInfo"
+}
+
+// StarlarkFunctionBody returns a starlark function body to process this request type.
+// The returned string is the body of a Starlark function which obtains
+// all request-relevant information about a target and returns a string containing
+// this information. The function should have the following properties:
+// - `target` is the only parameter to this function (a configured target).
+// - The return value must be a string.
+// - The function body should not be indented outside of its own scope.
+func (g getApexInfoType) StarlarkFunctionBody() string {
+ return `info = providers(target)["//build/bazel/rules/apex:apex.bzl%ApexInfo"]
+return "{%s}" % ",".join([
+ json_for_file("signed_output", info.signed_output),
+ json_for_file("unsigned_output", info.unsigned_output),
+ json_for_labels("provides_native_libs", info.provides_native_libs),
+ json_for_labels("requires_native_libs", info.requires_native_libs),
+ json_for_files("bundle_key_pair", info.bundle_key_pair),
+ json_for_files("container_key_pair", info.container_key_pair)
+ ])`
+}
+
+type ApexCqueryInfo struct {
+ SignedOutput string `json:"signed_output"`
+ UnsignedOutput string `json:"unsigned_output"`
+ ProvidesLibs []string `json:"provides_native_libs"`
+ RequiresLibs []string `json:"requires_native_libs"`
+ BundleKeyPair []string `json:"bundle_key_pair"`
+ ContainerKeyPair []string `json:"container_key_pair"`
+}
+
+// ParseResult returns a value obtained by parsing the result of the request's Starlark function.
+// The given rawString must correspond to the string output which was created by evaluating the
+// Starlark given in StarlarkFunctionBody.
+func (g getApexInfoType) ParseResult(rawString string) ApexCqueryInfo {
+ var info ApexCqueryInfo
+ if err := json.Unmarshal([]byte(rawString), &info); err != nil {
+ panic(fmt.Errorf("cannot parse cquery result '%s': %s", rawString, err))
+ }
+ return info
+}
+
// splitOrEmpty is a modification of strings.Split() that returns an empty list
// if the given string is empty.
func splitOrEmpty(s string, sep string) []string {
diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go
index 606e285..34248ce 100644
--- a/bazel/cquery/request_type_test.go
+++ b/bazel/cquery/request_type_test.go
@@ -148,13 +148,13 @@
description: "too few result splits",
input: "|",
expectedOutput: CcInfo{},
- expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", expectedSplits, []string{"", ""}),
+ expectedErrorMessage: fmt.Sprintf("expected %d items, got %q", expectedSplits, []string{"", ""}),
},
{
description: "too many result splits",
input: strings.Repeat("|", expectedSplits+1), // 2 too many
expectedOutput: CcInfo{},
- expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", expectedSplits, make([]string, expectedSplits+2)),
+ expectedErrorMessage: fmt.Sprintf("expected %d items, got %q", expectedSplits, make([]string, expectedSplits+2)),
},
}
for _, tc := range testCases {
@@ -167,3 +167,40 @@
}
}
}
+
+func TestGetApexInfoParseResults(t *testing.T) {
+ testCases := []struct {
+ description string
+ input string
+ expectedOutput ApexCqueryInfo
+ }{
+ {
+ description: "no result",
+ input: "{}",
+ expectedOutput: ApexCqueryInfo{},
+ },
+ {
+ description: "one result",
+ input: `{"signed_output":"my.apex",` +
+ `"unsigned_output":"my.apex.unsigned",` +
+ `"requires_native_libs":["//bionic/libc:libc","//bionic/libdl:libdl"],` +
+ `"bundle_key_pair":["foo.pem","foo.privkey"],` +
+ `"container_key_pair":["foo.x509.pem", "foo.pk8"],` +
+ `"provides_native_libs":[]}`,
+ expectedOutput: ApexCqueryInfo{
+ SignedOutput: "my.apex",
+ UnsignedOutput: "my.apex.unsigned",
+ RequiresLibs: []string{"//bionic/libc:libc", "//bionic/libdl:libdl"},
+ ProvidesLibs: []string{},
+ BundleKeyPair: []string{"foo.pem", "foo.privkey"},
+ ContainerKeyPair: []string{"foo.x509.pem", "foo.pk8"},
+ },
+ },
+ }
+ for _, tc := range testCases {
+ actualOutput := GetApexInfo.ParseResult(tc.input)
+ if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
+ t.Errorf("%q: expected %#v != actual %#v", tc.description, tc.expectedOutput, actualOutput)
+ }
+ }
+}
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index 34548ed..07557d6 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -20,15 +20,16 @@
"soong-android",
"soong-android-allowlists",
"soong-android-soongconfig",
- "soong-shared",
"soong-apex",
"soong-bazel",
"soong-cc",
"soong-cc-config",
"soong-etc",
"soong-genrule",
+ "soong-linkerconfig",
"soong-python",
"soong-sh",
+ "soong-shared",
"soong-starlark-format",
"soong-ui-metrics",
],
@@ -58,6 +59,7 @@
"java_library_host_conversion_test.go",
"java_plugin_conversion_test.go",
"java_proto_conversion_test.go",
+ "linker_config_conversion_test.go",
"performance_test.go",
"prebuilt_etc_conversion_test.go",
"python_binary_conversion_test.go",
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index be09616..74729e4 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -569,3 +569,58 @@
},
})
}
+
+func TestCcLibrarySharedClangUnknownFlags(t *testing.T) {
+ runCcLibrarySharedTestCase(t, bp2buildTestCase{
+ blueprint: soongCcProtoPreamble + `cc_library_shared {
+ name: "foo",
+ conlyflags: ["-a", "-finline-functions"],
+ cflags: ["-b","-finline-functions"],
+ cppflags: ["-c", "-finline-functions"],
+ ldflags: ["-d","-finline-functions", "-e"],
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ "conlyflags": `["-a"]`,
+ "copts": `["-b"]`,
+ "cppflags": `["-c"]`,
+ "linkopts": `[
+ "-d",
+ "-e",
+ ]`,
+ }),
+ },
+ })
+}
+
+func TestCCLibraryFlagSpaceSplitting(t *testing.T) {
+ runCcLibrarySharedTestCase(t, bp2buildTestCase{
+ blueprint: soongCcProtoPreamble + `cc_library_shared {
+ name: "foo",
+ conlyflags: [ "-include header.h"],
+ cflags: ["-include header.h"],
+ cppflags: ["-include header.h"],
+ version_script: "version_script",
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ "additional_linker_inputs": `["version_script"]`,
+ "conlyflags": `[
+ "-include",
+ "header.h",
+ ]`,
+ "copts": `[
+ "-include",
+ "header.h",
+ ]`,
+ "cppflags": `[
+ "-include",
+ "header.h",
+ ]`,
+ "linkopts": `["-Wl,--version-script,$(location version_script)"]`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index 4246f7d..8cf9bea 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -10,6 +10,8 @@
cc_config "android/soong/cc/config"
java_config "android/soong/java/config"
+ "android/soong/apex"
+
"github.com/google/blueprint/proptools"
)
@@ -28,6 +30,9 @@
files = append(files, newFile("java_toolchain", GeneratedBuildFileName, "")) // Creates a //java_toolchain package.
files = append(files, newFile("java_toolchain", "constants.bzl", java_config.BazelJavaToolchainVars(cfg)))
+ files = append(files, newFile("apex_toolchain", GeneratedBuildFileName, "")) // Creates a //apex_toolchain package.
+ files = append(files, newFile("apex_toolchain", "constants.bzl", apex.BazelApexToolchainVars()))
+
files = append(files, newFile("metrics", "converted_modules.txt", strings.Join(metrics.convertedModules, "\n")))
files = append(files, newFile("product_config", "soong_config_variables.bzl", cfg.Bp2buildSoongConfigDefinitions.String()))
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index b0d0740..0cb711c 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -104,6 +104,14 @@
basename: "constants.bzl",
},
{
+ dir: "apex_toolchain",
+ basename: GeneratedBuildFileName,
+ },
+ {
+ dir: "apex_toolchain",
+ basename: "constants.bzl",
+ },
+ {
dir: "metrics",
basename: "converted_modules.txt",
},
diff --git a/bp2build/linker_config_conversion_test.go b/bp2build/linker_config_conversion_test.go
new file mode 100644
index 0000000..4662af4
--- /dev/null
+++ b/bp2build/linker_config_conversion_test.go
@@ -0,0 +1,59 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package bp2build
+
+import (
+ "fmt"
+ "testing"
+
+ "android/soong/linkerconfig"
+)
+
+func runLinkerConfigTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ (&tc).moduleTypeUnderTest = "linker_config"
+ (&tc).moduleTypeUnderTestFactory = linkerconfig.LinkerConfigFactory
+ runBp2BuildTestCaseSimple(t, tc)
+}
+
+func TestLinkerConfigConvertsSrc(t *testing.T) {
+ runLinkerConfigTestCase(t,
+ bp2buildTestCase{
+ blueprint: `
+linker_config {
+ name: "foo",
+ src: "a.json",
+}
+`,
+ expectedBazelTargets: []string{makeBazelTarget("linker_config", "foo", attrNameToString{
+ "src": `"a.json"`,
+ })},
+ })
+
+}
+
+func TestLinkerConfigNoSrc(t *testing.T) {
+ runLinkerConfigTestCase(t,
+ bp2buildTestCase{
+ blueprint: `
+linker_config {
+ name: "foo",
+}
+`,
+ expectedBazelTargets: []string{},
+ expectedErr: fmt.Errorf("Android.bp:2:1: module \"foo\": src: empty src is not supported"),
+ })
+
+}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index fa30d09..6cd6733 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -20,6 +20,7 @@
"android/soong/android"
"android/soong/bazel"
+ "android/soong/cc/config"
"github.com/google/blueprint"
@@ -156,7 +157,7 @@
attrs := staticOrSharedAttributes{}
setAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) {
- attrs.Copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag))
+ attrs.Copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, true, filterOutStdFlag))
attrs.Srcs.SetSelectValue(axis, config, android.BazelLabelForModuleSrc(ctx, props.Srcs))
attrs.System_dynamic_deps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, props.System_shared_libs))
@@ -326,16 +327,39 @@
return strings.HasPrefix(flag, "-std=")
}
-func parseCommandLineFlags(soongFlags []string, filterOut filterOutFn) []string {
+func filterOutClangUnknownCflags(flag string) bool {
+ for _, f := range config.ClangUnknownCflags {
+ if f == flag {
+ return true
+ }
+ }
+ return false
+}
+
+func parseCommandLineFlags(soongFlags []string, noCoptsTokenization bool, filterOut ...filterOutFn) []string {
var result []string
for _, flag := range soongFlags {
- if filterOut != nil && filterOut(flag) {
+ skipFlag := false
+ for _, filter := range filterOut {
+ if filter != nil && filter(flag) {
+ skipFlag = true
+ }
+ }
+ if skipFlag {
continue
}
// Soong's cflags can contain spaces, like `-include header.h`. For
// Bazel's copts, split them up to be compatible with the
// no_copts_tokenization feature.
- result = append(result, strings.Split(flag, " ")...)
+ if noCoptsTokenization {
+ result = append(result, strings.Split(flag, " ")...)
+ } else {
+ // Soong's Version Script and Dynamic List Properties are added as flags
+ // to Bazel's linkopts using "($location label)" syntax.
+ // Splitting on spaces would separate this into two different flags
+ // "($ location" and "label)"
+ result = append(result, flag)
+ }
}
return result
}
@@ -362,10 +386,10 @@
// overridden. In Bazel we always allow overriding, via flags; however, this can cause
// incompatibilities, so we remove "-std=" flags from Cflag properties while leaving it in other
// cases.
- ca.copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag))
- ca.asFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Asflags, nil))
- ca.conlyFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Conlyflags, nil))
- ca.cppFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Cppflags, nil))
+ ca.copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, true, filterOutStdFlag, filterOutClangUnknownCflags))
+ ca.asFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Asflags, true, nil))
+ ca.conlyFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Conlyflags, true, filterOutClangUnknownCflags))
+ ca.cppFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Cppflags, true, filterOutClangUnknownCflags))
ca.rtti.SetSelectValue(axis, config, props.Rtti)
}
@@ -721,7 +745,7 @@
linkerFlags = append(linkerFlags, fmt.Sprintf("-Wl,--dynamic-list,$(location %s)", label.Label))
}
- la.linkopts.SetSelectValue(axis, config, linkerFlags)
+ la.linkopts.SetSelectValue(axis, config, parseCommandLineFlags(linkerFlags, false, filterOutClangUnknownCflags))
la.useLibcrt.SetSelectValue(axis, config, props.libCrt())
if axis == bazel.NoConfigAxis {
diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go
index 003b275..412a23b 100644
--- a/linkerconfig/linkerconfig.go
+++ b/linkerconfig/linkerconfig.go
@@ -22,6 +22,7 @@
"github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/bazel"
"android/soong/cc"
"android/soong/etc"
)
@@ -36,7 +37,7 @@
}
func registerLinkerConfigBuildComponent(ctx android.RegistrationContext) {
- ctx.RegisterModuleType("linker_config", linkerConfigFactory)
+ ctx.RegisterModuleType("linker_config", LinkerConfigFactory)
}
type linkerConfigProperties struct {
@@ -52,6 +53,7 @@
type linkerConfig struct {
android.ModuleBase
+ android.BazelModuleBase
properties linkerConfigProperties
outputFilePath android.OutputPath
@@ -100,6 +102,28 @@
ctx.InstallFile(l.installDirPath, l.outputFilePath.Base(), l.outputFilePath)
}
+type linkerConfigAttributes struct {
+ Src bazel.LabelAttribute
+}
+
+func (l *linkerConfig) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ if l.properties.Src == nil {
+ ctx.PropertyErrorf("src", "empty src is not supported")
+ return
+ }
+ src := android.BazelLabelForModuleSrcSingle(ctx, *l.properties.Src)
+ targetModuleProperties := bazel.BazelTargetModuleProperties{
+ Rule_class: "linker_config",
+ Bzl_load_location: "//build/bazel/rules:linker_config.bzl",
+ }
+ ctx.CreateBazelTargetModule(
+ targetModuleProperties,
+ android.CommonAttributes{Name: l.Name()},
+ &linkerConfigAttributes{
+ Src: bazel.LabelAttribute{Value: &src},
+ })
+}
+
func BuildLinkerConfig(ctx android.ModuleContext, builder *android.RuleBuilder,
input android.Path, otherModules []android.Module, output android.OutputPath) {
@@ -141,10 +165,11 @@
// linker_config generates protobuf file from json file. This protobuf file will be used from
// linkerconfig while generating ld.config.txt. Format of this file can be found from
// https://android.googlesource.com/platform/system/linkerconfig/+/master/README.md
-func linkerConfigFactory() android.Module {
+func LinkerConfigFactory() android.Module {
m := &linkerConfig{}
m.AddProperties(&m.properties)
android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibFirst)
+ android.InitBazelModule(m)
return m
}