Merge "sbox: run commands using script for large commands"
diff --git a/android/Android.bp b/android/Android.bp
index 6450a06..cfa2be3 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -19,6 +19,9 @@
"soong-ui-metrics_proto",
"golang-protobuf-proto",
"golang-protobuf-encoding-prototext",
+
+ // Only used for tests.
+ "androidmk-parser",
],
srcs: [
"androidmk.go",
diff --git a/android/androidmk.go b/android/androidmk.go
index b6b04a6..0adc2a6 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -25,7 +25,6 @@
"bytes"
"fmt"
"io"
- "io/ioutil"
"os"
"path/filepath"
"reflect"
@@ -35,6 +34,7 @@
"github.com/google/blueprint"
"github.com/google/blueprint/bootstrap"
+ "github.com/google/blueprint/pathtools"
)
func init() {
@@ -114,7 +114,7 @@
// If true, the module is skipped and does not appear on the final Android-<product name>.mk
// file. Useful when a module needs to be skipped conditionally.
Disabled bool
- // The postprocessing mk file to include, e.g. $(BUILD_SYSTEM)/soong_cc_prebuilt.mk
+ // The postprocessing mk file to include, e.g. $(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk
// If not set, $(BUILD_SYSTEM)/prebuilt.mk is used.
Include string
// Required modules that need to be built and included in the final build output when building
@@ -690,7 +690,7 @@
})
}
-func translateAndroidMk(ctx SingletonContext, mkFile string, mods []blueprint.Module) error {
+func translateAndroidMk(ctx SingletonContext, absMkFile string, mods []blueprint.Module) error {
buf := &bytes.Buffer{}
fmt.Fprintln(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))")
@@ -699,7 +699,7 @@
for _, mod := range mods {
err := translateAndroidMkModule(ctx, buf, mod)
if err != nil {
- os.Remove(mkFile)
+ os.Remove(absMkFile)
return err
}
@@ -719,27 +719,7 @@
fmt.Fprintf(buf, "STATS.SOONG_MODULE_TYPE.%s := %d\n", mod_type, typeStats[mod_type])
}
- // Don't write to the file if it hasn't changed
- if _, err := os.Stat(absolutePath(mkFile)); !os.IsNotExist(err) {
- if data, err := ioutil.ReadFile(absolutePath(mkFile)); err == nil {
- matches := buf.Len() == len(data)
-
- if matches {
- for i, value := range buf.Bytes() {
- if value != data[i] {
- matches = false
- break
- }
- }
- }
-
- if matches {
- return nil
- }
- }
- }
-
- return ioutil.WriteFile(absolutePath(mkFile), buf.Bytes(), 0666)
+ return pathtools.WriteFileIfChanged(absMkFile, buf.Bytes(), 0666)
}
func translateAndroidMkModule(ctx SingletonContext, w io.Writer, mod blueprint.Module) error {
diff --git a/android/bazel.go b/android/bazel.go
index cf27cb4..bf214a5 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -15,6 +15,7 @@
package android
import (
+ "android/soong/bazel"
"fmt"
"io/ioutil"
"path/filepath"
@@ -24,34 +25,37 @@
"github.com/google/blueprint/proptools"
)
-type bazelModuleProperties struct {
- // The label of the Bazel target replacing this Soong module. When run in conversion mode, this
- // will import the handcrafted build target into the autogenerated file. Note: this may result in
- // a conflict due to duplicate targets if bp2build_available is also set.
- Label *string
-
- // If true, bp2build will generate the converted Bazel target for this module. Note: this may
- // cause a conflict due to the duplicate targets if label is also set.
- //
- // This is a bool pointer to support tristates: true, false, not set.
- //
- // To opt-in a module, set bazel_module: { bp2build_available: true }
- // To opt-out a module, set bazel_module: { bp2build_available: false }
- // To defer the default setting for the directory, do not set the value.
- Bp2build_available *bool
-}
-
// Properties contains common module properties for Bazel migration purposes.
type properties struct {
// In USE_BAZEL_ANALYSIS=1 mode, this represents the Bazel target replacing
// this Soong module.
- Bazel_module bazelModuleProperties
+ Bazel_module bazel.BazelModuleProperties
}
+// namespacedVariableProperties is a map from a string representing a Soong
+// config variable namespace, like "android" or "vendor_name" to a struct
+// pointer representing the soong_config_variables property of a module created
+// by a soong_config_module_type or soong_config_module_type_import.
+type namespacedVariableProperties map[string]interface{}
+
// BazelModuleBase contains the property structs with metadata for modules which can be converted to
// Bazel.
type BazelModuleBase struct {
bazelProperties properties
+
+ // namespacedVariableProperties is used for soong_config_module_type support
+ // in bp2build. Soong config modules allow users to set module properties
+ // based on custom product variables defined in Android.bp files. These
+ // variables are namespaced to prevent clobbering, especially when set from
+ // Makefiles.
+ namespacedVariableProperties namespacedVariableProperties
+
+ // baseModuleType is set when this module was created from a module type
+ // defined by a soong_config_module_type. Every soong_config_module_type
+ // "wraps" another module type, e.g. a soong_config_module_type can wrap a
+ // cc_defaults to a custom_cc_defaults, or cc_binary to a custom_cc_binary.
+ // This baseModuleType is set to the wrapped module type.
+ baseModuleType string
}
// Bazelable is specifies the interface for modules that can be converted to Bazel.
@@ -63,6 +67,12 @@
ConvertWithBp2build(ctx BazelConversionContext) bool
convertWithBp2build(ctx BazelConversionContext, module blueprint.Module) bool
GetBazelBuildFileContents(c Config, path, name string) (string, error)
+
+ // For namespaced config variable support
+ namespacedVariableProps() namespacedVariableProperties
+ setNamespacedVariableProps(props namespacedVariableProperties)
+ BaseModuleType() string
+ SetBaseModuleType(string)
}
// BazelModule is a lightweight wrapper interface around Module for Bazel-convertible modules.
@@ -82,6 +92,22 @@
return &b.bazelProperties
}
+func (b *BazelModuleBase) namespacedVariableProps() namespacedVariableProperties {
+ return b.namespacedVariableProperties
+}
+
+func (b *BazelModuleBase) setNamespacedVariableProps(props namespacedVariableProperties) {
+ b.namespacedVariableProperties = props
+}
+
+func (b *BazelModuleBase) BaseModuleType() string {
+ return b.baseModuleType
+}
+
+func (b *BazelModuleBase) SetBaseModuleType(baseModuleType string) {
+ b.baseModuleType = baseModuleType
+}
+
// HasHandcraftedLabel returns whether this module has a handcrafted Bazel label.
func (b *BazelModuleBase) HasHandcraftedLabel() bool {
return b.bazelProperties.Bazel_module.Label != nil
@@ -166,6 +192,7 @@
"packages/apps/QuickSearchBox":/* recursive = */ true,
"packages/apps/WallpaperPicker":/* recursive = */ false,
+ "prebuilts/gcc":/* recursive = */ true,
"prebuilts/sdk":/* recursive = */ false,
"prebuilts/sdk/current/extras/app-toolkit":/* recursive = */ false,
"prebuilts/sdk/current/support":/* recursive = */ false,
@@ -177,6 +204,7 @@
bp2buildDefaultConfig = Bp2BuildConfig{
"bionic": Bp2BuildDefaultTrueRecursively,
"build/bazel/examples/apex/minimal": Bp2BuildDefaultTrueRecursively,
+ "build/soong/cc/libbuildversion": Bp2BuildDefaultTrue, // Skip tests subdir
"development/sdk": Bp2BuildDefaultTrueRecursively,
"external/arm-optimized-routines": Bp2BuildDefaultTrueRecursively,
"external/boringssl": Bp2BuildDefaultTrueRecursively,
@@ -228,6 +256,8 @@
// Per-module denylist to always opt modules out of both bp2build and mixed builds.
bp2buildModuleDoNotConvertList = []string{
+ "libprotobuf-cpp-full", "libprotobuf-cpp-lite", // Unsupported product&vendor suffix. b/204811222 and b/204810610.
+
"libc_malloc_debug", // depends on libunwindstack, which depends on unsupported module art_cc_library_statics
"libbase_ndk", // http://b/186826477, fails to link libctscamera2_jni for device (required for CtsCameraTestCases)
@@ -248,14 +278,8 @@
"platform_tools_properties",
"build_tools_source_properties",
- // //external/libcap/...
- "cap_names.h", // http://b/196105070 host toolchain misconfigurations for mixed builds
- "libcap", // http://b/196105070 host toolchain misconfigurations for mixed builds
-
- "libminijail", // depends on unconverted modules: libcap
- "getcap", // depends on unconverted modules: libcap
- "setcap", // depends on unconverted modules: libcap
- "minijail0", // depends on unconverted modules: libcap, libminijail
+ "libminijail", // b/202491296: Uses unsupported c_std property.
+ "minijail0", // depends on unconverted modules: libminijail
"drop_privs", // depends on unconverted modules: libminijail
// Tests. Handle later.
@@ -308,12 +332,11 @@
// Per-module denylist to opt modules out of mixed builds. Such modules will
// still be generated via bp2build.
mixedBuildsDisabledList = []string{
- "libbrotli", // http://b/198585397, ld.lld: error: bionic/libc/arch-arm64/generic/bionic/memmove.S:95:(.text+0x10): relocation R_AARCH64_CONDBR19 out of range: -1404176 is not in [-1048576, 1048575]; references __memcpy
- "func_to_syscall_nrs", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module.
- "libseccomp_policy_app_zygote_sources", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module.
- "libseccomp_policy_app_sources", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module.
- "libseccomp_policy_system_sources", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module.
- "minijail_constants_json", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module.
+ "libbrotli", // http://b/198585397, ld.lld: error: bionic/libc/arch-arm64/generic/bionic/memmove.S:95:(.text+0x10): relocation R_AARCH64_CONDBR19 out of range: -1404176 is not in [-1048576, 1048575]; references __memcpy
+ "minijail_constants_json", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module.
+
+ "cap_names.h", // TODO(b/204913827) runfiles need to be handled in mixed builds
+ "libcap", // TODO(b/204913827) runfiles need to be handled in mixed builds
}
// Used for quicker lookups
@@ -359,7 +382,11 @@
// MixedBuildsEnabled checks that a module is ready to be replaced by a
// converted or handcrafted Bazel target.
-func (b *BazelModuleBase) MixedBuildsEnabled(ctx BazelConversionPathContext) bool {
+func (b *BazelModuleBase) MixedBuildsEnabled(ctx ModuleContext) bool {
+ if ctx.Os() == Windows {
+ // Windows toolchains are not currently supported.
+ return false
+ }
if !ctx.Config().BazelContext.BazelEnabled() {
return false
}
@@ -399,7 +426,15 @@
// prevents mixed builds from using auto-converted modules just by matching
// the package dir; it also has to have a bp2build mutator as well.
if ctx.Config().bp2buildModuleTypeConfig[ctx.OtherModuleType(module)] == false {
- return false
+ if b, ok := module.(Bazelable); ok && b.BaseModuleType() != "" {
+ // For modules with custom types from soong_config_module_types,
+ // check that their _base module type_ has a bp2build mutator.
+ if ctx.Config().bp2buildModuleTypeConfig[b.BaseModuleType()] == false {
+ return false
+ }
+ } else {
+ return false
+ }
}
packagePath := ctx.OtherModuleDir(module)
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 3c6212e..0052551 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -602,8 +602,6 @@
platform_name = build_options(target)["//command_line_option:platforms"][0].name
if platform_name == "host":
return "HOST"
- elif platform_name.startswith("linux_glibc_"):
- return platform_name[len("linux_glibc_"):] + "|" + platform_name[:len("linux_glibc_")-1]
elif platform_name.startswith("android_"):
return platform_name[len("android_"):] + "|" + platform_name[:len("android_")-1]
elif platform_name.startswith("linux_"):
@@ -865,7 +863,7 @@
arch = "x86_64"
}
os := key.configKey.osType.Name
- if len(os) == 0 || os == "common_os" {
+ if len(os) == 0 || os == "common_os" || os == "linux_glibc" {
// Use host OS, which is currently hardcoded to be linux.
os = "linux"
}
diff --git a/android/config.go b/android/config.go
index 78d43c6..6f05565 100644
--- a/android/config.go
+++ b/android/config.go
@@ -155,6 +155,7 @@
fs pathtools.FileSystem
mockBpList string
+ runningAsBp2Build bool
bp2buildPackageConfig Bp2BuildConfig
bp2buildModuleTypeConfig map[string]bool
@@ -333,10 +334,8 @@
ShippingApiLevel: stringPtr("30"),
},
- outDir: buildDir,
- // soongOutDir is inconsistent with production (it should be buildDir + "/soong")
- // but a lot of tests assume this :(
- soongOutDir: buildDir,
+ outDir: buildDir,
+ soongOutDir: filepath.Join(buildDir, "soong"),
captureBuild: true,
env: envCopy,
@@ -564,11 +563,18 @@
// BlueprintToolLocation returns the directory containing build system tools
// from Blueprint, like soong_zip and merge_zips.
func (c *config) HostToolDir() string {
- return filepath.Join(c.soongOutDir, "host", c.PrebuiltOS(), "bin")
+ if c.KatiEnabled() {
+ return filepath.Join(c.outDir, "host", c.PrebuiltOS(), "bin")
+ } else {
+ return filepath.Join(c.soongOutDir, "host", c.PrebuiltOS(), "bin")
+ }
}
func (c *config) HostToolPath(ctx PathContext, tool string) Path {
path := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "bin", false, tool)
+ if ctx.Config().KatiEnabled() {
+ path = path.ToMakePath()
+ }
return path
}
@@ -578,11 +584,18 @@
ext = ".dylib"
}
path := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "lib64", false, lib+ext)
+ if ctx.Config().KatiEnabled() {
+ path = path.ToMakePath()
+ }
return path
}
-func (c *config) HostJavaToolPath(ctx PathContext, path string) Path {
- return PathForOutput(ctx, "host", c.PrebuiltOS(), "framework", path)
+func (c *config) HostJavaToolPath(ctx PathContext, tool string) Path {
+ path := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "framework", false, tool)
+ if ctx.Config().KatiEnabled() {
+ path = path.ToMakePath()
+ }
+ return path
}
// PrebuiltOS returns the name of the host OS used in prebuilts directories.
diff --git a/android/defs.go b/android/defs.go
index c8e2e9b..362b382 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -52,10 +52,10 @@
// A copy rule.
Cp = pctx.AndroidStaticRule("Cp",
blueprint.RuleParams{
- Command: "rm -f $out && cp $cpPreserveSymlinks $cpFlags $in $out",
+ Command: "rm -f $out && cp $cpPreserveSymlinks $cpFlags $in $out$extraCmds",
Description: "cp $out",
},
- "cpFlags")
+ "cpFlags", "extraCmds")
// A copy rule that only updates the output if it changed.
CpIfChanged = pctx.AndroidStaticRule("CpIfChanged",
@@ -68,10 +68,10 @@
CpExecutable = pctx.AndroidStaticRule("CpExecutable",
blueprint.RuleParams{
- Command: "rm -f $out && cp $cpPreserveSymlinks $cpFlags $in $out && chmod +x $out",
+ Command: "rm -f $out && cp $cpPreserveSymlinks $cpFlags $in $out && chmod +x $out$extraCmds",
Description: "cp $out",
},
- "cpFlags")
+ "cpFlags", "extraCmds")
// A timestamp touch rule.
Touch = pctx.AndroidStaticRule("Touch",
diff --git a/android/makevars.go b/android/makevars.go
index 20db65a..ece7091 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -142,15 +142,19 @@
var singletonMakeVarsProvidersKey = NewOnceKey("singletonMakeVarsProvidersKey")
+func getSingletonMakevarsProviders(config Config) *[]makeVarsProvider {
+ return config.Once(singletonMakeVarsProvidersKey, func() interface{} {
+ return &[]makeVarsProvider{}
+ }).(*[]makeVarsProvider)
+}
+
// registerSingletonMakeVarsProvider adds a singleton that implements SingletonMakeVarsProvider to
// the list of MakeVarsProviders to run.
func registerSingletonMakeVarsProvider(config Config, singleton SingletonMakeVarsProvider) {
// Singletons are registered on the Context and may be different between different Contexts,
// for example when running multiple tests. Store the SingletonMakeVarsProviders in the
// Config so they are attached to the Context.
- singletonMakeVarsProviders := config.Once(singletonMakeVarsProvidersKey, func() interface{} {
- return &[]makeVarsProvider{}
- }).(*[]makeVarsProvider)
+ singletonMakeVarsProviders := getSingletonMakevarsProviders(config)
*singletonMakeVarsProviders = append(*singletonMakeVarsProviders,
makeVarsProvider{pctx, singletonMakeVarsProviderAdapter(singleton)})
@@ -175,7 +179,9 @@
return &makeVarsSingleton{}
}
-type makeVarsSingleton struct{}
+type makeVarsSingleton struct {
+ installsForTesting []byte
+}
type makeVarsProvider struct {
pctx PackageContext
@@ -238,7 +244,7 @@
var katiSymlinks []katiInstall
providers := append([]makeVarsProvider(nil), makeVarsInitProviders...)
- providers = append(providers, *ctx.Config().Get(singletonMakeVarsProvidersKey).(*[]makeVarsProvider)...)
+ providers = append(providers, *getSingletonMakevarsProviders(ctx.Config())...)
for _, provider := range providers {
mctx := &makeVarsContext{
@@ -313,6 +319,8 @@
if err := pathtools.WriteFileIfChanged(installsFile, installsBytes, 0666); err != nil {
ctx.Errorf(err.Error())
}
+
+ s.installsForTesting = installsBytes
}
func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte {
@@ -414,6 +422,7 @@
fmt.Fprintln(buf)
for _, dist := range dists {
+ fmt.Fprintf(buf, ".PHONY: %s\n", strings.Join(dist.goals, " "))
fmt.Fprintf(buf, "$(call dist-for-goals,%s,%s)\n",
strings.Join(dist.goals, " "), strings.Join(dist.paths, " "))
}
@@ -447,6 +456,9 @@
for _, dep := range install.implicitDeps {
fmt.Fprintf(buf, " %s", dep.String())
}
+ if extraFiles := install.extraFiles; extraFiles != nil {
+ fmt.Fprintf(buf, " %s", extraFiles.zip.String())
+ }
if len(install.orderOnlyDeps) > 0 {
fmt.Fprintf(buf, " |")
}
@@ -454,26 +466,32 @@
fmt.Fprintf(buf, " %s", dep.String())
}
fmt.Fprintln(buf)
-
- fmt.Fprintf(buf, "\trm -f $@ && cp -f %s $< $@", preserveSymlinksFlag)
+ fmt.Fprintln(buf, "\t@echo \"Install $@\"")
+ fmt.Fprintf(buf, "\trm -f $@ && cp -f %s $< $@\n", preserveSymlinksFlag)
if install.executable {
- fmt.Fprintf(buf, " && chmod +x $@")
+ fmt.Fprintf(buf, "\tchmod +x $@\n")
}
- fmt.Fprintln(buf)
+ if extraFiles := install.extraFiles; extraFiles != nil {
+ fmt.Fprintf(buf, "\tunzip -qDD -d '%s' '%s'\n", extraFiles.dir.String(), extraFiles.zip.String())
+ }
fmt.Fprintln(buf)
}
for _, symlink := range symlinks {
fmt.Fprintf(buf, "%s:", symlink.to.String())
+ if symlink.from != nil {
+ // The symlink doesn't need updating when the target is modified, but we sometimes
+ // have a dependency on a symlink to a binary instead of to the binary directly, and
+ // the mtime of the symlink must be updated when the binary is modified, so use a
+ // normal dependency here instead of an order-only dependency.
+ fmt.Fprintf(buf, " %s", symlink.from.String())
+ }
for _, dep := range symlink.implicitDeps {
fmt.Fprintf(buf, " %s", dep.String())
}
- if symlink.from != nil || len(symlink.orderOnlyDeps) > 0 {
+ if len(symlink.orderOnlyDeps) > 0 {
fmt.Fprintf(buf, " |")
}
- if symlink.from != nil {
- fmt.Fprintf(buf, " %s", symlink.from.String())
- }
for _, dep := range symlink.orderOnlyDeps {
fmt.Fprintf(buf, " %s", dep.String())
}
@@ -491,6 +509,7 @@
fromStr = symlink.absFrom
}
+ fmt.Fprintln(buf, "\t@echo \"Symlink $@\"")
fmt.Fprintf(buf, "\trm -f $@ && ln -sfn %s $@", fromStr)
fmt.Fprintln(buf)
fmt.Fprintln(buf)
diff --git a/android/module.go b/android/module.go
index 3447f2b..e100330 100644
--- a/android/module.go
+++ b/android/module.go
@@ -381,6 +381,16 @@
// for which IsInstallDepNeeded returns true.
InstallFile(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath
+ // InstallFileWithExtraFilesZip creates a rule to copy srcPath to name in the installPath
+ // directory, and also unzip a zip file containing extra files to install into the same
+ // directory.
+ //
+ // The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
+ // installed file will be returned by PackagingSpecs() on this module or by
+ // TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+ // for which IsInstallDepNeeded returns true.
+ InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path, extraZip Path, deps ...Path) InstallPath
+
// InstallSymlink creates a rule to create a symlink from src srcPath to name in the installPath
// directory.
//
@@ -2235,10 +2245,16 @@
implicitDeps Paths
orderOnlyDeps Paths
executable bool
+ extraFiles *extraFilesZip
absFrom string
}
+type extraFilesZip struct {
+ zip Path
+ dir InstallPath
+}
+
type katiInstalls []katiInstall
// BuiltInstalled returns the katiInstalls in the form used by $(call copy-many-files) in Make, a
@@ -2852,12 +2868,20 @@
func (m *moduleContext) InstallFile(installPath InstallPath, name string, srcPath Path,
deps ...Path) InstallPath {
- return m.installFile(installPath, name, srcPath, deps, false)
+ return m.installFile(installPath, name, srcPath, deps, false, nil)
}
func (m *moduleContext) InstallExecutable(installPath InstallPath, name string, srcPath Path,
deps ...Path) InstallPath {
- return m.installFile(installPath, name, srcPath, deps, true)
+ return m.installFile(installPath, name, srcPath, deps, true, nil)
+}
+
+func (m *moduleContext) InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path,
+ extraZip Path, deps ...Path) InstallPath {
+ return m.installFile(installPath, name, srcPath, deps, false, &extraFilesZip{
+ zip: extraZip,
+ dir: installPath,
+ })
}
func (m *moduleContext) PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec {
@@ -2878,7 +2902,8 @@
return spec
}
-func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []Path, executable bool) InstallPath {
+func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []Path,
+ executable bool, extraZip *extraFilesZip) InstallPath {
fullInstallPath := installPath.Join(m, name)
m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, false)
@@ -2906,6 +2931,7 @@
implicitDeps: implicitDeps,
orderOnlyDeps: orderOnlyDeps,
executable: executable,
+ extraFiles: extraZip,
})
} else {
rule := Cp
@@ -2913,6 +2939,13 @@
rule = CpExecutable
}
+ extraCmds := ""
+ if extraZip != nil {
+ extraCmds += fmt.Sprintf(" && unzip -qDD -d '%s' '%s'",
+ extraZip.dir.String(), extraZip.zip.String())
+ implicitDeps = append(implicitDeps, extraZip.zip)
+ }
+
m.Build(pctx, BuildParams{
Rule: rule,
Description: "install " + fullInstallPath.Base(),
@@ -2921,6 +2954,9 @@
Implicits: implicitDeps,
OrderOnly: orderOnlyDeps,
Default: !m.Config().KatiEnabled(),
+ Args: map[string]string{
+ "extraCmds": extraCmds,
+ },
})
}
@@ -2953,6 +2989,10 @@
to: fullInstallPath,
})
} else {
+ // The symlink doesn't need updating when the target is modified, but we sometimes
+ // have a dependency on a symlink to a binary instead of to the binary directly, and
+ // the mtime of the symlink must be updated when the binary is modified, so use a
+ // normal dependency here instead of an order-only dependency.
m.Build(pctx, BuildParams{
Rule: Symlink,
Description: "install symlink " + fullInstallPath.Base(),
diff --git a/android/module_test.go b/android/module_test.go
index 9e2b0ca..8607a8d 100644
--- a/android/module_test.go
+++ b/android/module_test.go
@@ -15,7 +15,12 @@
package android
import (
+ "bytes"
+ "path/filepath"
+ "runtime"
"testing"
+
+ mkparser "android/soong/androidmk/parser"
)
func TestSrcIsModule(t *testing.T) {
@@ -199,17 +204,28 @@
}
}
+func (m *depsModule) InstallBypassMake() bool {
+ return true
+}
+
func (m *depsModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ outputFile := PathForModuleOut(ctx, ctx.ModuleName())
+ ctx.Build(pctx, BuildParams{
+ Rule: Touch,
+ Output: outputFile,
+ })
+ installFile := ctx.InstallFile(PathForModuleInstall(ctx), ctx.ModuleName(), outputFile)
+ ctx.InstallSymlink(PathForModuleInstall(ctx, "symlinks"), ctx.ModuleName(), installFile)
}
func (m *depsModule) DepsMutator(ctx BottomUpMutatorContext) {
- ctx.AddDependency(ctx.Module(), nil, m.props.Deps...)
+ ctx.AddDependency(ctx.Module(), installDepTag{}, m.props.Deps...)
}
func depsModuleFactory() Module {
m := &depsModule{}
m.AddProperties(&m.props)
- InitAndroidModule(m)
+ InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon)
return m
}
@@ -320,3 +336,286 @@
ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(expectedErrs)).
RunTestWithBp(t, bp)
}
+
+func TestInstall(t *testing.T) {
+ if runtime.GOOS != "linux" {
+ t.Skip("requires linux")
+ }
+ bp := `
+ deps {
+ name: "foo",
+ deps: ["bar"],
+ }
+
+ deps {
+ name: "bar",
+ deps: ["baz", "qux"],
+ }
+
+ deps {
+ name: "baz",
+ deps: ["qux"],
+ }
+
+ deps {
+ name: "qux",
+ }
+ `
+
+ result := GroupFixturePreparers(
+ prepareForModuleTests,
+ PrepareForTestWithArchMutator,
+ ).RunTestWithBp(t, bp)
+
+ module := func(name string, host bool) TestingModule {
+ variant := "android_common"
+ if host {
+ variant = result.Config.BuildOSCommonTarget.String()
+ }
+ return result.ModuleForTests(name, variant)
+ }
+
+ outputRule := func(name string) TestingBuildParams { return module(name, false).Output(name) }
+
+ installRule := func(name string) TestingBuildParams {
+ return module(name, false).Output(filepath.Join("out/soong/target/product/test_device/system", name))
+ }
+
+ symlinkRule := func(name string) TestingBuildParams {
+ return module(name, false).Output(filepath.Join("out/soong/target/product/test_device/system/symlinks", name))
+ }
+
+ hostOutputRule := func(name string) TestingBuildParams { return module(name, true).Output(name) }
+
+ hostInstallRule := func(name string) TestingBuildParams {
+ return module(name, true).Output(filepath.Join("out/soong/host/linux-x86", name))
+ }
+
+ hostSymlinkRule := func(name string) TestingBuildParams {
+ return module(name, true).Output(filepath.Join("out/soong/host/linux-x86/symlinks", name))
+ }
+
+ assertInputs := func(params TestingBuildParams, inputs ...Path) {
+ t.Helper()
+ AssertArrayString(t, "expected inputs", Paths(inputs).Strings(),
+ append(PathsIfNonNil(params.Input), params.Inputs...).Strings())
+ }
+
+ assertImplicits := func(params TestingBuildParams, implicits ...Path) {
+ t.Helper()
+ AssertArrayString(t, "expected implicit dependencies", Paths(implicits).Strings(),
+ append(PathsIfNonNil(params.Implicit), params.Implicits...).Strings())
+ }
+
+ assertOrderOnlys := func(params TestingBuildParams, orderonlys ...Path) {
+ t.Helper()
+ AssertArrayString(t, "expected orderonly dependencies", Paths(orderonlys).Strings(),
+ params.OrderOnly.Strings())
+ }
+
+ // Check host install rule dependencies
+ assertInputs(hostInstallRule("foo"), hostOutputRule("foo").Output)
+ assertImplicits(hostInstallRule("foo"),
+ hostInstallRule("bar").Output,
+ hostSymlinkRule("bar").Output,
+ hostInstallRule("baz").Output,
+ hostSymlinkRule("baz").Output,
+ hostInstallRule("qux").Output,
+ hostSymlinkRule("qux").Output,
+ )
+ assertOrderOnlys(hostInstallRule("foo"))
+
+ // Check host symlink rule dependencies. Host symlinks must use a normal dependency, not an
+ // order-only dependency, so that the tool gets updated when the symlink is depended on.
+ assertInputs(hostSymlinkRule("foo"), hostInstallRule("foo").Output)
+ assertImplicits(hostSymlinkRule("foo"))
+ assertOrderOnlys(hostSymlinkRule("foo"))
+
+ // Check device install rule dependencies
+ assertInputs(installRule("foo"), outputRule("foo").Output)
+ assertImplicits(installRule("foo"))
+ assertOrderOnlys(installRule("foo"),
+ installRule("bar").Output,
+ symlinkRule("bar").Output,
+ installRule("baz").Output,
+ symlinkRule("baz").Output,
+ installRule("qux").Output,
+ symlinkRule("qux").Output,
+ )
+
+ // Check device symlink rule dependencies. Device symlinks could use an order-only dependency,
+ // but the current implementation uses a normal dependency.
+ assertInputs(symlinkRule("foo"), installRule("foo").Output)
+ assertImplicits(symlinkRule("foo"))
+ assertOrderOnlys(symlinkRule("foo"))
+}
+
+func TestInstallBypassMake(t *testing.T) {
+ if runtime.GOOS != "linux" {
+ t.Skip("requires linux")
+ }
+ bp := `
+ deps {
+ name: "foo",
+ deps: ["bar"],
+ }
+
+ deps {
+ name: "bar",
+ deps: ["baz", "qux"],
+ }
+
+ deps {
+ name: "baz",
+ deps: ["qux"],
+ }
+
+ deps {
+ name: "qux",
+ }
+ `
+
+ result := GroupFixturePreparers(
+ prepareForModuleTests,
+ PrepareForTestWithArchMutator,
+ FixtureModifyConfig(SetKatiEnabledForTests),
+ FixtureRegisterWithContext(func(ctx RegistrationContext) {
+ ctx.RegisterSingletonType("makevars", makeVarsSingletonFunc)
+ }),
+ ).RunTestWithBp(t, bp)
+
+ installs := result.SingletonForTests("makevars").Singleton().(*makeVarsSingleton).installsForTesting
+ buf := bytes.NewBuffer(append([]byte(nil), installs...))
+ parser := mkparser.NewParser("makevars", buf)
+
+ nodes, errs := parser.Parse()
+ if len(errs) > 0 {
+ t.Fatalf("error parsing install rules: %s", errs[0])
+ }
+
+ rules := parseMkRules(t, result.Config, nodes)
+
+ module := func(name string, host bool) TestingModule {
+ variant := "android_common"
+ if host {
+ variant = result.Config.BuildOSCommonTarget.String()
+ }
+ return result.ModuleForTests(name, variant)
+ }
+
+ outputRule := func(name string) TestingBuildParams { return module(name, false).Output(name) }
+
+ ruleForOutput := func(output string) installMakeRule {
+ for _, rule := range rules {
+ if rule.target == output {
+ return rule
+ }
+ }
+ t.Fatalf("no make install rule for %s", output)
+ return installMakeRule{}
+ }
+
+ installRule := func(name string) installMakeRule {
+ return ruleForOutput(filepath.Join("out/target/product/test_device/system", name))
+ }
+
+ symlinkRule := func(name string) installMakeRule {
+ return ruleForOutput(filepath.Join("out/target/product/test_device/system/symlinks", name))
+ }
+
+ hostOutputRule := func(name string) TestingBuildParams { return module(name, true).Output(name) }
+
+ hostInstallRule := func(name string) installMakeRule {
+ return ruleForOutput(filepath.Join("out/host/linux-x86", name))
+ }
+
+ hostSymlinkRule := func(name string) installMakeRule {
+ return ruleForOutput(filepath.Join("out/host/linux-x86/symlinks", name))
+ }
+
+ assertDeps := func(rule installMakeRule, deps ...string) {
+ t.Helper()
+ AssertArrayString(t, "expected inputs", deps, rule.deps)
+ }
+
+ assertOrderOnlys := func(rule installMakeRule, orderonlys ...string) {
+ t.Helper()
+ AssertArrayString(t, "expected orderonly dependencies", orderonlys, rule.orderOnlyDeps)
+ }
+
+ // Check host install rule dependencies
+ assertDeps(hostInstallRule("foo"),
+ hostOutputRule("foo").Output.String(),
+ hostInstallRule("bar").target,
+ hostSymlinkRule("bar").target,
+ hostInstallRule("baz").target,
+ hostSymlinkRule("baz").target,
+ hostInstallRule("qux").target,
+ hostSymlinkRule("qux").target,
+ )
+ assertOrderOnlys(hostInstallRule("foo"))
+
+ // Check host symlink rule dependencies. Host symlinks must use a normal dependency, not an
+ // order-only dependency, so that the tool gets updated when the symlink is depended on.
+ assertDeps(hostSymlinkRule("foo"), hostInstallRule("foo").target)
+ assertOrderOnlys(hostSymlinkRule("foo"))
+
+ // Check device install rule dependencies
+ assertDeps(installRule("foo"), outputRule("foo").Output.String())
+ assertOrderOnlys(installRule("foo"),
+ installRule("bar").target,
+ symlinkRule("bar").target,
+ installRule("baz").target,
+ symlinkRule("baz").target,
+ installRule("qux").target,
+ symlinkRule("qux").target,
+ )
+
+ // Check device symlink rule dependencies. Device symlinks could use an order-only dependency,
+ // but the current implementation uses a normal dependency.
+ assertDeps(symlinkRule("foo"), installRule("foo").target)
+ assertOrderOnlys(symlinkRule("foo"))
+}
+
+type installMakeRule struct {
+ target string
+ deps []string
+ orderOnlyDeps []string
+}
+
+func parseMkRules(t *testing.T, config Config, nodes []mkparser.Node) []installMakeRule {
+ var rules []installMakeRule
+ for _, node := range nodes {
+ if mkParserRule, ok := node.(*mkparser.Rule); ok {
+ var rule installMakeRule
+
+ if targets := mkParserRule.Target.Words(); len(targets) == 0 {
+ t.Fatalf("no targets for rule %s", mkParserRule.Dump())
+ } else if len(targets) > 1 {
+ t.Fatalf("unsupported multiple targets for rule %s", mkParserRule.Dump())
+ } else if !targets[0].Const() {
+ t.Fatalf("unsupported non-const target for rule %s", mkParserRule.Dump())
+ } else {
+ rule.target = normalizeStringRelativeToTop(config, targets[0].Value(nil))
+ }
+
+ prereqList := &rule.deps
+ for _, prereq := range mkParserRule.Prerequisites.Words() {
+ if !prereq.Const() {
+ t.Fatalf("unsupported non-const prerequisite for rule %s", mkParserRule.Dump())
+ }
+
+ if prereq.Value(nil) == "|" {
+ prereqList = &rule.orderOnlyDeps
+ continue
+ }
+
+ *prereqList = append(*prereqList, normalizeStringRelativeToTop(config, prereq.Value(nil)))
+ }
+
+ rules = append(rules, rule)
+ }
+ }
+
+ return rules
+}
diff --git a/android/neverallow.go b/android/neverallow.go
index 04366d3..b36bf04 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -214,8 +214,11 @@
return []Rule{
NeverAllow().
ModuleType("makefile_goal").
+ // TODO(b/33691272): remove this after migrating seapp to Soong
+ Without("product_out_path", "obj/ETC/plat_seapp_contexts_intermediates/plat_seapp_contexts").
+ Without("product_out_path", "obj/ETC/plat_seapp_neverallows_intermediates/plat_seapp_neverallows").
WithoutMatcher("product_out_path", Regexp("^boot[0-9a-zA-Z.-]*[.]img$")).
- Because("Only boot images may be imported as a makefile goal."),
+ Because("Only boot images and seapp contexts may be imported as a makefile goal."),
}
}
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 35aadd8..edda244 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -293,7 +293,7 @@
`),
},
expectedErrors: []string{
- "Only boot images may be imported as a makefile goal.",
+ "Only boot images and seapp contexts may be imported as a makefile goal.",
},
},
}
diff --git a/android/paths.go b/android/paths.go
index 69ab5f7..e68106c 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -465,6 +465,9 @@
// PathForGoBinary returns the path to the installed location of a bootstrap_go_binary module.
func PathForGoBinary(ctx PathContext, goBinary bootstrap.GoBinaryTool) Path {
goBinaryInstallDir := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "bin", false)
+ if ctx.Config().KatiEnabled() {
+ goBinaryInstallDir = goBinaryInstallDir.ToMakePath()
+ }
rel := Rel(ctx, goBinaryInstallDir.String(), goBinary.InstallPath())
return goBinaryInstallDir.Join(ctx, rel)
}
@@ -1658,6 +1661,12 @@
return makePathForInstall(ctx, os, arch, partition, ctx.Debug(), pathComponents...)
}
+// PathForHostDexInstall returns an InstallPath representing the install path for the
+// module appended with paths...
+func PathForHostDexInstall(ctx ModuleInstallPathContext, pathComponents ...string) InstallPath {
+ return makePathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "", ctx.Debug(), pathComponents...)
+}
+
// PathForModuleInPartitionInstall is similar to PathForModuleInstall but partition is provided by the caller
func PathForModuleInPartitionInstall(ctx ModuleInstallPathContext, partition string, pathComponents ...string) InstallPath {
os, arch := osAndArch(ctx)
@@ -2055,7 +2064,12 @@
// Writes a file to the output directory. Attempting to write directly to the output directory
// will fail due to the sandbox of the soong_build process.
func WriteFileToOutputDir(path WritablePath, data []byte, perm os.FileMode) error {
- return ioutil.WriteFile(absolutePath(path.String()), data, perm)
+ absPath := absolutePath(path.String())
+ err := os.MkdirAll(filepath.Dir(absPath), 0777)
+ if err != nil {
+ return err
+ }
+ return ioutil.WriteFile(absPath, data, perm)
}
func RemoveAllOutputDir(path WritablePath) error {
diff --git a/android/paths_test.go b/android/paths_test.go
index 3f4625d..3cad852 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -993,7 +993,7 @@
{
name: "in out dir",
buildDir: "out",
- src: "out/a/b/c",
+ src: "out/soong/a/b/c",
err: "is in output",
},
}
@@ -1525,7 +1525,7 @@
fmt.Println(p.Rel(), p2.Rel())
// Output:
- // out/system/framework/boot.art out/system/framework/boot.oat
+ // out/soong/system/framework/boot.art out/soong/system/framework/boot.oat
// boot.art boot.oat
}
@@ -1539,7 +1539,7 @@
fmt.Println(p.Rel(), p2.Rel())
// Output:
- // out/system/framework/boot.art out/system/framework/oat/arm/boot.vdex
+ // out/soong/system/framework/boot.art out/soong/system/framework/oat/arm/boot.vdex
// boot.art oat/arm/boot.vdex
}
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index a1f8e63..fa40d1f 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -510,9 +510,9 @@
ctx.RegisterModuleType("prebuilt", newPrebuiltModule)
ctx.RegisterModuleType("source", newSourceModule)
ctx.RegisterModuleType("override_source", newOverrideSourceModule)
- ctx.RegisterModuleType("soong_config_module_type", soongConfigModuleTypeFactory)
- ctx.RegisterModuleType("soong_config_string_variable", soongConfigStringVariableDummyFactory)
- ctx.RegisterModuleType("soong_config_bool_variable", soongConfigBoolVariableDummyFactory)
+ ctx.RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory)
+ ctx.RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory)
+ ctx.RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory)
}
type prebuiltModule struct {
diff --git a/android/register.go b/android/register.go
index 5984862..4244398 100644
--- a/android/register.go
+++ b/android/register.go
@@ -161,6 +161,10 @@
return ctx
}
+func (ctx *Context) SetRunningAsBp2build() {
+ ctx.config.runningAsBp2Build = true
+}
+
// RegisterForBazelConversion registers an alternate shadow pipeline of
// singletons, module types and mutators to register for converting Blueprint
// files to semantically equivalent BUILD files.
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 1c6b1c0..f8de5fb 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -839,6 +839,14 @@
// The tool is in the Soong output directory, it will be copied to __SBOX_OUT_DIR__/tools/out
return filepath.Join(sboxToolsSubDir, "out", relOutSoong)
}
+ if ctx.Config().KatiEnabled() {
+ toolDir = toolDir.ToMakePath()
+ relOut, isRelOut, _ := maybeRelErr(toolDir.String(), path.String())
+ if isRelOut {
+ // The tool is in the Make output directory, it will be copied to __SBOX_OUT_DIR__/tools/out
+ return filepath.Join(sboxToolsSubDir, "out", relOut)
+ }
+ }
// The tool is in the source directory, it will be copied to __SBOX_OUT_DIR__/tools/src
return filepath.Join(sboxToolsSubDir, "src", path.String())
}
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index feee90f..3766bb0 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -64,10 +64,10 @@
fmt.Printf("outputs: %q\n", rule.Outputs())
// Output:
- // commands: "ld a.o b.o -o out/linked && echo success"
+ // commands: "ld a.o b.o -o out/soong/linked && echo success"
// tools: ["ld"]
// inputs: ["a.o" "b.o"]
- // outputs: ["out/linked"]
+ // outputs: ["out/soong/linked"]
}
func ExampleRuleBuilder_SymlinkOutputs() {
@@ -79,7 +79,7 @@
Tool(PathForSource(ctx, "ln")).
FlagWithInput("-s ", PathForTesting("a.o")).
SymlinkOutput(PathForOutput(ctx, "a"))
- rule.Command().Text("cp out/a out/b").
+ rule.Command().Text("cp out/soong/a out/soong/b").
ImplicitSymlinkOutput(PathForOutput(ctx, "b"))
fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && "))
@@ -89,11 +89,11 @@
fmt.Printf("symlink_outputs: %q\n", rule.SymlinkOutputs())
// Output:
- // commands: "ln -s a.o out/a && cp out/a out/b"
+ // commands: "ln -s a.o out/soong/a && cp out/soong/a out/soong/b"
// tools: ["ln"]
// inputs: ["a.o"]
- // outputs: ["out/a" "out/b"]
- // symlink_outputs: ["out/a" "out/b"]
+ // outputs: ["out/soong/a" "out/soong/b"]
+ // symlink_outputs: ["out/soong/a" "out/soong/b"]
}
func ExampleRuleBuilder_Temporary() {
@@ -117,10 +117,10 @@
fmt.Printf("outputs: %q\n", rule.Outputs())
// Output:
- // commands: "cp a out/b && cp out/b out/c"
+ // commands: "cp a out/soong/b && cp out/soong/b out/soong/c"
// tools: ["cp"]
// inputs: ["a"]
- // outputs: ["out/c"]
+ // outputs: ["out/soong/c"]
}
func ExampleRuleBuilder_DeleteTemporaryFiles() {
@@ -145,10 +145,10 @@
fmt.Printf("outputs: %q\n", rule.Outputs())
// Output:
- // commands: "cp a out/b && cp out/b out/c && rm -f out/b"
+ // commands: "cp a out/soong/b && cp out/soong/b out/soong/c && rm -f out/soong/b"
// tools: ["cp"]
// inputs: ["a"]
- // outputs: ["out/c"]
+ // outputs: ["out/soong/c"]
}
func ExampleRuleBuilder_Installs() {
@@ -168,7 +168,7 @@
fmt.Printf("rule.Installs().String() = %q\n", rule.Installs().String())
// Output:
- // rule.Installs().String() = "out/linked:/bin/linked out/linked:/sbin/linked"
+ // rule.Installs().String() = "out/soong/linked:/bin/linked out/soong/linked:/sbin/linked"
}
func ExampleRuleBuilderCommand() {
@@ -271,7 +271,7 @@
FlagWithRspFileInputList("@", PathForOutput(ctx, "foo.rsp"), PathsForTesting("a.java", "b.java")).
String())
// Output:
- // javac @out/foo.rsp
+ // javac @out/soong/foo.rsp
}
func ExampleRuleBuilderCommand_String() {
@@ -371,15 +371,15 @@
addCommands(rule)
wantCommands := []string{
- "out_local/module/DepFile Flag FlagWithArg=arg FlagWithDepFile=out_local/module/depfile " +
- "FlagWithInput=input FlagWithOutput=out_local/module/output FlagWithRspFileInputList=out_local/rsp " +
- "Input out_local/module/Output out_local/module/SymlinkOutput Text Tool after command2 old cmd",
- "command2 out_local/module/depfile2 input2 out_local/module/output2 tool2",
- "command3 input3 out_local/module/output2 out_local/module/output3 input3 out_local/module/output2",
+ "out_local/soong/module/DepFile Flag FlagWithArg=arg FlagWithDepFile=out_local/soong/module/depfile " +
+ "FlagWithInput=input FlagWithOutput=out_local/soong/module/output FlagWithRspFileInputList=out_local/soong/rsp " +
+ "Input out_local/soong/module/Output out_local/soong/module/SymlinkOutput Text Tool after command2 old cmd",
+ "command2 out_local/soong/module/depfile2 input2 out_local/soong/module/output2 tool2",
+ "command3 input3 out_local/soong/module/output2 out_local/soong/module/output3 input3 out_local/soong/module/output2",
}
- wantDepMergerCommand := "out_local/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer " +
- "out_local/module/DepFile out_local/module/depfile out_local/module/ImplicitDepFile out_local/module/depfile2"
+ wantDepMergerCommand := "out_local/soong/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer " +
+ "out_local/soong/module/DepFile out_local/soong/module/depfile out_local/soong/module/ImplicitDepFile out_local/soong/module/depfile2"
AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
@@ -403,13 +403,13 @@
wantCommands := []string{
"__SBOX_SANDBOX_DIR__/out/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_SANDBOX_DIR__/out/depfile " +
"FlagWithInput=input FlagWithOutput=__SBOX_SANDBOX_DIR__/out/output " +
- "FlagWithRspFileInputList=out_local/rsp Input __SBOX_SANDBOX_DIR__/out/Output " +
+ "FlagWithRspFileInputList=out_local/soong/rsp Input __SBOX_SANDBOX_DIR__/out/Output " +
"__SBOX_SANDBOX_DIR__/out/SymlinkOutput Text Tool after command2 old cmd",
"command2 __SBOX_SANDBOX_DIR__/out/depfile2 input2 __SBOX_SANDBOX_DIR__/out/output2 tool2",
"command3 input3 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/out/output3 input3 __SBOX_SANDBOX_DIR__/out/output2",
}
- wantDepMergerCommand := "out_local/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer __SBOX_SANDBOX_DIR__/out/DepFile __SBOX_SANDBOX_DIR__/out/depfile __SBOX_SANDBOX_DIR__/out/ImplicitDepFile __SBOX_SANDBOX_DIR__/out/depfile2"
+ wantDepMergerCommand := "out_local/soong/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer __SBOX_SANDBOX_DIR__/out/DepFile __SBOX_SANDBOX_DIR__/out/depfile __SBOX_SANDBOX_DIR__/out/ImplicitDepFile __SBOX_SANDBOX_DIR__/out/depfile2"
AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
@@ -433,7 +433,7 @@
wantCommands := []string{
"__SBOX_SANDBOX_DIR__/out/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_SANDBOX_DIR__/out/depfile " +
"FlagWithInput=input FlagWithOutput=__SBOX_SANDBOX_DIR__/out/output " +
- "FlagWithRspFileInputList=out_local/rsp Input __SBOX_SANDBOX_DIR__/out/Output " +
+ "FlagWithRspFileInputList=out_local/soong/rsp Input __SBOX_SANDBOX_DIR__/out/Output " +
"__SBOX_SANDBOX_DIR__/out/SymlinkOutput Text __SBOX_SANDBOX_DIR__/tools/src/Tool after command2 old cmd",
"command2 __SBOX_SANDBOX_DIR__/out/depfile2 input2 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/tools/src/tool2",
"command3 input3 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/out/output3 input3 __SBOX_SANDBOX_DIR__/out/output2",
diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go
index 17f6d66..065440d 100644
--- a/android/soong_config_modules.go
+++ b/android/soong_config_modules.go
@@ -31,10 +31,10 @@
)
func init() {
- RegisterModuleType("soong_config_module_type_import", soongConfigModuleTypeImportFactory)
- RegisterModuleType("soong_config_module_type", soongConfigModuleTypeFactory)
- RegisterModuleType("soong_config_string_variable", soongConfigStringVariableDummyFactory)
- RegisterModuleType("soong_config_bool_variable", soongConfigBoolVariableDummyFactory)
+ RegisterModuleType("soong_config_module_type_import", SoongConfigModuleTypeImportFactory)
+ RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory)
+ RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory)
+ RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory)
}
type soongConfigModuleTypeImport struct {
@@ -153,7 +153,7 @@
// Then libacme_foo would build with cflags:
// "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT".
-func soongConfigModuleTypeImportFactory() Module {
+func SoongConfigModuleTypeImportFactory() Module {
module := &soongConfigModuleTypeImport{}
module.AddProperties(&module.properties)
@@ -179,6 +179,7 @@
type soongConfigModuleTypeModule struct {
ModuleBase
+ BazelModuleBase
properties soongconfig.ModuleTypeProperties
}
@@ -262,7 +263,7 @@
// SOONG_CONFIG_acme_width := 200
//
// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE".
-func soongConfigModuleTypeFactory() Module {
+func SoongConfigModuleTypeFactory() Module {
module := &soongConfigModuleTypeModule{}
module.AddProperties(&module.properties)
@@ -296,7 +297,7 @@
// soong_config_string_variable defines a variable and a set of possible string values for use
// in a soong_config_module_type definition.
-func soongConfigStringVariableDummyFactory() Module {
+func SoongConfigStringVariableDummyFactory() Module {
module := &soongConfigStringVariableDummyModule{}
module.AddProperties(&module.properties, &module.stringProperties)
initAndroidModuleBase(module)
@@ -305,7 +306,7 @@
// soong_config_string_variable defines a variable with true or false values for use
// in a soong_config_module_type definition.
-func soongConfigBoolVariableDummyFactory() Module {
+func SoongConfigBoolVariableDummyFactory() Module {
module := &soongConfigBoolVariableDummyModule{}
module.AddProperties(&module.properties)
initAndroidModuleBase(module)
@@ -324,6 +325,9 @@
func (*soongConfigBoolVariableDummyModule) Nameless() {}
func (*soongConfigBoolVariableDummyModule) GenerateAndroidBuildActions(ctx ModuleContext) {}
+// importModuleTypes registers the module factories for a list of module types defined
+// in an Android.bp file. These module factories are scoped for the current Android.bp
+// file only.
func importModuleTypes(ctx LoadHookContext, from string, moduleTypes ...string) {
from = filepath.Clean(from)
if filepath.Ext(from) != ".bp" {
@@ -389,7 +393,7 @@
for name, moduleType := range mtDef.ModuleTypes {
factory := globalModuleTypes[moduleType.BaseModuleType]
if factory != nil {
- factories[name] = soongConfigModuleFactory(factory, moduleType)
+ factories[name] = configModuleFactory(factory, moduleType, ctx.Config().runningAsBp2Build)
} else {
reportErrors(ctx, from,
fmt.Errorf("missing global module type factory for %q", moduleType.BaseModuleType))
@@ -404,20 +408,40 @@
}).(map[string]blueprint.ModuleFactory)
}
-// soongConfigModuleFactory takes an existing soongConfigModuleFactory and a ModuleType and returns
-// a new soongConfigModuleFactory that wraps the existing soongConfigModuleFactory and adds conditional on Soong config
-// variables.
-func soongConfigModuleFactory(factory blueprint.ModuleFactory,
- moduleType *soongconfig.ModuleType) blueprint.ModuleFactory {
-
+// configModuleFactory takes an existing soongConfigModuleFactory and a
+// ModuleType to create a new ModuleFactory that uses a custom loadhook.
+func configModuleFactory(factory blueprint.ModuleFactory, moduleType *soongconfig.ModuleType, bp2build bool) blueprint.ModuleFactory {
conditionalFactoryProps := soongconfig.CreateProperties(factory, moduleType)
- if conditionalFactoryProps.IsValid() {
- return func() (blueprint.Module, []interface{}) {
- module, props := factory()
+ if !conditionalFactoryProps.IsValid() {
+ return factory
+ }
+ useBp2buildHook := bp2build && proptools.BoolDefault(moduleType.Bp2buildAvailable, false)
- conditionalProps := proptools.CloneEmptyProperties(conditionalFactoryProps)
- props = append(props, conditionalProps.Interface())
+ return func() (blueprint.Module, []interface{}) {
+ module, props := factory()
+ conditionalProps := proptools.CloneEmptyProperties(conditionalFactoryProps)
+ props = append(props, conditionalProps.Interface())
+ if useBp2buildHook {
+ // The loadhook is different for bp2build, since we don't want to set a specific
+ // set of property values based on a vendor var -- we want __all of them__ to
+ // generate select statements, so we put the entire soong_config_variables
+ // struct, together with the namespace representing those variables, while
+ // creating the custom module with the factory.
+ AddLoadHook(module, func(ctx LoadHookContext) {
+ if m, ok := module.(Bazelable); ok {
+ m.SetBaseModuleType(moduleType.BaseModuleType)
+ // Instead of applying all properties, keep the entire conditionalProps struct as
+ // part of the custom module so dependent modules can create the selects accordingly
+ m.setNamespacedVariableProps(namespacedVariableProperties{
+ moduleType.ConfigNamespace: conditionalProps.Interface(),
+ })
+ }
+ })
+ } else {
+ // Regular Soong operation wraps the existing module factory with a
+ // conditional on Soong config variables by reading the product
+ // config variables from Make.
AddLoadHook(module, func(ctx LoadHookContext) {
config := ctx.Config().VendorConfig(moduleType.ConfigNamespace)
newProps, err := soongconfig.PropertiesToApply(moduleType, conditionalProps, config)
@@ -429,10 +453,7 @@
ctx.AppendProperties(ps)
}
})
-
- return module, props
}
- } else {
- return factory
+ return module, props
}
}
diff --git a/android/soong_config_modules_test.go b/android/soong_config_modules_test.go
index 0ec9bcb..acb9d18 100644
--- a/android/soong_config_modules_test.go
+++ b/android/soong_config_modules_test.go
@@ -310,10 +310,10 @@
tc.preparer,
PrepareForTestWithDefaults,
FixtureRegisterWithContext(func(ctx RegistrationContext) {
- ctx.RegisterModuleType("soong_config_module_type_import", soongConfigModuleTypeImportFactory)
- ctx.RegisterModuleType("soong_config_module_type", soongConfigModuleTypeFactory)
- ctx.RegisterModuleType("soong_config_string_variable", soongConfigStringVariableDummyFactory)
- ctx.RegisterModuleType("soong_config_bool_variable", soongConfigBoolVariableDummyFactory)
+ ctx.RegisterModuleType("soong_config_module_type_import", SoongConfigModuleTypeImportFactory)
+ ctx.RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory)
+ ctx.RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory)
+ ctx.RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory)
ctx.RegisterModuleType("test_defaults", soongConfigTestDefaultsModuleFactory)
ctx.RegisterModuleType("test", soongConfigTestModuleFactory)
}),
@@ -372,10 +372,10 @@
fixtureForVendorVars(map[string]map[string]string{"acme": {"feature1": "1"}}),
PrepareForTestWithDefaults,
FixtureRegisterWithContext(func(ctx RegistrationContext) {
- ctx.RegisterModuleType("soong_config_module_type_import", soongConfigModuleTypeImportFactory)
- ctx.RegisterModuleType("soong_config_module_type", soongConfigModuleTypeFactory)
- ctx.RegisterModuleType("soong_config_string_variable", soongConfigStringVariableDummyFactory)
- ctx.RegisterModuleType("soong_config_bool_variable", soongConfigBoolVariableDummyFactory)
+ ctx.RegisterModuleType("soong_config_module_type_import", SoongConfigModuleTypeImportFactory)
+ ctx.RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory)
+ ctx.RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory)
+ ctx.RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory)
ctx.RegisterModuleType("test_defaults", soongConfigTestDefaultsModuleFactory)
ctx.RegisterModuleType("test", soongConfigTestModuleFactory)
}),
diff --git a/android/soongconfig/Android.bp b/android/soongconfig/Android.bp
index e7fa5a0..9bf3344 100644
--- a/android/soongconfig/Android.bp
+++ b/android/soongconfig/Android.bp
@@ -9,6 +9,7 @@
"blueprint",
"blueprint-parser",
"blueprint-proptools",
+ "soong-bazel",
],
srcs: [
"config.go",
diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go
index 34b180d..1af89ba 100644
--- a/android/soongconfig/modules.go
+++ b/android/soongconfig/modules.go
@@ -15,6 +15,7 @@
package soongconfig
import (
+ "android/soong/bazel"
"fmt"
"io"
"reflect"
@@ -28,7 +29,7 @@
const conditionsDefault = "conditions_default"
-var soongConfigProperty = proptools.FieldNameForProperty("soong_config_variables")
+var SoongConfigProperty = proptools.FieldNameForProperty("soong_config_variables")
// loadSoongConfigModuleTypeDefinition loads module types from an Android.bp file. It caches the
// result so each file is only parsed once.
@@ -120,6 +121,8 @@
// the list of properties that this module type will extend.
Properties []string
+
+ Bazel_module bazel.BazelModuleProperties
}
func processModuleTypeDef(v *SoongConfigDefinition, def *parser.Module) (errs []error) {
@@ -271,12 +274,12 @@
}
typ := reflect.StructOf([]reflect.StructField{{
- Name: soongConfigProperty,
+ Name: SoongConfigProperty,
Type: reflect.StructOf(fields),
}})
props := reflect.New(typ)
- structConditions := props.Elem().FieldByName(soongConfigProperty)
+ structConditions := props.Elem().FieldByName(SoongConfigProperty)
for i, c := range moduleType.Variables {
c.initializeProperties(structConditions.Field(i), affectablePropertiesType)
@@ -415,7 +418,7 @@
// soong_config_variables are expected to be in the same order as moduleType.Variables.
func PropertiesToApply(moduleType *ModuleType, props reflect.Value, config SoongConfig) ([]interface{}, error) {
var ret []interface{}
- props = props.Elem().FieldByName(soongConfigProperty)
+ props = props.Elem().FieldByName(SoongConfigProperty)
for i, c := range moduleType.Variables {
if ps, err := c.PropertiesToApply(config, props.Field(i)); err != nil {
return nil, err
@@ -433,6 +436,7 @@
affectableProperties []string
variableNames []string
+ Bp2buildAvailable *bool
}
func newModuleType(props *ModuleTypeProperties) (*ModuleType, []error) {
@@ -441,6 +445,7 @@
ConfigNamespace: props.Config_namespace,
BaseModuleType: props.Module_type,
variableNames: props.Variables,
+ Bp2buildAvailable: props.Bazel_module.Bp2build_available,
}
for _, name := range props.Bool_variables {
diff --git a/android/testing.go b/android/testing.go
index b9d8fa8..6290d43 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -458,6 +458,7 @@
// RegisterForBazelConversion prepares a test context for bp2build conversion.
func (ctx *TestContext) RegisterForBazelConversion() {
+ ctx.SetRunningAsBp2build()
RegisterMutatorsForBazelConversion(ctx.Context, ctx.bp2buildPreArch, ctx.bp2buildMutators)
}
diff --git a/android/variable.go b/android/variable.go
index e943640..89cd59e 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -15,6 +15,8 @@
package android
import (
+ "android/soong/android/soongconfig"
+ "android/soong/bazel"
"fmt"
"reflect"
"runtime"
@@ -487,14 +489,124 @@
// ProductConfigProperty contains the information for a single property (may be a struct) paired
// with the appropriate ProductConfigVariable.
type ProductConfigProperty struct {
- ProductConfigVariable string
- FullConfig string
- Property interface{}
+ // The name of the product variable, e.g. "safestack", "malloc_not_svelte",
+ // "board"
+ Name string
+
+ // Namespace of the variable, if this is a soong_config_module_type variable
+ // e.g. "acme", "ANDROID", "vendor_name"
+ Namespace string
+
+ // Unique configuration to identify this product config property (i.e. a
+ // primary key), as just using the product variable name is not sufficient.
+ //
+ // For product variables, this is the product variable name + optional
+ // archvariant information. e.g.
+ //
+ // product_variables: {
+ // foo: {
+ // cflags: ["-Dfoo"],
+ // },
+ // },
+ //
+ // FullConfig would be "foo".
+ //
+ // target: {
+ // android: {
+ // product_variables: {
+ // foo: {
+ // cflags: ["-Dfoo-android"],
+ // },
+ // },
+ // },
+ // },
+ //
+ // FullConfig would be "foo-android".
+ //
+ // For soong config variables, this is the namespace + product variable name
+ // + value of the variable, if applicable. The value can also be
+ // conditions_default.
+ //
+ // e.g.
+ //
+ // soong_config_variables: {
+ // feature1: {
+ // conditions_default: {
+ // cflags: ["-DDEFAULT1"],
+ // },
+ // cflags: ["-DFEATURE1"],
+ // },
+ // }
+ //
+ // where feature1 is created in the "acme" namespace, so FullConfig would be
+ // "acme__feature1" and "acme__feature1__conditions_default".
+ //
+ // e.g.
+ //
+ // soong_config_variables: {
+ // board: {
+ // soc_a: {
+ // cflags: ["-DSOC_A"],
+ // },
+ // soc_b: {
+ // cflags: ["-DSOC_B"],
+ // },
+ // soc_c: {},
+ // conditions_default: {
+ // cflags: ["-DSOC_DEFAULT"]
+ // },
+ // },
+ // }
+ //
+ // where board is created in the "acme" namespace, so FullConfig would be
+ // "acme__board__soc_a", "acme__board__soc_b", and
+ // "acme__board__conditions_default"
+ FullConfig string
}
-// ProductConfigProperties is a map of property name to a slice of ProductConfigProperty such that
-// all it all product variable-specific versions of a property are easily accessed together
-type ProductConfigProperties map[string]map[string]ProductConfigProperty
+func (p *ProductConfigProperty) ConfigurationAxis() bazel.ConfigurationAxis {
+ if p.Namespace == "" {
+ return bazel.ProductVariableConfigurationAxis(p.FullConfig)
+ } else {
+ // Soong config variables can be uniquely identified by the namespace
+ // (e.g. acme, android) and the product variable name (e.g. board, size)
+ return bazel.ProductVariableConfigurationAxis(p.Namespace + "__" + p.Name)
+ }
+}
+
+// SelectKey returns the literal string that represents this variable in a BUILD
+// select statement.
+func (p *ProductConfigProperty) SelectKey() string {
+ if p.Namespace == "" {
+ return strings.ToLower(p.FullConfig)
+ }
+
+ if p.FullConfig == bazel.ConditionsDefaultConfigKey {
+ return bazel.ConditionsDefaultConfigKey
+ }
+
+ value := p.FullConfig
+ if value == p.Name {
+ value = "enabled"
+ }
+ // e.g. acme__feature1__enabled, android__board__soc_a
+ return strings.ToLower(strings.Join([]string{p.Namespace, p.Name, value}, "__"))
+}
+
+// ProductConfigProperties is a map of maps to group property values according
+// their property name and the product config variable they're set under.
+//
+// The outer map key is the name of the property, like "cflags".
+//
+// The inner map key is a ProductConfigProperty, which is a struct of product
+// variable name, namespace, and the "full configuration" of the product
+// variable.
+//
+// e.g. product variable name: board, namespace: acme, full config: vendor_chip_foo
+//
+// The value of the map is the interface{} representing the value of the
+// property, like ["-DDEFINES"] for cflags.
+type ProductConfigProperties map[string]map[ProductConfigProperty]interface{}
// ProductVariableProperties returns a ProductConfigProperties containing only the properties which
// have been set for the module in the given context.
@@ -504,36 +616,162 @@
productConfigProperties := ProductConfigProperties{}
- if moduleBase.variableProperties == nil {
- return productConfigProperties
+ if moduleBase.variableProperties != nil {
+ productVariablesProperty := proptools.FieldNameForProperty("product_variables")
+ productVariableValues(
+ productVariablesProperty,
+ moduleBase.variableProperties,
+ "",
+ "",
+ &productConfigProperties)
+
+ for _, configToProps := range moduleBase.GetArchVariantProperties(ctx, moduleBase.variableProperties) {
+ for config, props := range configToProps {
+ // GetArchVariantProperties is creating an instance of the requested type
+ // and productVariablesValues expects an interface, so no need to cast
+ productVariableValues(
+ productVariablesProperty,
+ props,
+ "",
+ config,
+ &productConfigProperties)
+ }
+ }
}
- productVariableValues(moduleBase.variableProperties, "", &productConfigProperties)
-
- for _, configToProps := range moduleBase.GetArchVariantProperties(ctx, moduleBase.variableProperties) {
- for config, props := range configToProps {
- // GetArchVariantProperties is creating an instance of the requested type
- // and productVariablesValues expects an interface, so no need to cast
- productVariableValues(props, config, &productConfigProperties)
+ if m, ok := module.(Bazelable); ok && m.namespacedVariableProps() != nil {
+ for namespace, namespacedVariableProp := range m.namespacedVariableProps() {
+ productVariableValues(
+ soongconfig.SoongConfigProperty,
+ namespacedVariableProp,
+ namespace,
+ "",
+ &productConfigProperties)
}
}
return productConfigProperties
}
-func productVariableValues(variableProps interface{}, suffix string, productConfigProperties *ProductConfigProperties) {
+func (p *ProductConfigProperties) AddProductConfigProperty(
+ propertyName, namespace, productVariableName, config string, property interface{}) {
+ if (*p)[propertyName] == nil {
+ (*p)[propertyName] = make(map[ProductConfigProperty]interface{})
+ }
+
+ productConfigProp := ProductConfigProperty{
+ Namespace: namespace, // e.g. acme, android
+ Name: productVariableName, // e.g. size, feature1, feature2, FEATURE3, board
+ FullConfig: config, // e.g. size, feature1-x86, size__conditions_default
+ }
+
+ (*p)[propertyName][productConfigProp] = property
+}
+
+var (
+ conditionsDefaultField string = proptools.FieldNameForProperty(bazel.ConditionsDefaultConfigKey)
+)
+
+// maybeExtractConfigVarProp attempts to read this value as a config var struct
+// wrapped by interfaces and ptrs. If it's not the right type, the second return
+// value is false.
+func maybeExtractConfigVarProp(v reflect.Value) (reflect.Value, bool) {
+ if v.Kind() == reflect.Interface {
+ // The conditions_default value can be either
+ // 1) an ptr to an interface of a struct (bool config variables and product variables)
+ // 2) an interface of 1) (config variables with nested structs, like string vars)
+ v = v.Elem()
+ }
+ if v.Kind() != reflect.Ptr {
+ return v, false
+ }
+ v = reflect.Indirect(v)
+ if v.Kind() == reflect.Interface {
+ // Extract the struct from the interface
+ v = v.Elem()
+ }
+
+ if !v.IsValid() {
+ return v, false
+ }
+
+ if v.Kind() != reflect.Struct {
+ return v, false
+ }
+ return v, true
+}
+
+// productVariableValues uses reflection to convert a property struct for
+// product_variables and soong_config_variables to structs that can be generated
+// as select statements.
+func productVariableValues(
+ fieldName string, variableProps interface{}, namespace, suffix string, productConfigProperties *ProductConfigProperties) {
if suffix != "" {
suffix = "-" + suffix
}
- variableValues := reflect.ValueOf(variableProps).Elem().FieldByName("Product_variables")
+
+ // variableValues represent the product_variables or soong_config_variables
+ // struct.
+ variableValues := reflect.ValueOf(variableProps).Elem().FieldByName(fieldName)
+
+ // Example of product_variables:
+ //
+ // product_variables: {
+ // malloc_not_svelte: {
+ // shared_libs: ["malloc_not_svelte_shared_lib"],
+ // whole_static_libs: ["malloc_not_svelte_whole_static_lib"],
+ // exclude_static_libs: [
+ // "malloc_not_svelte_static_lib_excludes",
+ // "malloc_not_svelte_whole_static_lib_excludes",
+ // ],
+ // },
+ // },
+ //
+ // Example of soong_config_variables:
+ //
+ // soong_config_variables: {
+ // feature1: {
+ // conditions_default: {
+ // ...
+ // },
+ // cflags: ...
+ // },
+ // feature2: {
+ // cflags: ...
+ // conditions_default: {
+ // ...
+ // },
+ // },
+ // board: {
+ // soc_a: {
+ // ...
+ // },
+ // soc_a: {
+ // ...
+ // },
+ // soc_c: {},
+ // conditions_default: {
+ // ...
+ // },
+ // },
+ // }
for i := 0; i < variableValues.NumField(); i++ {
+ // e.g. Platform_sdk_version, Unbundled_build, Malloc_not_svelte, etc.
+ productVariableName := variableValues.Type().Field(i).Name
+
variableValue := variableValues.Field(i)
// Check if any properties were set for the module
if variableValue.IsZero() {
+ // e.g. feature1: {}, malloc_not_svelte: {}
continue
}
- // e.g. Platform_sdk_version, Unbundled_build, Malloc_not_svelte, etc.
- productVariableName := variableValues.Type().Field(i).Name
+
+ // Unlike product variables, config variables require a few more
+ // indirections to extract the struct from the reflect.Value.
+ if v, ok := maybeExtractConfigVarProp(variableValue); ok {
+ variableValue = v
+ }
+
for j := 0; j < variableValue.NumField(); j++ {
property := variableValue.Field(j)
// If the property wasn't set, no need to pass it along
@@ -543,14 +781,54 @@
// e.g. Asflags, Cflags, Enabled, etc.
propertyName := variableValue.Type().Field(j).Name
- if (*productConfigProperties)[propertyName] == nil {
- (*productConfigProperties)[propertyName] = make(map[string]ProductConfigProperty)
- }
- config := productVariableName + suffix
- (*productConfigProperties)[propertyName][config] = ProductConfigProperty{
- ProductConfigVariable: productVariableName,
- FullConfig: config,
- Property: property.Interface(),
+
+ if v, ok := maybeExtractConfigVarProp(property); ok {
+ // The field is a struct, which is used by:
+ // 1) soong_config_string_variables
+ //
+ // soc_a: {
+ // cflags: ...,
+ // }
+ //
+ // soc_b: {
+ // cflags: ...,
+ // }
+ //
+ // 2) conditions_default structs for all soong config variable types.
+ //
+ // conditions_default: {
+ // cflags: ...,
+ // static_libs: ...
+ // }
+ field := v
+ for k := 0; k < field.NumField(); k++ {
+ // Iterate over fields of this struct prop.
+ if field.Field(k).IsZero() {
+ continue
+ }
+ // config can also be "conditions_default".
+ config := proptools.PropertyNameForField(propertyName)
+ actualPropertyName := field.Type().Field(k).Name
+
+ productConfigProperties.AddProductConfigProperty(
+ actualPropertyName, // e.g. cflags, static_libs
+ namespace, // e.g. acme, android
+ productVariableName, // e.g. size, feature1, FEATURE2, board
+ config,
+ field.Field(k).Interface(), // e.g. ["-DDEFAULT"], ["foo", "bar"]
+ )
+ }
+ } else {
+ // Not a conditions_default or a struct prop, i.e. regular
+ // product variables, or not a string-typed config var.
+ config := productVariableName + suffix
+ productConfigProperties.AddProductConfigProperty(
+ propertyName,
+ namespace,
+ productVariableName,
+ config,
+ property.Interface(),
+ )
}
}
}
diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go
index f3ad152..1045ca6 100644
--- a/androidmk/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -58,6 +58,7 @@
"LOCAL_MODULE_STEM": stem,
"LOCAL_MODULE_HOST_OS": hostOs,
"LOCAL_RESOURCE_DIR": localizePathList("resource_dirs"),
+ "LOCAL_NOTICE_FILE": localizePathList("android_license_files"),
"LOCAL_SANITIZE": sanitize(""),
"LOCAL_SANITIZE_DIAG": sanitize("diag."),
"LOCAL_STRIP_MODULE": strip(),
@@ -111,7 +112,6 @@
"LOCAL_PROTOC_OPTIMIZE_TYPE": "proto.type",
"LOCAL_MODULE_OWNER": "owner",
"LOCAL_RENDERSCRIPT_TARGET_API": "renderscript.target_api",
- "LOCAL_NOTICE_FILE": "notice",
"LOCAL_JAVA_LANGUAGE_VERSION": "java_version",
"LOCAL_INSTRUMENTATION_FOR": "instrumentation_for",
"LOCAL_MANIFEST_FILE": "manifest",
@@ -185,6 +185,12 @@
"LOCAL_JACK_COVERAGE_EXCLUDE_FILTER": "jacoco.exclude_filter",
"LOCAL_FULL_LIBS_MANIFEST_FILES": "additional_manifests",
+
+ // will be rewrite later to "license_kinds:" by byfix
+ "LOCAL_LICENSE_KINDS": "android_license_kinds",
+ // will be removed later by byfix
+ // TODO: does this property matter in the license module?
+ "LOCAL_LICENSE_CONDITIONS": "android_license_conditions",
})
addStandardProperties(bpparser.BoolType,
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index 775a9a8..ca40aaa 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -1516,7 +1516,8 @@
],
}
`,
- }, {
+ },
+ {
desc: "Obsolete LOCAL_MODULE_PATH",
in: `
include $(CLEAR_VARS)
@@ -1532,7 +1533,37 @@
name: "foo",
}
-`},
+`,
+ },
+ {
+ desc: "LOCAL_LICENSE_KINDS, LOCAL_LICENSE_CONDITIONS, LOCAL_NOTICE_FILE",
+ // TODO(b/205615944): When valid "android_license_files" exists, the test requires an Android.mk
+ // file (and an Android.bp file is required as well if the license files locates outside the current
+ // directory). So plan to use a mock file system to mock the Android.mk and Android.bp files.
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_LICENSE_KINDS := license_kind
+LOCAL_LICENSE_CONDITIONS := license_condition
+LOCAL_NOTICE_FILE := license_notice
+include $(BUILD_PACKAGE)
+`,
+ expected: `
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "Android-Apache-2.0",
+ ],
+}
+
+android_app {
+ name: "foo",
+ // ANDROIDMK TRANSLATION ERROR: Only $(LOCAL_PATH)/.. values are allowed
+ // LOCAL_NOTICE_FILE := license_notice
+
+}
+`,
+ },
}
func TestEndToEnd(t *testing.T) {
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 94b8116..2048429 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -103,6 +103,11 @@
return moduleNames
}
+ // Avoid creating duplicate build rules for multi-installed APEXes.
+ if proptools.BoolDefault(a.properties.Multi_install_skip_symbol_files, false) {
+ return moduleNames
+ }
+
var postInstallCommands []string
for _, fi := range a.filesInfo {
if a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() {
@@ -258,7 +263,7 @@
if !ok {
panic(fmt.Sprintf("Expected %s to be AndroidAppSet", fi.module))
}
- fmt.Fprintln(w, "LOCAL_APK_SET_INSTALL_FILE :=", as.InstallFile())
+ fmt.Fprintln(w, "LOCAL_APK_SET_INSTALL_FILE :=", as.PackedAdditionalOutputs().String())
fmt.Fprintln(w, "LOCAL_APKCERTS_FILE :=", as.APKCertsFile().String())
fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_android_app_set.mk")
case nativeSharedLib, nativeExecutable, nativeTest:
@@ -272,7 +277,7 @@
fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", ccMod.CoverageOutputFile().String())
}
}
- fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_cc_prebuilt.mk")
+ fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk")
default:
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.stem())
if fi.builtFile == a.manifestPbOut && apexType == flattenedApex {
@@ -326,6 +331,9 @@
var required []string
var targetRequired []string
var hostRequired []string
+ required = append(required, a.RequiredModuleNames()...)
+ targetRequired = append(targetRequired, a.TargetRequiredModuleNames()...)
+ hostRequired = append(hostRequired, a.HostRequiredModuleNames()...)
installMapSet := make(map[string]bool) // set of dependency module:location mappings
for _, fi := range a.filesInfo {
required = append(required, fi.requiredModuleNames...)
@@ -446,23 +454,18 @@
fmt.Fprintf(w, dist)
}
- if a.apisUsedByModuleFile.String() != "" {
- goal := "apps_only"
- distFile := a.apisUsedByModuleFile.String()
- fmt.Fprintf(w, "ifneq (,$(filter $(my_register_name),$(TARGET_BUILD_APPS)))\n"+
- " $(call dist-for-goals,%s,%s:ndk_apis_usedby_apex/$(notdir %s))\n"+
- "endif\n",
- goal, distFile, distFile)
- }
-
- if a.apisBackedByModuleFile.String() != "" {
- goal := "apps_only"
- distFile := a.apisBackedByModuleFile.String()
- fmt.Fprintf(w, "ifneq (,$(filter $(my_register_name),$(TARGET_BUILD_APPS)))\n"+
- " $(call dist-for-goals,%s,%s:ndk_apis_backedby_apex/$(notdir %s))\n"+
- "endif\n",
- goal, distFile, distFile)
- }
+ distCoverageFiles(w, "ndk_apis_usedby_apex", a.nativeApisUsedByModuleFile.String())
+ distCoverageFiles(w, "ndk_apis_usedby_apex", a.nativeApisBackedByModuleFile.String())
+ distCoverageFiles(w, "java_apis_used_by_apex", a.javaApisUsedByModuleFile.String())
}
}}
}
+
+func distCoverageFiles(w io.Writer, dir string, distfile string) {
+ if distfile != "" {
+ goal := "apps_only"
+ fmt.Fprintf(w, "ifneq (,$(filter $(my_register_name),$(TARGET_BUILD_APPS)))\n"+
+ " $(call dist-for-goals,%s,%s:%s/$(notdir %s))\n"+
+ "endif\n", goal, distfile, dir, distfile)
+ }
+}
diff --git a/apex/apex.go b/apex/apex.go
index 33188cb..378efe6 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -145,6 +145,16 @@
// Should be only used in non-system apexes (e.g. vendor: true). Default is false.
Use_vndk_as_stable *bool
+ // Whether this is multi-installed APEX should skip installing symbol files.
+ // Multi-installed APEXes share the same apex_name and are installed at the same time.
+ // Default is false.
+ //
+ // Should be set to true for all multi-installed APEXes except the singular
+ // default version within the multi-installed group.
+ // Only the default version can install symbol files in $(PRODUCT_OUT}/apex,
+ // or else conflicting build rules may be created.
+ Multi_install_skip_symbol_files *bool
+
// List of SDKs that are used to build this APEX. A reference to an SDK should be either
// `name#version` or `name` which is an alias for `name#current`. If left empty,
// `platform#current` is implied. This value affects all modules included in this APEX. In
@@ -424,8 +434,9 @@
isCompressed bool
// Path of API coverage generate file
- apisUsedByModuleFile android.ModuleOutPath
- apisBackedByModuleFile android.ModuleOutPath
+ nativeApisUsedByModuleFile android.ModuleOutPath
+ nativeApisBackedByModuleFile android.ModuleOutPath
+ javaApisUsedByModuleFile android.ModuleOutPath
// Collect the module directory for IDE info in java/jdeps.go.
modulePaths []string
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 8aaa31a..59ea206 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -8350,6 +8350,46 @@
})
}
+func TestAndroidMk_RequiredModules(t *testing.T) {
+ ctx := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ updatable: false,
+ java_libs: ["foo"],
+ required: ["otherapex"],
+ }
+
+ apex {
+ name: "otherapex",
+ key: "myapex.key",
+ updatable: false,
+ java_libs: ["foo"],
+ required: ["otherapex"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_library {
+ name: "foo",
+ srcs: ["foo.java"],
+ apex_available: ["myapex", "otherapex"],
+ installable: true,
+ }
+ `)
+
+ apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+ data := android.AndroidMkDataForTest(t, ctx, apexBundle)
+ var builder strings.Builder
+ data.Custom(&builder, apexBundle.BaseModuleName(), "TARGET_", "", data)
+ androidMk := builder.String()
+ ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES += otherapex")
+}
+
func TestMain(m *testing.M) {
os.Exit(m.Run())
}
diff --git a/apex/builder.go b/apex/builder.go
index e22d694..3599c5d 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -67,6 +67,7 @@
pctx.HostBinToolVariable("sload_f2fs", "sload_f2fs")
pctx.HostBinToolVariable("make_erofs", "make_erofs")
pctx.HostBinToolVariable("apex_compression_tool", "apex_compression_tool")
+ pctx.HostBinToolVariable("dexdeps", "dexdeps")
pctx.SourcePathVariable("genNdkUsedbyApexPath", "build/soong/scripts/gen_ndk_usedby_apex.sh")
}
@@ -441,7 +442,8 @@
} else {
if fi.class == appSet {
copyCommands = append(copyCommands,
- fmt.Sprintf("unzip -qDD -d %s %s", destPathDir, fi.builtFile.String()))
+ fmt.Sprintf("unzip -qDD -d %s %s", destPathDir,
+ fi.module.(*java.AndroidAppSet).PackedAdditionalOutputs().String()))
} else {
copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath)
}
@@ -707,12 +709,12 @@
"readelf": "${config.ClangBin}/llvm-readelf",
},
})
- a.apisUsedByModuleFile = apisUsedbyOutputFile
+ a.nativeApisUsedByModuleFile = apisUsedbyOutputFile
- var libNames []string
+ var nativeLibNames []string
for _, f := range a.filesInfo {
if f.class == nativeSharedLib {
- libNames = append(libNames, f.stem())
+ nativeLibNames = append(nativeLibNames, f.stem())
}
}
apisBackedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_backing.txt")
@@ -720,9 +722,25 @@
rule.Command().
Tool(android.PathForSource(ctx, "build/soong/scripts/gen_ndk_backedby_apex.sh")).
Output(apisBackedbyOutputFile).
- Flags(libNames)
+ Flags(nativeLibNames)
rule.Build("ndk_backedby_list", "Generate API libraries backed by Apex")
- a.apisBackedByModuleFile = apisBackedbyOutputFile
+ a.nativeApisBackedByModuleFile = apisBackedbyOutputFile
+
+ var javaLibOrApkPath []android.Path
+ for _, f := range a.filesInfo {
+ if f.class == javaSharedLib || f.class == app {
+ javaLibOrApkPath = append(javaLibOrApkPath, f.builtFile)
+ }
+ }
+ javaApiUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.xml")
+ javaUsedByRule := android.NewRuleBuilder(pctx, ctx)
+ javaUsedByRule.Command().
+ Tool(android.PathForSource(ctx, "build/soong/scripts/gen_java_usedby_apex.sh")).
+ BuiltTool("dexdeps").
+ Output(javaApiUsedbyOutputFile).
+ Inputs(javaLibOrApkPath)
+ javaUsedByRule.Build("java_usedby_list", "Generate Java APIs used by Apex")
+ a.javaApisUsedByModuleFile = javaApiUsedbyOutputFile
bundleConfig := a.buildBundleConfig(ctx)
diff --git a/apex/testing.go b/apex/testing.go
index 69bd73e..337c862 100644
--- a/apex/testing.go
+++ b/apex/testing.go
@@ -24,6 +24,7 @@
android.MockFS{
// Needed by apex.
"system/core/rootdir/etc/public.libraries.android.txt": nil,
+ "build/soong/scripts/gen_java_usedby_apex.sh": nil,
"build/soong/scripts/gen_ndk_backedby_apex.sh": nil,
// Needed by prebuilt_apex.
"build/soong/scripts/unpack-prebuilt-apex.sh": nil,
diff --git a/bazel/aquery.go b/bazel/aquery.go
index 6d96b1c..fd8cf67 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -18,6 +18,7 @@
"encoding/json"
"fmt"
"path/filepath"
+ "regexp"
"strings"
"github.com/google/blueprint/proptools"
@@ -59,6 +60,8 @@
InputDepSetIds []int
Mnemonic string
OutputIds []int
+ TemplateContent string
+ Substitutions []KeyValuePair
}
// actionGraphContainer contains relevant portions of Bazel's aquery proto, ActionGraphContainer.
@@ -100,6 +103,20 @@
artifactIdToPath map[int]string
}
+// The tokens should be substituted with the value specified here, instead of the
+// one returned in 'substitutions' of TemplateExpand action.
+var TemplateActionOverriddenTokens = map[string]string{
+ // Uses "python3" for %python_binary% instead of the value returned by aquery
+ // which is "py3wrapper.sh". See removePy3wrapperScript.
+ "%python_binary%": "python3",
+}
+
+// This pattern matches the MANIFEST file created for a py_binary target.
+var manifestFilePattern = regexp.MustCompile(".*/.+\\.runfiles/MANIFEST$")
+
+// The file name of py3wrapper.sh, which is used by py_binary targets.
+var py3wrapperFileName = "/py3wrapper.sh"
+
func newAqueryHandler(aqueryResult actionGraphContainer) (*aqueryArtifactHandler, error) {
pathFragments := map[int]pathFragment{}
for _, pathFragment := range aqueryResult.PathFragments {
@@ -163,7 +180,31 @@
}
}
}
- return inputPaths, nil
+
+ // TODO(b/197135294): Clean up this custom runfiles handling logic when
+ // SourceSymlinkManifest and SymlinkTree actions are supported.
+ filteredInputPaths := filterOutPy3wrapperAndManifestFileFromInputPaths(inputPaths)
+
+ return filteredInputPaths, nil
+}
+
+// See go/python-binary-host-mixed-build for more details.
+// 1) For py3wrapper.sh, there is no action for creating py3wrapper.sh in the aquery output of
+// Bazel py_binary targets, so there is no Ninja build statements generated for creating it.
+// 2) For MANIFEST file, SourceSymlinkManifest action is in aquery output of Bazel py_binary targets,
+// but it doesn't contain sufficient information so no Ninja build statements are generated
+// for creating it.
+// So in mixed build mode, when these two are used as input of some Ninja build statement,
+// since there is no build statement to create them, they should be removed from input paths.
+func filterOutPy3wrapperAndManifestFileFromInputPaths(inputPaths []string) []string {
+ filteredInputPaths := []string{}
+ for _, path := range inputPaths {
+ if strings.HasSuffix(path, py3wrapperFileName) || manifestFilePattern.MatchString(path) {
+ continue
+ }
+ filteredInputPaths = append(filteredInputPaths, path)
+ }
+ return filteredInputPaths
}
func (a *aqueryArtifactHandler) artifactIdsFromDepsetId(depsetId int) ([]int, error) {
@@ -230,7 +271,7 @@
}
buildStatement := BuildStatement{
- Command: strings.Join(proptools.ShellEscapeList(actionEntry.Arguments), " "),
+ Command: strings.Join(proptools.ShellEscapeListIncludingSpaces(actionEntry.Arguments), " "),
Depfile: depfile,
OutputPaths: outputPaths,
InputPaths: inputPaths,
@@ -249,6 +290,45 @@
// Use absolute paths, because some soong actions don't play well with relative paths (for example, `cp -d`).
buildStatement.Command = fmt.Sprintf("mkdir -p %[1]s && rm -f %[2]s && ln -sf %[3]s %[2]s", outDir, out, in)
buildStatement.SymlinkPaths = outputPaths[:]
+ } else if isTemplateExpandAction(actionEntry) && len(actionEntry.Arguments) < 1 {
+ if len(outputPaths) != 1 {
+ return nil, fmt.Errorf("Expect 1 output to template expand action, got: output %q", outputPaths)
+ }
+ expandedTemplateContent := expandTemplateContent(actionEntry)
+ // The expandedTemplateContent is escaped for being used in double quotes and shell unescape,
+ // and the new line characters (\n) are also changed to \\n which avoids some Ninja escape on \n, which might
+ // change \n to space and mess up the format of Python programs.
+ // sed is used to convert \\n back to \n before saving to output file.
+ // See go/python-binary-host-mixed-build for more details.
+ command := fmt.Sprintf(`/bin/bash -c 'echo "%[1]s" | sed "s/\\\\n/\\n/g" > %[2]s && chmod a+x %[2]s'`,
+ escapeCommandlineArgument(expandedTemplateContent), outputPaths[0])
+ buildStatement.Command = command
+ } else if isPythonZipperAction(actionEntry) {
+ if len(inputPaths) < 1 || len(outputPaths) != 1 {
+ return nil, fmt.Errorf("Expect 1+ input and 1 output to python zipper action, got: input %q, output %q", inputPaths, outputPaths)
+ }
+ buildStatement.InputPaths, buildStatement.Command = removePy3wrapperScript(buildStatement)
+ buildStatement.Command = addCommandForPyBinaryRunfilesDir(buildStatement, inputPaths[0], outputPaths[0])
+ // Add the python zip file as input of the corresponding python binary stub script in Ninja build statements.
+ // In Ninja build statements, the outputs of dependents of a python binary have python binary stub script as input,
+ // which is not sufficient without the python zip file from which runfiles directory is created for py_binary.
+ //
+ // The following logic relies on that Bazel aquery output returns actions in the order that
+ // PythonZipper is after TemplateAction of creating Python binary stub script. If later Bazel doesn't return actions
+ // in that order, the following logic might not find the build statement generated for Python binary
+ // stub script and the build might fail. So the check of pyBinaryFound is added to help debug in case later Bazel might change aquery output.
+ // See go/python-binary-host-mixed-build for more details.
+ pythonZipFilePath := outputPaths[0]
+ pyBinaryFound := false
+ for i, _ := range buildStatements {
+ if len(buildStatements[i].OutputPaths) == 1 && buildStatements[i].OutputPaths[0]+".zip" == pythonZipFilePath {
+ buildStatements[i].InputPaths = append(buildStatements[i].InputPaths, pythonZipFilePath)
+ pyBinaryFound = true
+ }
+ }
+ if !pyBinaryFound {
+ return nil, fmt.Errorf("Could not find the correspondinging Python binary stub script of PythonZipper: %q", outputPaths)
+ }
} else if len(actionEntry.Arguments) < 1 {
return nil, fmt.Errorf("received action with no command: [%v]", buildStatement)
}
@@ -258,10 +338,85 @@
return buildStatements, nil
}
+// expandTemplateContent substitutes the tokens in a template.
+func expandTemplateContent(actionEntry action) string {
+ replacerString := []string{}
+ for _, pair := range actionEntry.Substitutions {
+ value := pair.Value
+ if val, ok := TemplateActionOverriddenTokens[pair.Key]; ok {
+ value = val
+ }
+ replacerString = append(replacerString, pair.Key, value)
+ }
+ replacer := strings.NewReplacer(replacerString...)
+ return replacer.Replace(actionEntry.TemplateContent)
+}
+
+func escapeCommandlineArgument(str string) string {
+ // \->\\, $->\$, `->\`, "->\", \n->\\n, '->'"'"'
+ replacer := strings.NewReplacer(
+ `\`, `\\`,
+ `$`, `\$`,
+ "`", "\\`",
+ `"`, `\"`,
+ "\n", "\\n",
+ `'`, `'"'"'`,
+ )
+ return replacer.Replace(str)
+}
+
+// removePy3wrapperScript removes py3wrapper.sh from the input paths and command of the action of
+// creating python zip file in mixed build mode. py3wrapper.sh is returned as input by aquery but
+// there is no action returned by aquery for creating it. So in mixed build "python3" is used
+// as the PYTHON_BINARY in python binary stub script, and py3wrapper.sh is not needed and should be
+// removed from input paths and command of creating python zip file.
+// See go/python-binary-host-mixed-build for more details.
+// TODO(b/205879240) remove this after py3wrapper.sh could be created in the mixed build mode.
+func removePy3wrapperScript(bs BuildStatement) (newInputPaths []string, newCommand string) {
+ // Remove from inputs
+ filteredInputPaths := []string{}
+ for _, path := range bs.InputPaths {
+ if !strings.HasSuffix(path, py3wrapperFileName) {
+ filteredInputPaths = append(filteredInputPaths, path)
+ }
+ }
+ newInputPaths = filteredInputPaths
+
+ // Remove from command line
+ var re = regexp.MustCompile(`\S*` + py3wrapperFileName)
+ newCommand = re.ReplaceAllString(bs.Command, "")
+ return
+}
+
+// addCommandForPyBinaryRunfilesDir adds commands creating python binary runfiles directory.
+// runfiles directory is created by using MANIFEST file and MANIFEST file is the output of
+// SourceSymlinkManifest action is in aquery output of Bazel py_binary targets,
+// but since SourceSymlinkManifest doesn't contain sufficient information
+// so MANIFEST file could not be created, which also blocks the creation of runfiles directory.
+// See go/python-binary-host-mixed-build for more details.
+// TODO(b/197135294) create runfiles directory from MANIFEST file once it can be created from SourceSymlinkManifest action.
+func addCommandForPyBinaryRunfilesDir(bs BuildStatement, zipperCommandPath, zipFilePath string) string {
+ // Unzip the zip file, zipFilePath looks like <python_binary>.zip
+ runfilesDirName := zipFilePath[0:len(zipFilePath)-4] + ".runfiles"
+ command := fmt.Sprintf("%s x %s -d %s", zipperCommandPath, zipFilePath, runfilesDirName)
+ // Create a symbolic link in <python_binary>.runfiles/, which is the expected structure
+ // when running the python binary stub script.
+ command += fmt.Sprintf(" && ln -sf runfiles/__main__ %s", runfilesDirName)
+ return bs.Command + " && " + command
+}
+
func isSymlinkAction(a action) bool {
return a.Mnemonic == "Symlink" || a.Mnemonic == "SolibSymlink"
}
+func isTemplateExpandAction(a action) bool {
+ return a.Mnemonic == "TemplateExpand"
+}
+
+func isPythonZipperAction(a action) bool {
+ return a.Mnemonic == "PythonZipper"
+}
+
func shouldSkipAction(a action) bool {
// TODO(b/180945121): Handle complex symlink actions.
if a.Mnemonic == "SymlinkTree" || a.Mnemonic == "SourceSymlinkManifest" {
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index 69f1115..68e50c2 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -709,7 +709,7 @@
}
expectedBuildStatements := []BuildStatement{
BuildStatement{
- Command: "/bin/bash -c touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out",
+ Command: "/bin/bash -c 'touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out'",
OutputPaths: []string{"bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"},
InputPaths: inputPaths,
Mnemonic: "Action",
@@ -1015,6 +1015,355 @@
assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file"], output ["symlink" "other_symlink"]`)
}
+func TestTemplateExpandActionSubstitutions(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [{
+ "id": 1,
+ "pathFragmentId": 1
+ }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "TemplateExpand",
+ "configurationId": 1,
+ "outputIds": [1],
+ "primaryOutputId": 1,
+ "executionPlatform": "//build/bazel/platforms:linux_x86_64",
+ "templateContent": "Test template substitutions: %token1%, %python_binary%",
+ "substitutions": [{
+ "key": "%token1%",
+ "value": "abcd"
+ },{
+ "key": "%python_binary%",
+ "value": "python3"
+ }]
+ }],
+ "pathFragments": [{
+ "id": 1,
+ "label": "template_file"
+ }]
+}`
+
+ actual, err := AqueryBuildStatements([]byte(inputString))
+
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
+ }
+
+ expectedBuildStatements := []BuildStatement{
+ BuildStatement{
+ Command: "/bin/bash -c 'echo \"Test template substitutions: abcd, python3\" | sed \"s/\\\\\\\\n/\\\\n/g\" > template_file && " +
+ "chmod a+x template_file'",
+ OutputPaths: []string{"template_file"},
+ Mnemonic: "TemplateExpand",
+ },
+ }
+ assertBuildStatements(t, expectedBuildStatements, actual)
+}
+
+func TestTemplateExpandActionNoOutput(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [{
+ "id": 1,
+ "pathFragmentId": 1
+ }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "TemplateExpand",
+ "configurationId": 1,
+ "primaryOutputId": 1,
+ "executionPlatform": "//build/bazel/platforms:linux_x86_64",
+ "templateContent": "Test template substitutions: %token1%, %python_binary%",
+ "substitutions": [{
+ "key": "%token1%",
+ "value": "abcd"
+ },{
+ "key": "%python_binary%",
+ "value": "python3"
+ }]
+ }],
+ "pathFragments": [{
+ "id": 1,
+ "label": "template_file"
+ }]
+}`
+
+ _, err := AqueryBuildStatements([]byte(inputString))
+ assertError(t, err, `Expect 1 output to template expand action, got: output []`)
+}
+
+func TestPythonZipperActionSuccess(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [{
+ "id": 1,
+ "pathFragmentId": 1
+ },{
+ "id": 2,
+ "pathFragmentId": 2
+ },{
+ "id": 3,
+ "pathFragmentId": 3
+ },{
+ "id": 4,
+ "pathFragmentId": 4
+ },{
+ "id": 5,
+ "pathFragmentId": 10
+ },{
+ "id": 10,
+ "pathFragmentId": 20
+ }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "TemplateExpand",
+ "configurationId": 1,
+ "outputIds": [1],
+ "primaryOutputId": 1,
+ "executionPlatform": "//build/bazel/platforms:linux_x86_64",
+ "templateContent": "Test template substitutions: %token1%, %python_binary%",
+ "substitutions": [{
+ "key": "%token1%",
+ "value": "abcd"
+ },{
+ "key": "%python_binary%",
+ "value": "python3"
+ }]
+ },{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "PythonZipper",
+ "configurationId": 1,
+ "arguments": ["../bazel_tools/tools/zip/zipper/zipper", "cC", "python_binary.zip", "__main__.py\u003dbazel-out/k8-fastbuild/bin/python_binary.temp", "__init__.py\u003d", "runfiles/__main__/__init__.py\u003d", "runfiles/__main__/python_binary.py\u003dpython_binary.py", "runfiles/bazel_tools/tools/python/py3wrapper.sh\u003dbazel-out/bazel_tools/k8-fastbuild/bin/tools/python/py3wrapper.sh"],
+ "outputIds": [2],
+ "inputDepSetIds": [1],
+ "primaryOutputId": 2
+ }],
+ "depSetOfFiles": [{
+ "id": 1,
+ "directArtifactIds": [4, 3, 5]
+ }],
+ "pathFragments": [{
+ "id": 1,
+ "label": "python_binary"
+ },{
+ "id": 2,
+ "label": "python_binary.zip"
+ },{
+ "id": 3,
+ "label": "python_binary.py"
+ },{
+ "id": 9,
+ "label": ".."
+ }, {
+ "id": 8,
+ "label": "bazel_tools",
+ "parentId": 9
+ }, {
+ "id": 7,
+ "label": "tools",
+ "parentId": 8
+ }, {
+ "id": 6,
+ "label": "zip",
+ "parentId": 7
+ }, {
+ "id": 5,
+ "label": "zipper",
+ "parentId": 6
+ }, {
+ "id": 4,
+ "label": "zipper",
+ "parentId": 5
+ },{
+ "id": 16,
+ "label": "bazel-out"
+ },{
+ "id": 15,
+ "label": "bazel_tools",
+ "parentId": 16
+ }, {
+ "id": 14,
+ "label": "k8-fastbuild",
+ "parentId": 15
+ }, {
+ "id": 13,
+ "label": "bin",
+ "parentId": 14
+ }, {
+ "id": 12,
+ "label": "tools",
+ "parentId": 13
+ }, {
+ "id": 11,
+ "label": "python",
+ "parentId": 12
+ }, {
+ "id": 10,
+ "label": "py3wrapper.sh",
+ "parentId": 11
+ },{
+ "id": 20,
+ "label": "python_binary"
+ }]
+}`
+ actual, err := AqueryBuildStatements([]byte(inputString))
+
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
+ }
+
+ expectedBuildStatements := []BuildStatement{
+ BuildStatement{
+ Command: "/bin/bash -c 'echo \"Test template substitutions: abcd, python3\" | sed \"s/\\\\\\\\n/\\\\n/g\" > python_binary && " +
+ "chmod a+x python_binary'",
+ InputPaths: []string{"python_binary.zip"},
+ OutputPaths: []string{"python_binary"},
+ Mnemonic: "TemplateExpand",
+ },
+ BuildStatement{
+ Command: "../bazel_tools/tools/zip/zipper/zipper cC python_binary.zip __main__.py=bazel-out/k8-fastbuild/bin/python_binary.temp " +
+ "__init__.py= runfiles/__main__/__init__.py= runfiles/__main__/python_binary.py=python_binary.py && " +
+ "../bazel_tools/tools/zip/zipper/zipper x python_binary.zip -d python_binary.runfiles && ln -sf runfiles/__main__ python_binary.runfiles",
+ InputPaths: []string{"../bazel_tools/tools/zip/zipper/zipper", "python_binary.py"},
+ OutputPaths: []string{"python_binary.zip"},
+ Mnemonic: "PythonZipper",
+ },
+ }
+ assertBuildStatements(t, expectedBuildStatements, actual)
+}
+
+func TestPythonZipperActionNoInput(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [{
+ "id": 1,
+ "pathFragmentId": 1
+ },{
+ "id": 2,
+ "pathFragmentId": 2
+ }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "PythonZipper",
+ "configurationId": 1,
+ "arguments": ["../bazel_tools/tools/zip/zipper/zipper", "cC", "python_binary.zip", "__main__.py\u003dbazel-out/k8-fastbuild/bin/python_binary.temp", "__init__.py\u003d", "runfiles/__main__/__init__.py\u003d", "runfiles/__main__/python_binary.py\u003dpython_binary.py", "runfiles/bazel_tools/tools/python/py3wrapper.sh\u003dbazel-out/bazel_tools/k8-fastbuild/bin/tools/python/py3wrapper.sh"],
+ "outputIds": [2],
+ "primaryOutputId": 2
+ }],
+ "pathFragments": [{
+ "id": 1,
+ "label": "python_binary"
+ },{
+ "id": 2,
+ "label": "python_binary.zip"
+ }]
+}`
+ _, err := AqueryBuildStatements([]byte(inputString))
+ assertError(t, err, `Expect 1+ input and 1 output to python zipper action, got: input [], output ["python_binary.zip"]`)
+}
+
+func TestPythonZipperActionNoOutput(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [{
+ "id": 1,
+ "pathFragmentId": 1
+ },{
+ "id": 2,
+ "pathFragmentId": 2
+ },{
+ "id": 3,
+ "pathFragmentId": 3
+ },{
+ "id": 4,
+ "pathFragmentId": 4
+ },{
+ "id": 5,
+ "pathFragmentId": 10
+ }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "PythonZipper",
+ "configurationId": 1,
+ "arguments": ["../bazel_tools/tools/zip/zipper/zipper", "cC", "python_binary.zip", "__main__.py\u003dbazel-out/k8-fastbuild/bin/python_binary.temp", "__init__.py\u003d", "runfiles/__main__/__init__.py\u003d", "runfiles/__main__/python_binary.py\u003dpython_binary.py", "runfiles/bazel_tools/tools/python/py3wrapper.sh\u003dbazel-out/bazel_tools/k8-fastbuild/bin/tools/python/py3wrapper.sh"],
+ "inputDepSetIds": [1]
+ }],
+ "depSetOfFiles": [{
+ "id": 1,
+ "directArtifactIds": [4, 3, 5]
+ }],
+ "pathFragments": [{
+ "id": 1,
+ "label": "python_binary"
+ },{
+ "id": 2,
+ "label": "python_binary.zip"
+ },{
+ "id": 3,
+ "label": "python_binary.py"
+ },{
+ "id": 9,
+ "label": ".."
+ }, {
+ "id": 8,
+ "label": "bazel_tools",
+ "parentId": 9
+ }, {
+ "id": 7,
+ "label": "tools",
+ "parentId": 8
+ }, {
+ "id": 6,
+ "label": "zip",
+ "parentId": 7
+ }, {
+ "id": 5,
+ "label": "zipper",
+ "parentId": 6
+ }, {
+ "id": 4,
+ "label": "zipper",
+ "parentId": 5
+ },{
+ "id": 16,
+ "label": "bazel-out"
+ },{
+ "id": 15,
+ "label": "bazel_tools",
+ "parentId": 16
+ }, {
+ "id": 14,
+ "label": "k8-fastbuild",
+ "parentId": 15
+ }, {
+ "id": 13,
+ "label": "bin",
+ "parentId": 14
+ }, {
+ "id": 12,
+ "label": "tools",
+ "parentId": 13
+ }, {
+ "id": 11,
+ "label": "python",
+ "parentId": 12
+ }, {
+ "id": 10,
+ "label": "py3wrapper.sh",
+ "parentId": 11
+ }]
+}`
+ _, err := AqueryBuildStatements([]byte(inputString))
+ assertError(t, err, `Expect 1+ input and 1 output to python zipper action, got: input ["../bazel_tools/tools/zip/zipper/zipper" "python_binary.py"], output []`)
+}
+
func assertError(t *testing.T, err error, expected string) {
t.Helper()
if err == nil {
@@ -1029,7 +1378,7 @@
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",
+ t.Errorf("expected %d build statements, but got %d,\n expected: %#v,\n actual: %#v",
len(expected), len(actual), expected, actual)
return
}
@@ -1040,7 +1389,7 @@
continue ACTUAL_LOOP
}
}
- t.Errorf("unexpected build statement %v.\n expected: %v",
+ t.Errorf("unexpected build statement %#v.\n expected: %#v",
actualStatement, expected)
return
}
diff --git a/bazel/configurability.go b/bazel/configurability.go
index f05c8e5..1993f76 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -158,9 +158,9 @@
}
// SelectKey returns the Bazel select key for a given configurationType and config string.
-func (ct configurationType) SelectKey(config string) string {
- ct.validateConfig(config)
- switch ct {
+func (ca ConfigurationAxis) SelectKey(config string) string {
+ ca.validateConfig(config)
+ switch ca.configurationType {
case noConfig:
panic(fmt.Errorf("SelectKey is unnecessary for noConfig ConfigurationType "))
case arch:
@@ -170,12 +170,13 @@
case osArch:
return platformOsArchMap[config]
case productVariables:
- if config == ConditionsDefaultConfigKey {
+ if strings.HasSuffix(config, ConditionsDefaultConfigKey) {
+ // e.g. "acme__feature1__conditions_default" or "android__board__conditions_default"
return ConditionsDefaultSelectKey
}
- return fmt.Sprintf("%s:%s", productVariableBazelPackage, strings.ToLower(config))
+ return fmt.Sprintf("%s:%s", productVariableBazelPackage, config)
default:
- panic(fmt.Errorf("Unrecognized ConfigurationType %d", ct))
+ panic(fmt.Errorf("Unrecognized ConfigurationType %d", ca.configurationType))
}
}
diff --git a/bazel/properties.go b/bazel/properties.go
index facbedd..a438481 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -24,6 +24,23 @@
"github.com/google/blueprint"
)
+type BazelModuleProperties struct {
+ // The label of the Bazel target replacing this Soong module. When run in conversion mode, this
+ // will import the handcrafted build target into the autogenerated file. Note: this may result in
+ // a conflict due to duplicate targets if bp2build_available is also set.
+ Label *string
+
+ // If true, bp2build will generate the converted Bazel target for this module. Note: this may
+ // cause a conflict due to the duplicate targets if label is also set.
+ //
+ // This is a bool pointer to support tristates: true, false, not set.
+ //
+ // To opt-in a module, set bazel_module: { bp2build_available: true }
+ // To opt-out a module, set bazel_module: { bp2build_available: false }
+ // To defer the default setting for the directory, do not set the value.
+ Bp2build_available *bool
+}
+
// BazelTargetModuleProperties contain properties and metadata used for
// Blueprint to BUILD file conversion.
type BazelTargetModuleProperties struct {
diff --git a/bp2build/android_app_certificate_conversion_test.go b/bp2build/android_app_certificate_conversion_test.go
index 022c687..6a53b00 100644
--- a/bp2build/android_app_certificate_conversion_test.go
+++ b/bp2build/android_app_certificate_conversion_test.go
@@ -42,8 +42,9 @@
certificate: "chamber_of_secrets_dir",
}
`,
- expectedBazelTargets: []string{`android_app_certificate(
- name = "com.android.apogee.cert",
- certificate = "chamber_of_secrets_dir",
-)`}})
+ expectedBazelTargets: []string{
+ makeBazelTarget("android_app_certificate", "com.android.apogee.cert", attrNameToString{
+ "certificate": `"chamber_of_secrets_dir"`,
+ }),
+ }})
}
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
index 456f18a..1a23db7 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -113,29 +113,30 @@
],
}
`,
- expectedBazelTargets: []string{`apex(
- name = "com.android.apogee",
- android_manifest = "ApogeeAndroidManifest.xml",
- binaries = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+ "android_manifest": `"ApogeeAndroidManifest.xml"`,
+ "binaries": `[
"binary_1",
"binary_2",
- ],
- certificate = ":com.android.apogee.certificate",
- file_contexts = ":com.android.apogee-file_contexts",
- installable = False,
- key = ":com.android.apogee.key",
- manifest = "apogee_manifest.json",
- min_sdk_version = "29",
- native_shared_libs = [
+ ]`,
+ "certificate": `":com.android.apogee.certificate"`,
+ "file_contexts": `":com.android.apogee-file_contexts"`,
+ "installable": "False",
+ "key": `":com.android.apogee.key"`,
+ "manifest": `"apogee_manifest.json"`,
+ "min_sdk_version": `"29"`,
+ "native_shared_libs": `[
":native_shared_lib_1",
":native_shared_lib_2",
- ],
- prebuilts = [
+ ]`,
+ "prebuilts": `[
":pretend_prebuilt_1",
":pretend_prebuilt_2",
- ],
- updatable = False,
-)`}})
+ ]`,
+ "updatable": "False",
+ }),
+ }})
}
func TestApexBundleDefaultPropertyValues(t *testing.T) {
@@ -151,10 +152,10 @@
manifest: "apogee_manifest.json",
}
`,
- expectedBazelTargets: []string{`apex(
- name = "com.android.apogee",
- manifest = "apogee_manifest.json",
-)`}})
+ expectedBazelTargets: []string{makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+ "manifest": `"apogee_manifest.json"`,
+ }),
+ }})
}
func TestApexBundleHasBazelModuleProps(t *testing.T) {
@@ -171,8 +172,8 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTargets: []string{`apex(
- name = "apogee",
- manifest = "manifest.json",
-)`}})
+ expectedBazelTargets: []string{makeBazelTarget("apex", "apogee", attrNameToString{
+ "manifest": `"manifest.json"`,
+ }),
+ }})
}
diff --git a/bp2build/apex_key_conversion_test.go b/bp2build/apex_key_conversion_test.go
index 8e1aa09..17f79a6 100644
--- a/bp2build/apex_key_conversion_test.go
+++ b/bp2build/apex_key_conversion_test.go
@@ -43,9 +43,9 @@
private_key: "com.android.apogee.pem",
}
`,
- expectedBazelTargets: []string{`apex_key(
- name = "com.android.apogee.key",
- private_key = "com.android.apogee.pem",
- public_key = "com.android.apogee.avbpubkey",
-)`}})
+ expectedBazelTargets: []string{makeBazelTarget("apex_key", "com.android.apogee.key", attrNameToString{
+ "private_key": `"com.android.apogee.pem"`,
+ "public_key": `"com.android.apogee.avbpubkey"`,
+ }),
+ }})
}
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index ee1d862..983604b 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -230,32 +230,32 @@
string_prop: "a",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`custom(
- name = "foo",
- string_list_prop = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("custom", "foo", attrNameToString{
+ "string_list_prop": `[
"a",
"b",
- ],
- string_prop = "a",
-)`,
+ ]`,
+ "string_prop": `"a"`,
+ }),
},
},
{
description: "control characters",
blueprint: `custom {
- name: "control_characters",
+ name: "foo",
string_list_prop: ["\t", "\n"],
string_prop: "a\t\n\r",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`custom(
- name = "control_characters",
- string_list_prop = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("custom", "foo", attrNameToString{
+ "string_list_prop": `[
"\t",
"\n",
- ],
- string_prop = "a\t\n\r",
-)`,
+ ]`,
+ "string_prop": `"a\t\n\r"`,
+ }),
},
},
{
@@ -271,14 +271,13 @@
arch_paths: ["abc"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`custom(
- name = "dep",
- arch_paths = ["abc"],
-)`,
- `custom(
- name = "has_dep",
- arch_paths = [":dep"],
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("custom", "dep", attrNameToString{
+ "arch_paths": `["abc"]`,
+ }),
+ makeBazelTarget("custom", "has_dep", attrNameToString{
+ "arch_paths": `[":dep"]`,
+ }),
},
},
{
@@ -311,9 +310,9 @@
},
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`custom(
- name = "arch_paths",
- arch_paths = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("custom", "arch_paths", attrNameToString{
+ "arch_paths": `select({
"//build/bazel/platforms/arch:arm": [
"arm.txt",
"lib32.txt",
@@ -368,8 +367,8 @@
"windows.txt",
],
"//conditions:default": [],
- }),
-)`,
+ })`,
+ }),
},
},
{
@@ -389,17 +388,16 @@
arch_paths: ["abc"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`custom(
- name = "dep",
- arch_paths = ["abc"],
-)`,
- `custom(
- name = "has_dep",
- arch_paths = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("custom", "dep", attrNameToString{
+ "arch_paths": `["abc"]`,
+ }),
+ makeBazelTarget("custom", "has_dep", attrNameToString{
+ "arch_paths": `select({
"//build/bazel/platforms/arch:x86": [":dep"],
"//conditions:default": [],
- }),
-)`,
+ })`,
+ }),
},
},
{
@@ -409,10 +407,10 @@
embedded_prop: "abc",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`custom(
- name = "embedded_props",
- embedded_attr = "abc",
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("custom", "embedded_props", attrNameToString{
+ "embedded_attr": `"abc"`,
+ }),
},
},
{
@@ -422,10 +420,10 @@
other_embedded_prop: "abc",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`custom(
- name = "ptr_to_embedded_props",
- other_embedded_attr = "abc",
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("custom", "ptr_to_embedded_props", attrNameToString{
+ "other_embedded_attr": `"abc"`,
+ }),
},
},
}
@@ -649,9 +647,7 @@
bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{
- `filegroup(
- name = "fg_foo",
-)`,
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{}),
},
},
{
@@ -665,9 +661,7 @@
bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{
- `filegroup(
- name = "fg_foo",
-)`,
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{}),
},
},
{
@@ -680,13 +674,13 @@
srcs: ["a", "b"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`filegroup(
- name = "fg_foo",
- srcs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ "srcs": `[
"a",
"b",
- ],
-)`,
+ ]`,
+ }),
},
},
{
@@ -700,10 +694,10 @@
exclude_srcs: ["a"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`filegroup(
- name = "fg_foo",
- srcs = ["b"],
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ "srcs": `["b"]`,
+ }),
},
},
{
@@ -712,18 +706,18 @@
moduleTypeUnderTestFactory: android.FileGroupFactory,
moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
blueprint: `filegroup {
- name: "foo",
+ name: "fg_foo",
srcs: ["**/*.txt"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`filegroup(
- name = "foo",
- srcs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ "srcs": `[
"other/a.txt",
"other/b.txt",
"other/subdir/a.txt",
- ],
-)`,
+ ]`,
+ }),
},
filesystem: map[string]string{
"other/a.txt": "",
@@ -737,21 +731,8 @@
moduleTypeUnderTest: "filegroup",
moduleTypeUnderTestFactory: android.FileGroupFactory,
moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
- blueprint: `filegroup {
- name: "foo",
- srcs: ["a.txt"],
- bazel_module: { bp2build_available: true },
-}`,
- dir: "other",
- expectedBazelTargets: []string{`filegroup(
- name = "fg_foo",
- srcs = [
- "a.txt",
- "b.txt",
- "subdir/a.txt",
- ],
-)`,
- },
+ blueprint: ``,
+ dir: "other",
filesystem: map[string]string{
"other/Android.bp": `filegroup {
name: "fg_foo",
@@ -763,6 +744,15 @@
"other/subdir/a.txt": "",
"other/file": "",
},
+ expectedBazelTargets: []string{
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ "srcs": `[
+ "a.txt",
+ "b.txt",
+ "subdir/a.txt",
+ ]`,
+ }),
+ },
},
{
description: "depends_on_other_dir_module",
@@ -770,21 +760,13 @@
moduleTypeUnderTestFactory: android.FileGroupFactory,
moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
blueprint: `filegroup {
- name: "foobar",
+ name: "fg_foo",
srcs: [
":foo",
"c",
],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`filegroup(
- name = "foobar",
- srcs = [
- "//other:foo",
- "c",
- ],
-)`,
- },
filesystem: map[string]string{
"other/Android.bp": `filegroup {
name: "foo",
@@ -792,6 +774,14 @@
bazel_module: { bp2build_available: true },
}`,
},
+ expectedBazelTargets: []string{
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ "srcs": `[
+ "//other:foo",
+ "c",
+ ]`,
+ }),
+ },
},
{
description: "depends_on_other_unconverted_module_error",
@@ -799,21 +789,21 @@
moduleTypeUnderTestFactory: android.FileGroupFactory,
moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
unconvertedDepsMode: errorModulesUnconvertedDeps,
- blueprint: `filegroup {
- name: "foobar",
- srcs: [
- ":foo",
- "c",
- ],
- bazel_module: { bp2build_available: true },
-}`,
- expectedErr: fmt.Errorf(`"foobar" depends on unconverted modules: foo`),
filesystem: map[string]string{
"other/Android.bp": `filegroup {
name: "foo",
srcs: ["a", "b"],
}`,
},
+ blueprint: `filegroup {
+ name: "fg_foo",
+ srcs: [
+ ":foo",
+ "c",
+ ],
+ bazel_module: { bp2build_available: true },
+}`,
+ expectedErr: fmt.Errorf(`"fg_foo" depends on unconverted modules: foo`),
},
}
@@ -1088,9 +1078,8 @@
"other/BUILD.bazel": `// definition for fg_bar`,
},
expectedBazelTargets: []string{
- `filegroup(
- name = "fg_foo",
-)`, `// definition for fg_bar`,
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{}),
+ `// definition for fg_bar`,
},
},
{
@@ -1098,6 +1087,9 @@
moduleTypeUnderTest: "filegroup",
moduleTypeUnderTestFactory: android.FileGroupFactory,
moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+ filesystem: map[string]string{
+ "other/BUILD.bazel": `// BUILD file`,
+ },
blueprint: `filegroup {
name: "fg_foo",
bazel_module: {
@@ -1112,14 +1104,9 @@
},
}`,
expectedBazelTargets: []string{
- `filegroup(
- name = "fg_bar",
-)`,
+ makeBazelTarget("filegroup", "fg_bar", map[string]string{}),
`// BUILD file`,
},
- filesystem: map[string]string{
- "other/BUILD.bazel": `// BUILD file`,
- },
},
}
@@ -1195,16 +1182,6 @@
exclude_srcs: ["c.txt"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`filegroup(
- name = "fg_foo",
- srcs = [
- "a.txt",
- "b.txt",
- "//dir:e.txt",
- "//dir:f.txt",
- ],
-)`,
- },
filesystem: map[string]string{
"a.txt": "",
"b.txt": "",
@@ -1213,6 +1190,16 @@
"dir/e.txt": "",
"dir/f.txt": "",
},
+ expectedBazelTargets: []string{
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ "srcs": `[
+ "a.txt",
+ "b.txt",
+ "//dir:e.txt",
+ "//dir:f.txt",
+ ]`,
+ }),
+ },
},
{
description: "filegroup in subdir exclude_srcs",
@@ -1235,66 +1222,22 @@
"dir/subdir/e.txt": "",
"dir/subdir/f.txt": "",
},
- expectedBazelTargets: []string{`filegroup(
- name = "fg_foo",
- srcs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ "srcs": `[
"a.txt",
"//dir/subdir:e.txt",
"//dir/subdir:f.txt",
- ],
-)`,
+ ]`,
+ }),
},
},
}
- dir := "."
for _, testCase := range testCases {
- fs := make(map[string][]byte)
- toParse := []string{
- "Android.bp",
- }
- for f, content := range testCase.filesystem {
- if strings.HasSuffix(f, "Android.bp") {
- toParse = append(toParse, f)
- }
- fs[f] = []byte(content)
- }
- config := android.TestConfig(buildDir, nil, testCase.blueprint, fs)
- ctx := android.NewTestContext(config)
- ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
- ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
- ctx.RegisterForBazelConversion()
-
- _, errs := ctx.ParseFileList(dir, toParse)
- if errored(t, testCase, errs) {
- continue
- }
- _, errs = ctx.ResolveDependencies(config)
- if errored(t, testCase, errs) {
- continue
- }
-
- checkDir := dir
- if testCase.dir != "" {
- checkDir = testCase.dir
- }
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- bazelTargets, err := generateBazelTargetsForDir(codegenCtx, checkDir)
- android.FailIfErrored(t, err)
- if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
- t.Errorf("%s: Expected %d bazel target, got %d\n%s", testCase.description, expectedCount, actualCount, bazelTargets)
- } else {
- for i, target := range bazelTargets {
- if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
- t.Errorf(
- "%s: Expected generated Bazel target to be '%s', got '%s'",
- testCase.description,
- w,
- g,
- )
- }
- }
- }
+ t.Run(testCase.description, func(t *testing.T) {
+ runBp2BuildTestCaseSimple(t, testCase)
+ })
}
}
@@ -1305,22 +1248,16 @@
moduleTypeUnderTest: "filegroup",
moduleTypeUnderTestFactory: android.FileGroupFactory,
moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
- blueprint: `filegroup {
- name: "reqd",
-}
-
+ blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
filegroup {
name: "fg_foo",
required: ["reqd"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`filegroup(
- name = "fg_foo",
- data = [":reqd"],
-)`,
- `filegroup(
- name = "reqd",
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ "data": `[":reqd"]`,
+ }),
},
},
{
@@ -1328,16 +1265,8 @@
moduleTypeUnderTest: "python_library",
moduleTypeUnderTestFactory: python.PythonLibraryFactory,
moduleTypeUnderTestBp2BuildMutator: python.PythonLibraryBp2Build,
- blueprint: `python_library {
- name: "reqdx86",
- bazel_module: { bp2build_available: false, },
-}
-
-python_library {
- name: "reqdarm",
- bazel_module: { bp2build_available: false, },
-}
-
+ blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqdx86") +
+ simpleModuleDoNotConvertBp2build("python_library", "reqdarm") + `
python_library {
name: "fg_foo",
arch: {
@@ -1350,15 +1279,15 @@
},
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`py_library(
- name = "fg_foo",
- data = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("py_library", "fg_foo", map[string]string{
+ "data": `select({
"//build/bazel/platforms/arch:arm": [":reqdarm"],
"//build/bazel/platforms/arch:x86": [":reqdx86"],
"//conditions:default": [],
- }),
- srcs_version = "PY3",
-)`,
+ })`,
+ "srcs_version": `"PY3"`,
+ }),
},
},
{
@@ -1366,11 +1295,11 @@
moduleTypeUnderTest: "python_library",
moduleTypeUnderTestFactory: python.PythonLibraryFactory,
moduleTypeUnderTestBp2BuildMutator: python.PythonLibraryBp2Build,
- blueprint: `python_library {
- name: "reqd",
- srcs: ["src.py"],
-}
-
+ filesystem: map[string]string{
+ "data.bin": "",
+ "src.py": "",
+ },
+ blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqd") + `
python_library {
name: "fg_foo",
data: ["data.bin"],
@@ -1378,23 +1307,13 @@
bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{
- `py_library(
- name = "fg_foo",
- data = [
+ makeBazelTarget("py_library", "fg_foo", map[string]string{
+ "data": `[
"data.bin",
":reqd",
- ],
- srcs_version = "PY3",
-)`,
- `py_library(
- name = "reqd",
- srcs = ["src.py"],
- srcs_version = "PY3",
-)`,
- },
- filesystem: map[string]string{
- "data.bin": "",
- "src.py": "",
+ ]`,
+ "srcs_version": `"PY3"`,
+ }),
},
},
{
@@ -1402,28 +1321,23 @@
moduleTypeUnderTest: "filegroup",
moduleTypeUnderTestFactory: android.FileGroupFactory,
moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
- blueprint: `filegroup {
- name: "reqd"
-}
+ blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
filegroup {
name: "fg_foo",
required: ["reqd"],
bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{
- `filegroup(
- name = "fg_foo",
- data = [":reqd"],
-)`,
- `filegroup(
- name = "reqd",
-)`,
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ "data": `[":reqd"]`,
+ }),
},
- filesystem: map[string]string{},
},
}
- for _, test := range testCases {
- runBp2BuildTestCaseSimple(t, test)
+ for _, tc := range testCases {
+ t.Run(tc.description, func(t *testing.T) {
+ runBp2BuildTestCaseSimple(t, tc)
+ })
}
}
diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go
index 0b71d89..f9abcba 100644
--- a/bp2build/cc_binary_conversion_test.go
+++ b/bp2build/cc_binary_conversion_test.go
@@ -28,6 +28,26 @@
compatibleWithPlaceHolder = "{target_compatible_with}"
)
+type testBazelTarget struct {
+ typ string
+ name string
+ attrs attrNameToString
+}
+
+func generateBazelTargetsForTest(targets []testBazelTarget) []string {
+ ret := make([]string, 0, len(targets))
+ for _, t := range targets {
+ ret = append(ret, makeBazelTarget(t.typ, t.name, t.attrs))
+ }
+ return ret
+}
+
+type ccBinaryBp2buildTestCase struct {
+ description string
+ blueprint string
+ targets []testBazelTarget
+}
+
func registerCcBinaryModuleTypes(ctx android.RegistrationContext) {
cc.RegisterCCBuildComponents(ctx)
ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
@@ -36,55 +56,56 @@
ctx.RegisterModuleType("genrule", genrule.GenRuleFactory)
}
-var binaryReplacer = strings.NewReplacer(ccBinaryTypePlaceHolder, "cc_binary", compatibleWithPlaceHolder, "")
-var hostBinaryReplacer = strings.NewReplacer(ccBinaryTypePlaceHolder, "cc_binary_host", compatibleWithPlaceHolder, `
- target_compatible_with = select({
- "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
- "//conditions:default": [],
- }),`)
+var binaryReplacer = strings.NewReplacer(ccBinaryTypePlaceHolder, "cc_binary")
+var hostBinaryReplacer = strings.NewReplacer(ccBinaryTypePlaceHolder, "cc_binary_host")
-func runCcBinaryTests(t *testing.T, tc bp2buildTestCase) {
+func runCcBinaryTests(t *testing.T, tc ccBinaryBp2buildTestCase) {
t.Helper()
runCcBinaryTestCase(t, tc)
runCcHostBinaryTestCase(t, tc)
}
-func runCcBinaryTestCase(t *testing.T, tc bp2buildTestCase) {
+func runCcBinaryTestCase(t *testing.T, tc ccBinaryBp2buildTestCase) {
t.Helper()
- testCase := tc
- testCase.expectedBazelTargets = append([]string{}, tc.expectedBazelTargets...)
- testCase.moduleTypeUnderTest = "cc_binary"
- testCase.moduleTypeUnderTestFactory = cc.BinaryFactory
- testCase.moduleTypeUnderTestBp2BuildMutator = cc.BinaryBp2build
- testCase.description = fmt.Sprintf("%s %s", testCase.moduleTypeUnderTest, testCase.description)
- testCase.blueprint = binaryReplacer.Replace(testCase.blueprint)
- for i, et := range testCase.expectedBazelTargets {
- testCase.expectedBazelTargets[i] = binaryReplacer.Replace(et)
+ moduleTypeUnderTest := "cc_binary"
+ testCase := bp2buildTestCase{
+ expectedBazelTargets: generateBazelTargetsForTest(tc.targets),
+ moduleTypeUnderTest: moduleTypeUnderTest,
+ moduleTypeUnderTestFactory: cc.BinaryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.BinaryBp2build,
+ description: fmt.Sprintf("%s %s", moduleTypeUnderTest, tc.description),
+ blueprint: binaryReplacer.Replace(tc.blueprint),
}
t.Run(testCase.description, func(t *testing.T) {
runBp2BuildTestCase(t, registerCcBinaryModuleTypes, testCase)
})
}
-func runCcHostBinaryTestCase(t *testing.T, tc bp2buildTestCase) {
+func runCcHostBinaryTestCase(t *testing.T, tc ccBinaryBp2buildTestCase) {
t.Helper()
testCase := tc
- testCase.expectedBazelTargets = append([]string{}, tc.expectedBazelTargets...)
- testCase.moduleTypeUnderTest = "cc_binary_host"
- testCase.moduleTypeUnderTestFactory = cc.BinaryHostFactory
- testCase.moduleTypeUnderTestBp2BuildMutator = cc.BinaryHostBp2build
- testCase.description = fmt.Sprintf("%s %s", testCase.moduleTypeUnderTest, testCase.description)
- testCase.blueprint = hostBinaryReplacer.Replace(testCase.blueprint)
- for i, et := range testCase.expectedBazelTargets {
- testCase.expectedBazelTargets[i] = hostBinaryReplacer.Replace(et)
+ for i, t := range testCase.targets {
+ t.attrs["target_compatible_with"] = `select({
+ "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ })`
+ testCase.targets[i] = t
}
+ moduleTypeUnderTest := "cc_binary_host"
t.Run(testCase.description, func(t *testing.T) {
- runBp2BuildTestCase(t, registerCcBinaryModuleTypes, testCase)
+ runBp2BuildTestCase(t, registerCcBinaryModuleTypes, bp2buildTestCase{
+ expectedBazelTargets: generateBazelTargetsForTest(testCase.targets),
+ moduleTypeUnderTest: moduleTypeUnderTest,
+ moduleTypeUnderTestFactory: cc.BinaryHostFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.BinaryHostBp2build,
+ description: fmt.Sprintf("%s %s", moduleTypeUnderTest, tc.description),
+ blueprint: hostBinaryReplacer.Replace(testCase.blueprint),
+ })
})
}
func TestBasicCcBinary(t *testing.T) {
- runCcBinaryTests(t, bp2buildTestCase{
+ runCcBinaryTests(t, ccBinaryBp2buildTestCase{
description: "basic -- properties -> attrs with little/no transformation",
blueprint: `
{rule_name} {
@@ -107,33 +128,35 @@
},
}
`,
- expectedBazelTargets: []string{`cc_binary(
- name = "foo",
- absolute_includes = ["absolute_dir"],
- asflags = ["-Dasflag"],
- conlyflags = ["-Dconlyflag"],
- copts = ["-Dcopt"],
- cppflags = ["-Dcppflag"],
- linkopts = ["ld-flag"],
- local_includes = [
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", attrNameToString{
+ "absolute_includes": `["absolute_dir"]`,
+ "asflags": `["-Dasflag"]`,
+ "conlyflags": `["-Dconlyflag"]`,
+ "copts": `["-Dcopt"]`,
+ "cppflags": `["-Dcppflag"]`,
+ "linkopts": `["ld-flag"]`,
+ "local_includes": `[
"dir",
".",
- ],
- rtti = True,
- srcs = ["a.cc"],
- strip = {
+ ]`,
+ "rtti": `True`,
+ "srcs": `["a.cc"]`,
+ "strip": `{
"all": True,
"keep_symbols": True,
"keep_symbols_and_debug_frame": True,
"keep_symbols_list": ["symbol"],
"none": True,
- },{target_compatible_with}
-)`},
+ }`,
+ },
+ },
+ },
})
}
func TestCcBinaryWithSharedLdflagDisableFeature(t *testing.T) {
- runCcBinaryTests(t, bp2buildTestCase{
+ runCcBinaryTests(t, ccBinaryBp2buildTestCase{
description: `ldflag "-shared" disables static_flag feature`,
blueprint: `
{rule_name} {
@@ -142,16 +165,18 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_binary(
- name = "foo",
- features = ["-static_flag"],
- linkopts = ["-shared"],{target_compatible_with}
-)`},
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", attrNameToString{
+ "features": `["-static_flag"]`,
+ "linkopts": `["-shared"]`,
+ },
+ },
+ },
})
}
func TestCcBinaryWithLinkStatic(t *testing.T) {
- runCcBinaryTests(t, bp2buildTestCase{
+ runCcBinaryTests(t, ccBinaryBp2buildTestCase{
description: "link static",
blueprint: `
{rule_name} {
@@ -160,15 +185,17 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_binary(
- name = "foo",
- linkshared = False,{target_compatible_with}
-)`},
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", attrNameToString{
+ "linkshared": `False`,
+ },
+ },
+ },
})
}
func TestCcBinaryVersionScript(t *testing.T) {
- runCcBinaryTests(t, bp2buildTestCase{
+ runCcBinaryTests(t, ccBinaryBp2buildTestCase{
description: `version script`,
blueprint: `
{rule_name} {
@@ -177,16 +204,18 @@
version_script: "vs",
}
`,
- expectedBazelTargets: []string{`cc_binary(
- name = "foo",
- additional_linker_inputs = ["vs"],
- linkopts = ["-Wl,--version-script,$(location vs)"],{target_compatible_with}
-)`},
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", attrNameToString{
+ "additional_linker_inputs": `["vs"]`,
+ "linkopts": `["-Wl,--version-script,$(location vs)"]`,
+ },
+ },
+ },
})
}
func TestCcBinarySplitSrcsByLang(t *testing.T) {
- runCcHostBinaryTestCase(t, bp2buildTestCase{
+ runCcHostBinaryTestCase(t, ccBinaryBp2buildTestCase{
description: "split srcs by lang",
blueprint: `
{rule_name} {
@@ -200,26 +229,28 @@
include_build_directory: false,
}
` + simpleModuleDoNotConvertBp2build("filegroup", "fg_foo"),
- expectedBazelTargets: []string{`cc_binary(
- name = "foo",
- srcs = [
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", attrNameToString{
+ "srcs": `[
"cpponly.cpp",
":fg_foo_cpp_srcs",
- ],
- srcs_as = [
+ ]`,
+ "srcs_as": `[
"asonly.S",
":fg_foo_as_srcs",
- ],
- srcs_c = [
+ ]`,
+ "srcs_c": `[
"conly.c",
":fg_foo_c_srcs",
- ],{target_compatible_with}
-)`},
+ ]`,
+ },
+ },
+ },
})
}
func TestCcBinaryDoNotDistinguishBetweenDepsAndImplementationDeps(t *testing.T) {
- runCcBinaryTestCase(t, bp2buildTestCase{
+ runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
description: "no implementation deps",
blueprint: `
genrule {
@@ -251,26 +282,28 @@
simpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep") +
simpleModuleDoNotConvertBp2build("cc_library", "shared_dep") +
simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep"),
- expectedBazelTargets: []string{`cc_binary(
- name = "foo",
- deps = [
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", attrNameToString{
+ "deps": `[
":implementation_static_dep",
":static_dep",
- ],
- dynamic_deps = [
+ ]`,
+ "dynamic_deps": `[
":implementation_shared_dep",
":shared_dep",
- ],
- srcs = [
+ ]`,
+ "srcs": `[
"foo.cpp",
":generated_hdr",
":export_generated_hdr",
- ],{target_compatible_with}
- whole_archive_deps = [
+ ]`,
+ "whole_archive_deps": `[
":not_explicitly_exported_whole_static_dep",
":whole_static_dep",
- ],
-)`},
+ ]`,
+ },
+ },
+ },
})
}
@@ -278,19 +311,21 @@
baseTestCases := []struct {
description string
soongProperty string
- bazelAttr string
+ bazelAttr attrNameToString
}{
{
description: "nocrt: true",
soongProperty: `nocrt: true,`,
- bazelAttr: ` link_crt = False,`,
+ bazelAttr: attrNameToString{"link_crt": `False`},
},
{
description: "nocrt: false",
soongProperty: `nocrt: false,`,
+ bazelAttr: attrNameToString{},
},
{
description: "nocrt: not set",
+ bazelAttr: attrNameToString{},
},
}
@@ -300,24 +335,16 @@
}
`
- baseBazelTarget := `cc_binary(
- name = "foo",%s{target_compatible_with}
-)`
-
for _, btc := range baseTestCases {
prop := btc.soongProperty
if len(prop) > 0 {
prop = "\n" + prop
}
- attr := btc.bazelAttr
- if len(attr) > 0 {
- attr = "\n" + attr
- }
- runCcBinaryTests(t, bp2buildTestCase{
+ runCcBinaryTests(t, ccBinaryBp2buildTestCase{
description: btc.description,
blueprint: fmt.Sprintf(baseBlueprint, prop),
- expectedBazelTargets: []string{
- fmt.Sprintf(baseBazelTarget, attr),
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", btc.bazelAttr},
},
})
}
@@ -327,20 +354,21 @@
baseTestCases := []struct {
description string
soongProperty string
- bazelAttr string
+ bazelAttr attrNameToString
}{
{
description: "no_libcrt: true",
soongProperty: `no_libcrt: true,`,
- bazelAttr: ` use_libcrt = False,`,
+ bazelAttr: attrNameToString{"use_libcrt": `False`},
},
{
description: "no_libcrt: false",
soongProperty: `no_libcrt: false,`,
- bazelAttr: ` use_libcrt = True,`,
+ bazelAttr: attrNameToString{"use_libcrt": `True`},
},
{
description: "no_libcrt: not set",
+ bazelAttr: attrNameToString{},
},
}
@@ -350,24 +378,16 @@
}
`
- baseBazelTarget := `cc_binary(
- name = "foo",{target_compatible_with}%s
-)`
-
for _, btc := range baseTestCases {
prop := btc.soongProperty
if len(prop) > 0 {
prop = "\n" + prop
}
- attr := btc.bazelAttr
- if len(attr) > 0 {
- attr = "\n" + attr
- }
- runCcBinaryTests(t, bp2buildTestCase{
+ runCcBinaryTests(t, ccBinaryBp2buildTestCase{
description: btc.description,
blueprint: fmt.Sprintf(baseBlueprint, prop),
- expectedBazelTargets: []string{
- fmt.Sprintf(baseBazelTarget, attr),
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", btc.bazelAttr},
},
})
}
@@ -377,31 +397,35 @@
baseTestCases := []struct {
description string
soongProperty string
- bazelAttr string
+ bazelAttr attrNameToString
}{
{
description: "pack_relocation: true",
soongProperty: `pack_relocations: true,`,
+ bazelAttr: attrNameToString{},
},
{
description: "pack_relocations: false",
soongProperty: `pack_relocations: false,`,
- bazelAttr: ` features = ["disable_pack_relocations"],`,
+ bazelAttr: attrNameToString{"features": `["disable_pack_relocations"]`},
},
{
description: "pack_relocations: not set",
+ bazelAttr: attrNameToString{},
},
{
description: "pack_relocation: true",
soongProperty: `allow_undefined_symbols: true,`,
- bazelAttr: ` features = ["-no_undefined_symbols"],`,
+ bazelAttr: attrNameToString{"features": `["-no_undefined_symbols"]`},
},
{
description: "allow_undefined_symbols: false",
soongProperty: `allow_undefined_symbols: false,`,
+ bazelAttr: attrNameToString{},
},
{
description: "allow_undefined_symbols: not set",
+ bazelAttr: attrNameToString{},
},
}
@@ -410,25 +434,16 @@
include_build_directory: false,
}
`
-
- baseBazelTarget := `cc_binary(
- name = "foo",%s{target_compatible_with}
-)`
-
for _, btc := range baseTestCases {
prop := btc.soongProperty
if len(prop) > 0 {
prop = "\n" + prop
}
- attr := btc.bazelAttr
- if len(attr) > 0 {
- attr = "\n" + attr
- }
- runCcBinaryTests(t, bp2buildTestCase{
+ runCcBinaryTests(t, ccBinaryBp2buildTestCase{
description: btc.description,
blueprint: fmt.Sprintf(baseBlueprint, prop),
- expectedBazelTargets: []string{
- fmt.Sprintf(baseBazelTarget, attr),
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", btc.bazelAttr},
},
})
}
diff --git a/bp2build/cc_genrule_conversion_test.go b/bp2build/cc_genrule_conversion_test.go
index a7e9cb2..b3624dd 100644
--- a/bp2build/cc_genrule_conversion_test.go
+++ b/bp2build/cc_genrule_conversion_test.go
@@ -39,15 +39,15 @@
func runCcGenruleTestCase(t *testing.T, tc bp2buildTestCase) {
t.Helper()
+ (&tc).moduleTypeUnderTest = "cc_genrule"
+ (&tc).moduleTypeUnderTestFactory = cc.GenRuleFactory
+ (&tc).moduleTypeUnderTestBp2BuildMutator = genrule.CcGenruleBp2Build
runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
}
func TestCliVariableReplacement(t *testing.T) {
runCcGenruleTestCase(t, bp2buildTestCase{
- description: "cc_genrule with command line variable replacements",
- moduleTypeUnderTest: "cc_genrule",
- moduleTypeUnderTestFactory: cc.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.CcGenruleBp2Build,
+ description: "cc_genrule with command line variable replacements",
blueprint: `cc_genrule {
name: "foo.tool",
out: ["foo_tool.out"],
@@ -65,29 +65,24 @@
bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{
- `genrule(
- name = "foo",
- cmd = "$(location :foo.tool) --genDir=$(RULEDIR) arg $(SRCS) $(OUTS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
- tools = [":foo.tool"],
-)`,
- `genrule(
- name = "foo.tool",
- cmd = "cp $(SRCS) $(OUTS)",
- outs = ["foo_tool.out"],
- srcs = ["foo_tool.in"],
-)`,
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(location :foo.tool) --genDir=$(RULEDIR) arg $(SRCS) $(OUTS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ "tools": `[":foo.tool"]`,
+ }),
+ makeBazelTarget("genrule", "foo.tool", attrNameToString{
+ "cmd": `"cp $(SRCS) $(OUTS)"`,
+ "outs": `["foo_tool.out"]`,
+ "srcs": `["foo_tool.in"]`,
+ }),
},
})
}
func TestUsingLocationsLabel(t *testing.T) {
runCcGenruleTestCase(t, bp2buildTestCase{
- description: "cc_genrule using $(locations :label)",
- moduleTypeUnderTest: "cc_genrule",
- moduleTypeUnderTestFactory: cc.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.CcGenruleBp2Build,
+ description: "cc_genrule using $(locations :label)",
blueprint: `cc_genrule {
name: "foo.tools",
out: ["foo_tool.out", "foo_tool2.out"],
@@ -104,32 +99,28 @@
cmd: "$(locations :foo.tools) -s $(out) $(in)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "$(locations :foo.tools) -s $(OUTS) $(SRCS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
- tools = [":foo.tools"],
-)`,
- `genrule(
- name = "foo.tools",
- cmd = "cp $(SRCS) $(OUTS)",
- outs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(locations :foo.tools) -s $(OUTS) $(SRCS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ "tools": `[":foo.tools"]`,
+ }),
+ makeBazelTarget("genrule", "foo.tools", attrNameToString{
+ "cmd": `"cp $(SRCS) $(OUTS)"`,
+ "outs": `[
"foo_tool.out",
"foo_tool2.out",
- ],
- srcs = ["foo_tool.in"],
-)`,
+ ]`,
+ "srcs": `["foo_tool.in"]`,
+ }),
},
})
}
func TestUsingLocationsAbsoluteLabel(t *testing.T) {
runCcGenruleTestCase(t, bp2buildTestCase{
- description: "cc_genrule using $(locations //absolute:label)",
- moduleTypeUnderTest: "cc_genrule",
- moduleTypeUnderTestFactory: cc.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.CcGenruleBp2Build,
+ description: "cc_genrule using $(locations //absolute:label)",
blueprint: `cc_genrule {
name: "foo",
out: ["foo.out"],
@@ -138,24 +129,21 @@
cmd: "$(locations :foo.tool) -s $(out) $(in)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
- tools = ["//other:foo.tool"],
-)`,
- },
filesystem: otherCcGenruleBp,
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(locations //other:foo.tool) -s $(OUTS) $(SRCS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ "tools": `["//other:foo.tool"]`,
+ }),
+ },
})
}
func TestSrcsUsingAbsoluteLabel(t *testing.T) {
runCcGenruleTestCase(t, bp2buildTestCase{
- description: "cc_genrule srcs using $(locations //absolute:label)",
- moduleTypeUnderTest: "cc_genrule",
- moduleTypeUnderTestFactory: cc.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.CcGenruleBp2Build,
+ description: "cc_genrule srcs using $(locations //absolute:label)",
blueprint: `cc_genrule {
name: "foo",
out: ["foo.out"],
@@ -164,24 +152,21 @@
cmd: "$(locations :foo.tool) -s $(out) $(location :other.tool)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "$(locations //other:foo.tool) -s $(OUTS) $(location //other:other.tool)",
- outs = ["foo.out"],
- srcs = ["//other:other.tool"],
- tools = ["//other:foo.tool"],
-)`,
- },
filesystem: otherCcGenruleBp,
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(locations //other:foo.tool) -s $(OUTS) $(location //other:other.tool)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["//other:other.tool"]`,
+ "tools": `["//other:foo.tool"]`,
+ }),
+ },
})
}
func TestLocationsLabelUsesFirstToolFile(t *testing.T) {
runCcGenruleTestCase(t, bp2buildTestCase{
- description: "cc_genrule using $(location) label should substitute first tool label automatically",
- moduleTypeUnderTest: "cc_genrule",
- moduleTypeUnderTestFactory: cc.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.CcGenruleBp2Build,
+ description: "cc_genrule using $(location) label should substitute first tool label automatically",
blueprint: `cc_genrule {
name: "foo",
out: ["foo.out"],
@@ -190,27 +175,24 @@
cmd: "$(location) -s $(out) $(in)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "$(location //other:foo.tool) -s $(OUTS) $(SRCS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
- tools = [
+ filesystem: otherCcGenruleBp,
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(location //other:foo.tool) -s $(OUTS) $(SRCS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ "tools": `[
"//other:foo.tool",
"//other:other.tool",
- ],
-)`,
+ ]`,
+ }),
},
- filesystem: otherCcGenruleBp,
})
}
func TestLocationsLabelUsesFirstTool(t *testing.T) {
runCcGenruleTestCase(t, bp2buildTestCase{
- description: "cc_genrule using $(locations) label should substitute first tool label automatically",
- moduleTypeUnderTest: "cc_genrule",
- moduleTypeUnderTestFactory: cc.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.CcGenruleBp2Build,
+ description: "cc_genrule using $(locations) label should substitute first tool label automatically",
blueprint: `cc_genrule {
name: "foo",
out: ["foo.out"],
@@ -219,27 +201,24 @@
cmd: "$(locations) -s $(out) $(in)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
- tools = [
+ filesystem: otherCcGenruleBp,
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(locations //other:foo.tool) -s $(OUTS) $(SRCS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ "tools": `[
"//other:foo.tool",
"//other:other.tool",
- ],
-)`,
+ ]`,
+ }),
},
- filesystem: otherCcGenruleBp,
})
}
func TestWithoutToolsOrToolFiles(t *testing.T) {
runCcGenruleTestCase(t, bp2buildTestCase{
- description: "cc_genrule without tools or tool_files can convert successfully",
- moduleTypeUnderTest: "cc_genrule",
- moduleTypeUnderTestFactory: cc.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.CcGenruleBp2Build,
+ description: "cc_genrule without tools or tool_files can convert successfully",
blueprint: `cc_genrule {
name: "foo",
out: ["foo.out"],
@@ -247,12 +226,12 @@
cmd: "cp $(in) $(out)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "cp $(SRCS) $(OUTS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"cp $(SRCS) $(OUTS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ }),
},
})
}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index cbdc167..a3d902a 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -81,8 +81,8 @@
"x86_64.cpp": "",
"foo-dir/a.h": "",
},
- blueprint: soongCcLibraryPreamble + `
-cc_library_headers { name: "some-headers" }
+ blueprint: soongCcLibraryPreamble +
+ simpleModuleDoNotConvertBp2build("cc_library_headers", "some-headers") + `
cc_library {
name: "foo-lib",
srcs: ["impl.cpp"],
@@ -117,17 +117,17 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "foo-lib",
- copts = ["-Wall"],
- export_includes = ["foo-dir"],
- implementation_deps = [":some-headers"],
- linkopts = ["-Wl,--exclude-libs=bar.a"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "foo-lib", attrNameToString{
+ "copts": `["-Wall"]`,
+ "export_includes": `["foo-dir"]`,
+ "implementation_deps": `[":some-headers"]`,
+ "linkopts": `["-Wl,--exclude-libs=bar.a"] + select({
"//build/bazel/platforms/arch:x86": ["-Wl,--exclude-libs=baz.a"],
"//build/bazel/platforms/arch:x86_64": ["-Wl,--exclude-libs=qux.a"],
"//conditions:default": [],
- }),
- srcs = ["impl.cpp"] + select({
+ })`,
+ "srcs": `["impl.cpp"] + select({
"//build/bazel/platforms/arch:x86": ["x86.cpp"],
"//build/bazel/platforms/arch:x86_64": ["x86_64.cpp"],
"//conditions:default": [],
@@ -140,8 +140,10 @@
"//build/bazel/platforms/os:linux": ["linux.cpp"],
"//build/bazel/platforms/os:linux_bionic": ["bionic.cpp"],
"//conditions:default": [],
- }),
-)`}})
+ })`,
+ }),
+ },
+ })
}
func TestCcLibraryTrimmedLdAndroid(t *testing.T) {
@@ -188,16 +190,17 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "fake-ld-android",
- copts = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "fake-ld-android", attrNameToString{
+ "srcs": `["ld_android.cpp"]`,
+ "copts": `[
"-Wall",
"-Wextra",
"-Wunused",
"-Werror",
- ],
- implementation_deps = [":libc_headers"],
- linkopts = [
+ ]`,
+ "implementation_deps": `[":libc_headers"]`,
+ "linkopts": `[
"-Wl,--exclude-libs=libgcc.a",
"-Wl,--exclude-libs=libgcc_stripped.a",
"-Wl,--exclude-libs=libclang_rt.builtins-arm-android.a",
@@ -208,9 +211,9 @@
"//build/bazel/platforms/arch:x86": ["-Wl,--exclude-libs=libgcc_eh.a"],
"//build/bazel/platforms/arch:x86_64": ["-Wl,--exclude-libs=libgcc_eh.a"],
"//conditions:default": [],
- }),
- srcs = ["ld_android.cpp"],
-)`},
+ })`,
+ }),
+ },
})
}
@@ -255,15 +258,16 @@
`,
},
blueprint: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
- name = "fake-libarm-optimized-routines-math",
- copts = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "fake-libarm-optimized-routines-math", attrNameToString{
+ "copts": `select({
"//build/bazel/platforms/arch:arm64": ["-DHAVE_FAST_FMA=1"],
"//conditions:default": [],
- }),
- local_includes = ["."],
- srcs_c = ["math/cosf.c"],
-)`},
+ })`,
+ "local_includes": `["."]`,
+ "srcs_c": `["math/cosf.c"]`,
+ }),
+ },
})
}
@@ -348,28 +352,29 @@
bazel_module: { bp2build_available: false },
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- copts = ["bothflag"],
- implementation_deps = [":static_dep_for_both"],
- implementation_dynamic_deps = [":shared_dep_for_both"],
- shared = {
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "a", attrNameToString{
+ "copts": `["bothflag"]`,
+ "implementation_deps": `[":static_dep_for_both"]`,
+ "implementation_dynamic_deps": `[":shared_dep_for_both"]`,
+ "shared": `{
"copts": ["sharedflag"],
"implementation_deps": [":static_dep_for_shared"],
"implementation_dynamic_deps": [":shared_dep_for_shared"],
"srcs": ["sharedonly.cpp"],
"whole_archive_deps": [":whole_static_lib_for_shared"],
- },
- srcs = ["both.cpp"],
- static = {
+ }`,
+ "srcs": `["both.cpp"]`,
+ "static": `{
"copts": ["staticflag"],
"implementation_deps": [":static_dep_for_static"],
"implementation_dynamic_deps": [":shared_dep_for_static"],
"srcs": ["staticonly.cpp"],
"whole_archive_deps": [":whole_static_lib_for_static"],
- },
- whole_archive_deps = [":whole_static_lib_for_both"],
-)`},
+ }`,
+ "whole_archive_deps": `[":whole_static_lib_for_both"]`,
+ }),
+ },
})
}
@@ -432,14 +437,14 @@
simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_static") +
simpleModuleDoNotConvertBp2build("cc_library", "shared_dep_for_both") +
simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_both"),
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- copts = ["bothflag"],
- deps = [":static_dep_for_both"],
- dynamic_deps = [":shared_dep_for_both"],
- implementation_deps = [":implementation_static_dep_for_both"],
- implementation_dynamic_deps = [":implementation_shared_dep_for_both"],
- shared = {
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "a", attrNameToString{
+ "copts": `["bothflag"]`,
+ "deps": `[":static_dep_for_both"]`,
+ "dynamic_deps": `[":shared_dep_for_both"]`,
+ "implementation_deps": `[":implementation_static_dep_for_both"]`,
+ "implementation_dynamic_deps": `[":implementation_shared_dep_for_both"]`,
+ "shared": `{
"copts": ["sharedflag"],
"deps": [":static_dep_for_shared"],
"dynamic_deps": [":shared_dep_for_shared"],
@@ -450,9 +455,9 @@
":not_explicitly_exported_whole_static_dep_for_shared",
":whole_static_dep_for_shared",
],
- },
- srcs = ["both.cpp"],
- static = {
+ }`,
+ "srcs": `["both.cpp"]`,
+ "static": `{
"copts": ["staticflag"],
"deps": [":static_dep_for_static"],
"dynamic_deps": [":shared_dep_for_static"],
@@ -463,12 +468,13 @@
":not_explicitly_exported_whole_static_dep_for_static",
":whole_static_dep_for_static",
],
- },
- whole_archive_deps = [
+ }`,
+ "whole_archive_deps": `[
":not_explicitly_exported_whole_static_dep_for_both",
":whole_static_dep_for_both",
- ],
-)`},
+ ]`,
+ }),
+ },
})
}
@@ -501,16 +507,17 @@
`,
},
blueprint: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- shared = {
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "a", attrNameToString{
+ "shared": `{
"whole_archive_deps": [":whole_static_lib_for_shared_alwayslink"],
- },
- static = {
+ }`,
+ "static": `{
"whole_archive_deps": [":whole_static_lib_for_static_alwayslink"],
- },
- whole_archive_deps = [":whole_static_lib_for_both_alwayslink"],
-)`},
+ }`,
+ "whole_archive_deps": `[":whole_static_lib_for_both_alwayslink"]`,
+ }),
+ },
})
}
@@ -591,12 +598,12 @@
`,
},
blueprint: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- copts = ["bothflag"],
- implementation_deps = [":static_dep_for_both"],
- local_includes = ["."],
- shared = {
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "a", attrNameToString{
+ "copts": `["bothflag"]`,
+ "implementation_deps": `[":static_dep_for_both"]`,
+ "local_includes": `["."]`,
+ "shared": `{
"copts": ["sharedflag"] + select({
"//build/bazel/platforms/arch:arm": ["-DARM_SHARED"],
"//conditions:default": [],
@@ -629,9 +636,9 @@
"//build/bazel/platforms/arch:arm": [":arm_whole_static_dep_for_shared"],
"//conditions:default": [],
}),
- },
- srcs = ["both.cpp"],
- static = {
+ }`,
+ "srcs": `["both.cpp"]`,
+ "static": `{
"copts": ["staticflag"] + select({
"//build/bazel/platforms/arch:x86": ["-DX86_STATIC"],
"//conditions:default": [],
@@ -644,8 +651,9 @@
"//build/bazel/platforms/arch:x86": ["x86_static.cpp"],
"//conditions:default": [],
}),
- },
-)`},
+ }`,
+ }),
+ },
})
}
@@ -729,10 +737,10 @@
`,
},
blueprint: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- local_includes = ["."],
- shared = {
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "a", attrNameToString{
+ "local_includes": `["."]`,
+ "shared": `{
"srcs": [
"shared_source.cpp",
"shared_source.cc",
@@ -747,22 +755,22 @@
"shared_source.c",
":shared_filegroup_c_srcs",
],
- },
- srcs = [
+ }`,
+ "srcs": `[
"both_source.cpp",
"both_source.cc",
":both_filegroup_cpp_srcs",
- ],
- srcs_as = [
+ ]`,
+ "srcs_as": `[
"both_source.s",
"both_source.S",
":both_filegroup_as_srcs",
- ],
- srcs_c = [
+ ]`,
+ "srcs_c": `[
"both_source.c",
":both_filegroup_c_srcs",
- ],
- static = {
+ ]`,
+ "static": `{
"srcs": [
"static_source.cpp",
"static_source.cc",
@@ -777,8 +785,9 @@
"static_source.c",
":static_filegroup_c_srcs",
],
- },
-)`},
+ }`,
+ }),
+ },
})
}
@@ -801,12 +810,13 @@
`,
},
blueprint: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- additional_linker_inputs = ["v.map"],
- linkopts = ["-Wl,--version-script,$(location v.map)"],
- srcs = ["a.cpp"],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "a", attrNameToString{
+ "additional_linker_inputs": `["v.map"]`,
+ "linkopts": `["-Wl,--version-script,$(location v.map)"]`,
+ "srcs": `["a.cpp"]`,
+ }),
+ },
})
}
@@ -837,20 +847,21 @@
`,
},
blueprint: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- additional_linker_inputs = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "a", attrNameToString{
+ "additional_linker_inputs": `select({
"//build/bazel/platforms/arch:arm": ["arm.map"],
"//build/bazel/platforms/arch:arm64": ["arm64.map"],
"//conditions:default": [],
- }),
- linkopts = select({
+ })`,
+ "linkopts": `select({
"//build/bazel/platforms/arch:arm": ["-Wl,--version-script,$(location arm.map)"],
"//build/bazel/platforms/arch:arm64": ["-Wl,--version-script,$(location arm64.map)"],
"//conditions:default": [],
- }),
- srcs = ["a.cpp"],
-)`},
+ })`,
+ "srcs": `["a.cpp"]`,
+ }),
+ },
})
}
@@ -872,10 +883,11 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- implementation_dynamic_deps = [":mylib"],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "a", attrNameToString{
+ "implementation_dynamic_deps": `[":mylib"]`,
+ }),
+ },
})
}
@@ -917,34 +929,33 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- features = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "a", attrNameToString{
+ "features": `[
"disable_pack_relocations",
"-no_undefined_symbols",
- ],
- srcs = ["a.cpp"],
-)`, `cc_library(
- name = "b",
- features = select({
+ ]`,
+ "srcs": `["a.cpp"]`,
+ }), makeBazelTarget("cc_library", "b", attrNameToString{
+ "features": `select({
"//build/bazel/platforms/arch:x86_64": [
"disable_pack_relocations",
"-no_undefined_symbols",
],
"//conditions:default": [],
- }),
- srcs = ["b.cpp"],
-)`, `cc_library(
- name = "c",
- features = select({
+ })`,
+ "srcs": `["b.cpp"]`,
+ }), makeBazelTarget("cc_library", "c", attrNameToString{
+ "features": `select({
"//build/bazel/platforms/os:darwin": [
"disable_pack_relocations",
"-no_undefined_symbols",
],
"//conditions:default": [],
- }),
- srcs = ["c.cpp"],
-)`},
+ })`,
+ "srcs": `["c.cpp"]`,
+ }),
+ },
})
}
@@ -961,13 +972,14 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- copts = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "a", attrNameToString{
+ "copts": `[
"-include",
"header.h",
- ],
-)`},
+ ]`,
+ }),
+ },
})
}
@@ -998,10 +1010,10 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- copts = ["-Wall"],
- cppflags = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "a", attrNameToString{
+ "copts": `["-Wall"]`,
+ "cppflags": `[
"-fsigned-char",
"-pedantic",
] + select({
@@ -1010,9 +1022,10 @@
}) + select({
"//build/bazel/platforms/os:android": ["-DANDROID=1"],
"//conditions:default": [],
- }),
- srcs = ["a.cpp"],
-)`},
+ })`,
+ "srcs": `["a.cpp"]`,
+ }),
+ },
})
}
@@ -1097,31 +1110,30 @@
}
`,
expectedBazelTargets: []string{
- `cc_library(
- name = "foo_static",
- implementation_deps = select({
+ makeBazelTarget("cc_library", "foo_static", attrNameToString{
+ "implementation_deps": `select({
"//build/bazel/platforms/arch:arm": [],
"//conditions:default": [":arm_static_lib_excludes_bp2build_cc_library_static"],
}) + select({
"//build/bazel/product_variables:malloc_not_svelte": [],
"//conditions:default": [":malloc_not_svelte_static_lib_excludes_bp2build_cc_library_static"],
- }),
- implementation_dynamic_deps = select({
+ })`,
+ "implementation_dynamic_deps": `select({
"//build/bazel/platforms/arch:arm": [],
"//conditions:default": [":arm_shared_lib_excludes"],
}) + select({
"//build/bazel/product_variables:malloc_not_svelte": [":malloc_not_svelte_shared_lib"],
"//conditions:default": [],
- }),
- srcs_c = ["common.c"],
- whole_archive_deps = select({
+ })`,
+ "srcs_c": `["common.c"]`,
+ "whole_archive_deps": `select({
"//build/bazel/platforms/arch:arm": [],
"//conditions:default": [":arm_whole_static_lib_excludes_bp2build_cc_library_static"],
}) + select({
"//build/bazel/product_variables:malloc_not_svelte": [":malloc_not_svelte_whole_static_lib_bp2build_cc_library_static"],
"//conditions:default": [":malloc_not_svelte_whole_static_lib_excludes_bp2build_cc_library_static"],
- }),
-)`,
+ })`,
+ }),
},
})
}
@@ -1143,11 +1155,13 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "foo-lib",
- link_crt = False,
- srcs = ["impl.cpp"],
-)`}})
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "foo-lib", attrNameToString{
+ "link_crt": `False`,
+ "srcs": `["impl.cpp"]`,
+ }),
+ },
+ })
}
func TestCCLibraryNoCrtFalse(t *testing.T) {
@@ -1167,10 +1181,12 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "foo-lib",
- srcs = ["impl.cpp"],
-)`}})
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "foo-lib", attrNameToString{
+ "srcs": `["impl.cpp"]`,
+ }),
+ },
+ })
}
func TestCCLibraryNoCrtArchVariant(t *testing.T) {
@@ -1219,11 +1235,12 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "foo-lib",
- srcs = ["impl.cpp"],
- use_libcrt = False,
-)`}})
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "foo-lib", attrNameToString{
+ "srcs": `["impl.cpp"]`,
+ "use_libcrt": `False`,
+ }),
+ }})
}
func TestCCLibraryNoLibCrtFalse(t *testing.T) {
@@ -1243,11 +1260,12 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "foo-lib",
- srcs = ["impl.cpp"],
- use_libcrt = True,
-)`}})
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "foo-lib", attrNameToString{
+ "srcs": `["impl.cpp"]`,
+ "use_libcrt": `True`,
+ }),
+ }})
}
func TestCCLibraryNoLibCrtArchVariant(t *testing.T) {
@@ -1273,15 +1291,16 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "foo-lib",
- srcs = ["impl.cpp"],
- use_libcrt = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "foo-lib", attrNameToString{
+ "srcs": `["impl.cpp"]`,
+ "use_libcrt": `select({
"//build/bazel/platforms/arch:arm": False,
"//build/bazel/platforms/arch:x86": False,
"//conditions:default": None,
- }),
-)`}})
+ })`,
+ }),
+ }})
}
func TestCcLibraryStrip(t *testing.T) {
@@ -1331,34 +1350,29 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "all",
- strip = {
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "all", attrNameToString{
+ "strip": `{
"all": True,
- },
-)`, `cc_library(
- name = "keep_symbols",
- strip = {
+ }`,
+ }), makeBazelTarget("cc_library", "keep_symbols", attrNameToString{
+ "strip": `{
"keep_symbols": True,
- },
-)`, `cc_library(
- name = "keep_symbols_and_debug_frame",
- strip = {
+ }`,
+ }), makeBazelTarget("cc_library", "keep_symbols_and_debug_frame", attrNameToString{
+ "strip": `{
"keep_symbols_and_debug_frame": True,
- },
-)`, `cc_library(
- name = "keep_symbols_list",
- strip = {
+ }`,
+ }), makeBazelTarget("cc_library", "keep_symbols_list", attrNameToString{
+ "strip": `{
"keep_symbols_list": ["symbol"],
- },
-)`, `cc_library(
- name = "none",
- strip = {
+ }`,
+ }), makeBazelTarget("cc_library", "none", attrNameToString{
+ "strip": `{
"none": True,
- },
-)`, `cc_library(
- name = "nothing",
-)`},
+ }`,
+ }), makeBazelTarget("cc_library", "nothing", attrNameToString{}),
+ },
})
}
@@ -1393,9 +1407,9 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "multi-arch",
- strip = {
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "multi-arch", attrNameToString{
+ "strip": `{
"keep_symbols": select({
"//build/bazel/platforms/arch:arm64": True,
"//conditions:default": None,
@@ -1411,8 +1425,9 @@
],
"//conditions:default": [],
}),
- },
-)`},
+ }`,
+ }),
+ },
})
}
@@ -1429,10 +1444,11 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "root_empty",
- system_dynamic_deps = [],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "root_empty", attrNameToString{
+ "system_dynamic_deps": `[]`,
+ }),
+ },
})
}
@@ -1451,12 +1467,13 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "static_empty",
- static = {
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "static_empty", attrNameToString{
+ "static": `{
"system_dynamic_deps": [],
- },
-)`},
+ }`,
+ }),
+ },
})
}
@@ -1475,12 +1492,13 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "shared_empty",
- shared = {
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "shared_empty", attrNameToString{
+ "shared": `{
"system_dynamic_deps": [],
- },
-)`},
+ }`,
+ }),
+ },
})
}
@@ -1503,12 +1521,13 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "shared_empty",
- shared = {
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "shared_empty", attrNameToString{
+ "shared": `{
"system_dynamic_deps": [],
- },
-)`},
+ }`,
+ }),
+ },
})
}
@@ -1533,10 +1552,11 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "target_linux_bionic_empty",
- system_dynamic_deps = [],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "target_linux_bionic_empty", attrNameToString{
+ "system_dynamic_deps": `[]`,
+ }),
+ },
})
}
@@ -1557,10 +1577,11 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "target_bionic_empty",
- system_dynamic_deps = [],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "target_bionic_empty", attrNameToString{
+ "system_dynamic_deps": `[]`,
+ }),
+ },
})
}
@@ -1589,13 +1610,14 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "foo",
- shared = {
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "foo", attrNameToString{
+ "shared": `{
"system_dynamic_deps": [":libm"],
- },
- system_dynamic_deps = [":libc"],
-)`},
+ }`,
+ "system_dynamic_deps": `[":libc"]`,
+ }),
+ },
})
}
@@ -1637,9 +1659,9 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "foo-lib",
- srcs = ["base.cpp"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "foo-lib", attrNameToString{
+ "srcs": `["base.cpp"] + select({
"//build/bazel/platforms/os:android": [
"linux.cpp",
"bionic.cpp",
@@ -1660,9 +1682,10 @@
],
"//build/bazel/platforms/os:windows": ["windows.cpp"],
"//conditions:default": [],
- }),
-)`}})
-
+ })`,
+ }),
+ },
+ })
}
func TestCcLibraryCppStdWithGnuExtensions_ConvertsToFeatureAttr(t *testing.T) {
@@ -1714,17 +1737,17 @@
{cpp_std: "gnu++17", gnu_extensions: "true", bazel_cpp_std: "gnu++17"},
}
for _, tc := range testCases {
- cppStdAttr := ""
+ cppStdProp := ""
if tc.cpp_std != "" {
- cppStdAttr = fmt.Sprintf(" cpp_std: \"%s\",", tc.cpp_std)
+ cppStdProp = fmt.Sprintf(" cpp_std: \"%s\",", tc.cpp_std)
}
- gnuExtensionsAttr := ""
+ gnuExtensionsProp := ""
if tc.gnu_extensions != "" {
- gnuExtensionsAttr = fmt.Sprintf(" gnu_extensions: %s,", tc.gnu_extensions)
+ gnuExtensionsProp = fmt.Sprintf(" gnu_extensions: %s,", tc.gnu_extensions)
}
- bazelCppStdAttr := ""
+ attrs := attrNameToString{}
if tc.bazel_cpp_std != "" {
- bazelCppStdAttr = fmt.Sprintf("\n cpp_std = \"%s\",", tc.bazel_cpp_std)
+ attrs["cpp_std"] = fmt.Sprintf(`"%s"`, tc.bazel_cpp_std)
}
runCcLibraryTestCase(t, bp2buildTestCase{
@@ -1740,10 +1763,10 @@
%s // gnu_extensions: *bool
include_build_directory: false,
}
-`, cppStdAttr, gnuExtensionsAttr),
- expectedBazelTargets: []string{fmt.Sprintf(`cc_library(
- name = "a",%s
-)`, bazelCppStdAttr)},
+`, cppStdProp, gnuExtensionsProp),
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library", "a", attrs),
+ },
})
runCcLibraryStaticTestCase(t, bp2buildTestCase{
@@ -1759,10 +1782,10 @@
%s // gnu_extensions: *bool
include_build_directory: false,
}
-`, cppStdAttr, gnuExtensionsAttr),
- expectedBazelTargets: []string{fmt.Sprintf(`cc_library_static(
- name = "a",%s
-)`, bazelCppStdAttr)},
+`, cppStdProp, gnuExtensionsProp),
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "a", attrs),
+ },
})
runCcLibrarySharedTestCase(t, bp2buildTestCase{
@@ -1778,10 +1801,10 @@
%s // gnu_extensions: *bool
include_build_directory: false,
}
-`, cppStdAttr, gnuExtensionsAttr),
- expectedBazelTargets: []string{fmt.Sprintf(`cc_library_shared(
- name = "a",%s
-)`, bazelCppStdAttr)},
+`, cppStdProp, gnuExtensionsProp),
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "a", attrs),
+ },
})
}
}
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index e43672b..76fdab2 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -128,9 +128,9 @@
// TODO: Also support export_header_lib_headers
}`,
- expectedBazelTargets: []string{`cc_library_headers(
- name = "foo_headers",
- export_includes = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
+ "export_includes": `[
"dir-1",
"dir-2",
] + select({
@@ -138,12 +138,13 @@
"//build/bazel/platforms/arch:x86": ["arch_x86_exported_include_dir"],
"//build/bazel/platforms/arch:x86_64": ["arch_x86_64_exported_include_dir"],
"//conditions:default": [],
- }),
- implementation_deps = [
+ })`,
+ "implementation_deps": `[
":lib-1",
":lib-2",
- ],
-)`},
+ ]`,
+ }),
+ },
})
}
@@ -191,17 +192,18 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_headers(
- name = "foo_headers",
- implementation_deps = [":base-lib"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
+ "implementation_deps": `[":base-lib"] + select({
"//build/bazel/platforms/os:android": [":android-lib"],
"//build/bazel/platforms/os:darwin": [":darwin-lib"],
"//build/bazel/platforms/os:linux": [":linux-lib"],
"//build/bazel/platforms/os:linux_bionic": [":linux_bionic-lib"],
"//build/bazel/platforms/os:windows": [":windows-lib"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
@@ -231,17 +233,18 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_headers(
- name = "foo_headers",
- deps = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
+ "deps": `select({
"//build/bazel/platforms/os:android": [":exported-lib"],
"//conditions:default": [],
- }),
- implementation_deps = select({
+ })`,
+ "implementation_deps": `select({
"//build/bazel/platforms/os:android": [":android-lib"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
@@ -288,9 +291,9 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_headers(
- name = "foo_headers",
- export_system_includes = ["shared_include_dir"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
+ "export_system_includes": `["shared_include_dir"] + select({
"//build/bazel/platforms/arch:arm": ["arm_include_dir"],
"//build/bazel/platforms/arch:x86_64": ["x86_64_include_dir"],
"//conditions:default": [],
@@ -299,8 +302,9 @@
"//build/bazel/platforms/os:darwin": ["darwin_include_dir"],
"//build/bazel/platforms/os:linux": ["linux_include_dir"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
@@ -330,9 +334,10 @@
no_libcrt: true,
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_headers(
- name = "lib-1",
- export_includes = ["lib-1"],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_headers", "lib-1", attrNameToString{
+ "export_includes": `["lib-1"]`,
+ }),
+ },
})
}
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index bb15776..4ec95c3 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -37,15 +37,15 @@
func runCcLibrarySharedTestCase(t *testing.T, tc bp2buildTestCase) {
t.Helper()
+ (&tc).moduleTypeUnderTest = "cc_library_shared"
+ (&tc).moduleTypeUnderTestFactory = cc.LibrarySharedFactory
+ (&tc).moduleTypeUnderTestBp2BuildMutator = cc.CcLibrarySharedBp2Build
runBp2BuildTestCase(t, registerCcLibrarySharedModuleTypes, tc)
}
func TestCcLibrarySharedSimple(t *testing.T) {
runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared simple overall test",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
+ description: "cc_library_shared simple overall test",
filesystem: map[string]string{
// NOTE: include_dir headers *should not* appear in Bazel hdrs later (?)
"include_dir_1/include_dir_1_a.h": "",
@@ -140,52 +140,50 @@
// TODO: Also support export_header_lib_headers
}`,
- expectedBazelTargets: []string{`cc_library_shared(
- name = "foo_shared",
- absolute_includes = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ "absolute_includes": `[
"include_dir_1",
"include_dir_2",
- ],
- copts = [
+ ]`,
+ "copts": `[
"-Dflag1",
"-Dflag2",
- ],
- export_includes = [
+ ]`,
+ "export_includes": `[
"export_include_dir_1",
"export_include_dir_2",
- ],
- implementation_deps = [
+ ]`,
+ "implementation_deps": `[
":header_lib_1",
":header_lib_2",
- ],
- implementation_dynamic_deps = [
+ ]`,
+ "implementation_dynamic_deps": `[
":shared_lib_1",
":shared_lib_2",
- ],
- local_includes = [
+ ]`,
+ "local_includes": `[
"local_include_dir_1",
"local_include_dir_2",
".",
- ],
- srcs = [
+ ]`,
+ "srcs": `[
"foo_shared1.cc",
"foo_shared2.cc",
- ],
- whole_archive_deps = [
+ ]`,
+ "whole_archive_deps": `[
":whole_static_lib_1",
":whole_static_lib_2",
- ],
-)`},
+ ]`,
+ }),
+ },
})
}
func TestCcLibrarySharedArchSpecificSharedLib(t *testing.T) {
runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared arch-specific shared_libs with whole_static_libs",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library_shared arch-specific shared_libs with whole_static_libs",
+ filesystem: map[string]string{},
blueprint: soongCcLibrarySharedPreamble + `
cc_library_static {
name: "static_dep",
@@ -200,27 +198,25 @@
arch: { arm64: { shared_libs: ["shared_dep"], whole_static_libs: ["static_dep"] } },
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_shared(
- name = "foo_shared",
- implementation_dynamic_deps = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ "implementation_dynamic_deps": `select({
"//build/bazel/platforms/arch:arm64": [":shared_dep"],
"//conditions:default": [],
- }),
- whole_archive_deps = select({
+ })`,
+ "whole_archive_deps": `select({
"//build/bazel/platforms/arch:arm64": [":static_dep"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibrarySharedOsSpecificSharedLib(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_shared os-specific shared_libs",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
- filesystem: map[string]string{},
+ runCcLibrarySharedTestCase(t, bp2buildTestCase{
+ description: "cc_library_shared os-specific shared_libs",
+ filesystem: map[string]string{},
blueprint: soongCcLibrarySharedPreamble + `
cc_library_shared {
name: "shared_dep",
@@ -231,23 +227,21 @@
target: { android: { shared_libs: ["shared_dep"], } },
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_shared(
- name = "foo_shared",
- implementation_dynamic_deps = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ "implementation_dynamic_deps": `select({
"//build/bazel/platforms/os:android": [":shared_dep"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibrarySharedBaseArchOsSpecificSharedLib(t *testing.T) {
runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared base, arch, and os-specific shared_libs",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library_shared base, arch, and os-specific shared_libs",
+ filesystem: map[string]string{},
blueprint: soongCcLibrarySharedPreamble + `
cc_library_shared {
name: "shared_dep",
@@ -268,25 +262,23 @@
arch: { arm64: { shared_libs: ["shared_dep3"] } },
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_shared(
- name = "foo_shared",
- implementation_dynamic_deps = [":shared_dep"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ "implementation_dynamic_deps": `[":shared_dep"] + select({
"//build/bazel/platforms/arch:arm64": [":shared_dep3"],
"//conditions:default": [],
}) + select({
"//build/bazel/platforms/os:android": [":shared_dep2"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibrarySharedSimpleExcludeSrcs(t *testing.T) {
runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared simple exclude_srcs",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
+ description: "cc_library_shared simple exclude_srcs",
filesystem: map[string]string{
"common.c": "",
"foo-a.c": "",
@@ -299,23 +291,21 @@
exclude_srcs: ["foo-excluded.c"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_shared(
- name = "foo_shared",
- srcs_c = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ "srcs_c": `[
"common.c",
"foo-a.c",
- ],
-)`},
+ ]`,
+ }),
+ },
})
}
func TestCcLibrarySharedStrip(t *testing.T) {
runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared stripping",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library_shared stripping",
+ filesystem: map[string]string{},
blueprint: soongCcLibrarySharedPreamble + `
cc_library_shared {
name: "foo_shared",
@@ -328,9 +318,9 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_shared(
- name = "foo_shared",
- strip = {
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ "strip": `{
"all": True,
"keep_symbols": False,
"keep_symbols_and_debug_frame": True,
@@ -339,17 +329,15 @@
"sym2",
],
"none": False,
- },
-)`},
+ }`,
+ }),
+ },
})
}
func TestCcLibrarySharedVersionScript(t *testing.T) {
runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared version script",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
+ description: "cc_library_shared version script",
filesystem: map[string]string{
"version_script": "",
},
@@ -359,20 +347,18 @@
version_script: "version_script",
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_shared(
- name = "foo_shared",
- additional_linker_inputs = ["version_script"],
- linkopts = ["-Wl,--version-script,$(location version_script)"],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ "additional_linker_inputs": `["version_script"]`,
+ "linkopts": `["-Wl,--version-script,$(location version_script)"]`,
+ }),
+ },
})
}
func TestCcLibrarySharedNoCrtTrue(t *testing.T) {
runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared - nocrt: true emits attribute",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
+ description: "cc_library_shared - nocrt: true emits attribute",
filesystem: map[string]string{
"impl.cpp": "",
},
@@ -384,19 +370,18 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library_shared(
- name = "foo_shared",
- link_crt = False,
- srcs = ["impl.cpp"],
-)`}})
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ "link_crt": `False`,
+ "srcs": `["impl.cpp"]`,
+ }),
+ },
+ })
}
func TestCcLibrarySharedNoCrtFalse(t *testing.T) {
runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared - nocrt: false doesn't emit attribute",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
+ description: "cc_library_shared - nocrt: false doesn't emit attribute",
filesystem: map[string]string{
"impl.cpp": "",
},
@@ -408,18 +393,17 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library_shared(
- name = "foo_shared",
- srcs = ["impl.cpp"],
-)`}})
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ "srcs": `["impl.cpp"]`,
+ }),
+ },
+ })
}
func TestCcLibrarySharedNoCrtArchVariant(t *testing.T) {
runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared - nocrt in select",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
+ description: "cc_library_shared - nocrt in select",
filesystem: map[string]string{
"impl.cpp": "",
},
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 9887811..2f760d2 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -79,15 +79,16 @@
func runCcLibraryStaticTestCase(t *testing.T, tc bp2buildTestCase) {
t.Helper()
+
+ (&tc).moduleTypeUnderTest = "cc_library_static"
+ (&tc).moduleTypeUnderTestFactory = cc.LibraryStaticFactory
+ (&tc).moduleTypeUnderTestBp2BuildMutator = cc.CcLibraryStaticBp2Build
runBp2BuildTestCase(t, registerCcLibraryStaticModuleTypes, tc)
}
func TestCcLibraryStaticSimple(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static test",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static test",
filesystem: map[string]string{
// NOTE: include_dir headers *should not* appear in Bazel hdrs later (?)
"include_dir_1/include_dir_1_a.h": "",
@@ -182,49 +183,47 @@
// TODO: Also support export_header_lib_headers
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- absolute_includes = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "absolute_includes": `[
"include_dir_1",
"include_dir_2",
- ],
- copts = [
+ ]`,
+ "copts": `[
"-Dflag1",
"-Dflag2",
- ],
- export_includes = [
+ ]`,
+ "export_includes": `[
"export_include_dir_1",
"export_include_dir_2",
- ],
- implementation_deps = [
+ ]`,
+ "implementation_deps": `[
":header_lib_1",
":header_lib_2",
":static_lib_1",
":static_lib_2",
- ],
- local_includes = [
+ ]`,
+ "local_includes": `[
"local_include_dir_1",
"local_include_dir_2",
".",
- ],
- srcs = [
+ ]`,
+ "srcs": `[
"foo_static1.cc",
"foo_static2.cc",
- ],
- whole_archive_deps = [
+ ]`,
+ "whole_archive_deps": `[
":whole_static_lib_1",
":whole_static_lib_2",
- ],
-)`},
+ ]`,
+ }),
+ },
})
}
func TestCcLibraryStaticSubpackage(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static subpackage test",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static subpackage test",
filesystem: map[string]string{
// subpackage with subdirectory
"subpackage/Android.bp": "",
@@ -247,20 +246,18 @@
"subpackage",
],
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- absolute_includes = ["subpackage"],
- local_includes = ["."],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "absolute_includes": `["subpackage"]`,
+ "local_includes": `["."]`,
+ }),
+ },
})
}
func TestCcLibraryStaticExportIncludeDir(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static export include dir",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static export include dir",
filesystem: map[string]string{
// subpackage with subdirectory
"subpackage/Android.bp": "",
@@ -273,19 +270,17 @@
export_include_dirs: ["subpackage"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- export_includes = ["subpackage"],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "export_includes": `["subpackage"]`,
+ }),
+ },
})
}
func TestCcLibraryStaticExportSystemIncludeDir(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static export system include dir",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static export system include dir",
filesystem: map[string]string{
// subpackage with subdirectory
"subpackage/Android.bp": "",
@@ -298,20 +293,18 @@
export_system_include_dirs: ["subpackage"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- export_system_includes = ["subpackage"],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "export_system_includes": `["subpackage"]`,
+ }),
+ },
})
}
func TestCcLibraryStaticManyIncludeDirs(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static include_dirs, local_include_dirs, export_include_dirs (b/183742505)",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- dir: "subpackage",
+ description: "cc_library_static include_dirs, local_include_dirs, export_include_dirs (b/183742505)",
+ dir: "subpackage",
filesystem: map[string]string{
// subpackage with subdirectory
"subpackage/Android.bp": `
@@ -335,28 +328,25 @@
"subpackage3/subsubpackage/header.h": "",
},
blueprint: soongCcLibraryStaticPreamble,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- absolute_includes = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "absolute_includes": `[
"subpackage/subsubpackage",
"subpackage2",
"subpackage3/subsubpackage",
- ],
- export_includes = ["./exported_subsubpackage"],
- local_includes = [
+ ]`,
+ "export_includes": `["./exported_subsubpackage"]`,
+ "local_includes": `[
"subsubpackage2",
".",
- ],
-)`},
+ ]`,
+ })},
})
}
func TestCcLibraryStaticIncludeBuildDirectoryDisabled(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static include_build_directory disabled",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static include_build_directory disabled",
filesystem: map[string]string{
// subpackage with subdirectory
"subpackage/Android.bp": "",
@@ -370,20 +360,18 @@
local_include_dirs: ["subpackage2"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- absolute_includes = ["subpackage"],
- local_includes = ["subpackage2"],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "absolute_includes": `["subpackage"]`,
+ "local_includes": `["subpackage2"]`,
+ }),
+ },
})
}
func TestCcLibraryStaticIncludeBuildDirectoryEnabled(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static include_build_directory enabled",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static include_build_directory enabled",
filesystem: map[string]string{
// subpackage with subdirectory
"subpackage/Android.bp": "",
@@ -399,24 +387,22 @@
local_include_dirs: ["subpackage2"],
include_build_directory: true,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- absolute_includes = ["subpackage"],
- local_includes = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "absolute_includes": `["subpackage"]`,
+ "local_includes": `[
"subpackage2",
".",
- ],
-)`},
+ ]`,
+ }),
+ },
})
}
func TestCcLibraryStaticArchSpecificStaticLib(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static arch-specific static_libs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library_static arch-specific static_libs",
+ filesystem: map[string]string{},
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "static_dep",
@@ -431,27 +417,25 @@
arch: { arm64: { static_libs: ["static_dep"], whole_static_libs: ["static_dep2"] } },
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- implementation_deps = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "implementation_deps": `select({
"//build/bazel/platforms/arch:arm64": [":static_dep"],
"//conditions:default": [],
- }),
- whole_archive_deps = select({
+ })`,
+ "whole_archive_deps": `select({
"//build/bazel/platforms/arch:arm64": [":static_dep2"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryStaticOsSpecificStaticLib(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static os-specific static_libs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library_static os-specific static_libs",
+ filesystem: map[string]string{},
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "static_dep",
@@ -466,27 +450,25 @@
target: { android: { static_libs: ["static_dep"], whole_static_libs: ["static_dep2"] } },
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- implementation_deps = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "implementation_deps": `select({
"//build/bazel/platforms/os:android": [":static_dep"],
"//conditions:default": [],
- }),
- whole_archive_deps = select({
+ })`,
+ "whole_archive_deps": `select({
"//build/bazel/platforms/os:android": [":static_dep2"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryStaticBaseArchOsSpecificStaticLib(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static base, arch and os-specific static_libs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library_static base, arch and os-specific static_libs",
+ filesystem: map[string]string{},
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "static_dep",
@@ -512,26 +494,24 @@
arch: { arm64: { static_libs: ["static_dep4"] } },
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- implementation_deps = [":static_dep"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "implementation_deps": `[":static_dep"] + select({
"//build/bazel/platforms/arch:arm64": [":static_dep4"],
"//conditions:default": [],
}) + select({
"//build/bazel/platforms/os:android": [":static_dep3"],
"//conditions:default": [],
- }),
- whole_archive_deps = [":static_dep2"],
-)`},
+ })`,
+ "whole_archive_deps": `[":static_dep2"]`,
+ }),
+ },
})
}
func TestCcLibraryStaticSimpleExcludeSrcs(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static simple exclude_srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static simple exclude_srcs",
filesystem: map[string]string{
"common.c": "",
"foo-a.c": "",
@@ -544,22 +524,20 @@
exclude_srcs: ["foo-excluded.c"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- srcs_c = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs_c": `[
"common.c",
"foo-a.c",
- ],
-)`},
+ ]`,
+ }),
+ },
})
}
func TestCcLibraryStaticOneArchSrcs(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static one arch specific srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static one arch specific srcs",
filesystem: map[string]string{
"common.c": "",
"foo-arm.c": "",
@@ -571,22 +549,20 @@
arch: { arm: { srcs: ["foo-arm.c"] } },
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- srcs_c = ["common.c"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs_c": `["common.c"] + select({
"//build/bazel/platforms/arch:arm": ["foo-arm.c"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryStaticOneArchSrcsExcludeSrcs(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static one arch specific srcs and exclude_srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static one arch specific srcs and exclude_srcs",
filesystem: map[string]string{
"common.c": "",
"for-arm.c": "",
@@ -603,22 +579,20 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- srcs_c = ["common.c"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs_c": `["common.c"] + select({
"//build/bazel/platforms/arch:arm": ["for-arm.c"],
"//conditions:default": ["not-for-arm.c"],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryStaticTwoArchExcludeSrcs(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static arch specific exclude_srcs for 2 architectures",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static arch specific exclude_srcs for 2 architectures",
filesystem: map[string]string{
"common.c": "",
"for-arm.c": "",
@@ -637,9 +611,9 @@
},
include_build_directory: false,
} `,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- srcs_c = ["common.c"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs_c": `["common.c"] + select({
"//build/bazel/platforms/arch:arm": [
"not-for-x86.c",
"for-arm.c",
@@ -652,16 +626,15 @@
"not-for-arm.c",
"not-for-x86.c",
],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
+
func TestCcLibraryStaticFourArchExcludeSrcs(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static arch specific exclude_srcs for 4 architectures",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static arch specific exclude_srcs for 4 architectures",
filesystem: map[string]string{
"common.c": "",
"for-arm.c": "",
@@ -687,9 +660,9 @@
},
include_build_directory: false,
} `,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- srcs_c = ["common.c"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs_c": `["common.c"] + select({
"//build/bazel/platforms/arch:arm": [
"not-for-arm64.c",
"not-for-x86.c",
@@ -720,17 +693,15 @@
"not-for-x86.c",
"not-for-x86_64.c",
],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryStaticOneArchEmpty(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static one arch empty",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static one arch empty",
filesystem: map[string]string{
"common.cc": "",
"foo-no-arm.cc": "",
@@ -746,22 +717,20 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- srcs = ["common.cc"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs": `["common.cc"] + select({
"//build/bazel/platforms/arch:arm": [],
"//conditions:default": ["foo-no-arm.cc"],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryStaticOneArchEmptyOtherSet(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static one arch empty other set",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static one arch empty other set",
filesystem: map[string]string{
"common.cc": "",
"foo-no-arm.cc": "",
@@ -779,27 +748,25 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- srcs = ["common.cc"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs": `["common.cc"] + select({
"//build/bazel/platforms/arch:arm": [],
"//build/bazel/platforms/arch:x86": [
"foo-no-arm.cc",
"x86-only.cc",
],
"//conditions:default": ["foo-no-arm.cc"],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryStaticMultipleDepSameName(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static multiple dep same name panic",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library_static multiple dep same name panic",
+ filesystem: map[string]string{},
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "static_dep",
@@ -810,19 +777,17 @@
static_libs: ["static_dep", "static_dep"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- implementation_deps = [":static_dep"],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "implementation_deps": `[":static_dep"]`,
+ }),
+ },
})
}
func TestCcLibraryStaticOneMultilibSrcsExcludeSrcs(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static 1 multilib srcs and exclude_srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static 1 multilib srcs and exclude_srcs",
filesystem: map[string]string{
"common.c": "",
"for-lib32.c": "",
@@ -837,23 +802,21 @@
},
include_build_directory: false,
} `,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- srcs_c = ["common.c"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs_c": `["common.c"] + select({
"//build/bazel/platforms/arch:arm": ["for-lib32.c"],
"//build/bazel/platforms/arch:x86": ["for-lib32.c"],
"//conditions:default": ["not-for-lib32.c"],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryStaticTwoMultilibSrcsExcludeSrcs(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static 2 multilib srcs and exclude_srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static 2 multilib srcs and exclude_srcs",
filesystem: map[string]string{
"common.c": "",
"for-lib32.c": "",
@@ -863,7 +826,7 @@
},
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
- name: "foo_static2",
+ name: "foo_static",
srcs: ["common.c", "not-for-*.c"],
multilib: {
lib32: { srcs: ["for-lib32.c"], exclude_srcs: ["not-for-lib32.c"] },
@@ -871,9 +834,9 @@
},
include_build_directory: false,
} `,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static2",
- srcs_c = ["common.c"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs_c": `["common.c"] + select({
"//build/bazel/platforms/arch:arm": [
"not-for-lib64.c",
"for-lib32.c",
@@ -894,17 +857,15 @@
"not-for-lib32.c",
"not-for-lib64.c",
],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibrarySTaticArchMultilibSrcsExcludeSrcs(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static arch and multilib srcs and exclude_srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static arch and multilib srcs and exclude_srcs",
filesystem: map[string]string{
"common.c": "",
"for-arm.c": "",
@@ -923,7 +884,7 @@
},
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
- name: "foo_static3",
+ name: "foo_static",
srcs: ["common.c", "not-for-*.c"],
exclude_srcs: ["not-for-everything.c"],
arch: {
@@ -938,9 +899,9 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static3",
- srcs_c = ["common.c"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs_c": `["common.c"] + select({
"//build/bazel/platforms/arch:arm": [
"not-for-arm64.c",
"not-for-lib64.c",
@@ -981,16 +942,14 @@
"not-for-x86.c",
"not-for-x86_64.c",
],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryStaticGeneratedHeadersAllPartitions(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
blueprint: soongCcLibraryStaticPreamble + `
genrule {
name: "generated_hdr",
@@ -1009,31 +968,29 @@
export_generated_headers: ["export_generated_hdr"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- hdrs = [":export_generated_hdr"],
- srcs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "hdrs": `[":export_generated_hdr"]`,
+ "srcs": `[
"cpp_src.cpp",
":generated_hdr",
- ],
- srcs_as = [
+ ]`,
+ "srcs_as": `[
"as_src.S",
":generated_hdr",
- ],
- srcs_c = [
+ ]`,
+ "srcs_c": `[
"c_src.c",
":generated_hdr",
- ],
-)`},
+ ]`,
+ }),
+ },
})
}
func TestCcLibraryStaticArchSrcsExcludeSrcsGeneratedFiles(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static arch srcs/exclude_srcs with generated files",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static arch srcs/exclude_srcs with generated files",
filesystem: map[string]string{
"common.cpp": "",
"for-x86.cpp": "",
@@ -1082,7 +1039,7 @@
}
cc_library_static {
- name: "foo_static3",
+ name: "foo_static",
srcs: ["common.cpp", "not-for-*.cpp"],
exclude_srcs: ["not-for-everything.cpp"],
generated_sources: ["generated_src", "generated_src_other_pkg", "generated_src_not_x86"],
@@ -1105,9 +1062,9 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static3",
- srcs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs": `[
"common.cpp",
":generated_src",
"//dep:generated_src_other_pkg",
@@ -1128,18 +1085,16 @@
"//dep:generated_hdr_other_pkg_android",
],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryStaticGetTargetProperties(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static complex GetTargetProperties",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static complex GetTargetProperties",
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
@@ -1168,9 +1123,9 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- srcs_c = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs_c": `select({
"//build/bazel/platforms/os:android": ["android_src.c"],
"//conditions:default": [],
}) + select({
@@ -1181,17 +1136,15 @@
"//build/bazel/platforms/os_arch:linux_bionic_arm64": ["linux_bionic_arm64_src.c"],
"//build/bazel/platforms/os_arch:linux_bionic_x86_64": ["linux_bionic_x86_64_src.c"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryStaticProductVariableSelects(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static product variable selects",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static product variable selects",
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
@@ -1209,9 +1162,9 @@
},
include_build_directory: false,
} `,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- copts = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "copts": `select({
"//build/bazel/product_variables:binder32bit": ["-Wbinder32bit"],
"//conditions:default": [],
}) + select({
@@ -1220,19 +1173,17 @@
}) + select({
"//build/bazel/product_variables:malloc_zero_contents": ["-Wmalloc_zero_contents"],
"//conditions:default": [],
- }),
- srcs_c = ["common.c"],
-)`},
+ })`,
+ "srcs_c": `["common.c"]`,
+ }),
+ },
})
}
func TestCcLibraryStaticProductVariableArchSpecificSelects(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static arch-specific product variable selects",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library_static arch-specific product variable selects",
+ filesystem: map[string]string{},
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
@@ -1271,9 +1222,9 @@
},
include_build_directory: false,
} `,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- copts = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "copts": `select({
"//build/bazel/product_variables:malloc_not_svelte": ["-Wmalloc_not_svelte"],
"//conditions:default": [],
}) + select({
@@ -1288,19 +1239,17 @@
}) + select({
"//build/bazel/product_variables:malloc_not_svelte-x86": ["-Wlib32_malloc_not_svelte"],
"//conditions:default": [],
- }),
- srcs_c = ["common.c"],
-)`},
+ })`,
+ "srcs_c": `["common.c"]`,
+ }),
+ },
})
}
func TestCcLibraryStaticProductVariableStringReplacement(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static product variable string replacement",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library_static product variable string replacement",
+ filesystem: map[string]string{},
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
@@ -1312,23 +1261,21 @@
},
include_build_directory: false,
} `,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- asflags = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "asflags": `select({
"//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
"//conditions:default": [],
- }),
- srcs_as = ["common.S"],
-)`},
+ })`,
+ "srcs_as": `["common.S"]`,
+ }),
+ },
})
}
func TestStaticLibrary_SystemSharedLibsRootEmpty(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static system_shared_lib empty root",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static system_shared_lib empty root",
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "root_empty",
@@ -1336,19 +1283,17 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "root_empty",
- system_dynamic_deps = [],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "root_empty", attrNameToString{
+ "system_dynamic_deps": `[]`,
+ }),
+ },
})
}
func TestStaticLibrary_SystemSharedLibsStaticEmpty(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static system_shared_lib empty static default",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static system_shared_lib empty static default",
blueprint: soongCcLibraryStaticPreamble + `
cc_defaults {
name: "static_empty_defaults",
@@ -1362,19 +1307,17 @@
defaults: ["static_empty_defaults"],
}
`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "static_empty",
- system_dynamic_deps = [],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "static_empty", attrNameToString{
+ "system_dynamic_deps": `[]`,
+ }),
+ },
})
}
func TestStaticLibrary_SystemSharedLibsBionicEmpty(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static system_shared_lib empty for bionic variant",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static system_shared_lib empty for bionic variant",
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "target_bionic_empty",
@@ -1386,10 +1329,11 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "target_bionic_empty",
- system_dynamic_deps = [],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "target_bionic_empty", attrNameToString{
+ "system_dynamic_deps": `[]`,
+ }),
+ },
})
}
@@ -1399,10 +1343,7 @@
// only for linux_bionic, but `android` had `["libc", "libdl", "libm"].
// b/195791252 tracks the fix.
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static system_shared_lib empty for linux_bionic variant",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static system_shared_lib empty for linux_bionic variant",
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "target_linux_bionic_empty",
@@ -1414,19 +1355,17 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "target_linux_bionic_empty",
- system_dynamic_deps = [],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "target_linux_bionic_empty", attrNameToString{
+ "system_dynamic_deps": `[]`,
+ }),
+ },
})
}
func TestStaticLibrary_SystemSharedLibsBionic(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static system_shared_libs set for bionic variant",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static system_shared_libs set for bionic variant",
blueprint: soongCcLibraryStaticPreamble + `
cc_library{name: "libc"}
@@ -1440,23 +1379,21 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "target_bionic",
- system_dynamic_deps = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "target_bionic", attrNameToString{
+ "system_dynamic_deps": `select({
"//build/bazel/platforms/os:android": [":libc"],
"//build/bazel/platforms/os:linux_bionic": [":libc"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestStaticLibrary_SystemSharedLibsLinuxRootAndLinuxBionic(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static system_shared_libs set for root and linux_bionic variant",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static system_shared_libs set for root and linux_bionic variant",
blueprint: soongCcLibraryStaticPreamble + `
cc_library{name: "libc"}
cc_library{name: "libm"}
@@ -1472,12 +1409,13 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "target_linux_bionic",
- system_dynamic_deps = [":libc"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "target_linux_bionic", attrNameToString{
+ "system_dynamic_deps": `[":libc"] + select({
"//build/bazel/platforms/os:linux_bionic": [":libm"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
index c4b276a..5ab9129 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -28,15 +28,15 @@
func runCcObjectTestCase(t *testing.T, tc bp2buildTestCase) {
t.Helper()
+ (&tc).moduleTypeUnderTest = "cc_object"
+ (&tc).moduleTypeUnderTestFactory = cc.ObjectFactory
+ (&tc).moduleTypeUnderTestBp2BuildMutator = cc.ObjectBp2Build
runBp2BuildTestCase(t, registerCcObjectModuleTypes, tc)
}
func TestCcObjectSimple(t *testing.T) {
runCcObjectTestCase(t, bp2buildTestCase{
- description: "simple cc_object generates cc_object with include header dep",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ description: "simple cc_object generates cc_object with include header dep",
filesystem: map[string]string{
"a/b/foo.h": "",
"a/b/bar.h": "",
@@ -58,30 +58,27 @@
exclude_srcs: ["a/b/exclude.c"],
}
`,
- expectedBazelTargets: []string{`cc_object(
- name = "foo",
- copts = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_object", "foo", attrNameToString{
+ "copts": `[
"-fno-addrsig",
"-Wno-gcc-compat",
"-Wall",
"-Werror",
- ],
- local_includes = [
+ ]`,
+ "local_includes": `[
"include",
".",
- ],
- srcs = ["a/b/c.c"],
- system_dynamic_deps = [],
-)`,
+ ]`,
+ "srcs": `["a/b/c.c"]`,
+ "system_dynamic_deps": `[]`,
+ }),
},
})
}
func TestCcObjectDefaults(t *testing.T) {
runCcObjectTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
blueprint: `cc_object {
name: "foo",
system_shared_libs: [],
@@ -101,33 +98,26 @@
cc_defaults {
name: "foo_bar_defaults",
cflags: [
- "-Wno-gcc-compat",
- "-Wall",
"-Werror",
],
}
`,
- expectedBazelTargets: []string{`cc_object(
- name = "foo",
- copts = [
- "-Wno-gcc-compat",
- "-Wall",
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_object", "foo", attrNameToString{
+ "copts": `[
"-Werror",
"-fno-addrsig",
- ],
- local_includes = ["."],
- srcs = ["a/b/c.c"],
- system_dynamic_deps = [],
-)`,
+ ]`,
+ "local_includes": `["."]`,
+ "srcs": `["a/b/c.c"]`,
+ "system_dynamic_deps": `[]`,
+ }),
}})
}
func TestCcObjectCcObjetDepsInObjs(t *testing.T) {
runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object with cc_object deps in objs props",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ description: "cc_object with cc_object deps in objs props",
filesystem: map[string]string{
"a/b/c.c": "",
"x/y/z.c": "",
@@ -147,28 +137,24 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_object(
- name = "bar",
- copts = ["-fno-addrsig"],
- srcs = ["x/y/z.c"],
- system_dynamic_deps = [],
-)`, `cc_object(
- name = "foo",
- copts = ["-fno-addrsig"],
- deps = [":bar"],
- srcs = ["a/b/c.c"],
- system_dynamic_deps = [],
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_object", "bar", attrNameToString{
+ "copts": `["-fno-addrsig"]`,
+ "srcs": `["x/y/z.c"]`,
+ "system_dynamic_deps": `[]`,
+ }), makeBazelTarget("cc_object", "foo", attrNameToString{
+ "copts": `["-fno-addrsig"]`,
+ "deps": `[":bar"]`,
+ "srcs": `["a/b/c.c"]`,
+ "system_dynamic_deps": `[]`,
+ }),
},
})
}
func TestCcObjectIncludeBuildDirFalse(t *testing.T) {
runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object with include_build_dir: false",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ description: "cc_object with include_build_dir: false",
filesystem: map[string]string{
"a/b/c.c": "",
"x/y/z.c": "",
@@ -180,22 +166,19 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_object(
- name = "foo",
- copts = ["-fno-addrsig"],
- srcs = ["a/b/c.c"],
- system_dynamic_deps = [],
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_object", "foo", attrNameToString{
+ "copts": `["-fno-addrsig"]`,
+ "srcs": `["a/b/c.c"]`,
+ "system_dynamic_deps": `[]`,
+ }),
},
})
}
func TestCcObjectProductVariable(t *testing.T) {
runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object with product variable",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ description: "cc_object with product variable",
blueprint: `cc_object {
name: "foo",
system_shared_libs: [],
@@ -208,26 +191,23 @@
srcs: ["src.S"],
}
`,
- expectedBazelTargets: []string{`cc_object(
- name = "foo",
- asflags = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_object", "foo", attrNameToString{
+ "asflags": `select({
"//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
"//conditions:default": [],
- }),
- copts = ["-fno-addrsig"],
- srcs_as = ["src.S"],
- system_dynamic_deps = [],
-)`,
+ })`,
+ "copts": `["-fno-addrsig"]`,
+ "srcs_as": `["src.S"]`,
+ "system_dynamic_deps": `[]`,
+ }),
},
})
}
func TestCcObjectCflagsOneArch(t *testing.T) {
runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object setting cflags for one arch",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ description: "cc_object setting cflags for one arch",
blueprint: `cc_object {
name: "foo",
system_shared_libs: [],
@@ -244,28 +224,24 @@
}
`,
expectedBazelTargets: []string{
- `cc_object(
- name = "foo",
- copts = ["-fno-addrsig"] + select({
+ makeBazelTarget("cc_object", "foo", attrNameToString{
+ "copts": `["-fno-addrsig"] + select({
"//build/bazel/platforms/arch:x86": ["-fPIC"],
"//conditions:default": [],
- }),
- srcs = ["a.cpp"] + select({
+ })`,
+ "srcs": `["a.cpp"] + select({
"//build/bazel/platforms/arch:arm": ["arch/arm/file.cpp"],
"//conditions:default": [],
- }),
- system_dynamic_deps = [],
-)`,
+ })`,
+ "system_dynamic_deps": `[]`,
+ }),
},
})
}
func TestCcObjectCflagsFourArch(t *testing.T) {
runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object setting cflags for 4 architectures",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ description: "cc_object setting cflags for 4 architectures",
blueprint: `cc_object {
name: "foo",
system_shared_libs: [],
@@ -292,34 +268,30 @@
}
`,
expectedBazelTargets: []string{
- `cc_object(
- name = "foo",
- copts = ["-fno-addrsig"] + select({
+ makeBazelTarget("cc_object", "foo", attrNameToString{
+ "copts": `["-fno-addrsig"] + select({
"//build/bazel/platforms/arch:arm": ["-Wall"],
"//build/bazel/platforms/arch:arm64": ["-Wall"],
"//build/bazel/platforms/arch:x86": ["-fPIC"],
"//build/bazel/platforms/arch:x86_64": ["-fPIC"],
"//conditions:default": [],
- }),
- srcs = ["base.cpp"] + select({
+ })`,
+ "srcs": `["base.cpp"] + select({
"//build/bazel/platforms/arch:arm": ["arm.cpp"],
"//build/bazel/platforms/arch:arm64": ["arm64.cpp"],
"//build/bazel/platforms/arch:x86": ["x86.cpp"],
"//build/bazel/platforms/arch:x86_64": ["x86_64.cpp"],
"//conditions:default": [],
- }),
- system_dynamic_deps = [],
-)`,
+ })`,
+ "system_dynamic_deps": `[]`,
+ }),
},
})
}
func TestCcObjectLinkerScript(t *testing.T) {
runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object setting linker_script",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ description: "cc_object setting linker_script",
blueprint: `cc_object {
name: "foo",
srcs: ["base.cpp"],
@@ -328,22 +300,18 @@
}
`,
expectedBazelTargets: []string{
- `cc_object(
- name = "foo",
- copts = ["-fno-addrsig"],
- linker_script = "bunny.lds",
- srcs = ["base.cpp"],
-)`,
+ makeBazelTarget("cc_object", "foo", attrNameToString{
+ "copts": `["-fno-addrsig"]`,
+ "linker_script": `"bunny.lds"`,
+ "srcs": `["base.cpp"]`,
+ }),
},
})
}
func TestCcObjectDepsAndLinkerScriptSelects(t *testing.T) {
runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object setting deps and linker_script across archs",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ description: "cc_object setting deps and linker_script across archs",
blueprint: `cc_object {
name: "foo",
srcs: ["base.cpp"],
@@ -389,33 +357,29 @@
}
`,
expectedBazelTargets: []string{
- `cc_object(
- name = "foo",
- copts = ["-fno-addrsig"],
- deps = select({
+ makeBazelTarget("cc_object", "foo", attrNameToString{
+ "copts": `["-fno-addrsig"]`,
+ "deps": `select({
"//build/bazel/platforms/arch:arm": [":arm_obj"],
"//build/bazel/platforms/arch:x86": [":x86_obj"],
"//build/bazel/platforms/arch:x86_64": [":x86_64_obj"],
"//conditions:default": [],
- }),
- linker_script = select({
+ })`,
+ "linker_script": `select({
"//build/bazel/platforms/arch:arm": "arm.lds",
"//build/bazel/platforms/arch:x86": "x86.lds",
"//build/bazel/platforms/arch:x86_64": "x86_64.lds",
"//conditions:default": None,
- }),
- srcs = ["base.cpp"],
-)`,
+ })`,
+ "srcs": `["base.cpp"]`,
+ }),
},
})
}
func TestCcObjectSelectOnLinuxAndBionicArchs(t *testing.T) {
runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object setting srcs based on linux and bionic archs",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ description: "cc_object setting srcs based on linux and bionic archs",
blueprint: `cc_object {
name: "foo",
srcs: ["base.cpp"],
@@ -434,10 +398,9 @@
}
`,
expectedBazelTargets: []string{
- `cc_object(
- name = "foo",
- copts = ["-fno-addrsig"],
- srcs = ["base.cpp"] + select({
+ makeBazelTarget("cc_object", "foo", attrNameToString{
+ "copts": `["-fno-addrsig"]`,
+ "srcs": `["base.cpp"] + select({
"//build/bazel/platforms/os_arch:android_arm64": [
"linux_arm64.cpp",
"bionic_arm64.cpp",
@@ -450,8 +413,8 @@
"//build/bazel/platforms/os_arch:linux_glibc_x86": ["linux_x86.cpp"],
"//build/bazel/platforms/os_arch:linux_musl_x86": ["linux_x86.cpp"],
"//conditions:default": [],
- }),
-)`,
+ })`,
+ }),
},
})
}
diff --git a/bp2build/cc_prebuilt_library_shared_test.go b/bp2build/cc_prebuilt_library_shared_test.go
index 97545c8..bac3908 100644
--- a/bp2build/cc_prebuilt_library_shared_test.go
+++ b/bp2build/cc_prebuilt_library_shared_test.go
@@ -23,10 +23,9 @@
bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{
- `prebuilt_library_shared(
- name = "libtest",
- shared_library = "libf.so",
-)`,
+ makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{
+ "shared_library": `"libf.so"`,
+ }),
},
})
}
@@ -52,14 +51,13 @@
bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{
- `prebuilt_library_shared(
- name = "libtest",
- shared_library = select({
+ makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{
+ "shared_library": `select({
"//build/bazel/platforms/arch:arm": "libg.so",
"//build/bazel/platforms/arch:arm64": "libf.so",
"//conditions:default": None,
- }),
-)`,
+ })`,
+ }),
},
})
}
diff --git a/bp2build/filegroup_conversion_test.go b/bp2build/filegroup_conversion_test.go
index ad99236..9f4add2 100644
--- a/bp2build/filegroup_conversion_test.go
+++ b/bp2build/filegroup_conversion_test.go
@@ -23,6 +23,9 @@
func runFilegroupTestCase(t *testing.T, tc bp2buildTestCase) {
t.Helper()
+ (&tc).moduleTypeUnderTest = "filegroup"
+ (&tc).moduleTypeUnderTestFactory = android.FileGroupFactory
+ (&tc).moduleTypeUnderTestBp2BuildMutator = android.FilegroupBp2Build
runBp2BuildTestCase(t, registerFilegroupModuleTypes, tc)
}
@@ -30,11 +33,8 @@
func TestFilegroupSameNameAsFile_OneFile(t *testing.T) {
runFilegroupTestCase(t, bp2buildTestCase{
- description: "filegroup - same name as file, with one file",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
- filesystem: map[string]string{},
+ description: "filegroup - same name as file, with one file",
+ filesystem: map[string]string{},
blueprint: `
filegroup {
name: "foo",
@@ -46,11 +46,8 @@
func TestFilegroupSameNameAsFile_MultipleFiles(t *testing.T) {
runFilegroupTestCase(t, bp2buildTestCase{
- description: "filegroup - same name as file, with multiple files",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
- filesystem: map[string]string{},
+ description: "filegroup - same name as file, with multiple files",
+ filesystem: map[string]string{},
blueprint: `
filegroup {
name: "foo",
diff --git a/bp2build/genrule_conversion_test.go b/bp2build/genrule_conversion_test.go
index f3bc1ba..5976666 100644
--- a/bp2build/genrule_conversion_test.go
+++ b/bp2build/genrule_conversion_test.go
@@ -17,10 +17,21 @@
import (
"android/soong/android"
"android/soong/genrule"
- "strings"
"testing"
)
+func registerGenruleModuleTypes(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("genrule_defaults", func() android.Module { return genrule.DefaultsFactory() })
+}
+
+func runGenruleTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ (&tc).moduleTypeUnderTest = "genrule"
+ (&tc).moduleTypeUnderTestFactory = genrule.GenRuleFactory
+ (&tc).moduleTypeUnderTestBp2BuildMutator = genrule.GenruleBp2Build
+ runBp2BuildTestCase(t, registerGenruleModuleTypes, tc)
+}
+
func TestGenruleBp2Build(t *testing.T) {
otherGenruleBp := map[string]string{
"other/Android.bp": `genrule {
@@ -39,10 +50,7 @@
testCases := []bp2buildTestCase{
{
- description: "genrule with command line variable replacements",
- moduleTypeUnderTest: "genrule",
- moduleTypeUnderTestFactory: genrule.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+ description: "genrule with command line variable replacements",
blueprint: `genrule {
name: "foo.tool",
out: ["foo_tool.out"],
@@ -60,26 +68,21 @@
bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{
- `genrule(
- name = "foo",
- cmd = "$(location :foo.tool) --genDir=$(GENDIR) arg $(SRCS) $(OUTS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
- tools = [":foo.tool"],
-)`,
- `genrule(
- name = "foo.tool",
- cmd = "cp $(SRCS) $(OUTS)",
- outs = ["foo_tool.out"],
- srcs = ["foo_tool.in"],
-)`,
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(location :foo.tool) --genDir=$(GENDIR) arg $(SRCS) $(OUTS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ "tools": `[":foo.tool"]`,
+ }),
+ makeBazelTarget("genrule", "foo.tool", attrNameToString{
+ "cmd": `"cp $(SRCS) $(OUTS)"`,
+ "outs": `["foo_tool.out"]`,
+ "srcs": `["foo_tool.in"]`,
+ }),
},
},
{
- description: "genrule using $(locations :label)",
- moduleTypeUnderTest: "genrule",
- moduleTypeUnderTestFactory: genrule.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+ description: "genrule using $(locations :label)",
blueprint: `genrule {
name: "foo.tools",
out: ["foo_tool.out", "foo_tool2.out"],
@@ -96,29 +99,25 @@
cmd: "$(locations :foo.tools) -s $(out) $(in)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "$(locations :foo.tools) -s $(OUTS) $(SRCS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
- tools = [":foo.tools"],
-)`,
- `genrule(
- name = "foo.tools",
- cmd = "cp $(SRCS) $(OUTS)",
- outs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(locations :foo.tools) -s $(OUTS) $(SRCS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ "tools": `[":foo.tools"]`,
+ }),
+ makeBazelTarget("genrule", "foo.tools", attrNameToString{
+ "cmd": `"cp $(SRCS) $(OUTS)"`,
+ "outs": `[
"foo_tool.out",
"foo_tool2.out",
- ],
- srcs = ["foo_tool.in"],
-)`,
+ ]`,
+ "srcs": `["foo_tool.in"]`,
+ }),
},
},
{
- description: "genrule using $(locations //absolute:label)",
- moduleTypeUnderTest: "genrule",
- moduleTypeUnderTestFactory: genrule.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+ description: "genrule using $(locations //absolute:label)",
blueprint: `genrule {
name: "foo",
out: ["foo.out"],
@@ -127,21 +126,18 @@
cmd: "$(locations :foo.tool) -s $(out) $(in)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
- tools = ["//other:foo.tool"],
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(locations //other:foo.tool) -s $(OUTS) $(SRCS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ "tools": `["//other:foo.tool"]`,
+ }),
},
filesystem: otherGenruleBp,
},
{
- description: "genrule srcs using $(locations //absolute:label)",
- moduleTypeUnderTest: "genrule",
- moduleTypeUnderTestFactory: genrule.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+ description: "genrule srcs using $(locations //absolute:label)",
blueprint: `genrule {
name: "foo",
out: ["foo.out"],
@@ -150,21 +146,18 @@
cmd: "$(locations :foo.tool) -s $(out) $(location :other.tool)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "$(locations //other:foo.tool) -s $(OUTS) $(location //other:other.tool)",
- outs = ["foo.out"],
- srcs = ["//other:other.tool"],
- tools = ["//other:foo.tool"],
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(locations //other:foo.tool) -s $(OUTS) $(location //other:other.tool)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["//other:other.tool"]`,
+ "tools": `["//other:foo.tool"]`,
+ }),
},
filesystem: otherGenruleBp,
},
{
- description: "genrule using $(location) label should substitute first tool label automatically",
- moduleTypeUnderTest: "genrule",
- moduleTypeUnderTestFactory: genrule.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+ description: "genrule using $(location) label should substitute first tool label automatically",
blueprint: `genrule {
name: "foo",
out: ["foo.out"],
@@ -173,24 +166,21 @@
cmd: "$(location) -s $(out) $(in)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "$(location //other:foo.tool) -s $(OUTS) $(SRCS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
- tools = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(location //other:foo.tool) -s $(OUTS) $(SRCS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ "tools": `[
"//other:foo.tool",
"//other:other.tool",
- ],
-)`,
+ ]`,
+ }),
},
filesystem: otherGenruleBp,
},
{
- description: "genrule using $(locations) label should substitute first tool label automatically",
- moduleTypeUnderTest: "genrule",
- moduleTypeUnderTestFactory: genrule.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+ description: "genrule using $(locations) label should substitute first tool label automatically",
blueprint: `genrule {
name: "foo",
out: ["foo.out"],
@@ -199,24 +189,21 @@
cmd: "$(locations) -s $(out) $(in)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
- tools = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(locations //other:foo.tool) -s $(OUTS) $(SRCS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ "tools": `[
"//other:foo.tool",
"//other:other.tool",
- ],
-)`,
+ ]`,
+ }),
},
filesystem: otherGenruleBp,
},
{
- description: "genrule without tools or tool_files can convert successfully",
- moduleTypeUnderTest: "genrule",
- moduleTypeUnderTestFactory: genrule.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+ description: "genrule without tools or tool_files can convert successfully",
blueprint: `genrule {
name: "foo",
out: ["foo.out"],
@@ -224,85 +211,28 @@
cmd: "cp $(in) $(out)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "cp $(SRCS) $(OUTS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"cp $(SRCS) $(OUTS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ }),
},
},
}
- dir := "."
for _, testCase := range testCases {
- fs := make(map[string][]byte)
- toParse := []string{
- "Android.bp",
- }
- for f, content := range testCase.filesystem {
- if strings.HasSuffix(f, "Android.bp") {
- toParse = append(toParse, f)
- }
- fs[f] = []byte(content)
- }
- config := android.TestConfig(buildDir, nil, testCase.blueprint, fs)
- ctx := android.NewTestContext(config)
- ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
- ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
- ctx.RegisterForBazelConversion()
-
- _, errs := ctx.ParseFileList(dir, toParse)
- if errored(t, testCase, errs) {
- continue
- }
- _, errs = ctx.ResolveDependencies(config)
- if errored(t, testCase, errs) {
- continue
- }
-
- checkDir := dir
- if testCase.dir != "" {
- checkDir = testCase.dir
- }
-
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- bazelTargets, err := generateBazelTargetsForDir(codegenCtx, checkDir)
- android.FailIfErrored(t, err)
- if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
- t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount)
- } else {
- for i, target := range bazelTargets {
- if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
- t.Errorf(
- "%s: Expected generated Bazel target to be '%s', got '%s'",
- testCase.description,
- w,
- g,
- )
- }
- }
- }
+ t.Run(testCase.description, func(t *testing.T) {
+ runGenruleTestCase(t, testCase)
+ })
}
}
func TestBp2BuildInlinesDefaults(t *testing.T) {
- testCases := []struct {
- moduleTypesUnderTest map[string]android.ModuleFactory
- bp2buildMutatorsUnderTest map[string]bp2buildMutator
- bp string
- expectedBazelTarget string
- description string
- }{
+ testCases := []bp2buildTestCase{
{
- moduleTypesUnderTest: map[string]android.ModuleFactory{
- "genrule": genrule.GenRuleFactory,
- "genrule_defaults": func() android.Module { return genrule.DefaultsFactory() },
- },
- bp2buildMutatorsUnderTest: map[string]bp2buildMutator{
- "genrule": genrule.GenruleBp2Build,
- },
- bp: `genrule_defaults {
+ description: "genrule applies properties from a genrule_defaults dependency if not specified",
+ blueprint: `genrule_defaults {
name: "gen_defaults",
cmd: "do-something $(in) $(out)",
}
@@ -314,23 +244,17 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTarget: `genrule(
- name = "gen",
- cmd = "do-something $(SRCS) $(OUTS)",
- outs = ["out"],
- srcs = ["in1"],
-)`,
- description: "genrule applies properties from a genrule_defaults dependency if not specified",
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "gen", attrNameToString{
+ "cmd": `"do-something $(SRCS) $(OUTS)"`,
+ "outs": `["out"]`,
+ "srcs": `["in1"]`,
+ }),
+ },
},
{
- moduleTypesUnderTest: map[string]android.ModuleFactory{
- "genrule": genrule.GenRuleFactory,
- "genrule_defaults": func() android.Module { return genrule.DefaultsFactory() },
- },
- bp2buildMutatorsUnderTest: map[string]bp2buildMutator{
- "genrule": genrule.GenruleBp2Build,
- },
- bp: `genrule_defaults {
+ description: "genrule does merges properties from a genrule_defaults dependency, latest-first",
+ blueprint: `genrule_defaults {
name: "gen_defaults",
out: ["out-from-defaults"],
srcs: ["in-from-defaults"],
@@ -345,29 +269,23 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTarget: `genrule(
- name = "gen",
- cmd = "do-something $(SRCS) $(OUTS)",
- outs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "gen", attrNameToString{
+ "cmd": `"do-something $(SRCS) $(OUTS)"`,
+ "outs": `[
"out-from-defaults",
"out",
- ],
- srcs = [
+ ]`,
+ "srcs": `[
"in-from-defaults",
"in1",
- ],
-)`,
- description: "genrule does merges properties from a genrule_defaults dependency, latest-first",
+ ]`,
+ }),
+ },
},
{
- moduleTypesUnderTest: map[string]android.ModuleFactory{
- "genrule": genrule.GenRuleFactory,
- "genrule_defaults": func() android.Module { return genrule.DefaultsFactory() },
- },
- bp2buildMutatorsUnderTest: map[string]bp2buildMutator{
- "genrule": genrule.GenruleBp2Build,
- },
- bp: `genrule_defaults {
+ description: "genrule applies properties from list of genrule_defaults",
+ blueprint: `genrule_defaults {
name: "gen_defaults1",
cmd: "cp $(in) $(out)",
}
@@ -384,23 +302,17 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTarget: `genrule(
- name = "gen",
- cmd = "cp $(SRCS) $(OUTS)",
- outs = ["out"],
- srcs = ["in1"],
-)`,
- description: "genrule applies properties from list of genrule_defaults",
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "gen", attrNameToString{
+ "cmd": `"cp $(SRCS) $(OUTS)"`,
+ "outs": `["out"]`,
+ "srcs": `["in1"]`,
+ }),
+ },
},
{
- moduleTypesUnderTest: map[string]android.ModuleFactory{
- "genrule": genrule.GenRuleFactory,
- "genrule_defaults": func() android.Module { return genrule.DefaultsFactory() },
- },
- bp2buildMutatorsUnderTest: map[string]bp2buildMutator{
- "genrule": genrule.GenruleBp2Build,
- },
- bp: `genrule_defaults {
+ description: "genrule applies properties from genrule_defaults transitively",
+ blueprint: `genrule_defaults {
name: "gen_defaults1",
defaults: ["gen_defaults2"],
cmd: "cmd1 $(in) $(out)", // overrides gen_defaults2's cmd property value.
@@ -427,55 +339,26 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTarget: `genrule(
- name = "gen",
- cmd = "cmd1 $(SRCS) $(OUTS)",
- outs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "gen", attrNameToString{
+ "cmd": `"cmd1 $(SRCS) $(OUTS)"`,
+ "outs": `[
"out-from-3",
"out-from-2",
"out",
- ],
- srcs = [
+ ]`,
+ "srcs": `[
"srcs-from-3",
"in1",
- ],
-)`,
- description: "genrule applies properties from genrule_defaults transitively",
+ ]`,
+ }),
+ },
},
}
- dir := "."
for _, testCase := range testCases {
- config := android.TestConfig(buildDir, nil, testCase.bp, nil)
- ctx := android.NewTestContext(config)
- for m, factory := range testCase.moduleTypesUnderTest {
- ctx.RegisterModuleType(m, factory)
- }
- for mutator, f := range testCase.bp2buildMutatorsUnderTest {
- ctx.RegisterBp2BuildMutator(mutator, f)
- }
- ctx.RegisterForBazelConversion()
-
- _, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
- android.FailIfErrored(t, errs)
- _, errs = ctx.ResolveDependencies(config)
- android.FailIfErrored(t, errs)
-
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
- android.FailIfErrored(t, err)
- if actualCount := len(bazelTargets); actualCount != 1 {
- t.Fatalf("%s: Expected 1 bazel target, got %d", testCase.description, actualCount)
- }
-
- actualBazelTarget := bazelTargets[0]
- if actualBazelTarget.content != testCase.expectedBazelTarget {
- t.Errorf(
- "%s: Expected generated Bazel target to be '%s', got '%s'",
- testCase.description,
- testCase.expectedBazelTarget,
- actualBazelTarget.content,
- )
- }
+ t.Run(testCase.description, func(t *testing.T) {
+ runGenruleTestCase(t, testCase)
+ })
}
}
diff --git a/bp2build/prebuilt_etc_conversion_test.go b/bp2build/prebuilt_etc_conversion_test.go
index 62e407b..1189309 100644
--- a/bp2build/prebuilt_etc_conversion_test.go
+++ b/bp2build/prebuilt_etc_conversion_test.go
@@ -23,6 +23,9 @@
func runPrebuiltEtcTestCase(t *testing.T, tc bp2buildTestCase) {
t.Helper()
+ (&tc).moduleTypeUnderTest = "prebuilt_etc"
+ (&tc).moduleTypeUnderTestFactory = etc.PrebuiltEtcFactory
+ (&tc).moduleTypeUnderTestBp2BuildMutator = etc.PrebuiltEtcBp2Build
runBp2BuildTestCase(t, registerPrebuiltEtcModuleTypes, tc)
}
@@ -31,11 +34,8 @@
func TestPrebuiltEtcSimple(t *testing.T) {
runPrebuiltEtcTestCase(t, bp2buildTestCase{
- description: "prebuilt_etc - simple example",
- moduleTypeUnderTest: "prebuilt_etc",
- moduleTypeUnderTestFactory: etc.PrebuiltEtcFactory,
- moduleTypeUnderTestBp2BuildMutator: etc.PrebuiltEtcBp2Build,
- filesystem: map[string]string{},
+ description: "prebuilt_etc - simple example",
+ filesystem: map[string]string{},
blueprint: `
prebuilt_etc {
name: "apex_tz_version",
@@ -45,22 +45,19 @@
installable: false,
}
`,
- expectedBazelTargets: []string{`prebuilt_etc(
- name = "apex_tz_version",
- filename = "tz_version",
- installable = False,
- src = "version/tz_version",
- sub_dir = "tz",
-)`}})
+ expectedBazelTargets: []string{
+ makeBazelTarget("prebuilt_etc", "apex_tz_version", attrNameToString{
+ "filename": `"tz_version"`,
+ "installable": `False`,
+ "src": `"version/tz_version"`,
+ "sub_dir": `"tz"`,
+ })}})
}
func TestPrebuiltEtcArchVariant(t *testing.T) {
runPrebuiltEtcTestCase(t, bp2buildTestCase{
- description: "prebuilt_etc - simple example",
- moduleTypeUnderTest: "prebuilt_etc",
- moduleTypeUnderTestFactory: etc.PrebuiltEtcFactory,
- moduleTypeUnderTestBp2BuildMutator: etc.PrebuiltEtcBp2Build,
- filesystem: map[string]string{},
+ description: "prebuilt_etc - arch variant",
+ filesystem: map[string]string{},
blueprint: `
prebuilt_etc {
name: "apex_tz_version",
@@ -78,15 +75,15 @@
}
}
`,
- expectedBazelTargets: []string{`prebuilt_etc(
- name = "apex_tz_version",
- filename = "tz_version",
- installable = False,
- src = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("prebuilt_etc", "apex_tz_version", attrNameToString{
+ "filename": `"tz_version"`,
+ "installable": `False`,
+ "src": `select({
"//build/bazel/platforms/arch:arm": "arm",
"//build/bazel/platforms/arch:arm64": "arm64",
"//conditions:default": "version/tz_version",
- }),
- sub_dir = "tz",
-)`}})
+ })`,
+ "sub_dir": `"tz"`,
+ })}})
}
diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go
index 5b4829e..01b6aa2 100644
--- a/bp2build/python_binary_conversion_test.go
+++ b/bp2build/python_binary_conversion_test.go
@@ -7,7 +7,8 @@
"android/soong/python"
)
-func runBp2BuildTestCaseWithLibs(t *testing.T, tc bp2buildTestCase) {
+func runBp2BuildTestCaseWithPythonLibraries(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
ctx.RegisterModuleType("python_library", python.PythonLibraryFactory)
ctx.RegisterModuleType("python_library_host", python.PythonLibraryHostFactory)
@@ -15,7 +16,7 @@
}
func TestPythonBinaryHostSimple(t *testing.T) {
- runBp2BuildTestCaseWithLibs(t, bp2buildTestCase{
+ runBp2BuildTestCaseWithPythonLibraries(t, bp2buildTestCase{
description: "simple python_binary_host converts to a native py_binary",
moduleTypeUnderTest: "python_binary_host",
moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
@@ -41,17 +42,17 @@
srcs: ["b/e.py"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`py_binary(
- name = "foo",
- data = ["files/data.txt"],
- deps = [":bar"],
- main = "a.py",
- srcs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("py_binary", "foo", attrNameToString{
+ "data": `["files/data.txt"]`,
+ "deps": `[":bar"]`,
+ "main": `"a.py"`,
+ "srcs": `[
"a.py",
"b/c.py",
"b/d.py",
- ],
-)`,
+ ]`,
+ }),
},
})
}
@@ -77,11 +78,11 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTargets: []string{`py_binary(
- name = "foo",
- python_version = "PY2",
- srcs = ["a.py"],
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("py_binary", "foo", attrNameToString{
+ "python_version": `"PY2"`,
+ "srcs": `["a.py"]`,
+ }),
},
})
}
@@ -109,10 +110,9 @@
`,
expectedBazelTargets: []string{
// python_version is PY3 by default.
- `py_binary(
- name = "foo",
- srcs = ["a.py"],
-)`,
+ makeBazelTarget("py_binary", "foo", attrNameToString{
+ "srcs": `["a.py"]`,
+ }),
},
})
}
@@ -139,14 +139,13 @@
},
}`,
expectedBazelTargets: []string{
- `py_binary(
- name = "foo-arm",
- srcs = select({
+ makeBazelTarget("py_binary", "foo-arm", attrNameToString{
+ "srcs": `select({
"//build/bazel/platforms/arch:arm": ["arm.py"],
"//build/bazel/platforms/arch:x86": ["x86.py"],
"//conditions:default": [],
- }),
-)`,
+ })`,
+ }),
},
})
}
diff --git a/bp2build/python_library_conversion_test.go b/bp2build/python_library_conversion_test.go
index 7f983ad..e334592 100644
--- a/bp2build/python_library_conversion_test.go
+++ b/bp2build/python_library_conversion_test.go
@@ -11,38 +11,49 @@
// TODO(alexmarquez): Should be lifted into a generic Bp2Build file
type PythonLibBp2Build func(ctx android.TopDownMutatorContext)
-func TestPythonLibrary(t *testing.T) {
- testPythonLib(t, "python_library",
- python.PythonLibraryFactory, python.PythonLibraryBp2Build,
- func(ctx android.RegistrationContext) {})
-}
-
-func TestPythonLibraryHost(t *testing.T) {
- testPythonLib(t, "python_library_host",
- python.PythonLibraryHostFactory, python.PythonLibraryHostBp2Build,
- func(ctx android.RegistrationContext) {
- ctx.RegisterModuleType("python_library", python.PythonLibraryFactory)
- })
-}
-
-func testPythonLib(t *testing.T, modType string,
- factory android.ModuleFactory, mutator PythonLibBp2Build,
- registration func(ctx android.RegistrationContext)) {
+func runPythonLibraryTestCase(t *testing.T, tc bp2buildTestCase) {
t.Helper()
- // Simple
- runBp2BuildTestCase(t, registration, bp2buildTestCase{
- description: fmt.Sprintf("simple %s converts to a native py_library", modType),
- moduleTypeUnderTest: modType,
- moduleTypeUnderTestFactory: factory,
- moduleTypeUnderTestBp2BuildMutator: mutator,
- filesystem: map[string]string{
- "a.py": "",
- "b/c.py": "",
- "b/d.py": "",
- "b/e.py": "",
- "files/data.txt": "",
- },
- blueprint: fmt.Sprintf(`%s {
+ testCase := tc
+ testCase.description = fmt.Sprintf(testCase.description, "python_library")
+ testCase.blueprint = fmt.Sprintf(testCase.blueprint, "python_library")
+ testCase.moduleTypeUnderTest = "python_library"
+ testCase.moduleTypeUnderTestFactory = python.PythonLibraryFactory
+ testCase.moduleTypeUnderTestBp2BuildMutator = python.PythonLibraryBp2Build
+ runBp2BuildTestCaseSimple(t, testCase)
+}
+
+func runPythonLibraryHostTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ testCase := tc
+ testCase.description = fmt.Sprintf(testCase.description, "python_library_host")
+ testCase.blueprint = fmt.Sprintf(testCase.blueprint, "python_library_host")
+ testCase.moduleTypeUnderTest = "python_library_host"
+ testCase.moduleTypeUnderTestFactory = python.PythonLibraryHostFactory
+ testCase.moduleTypeUnderTestBp2BuildMutator = python.PythonLibraryHostBp2Build
+ runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("python_library", python.PythonLibraryFactory)
+ },
+ testCase)
+}
+
+func runPythonLibraryTestCases(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ runPythonLibraryTestCase(t, tc)
+ runPythonLibraryHostTestCase(t, tc)
+}
+
+func TestSimplePythonLib(t *testing.T) {
+ testCases := []bp2buildTestCase{
+ {
+ description: "simple %s converts to a native py_library",
+ filesystem: map[string]string{
+ "a.py": "",
+ "b/c.py": "",
+ "b/d.py": "",
+ "b/e.py": "",
+ "files/data.txt": "",
+ },
+ blueprint: `%s {
name: "foo",
srcs: ["**/*.py"],
exclude_srcs: ["b/e.py"],
@@ -54,28 +65,23 @@
name: "bar",
srcs: ["b/e.py"],
bazel_module: { bp2build_available: false },
- }`, modType),
- expectedBazelTargets: []string{`py_library(
- name = "foo",
- data = ["files/data.txt"],
- deps = [":bar"],
- srcs = [
+ }`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("py_library", "foo", attrNameToString{
+ "data": `["files/data.txt"]`,
+ "deps": `[":bar"]`,
+ "srcs": `[
"a.py",
"b/c.py",
"b/d.py",
- ],
- srcs_version = "PY3",
-)`,
+ ]`,
+ "srcs_version": `"PY3"`,
+ }),
+ },
},
- })
-
- // PY2
- runBp2BuildTestCaseSimple(t, bp2buildTestCase{
- description: fmt.Sprintf("py2 %s converts to a native py_library", modType),
- moduleTypeUnderTest: modType,
- moduleTypeUnderTestFactory: factory,
- moduleTypeUnderTestBp2BuildMutator: mutator,
- blueprint: fmt.Sprintf(`%s {
+ {
+ description: "py2 %s converts to a native py_library",
+ blueprint: `%s {
name: "foo",
srcs: ["a.py"],
version: {
@@ -88,22 +94,17 @@
},
bazel_module: { bp2build_available: true },
-}`, modType),
- expectedBazelTargets: []string{`py_library(
- name = "foo",
- srcs = ["a.py"],
- srcs_version = "PY2",
-)`,
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("py_library", "foo", attrNameToString{
+ "srcs": `["a.py"]`,
+ "srcs_version": `"PY2"`,
+ }),
+ },
},
- })
-
- // PY3
- runBp2BuildTestCaseSimple(t, bp2buildTestCase{
- description: fmt.Sprintf("py3 %s converts to a native py_library", modType),
- moduleTypeUnderTest: modType,
- moduleTypeUnderTestFactory: factory,
- moduleTypeUnderTestBp2BuildMutator: mutator,
- blueprint: fmt.Sprintf(`%s {
+ {
+ description: "py3 %s converts to a native py_library",
+ blueprint: `%s {
name: "foo",
srcs: ["a.py"],
version: {
@@ -116,22 +117,17 @@
},
bazel_module: { bp2build_available: true },
-}`, modType),
- expectedBazelTargets: []string{`py_library(
- name = "foo",
- srcs = ["a.py"],
- srcs_version = "PY3",
-)`,
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("py_library", "foo", attrNameToString{
+ "srcs": `["a.py"]`,
+ "srcs_version": `"PY3"`,
+ }),
+ },
},
- })
-
- // Both
- runBp2BuildTestCaseSimple(t, bp2buildTestCase{
- description: fmt.Sprintf("py2&3 %s converts to a native py_library", modType),
- moduleTypeUnderTest: modType,
- moduleTypeUnderTestFactory: factory,
- moduleTypeUnderTestBp2BuildMutator: mutator,
- blueprint: fmt.Sprintf(`%s {
+ {
+ description: "py2&3 %s converts to a native py_library",
+ blueprint: `%s {
name: "foo",
srcs: ["a.py"],
version: {
@@ -144,44 +140,31 @@
},
bazel_module: { bp2build_available: true },
-}`, modType),
- expectedBazelTargets: []string{
- // srcs_version is PY2ANDPY3 by default.
- `py_library(
- name = "foo",
- srcs = ["a.py"],
-)`,
+}`,
+ expectedBazelTargets: []string{
+ // srcs_version is PY2ANDPY3 by default.
+ makeBazelTarget("py_library", "foo", attrNameToString{
+ "srcs": `["a.py"]`,
+ }),
+ },
},
- })
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.description, func(t *testing.T) {
+ runPythonLibraryTestCases(t, tc)
+ })
+ }
}
-func TestPythonLibraryArchVariance(t *testing.T) {
- testPythonArchVariance(t, "python_library", "py_library",
- python.PythonLibraryFactory, python.PythonLibraryBp2Build,
- func(ctx android.RegistrationContext) {})
-}
-
-func TestPythonLibraryHostArchVariance(t *testing.T) {
- testPythonArchVariance(t, "python_library_host", "py_library",
- python.PythonLibraryHostFactory, python.PythonLibraryHostBp2Build,
- func(ctx android.RegistrationContext) {})
-}
-
-// TODO: refactor python_binary_conversion_test to use this
-func testPythonArchVariance(t *testing.T, modType, bazelTarget string,
- factory android.ModuleFactory, mutator PythonLibBp2Build,
- registration func(ctx android.RegistrationContext)) {
- t.Helper()
- runBp2BuildTestCase(t, registration, bp2buildTestCase{
- description: fmt.Sprintf("test %s arch variants", modType),
- moduleTypeUnderTest: modType,
- moduleTypeUnderTestFactory: factory,
- moduleTypeUnderTestBp2BuildMutator: mutator,
+func TestPythonArchVariance(t *testing.T) {
+ runPythonLibraryTestCases(t, bp2buildTestCase{
+ description: "test %s arch variants",
filesystem: map[string]string{
"dir/arm.py": "",
"dir/x86.py": "",
},
- blueprint: fmt.Sprintf(`%s {
+ blueprint: `%s {
name: "foo",
arch: {
arm: {
@@ -191,17 +174,16 @@
srcs: ["x86.py"],
},
},
- }`, modType),
+ }`,
expectedBazelTargets: []string{
- fmt.Sprintf(`%s(
- name = "foo",
- srcs = select({
+ makeBazelTarget("py_library", "foo", attrNameToString{
+ "srcs": `select({
"//build/bazel/platforms/arch:arm": ["arm.py"],
"//build/bazel/platforms/arch:x86": ["x86.py"],
"//conditions:default": [],
- }),
- srcs_version = "PY3",
-)`, bazelTarget),
+ })`,
+ "srcs_version": `"PY3"`,
+ }),
},
})
}
diff --git a/bp2build/sh_conversion_test.go b/bp2build/sh_conversion_test.go
index 82e0a14..1ca4a0e 100644
--- a/bp2build/sh_conversion_test.go
+++ b/bp2build/sh_conversion_test.go
@@ -64,9 +64,9 @@
src: "foo.sh",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`sh_binary(
- name = "foo",
- srcs = ["foo.sh"],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("sh_binary", "foo", attrNameToString{
+ "srcs": `["foo.sh"]`,
+ })},
})
}
diff --git a/bp2build/soong_config_module_type_conversion_test.go b/bp2build/soong_config_module_type_conversion_test.go
new file mode 100644
index 0000000..2e6f54c
--- /dev/null
+++ b/bp2build/soong_config_module_type_conversion_test.go
@@ -0,0 +1,326 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package bp2build
+
+import (
+ "android/soong/android"
+ "android/soong/cc"
+ "testing"
+)
+
+func runSoongConfigModuleTypeTest(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ runBp2BuildTestCase(t, registerSoongConfigModuleTypes, tc)
+}
+
+func registerSoongConfigModuleTypes(ctx android.RegistrationContext) {
+ cc.RegisterCCBuildComponents(ctx)
+
+ ctx.RegisterModuleType("soong_config_module_type_import", android.SoongConfigModuleTypeImportFactory)
+ ctx.RegisterModuleType("soong_config_module_type", android.SoongConfigModuleTypeFactory)
+ ctx.RegisterModuleType("soong_config_string_variable", android.SoongConfigStringVariableDummyFactory)
+ ctx.RegisterModuleType("soong_config_bool_variable", android.SoongConfigBoolVariableDummyFactory)
+}
+
+func TestSoongConfigModuleType(t *testing.T) {
+ bp := `
+soong_config_module_type {
+ name: "custom_cc_library_static",
+ module_type: "cc_library_static",
+ config_namespace: "acme",
+ bool_variables: ["feature1"],
+ properties: ["cflags"],
+ bazel_module: { bp2build_available: true },
+}
+
+custom_cc_library_static {
+ name: "foo",
+ bazel_module: { bp2build_available: true },
+ soong_config_variables: {
+ feature1: {
+ conditions_default: {
+ cflags: ["-DDEFAULT1"],
+ },
+ cflags: ["-DFEATURE1"],
+ },
+ },
+}
+`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - soong_config_module_type is supported in bp2build",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ blueprint: bp,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "foo",
+ copts = select({
+ "//build/bazel/product_variables:acme__feature1__enabled": ["-DFEATURE1"],
+ "//conditions:default": ["-DDEFAULT1"],
+ }),
+ local_includes = ["."],
+)`}})
+}
+
+func TestSoongConfigModuleTypeImport(t *testing.T) {
+ configBp := `
+soong_config_module_type {
+ name: "custom_cc_library_static",
+ module_type: "cc_library_static",
+ config_namespace: "acme",
+ bool_variables: ["feature1"],
+ properties: ["cflags"],
+ bazel_module: { bp2build_available: true },
+}
+`
+ bp := `
+soong_config_module_type_import {
+ from: "foo/bar/SoongConfig.bp",
+ module_types: ["custom_cc_library_static"],
+}
+
+custom_cc_library_static {
+ name: "foo",
+ bazel_module: { bp2build_available: true },
+ soong_config_variables: {
+ feature1: {
+ conditions_default: {
+ cflags: ["-DDEFAULT1"],
+ },
+ cflags: ["-DFEATURE1"],
+ },
+ },
+}
+`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - soong_config_module_type_import is supported in bp2build",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ filesystem: map[string]string{
+ "foo/bar/SoongConfig.bp": configBp,
+ },
+ blueprint: bp,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "foo",
+ copts = select({
+ "//build/bazel/product_variables:acme__feature1__enabled": ["-DFEATURE1"],
+ "//conditions:default": ["-DDEFAULT1"],
+ }),
+ local_includes = ["."],
+)`}})
+}
+
+func TestSoongConfigModuleType_StringVar(t *testing.T) {
+ bp := `
+soong_config_string_variable {
+ name: "board",
+ values: ["soc_a", "soc_b", "soc_c"],
+}
+
+soong_config_module_type {
+ name: "custom_cc_library_static",
+ module_type: "cc_library_static",
+ config_namespace: "acme",
+ variables: ["board"],
+ properties: ["cflags"],
+ bazel_module: { bp2build_available: true },
+}
+
+custom_cc_library_static {
+ name: "foo",
+ bazel_module: { bp2build_available: true },
+ soong_config_variables: {
+ board: {
+ soc_a: {
+ cflags: ["-DSOC_A"],
+ },
+ soc_b: {
+ cflags: ["-DSOC_B"],
+ },
+ soc_c: {},
+ conditions_default: {
+ cflags: ["-DSOC_DEFAULT"]
+ },
+ },
+ },
+}
+`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - generates selects for string vars",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ blueprint: bp,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "foo",
+ copts = select({
+ "//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"],
+ "//build/bazel/product_variables:acme__board__soc_b": ["-DSOC_B"],
+ "//conditions:default": ["-DSOC_DEFAULT"],
+ }),
+ local_includes = ["."],
+)`}})
+}
+
+func TestSoongConfigModuleType_StringAndBoolVar(t *testing.T) {
+ bp := `
+soong_config_bool_variable {
+ name: "feature1",
+}
+
+soong_config_bool_variable {
+ name: "feature2",
+}
+
+soong_config_string_variable {
+ name: "board",
+ values: ["soc_a", "soc_b", "soc_c"],
+}
+
+soong_config_module_type {
+ name: "custom_cc_library_static",
+ module_type: "cc_library_static",
+ config_namespace: "acme",
+ variables: ["feature1", "feature2", "board"],
+ properties: ["cflags"],
+ bazel_module: { bp2build_available: true },
+}
+
+custom_cc_library_static {
+ name: "foo",
+ bazel_module: { bp2build_available: true },
+ soong_config_variables: {
+ feature1: {
+ conditions_default: {
+ cflags: ["-DDEFAULT1"],
+ },
+ cflags: ["-DFEATURE1"],
+ },
+ feature2: {
+ cflags: ["-DFEATURE2"],
+ conditions_default: {
+ cflags: ["-DDEFAULT2"],
+ },
+ },
+ board: {
+ soc_a: {
+ cflags: ["-DSOC_A"],
+ },
+ soc_b: {
+ cflags: ["-DSOC_B"],
+ },
+ soc_c: {},
+ conditions_default: {
+ cflags: ["-DSOC_DEFAULT"]
+ },
+ },
+ },
+}`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - generates selects for multiple variable types",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ blueprint: bp,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "foo",
+ copts = select({
+ "//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"],
+ "//build/bazel/product_variables:acme__board__soc_b": ["-DSOC_B"],
+ "//conditions:default": ["-DSOC_DEFAULT"],
+ }) + select({
+ "//build/bazel/product_variables:acme__feature1__enabled": ["-DFEATURE1"],
+ "//conditions:default": ["-DDEFAULT1"],
+ }) + select({
+ "//build/bazel/product_variables:acme__feature2__enabled": ["-DFEATURE2"],
+ "//conditions:default": ["-DDEFAULT2"],
+ }),
+ local_includes = ["."],
+)`}})
+}
+
+func TestSoongConfigModuleType_StringVar_LabelListDeps(t *testing.T) {
+ bp := `
+soong_config_string_variable {
+ name: "board",
+ values: ["soc_a", "soc_b", "soc_c"],
+}
+
+soong_config_module_type {
+ name: "custom_cc_library_static",
+ module_type: "cc_library_static",
+ config_namespace: "acme",
+ variables: ["board"],
+ properties: ["cflags", "static_libs"],
+ bazel_module: { bp2build_available: true },
+}
+
+custom_cc_library_static {
+ name: "foo",
+ bazel_module: { bp2build_available: true },
+ soong_config_variables: {
+ board: {
+ soc_a: {
+ cflags: ["-DSOC_A"],
+ static_libs: ["soc_a_dep"],
+ },
+ soc_b: {
+ cflags: ["-DSOC_B"],
+ static_libs: ["soc_b_dep"],
+ },
+ soc_c: {},
+ conditions_default: {
+ cflags: ["-DSOC_DEFAULT"],
+ static_libs: ["soc_default_static_dep"],
+ },
+ },
+ },
+}`
+
+ otherDeps := `
+cc_library_static { name: "soc_a_dep", bazel_module: { bp2build_available: false } }
+cc_library_static { name: "soc_b_dep", bazel_module: { bp2build_available: false } }
+cc_library_static { name: "soc_default_static_dep", bazel_module: { bp2build_available: false } }
+`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - generates selects for label list attributes",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ blueprint: bp,
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": otherDeps,
+ },
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "foo",
+ copts = select({
+ "//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"],
+ "//build/bazel/product_variables:acme__board__soc_b": ["-DSOC_B"],
+ "//conditions:default": ["-DSOC_DEFAULT"],
+ }),
+ implementation_deps = select({
+ "//build/bazel/product_variables:acme__board__soc_a": ["//foo/bar:soc_a_dep"],
+ "//build/bazel/product_variables:acme__board__soc_b": ["//foo/bar:soc_b_dep"],
+ "//conditions:default": ["//foo/bar:soc_default_static_dep"],
+ }),
+ local_includes = ["."],
+)`}})
+}
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 7c2f43a..daa9c22 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -364,3 +364,16 @@
bazel_module: { bp2build_available: false },
}`, typ, name)
}
+
+type attrNameToString map[string]string
+
+func makeBazelTarget(typ, name string, attrs attrNameToString) string {
+ attrStrings := make([]string, 0, len(attrs)+1)
+ attrStrings = append(attrStrings, fmt.Sprintf(` name = "%s",`, name))
+ for _, k := range android.SortedStringKeys(attrs) {
+ attrStrings = append(attrStrings, fmt.Sprintf(" %s = %s,", k, attrs[k]))
+ }
+ return fmt.Sprintf(`%s(
+%s
+)`, typ, strings.Join(attrStrings, "\n"))
+}
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index a608630..e1140b8 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -19,9 +19,13 @@
import (
"bytes"
"errors"
+ "flag"
"fmt"
"io"
+ "os"
"path/filepath"
+ "reflect"
+ "sort"
"strings"
"github.com/google/blueprint/parser"
@@ -137,11 +141,35 @@
Fix: runPatchListMod(removeObsoleteProperty("sanitize.scudo")),
},
{
+ Name: "removeAndroidLicenseKinds",
+ Fix: runPatchListMod(removeIncorrectProperties("android_license_kinds")),
+ },
+ {
+ Name: "removeAndroidLicenseConditions",
+ Fix: runPatchListMod(removeIncorrectProperties("android_license_conditions")),
+ },
+ {
+ Name: "removeAndroidLicenseFiles",
+ Fix: runPatchListMod(removeIncorrectProperties("android_license_files")),
+ },
+ {
Name: "formatFlagProperties",
Fix: runPatchListMod(formatFlagProperties),
},
}
+// for fix that only need to run once
+var fixStepsOnce = []FixStep{
+ {
+ Name: "haveSameLicense",
+ Fix: haveSameLicense,
+ },
+ {
+ Name: "rewriteLicenseProperties",
+ Fix: runPatchListMod(rewriteLicenseProperties),
+ },
+}
+
func NewFixRequest() FixRequest {
return FixRequest{}
}
@@ -196,6 +224,16 @@
return nil, err
}
+ // run fix that is expected to run once first
+ configOnce := NewFixRequest()
+ configOnce.steps = append(configOnce.steps, fixStepsOnce...)
+ if len(configOnce.steps) > 0 {
+ err = f.fixTreeOnce(configOnce)
+ if err != nil {
+ return nil, err
+ }
+ }
+
maxNumIterations := 20
i := 0
for {
@@ -1413,3 +1451,304 @@
}
return nil
}
+
+// rewrite the "android_license_kinds" and "android_license_files" properties to a package module
+// (and a license module when needed).
+func rewriteLicenseProperties(mod *parser.Module, buf []byte, patchList *parser.PatchList) error {
+ // if a package module has been added, no more action is needed.
+ for _, patch := range *patchList {
+ if strings.Contains(patch.Replacement, "package {") {
+ return nil
+ }
+ }
+
+ licenseKindsPropertyName := "android_license_kinds"
+ licenseFilesPropertyName := "android_license_files"
+
+ androidBpFileErr := "// Error: No Android.bp file is found at\n" +
+ "// %s\n" +
+ "// Please add one there with the needed license module first.\n"
+ licenseModuleErr := "// Error: Cannot get the name of the license module in the\n" +
+ "// %s file.\n" +
+ "// If no such license module exists, please add one there first.\n"
+
+ defaultApplicableLicense := "Android-Apache-2.0"
+ var licenseModuleName, licensePatch string
+ var hasFileInParentDir bool
+
+ // when LOCAL_NOTICE_FILE is not empty
+ if hasNonEmptyLiteralListProperty(mod, licenseFilesPropertyName) {
+ hasFileInParentDir = hasValueStartWithTwoDotsLiteralList(mod, licenseFilesPropertyName)
+ // if have LOCAL_NOTICE_FILE outside the current directory, need to find and refer to the license
+ // module in the LOCAL_NOTICE_FILE location directly and no new license module needs to be created
+ if hasFileInParentDir {
+ bpPath, ok := getPathFromProperty(mod, licenseFilesPropertyName)
+ if !ok {
+ bpDir, err := getDirFromProperty(mod, licenseFilesPropertyName)
+ if err != nil {
+ return err
+ }
+ licensePatch += fmt.Sprintf(androidBpFileErr, bpDir)
+ } else {
+ licenseModuleName, _ = getModuleName(bpPath, "license")
+ if len(licenseModuleName) == 0 {
+ licensePatch += fmt.Sprintf(licenseModuleErr, bpPath)
+ }
+ defaultApplicableLicense = licenseModuleName
+ }
+ } else {
+ // if have LOCAL_NOTICE_FILE in the current directory, need to create a new license module
+ relativePath := getModuleRelativePath()
+ if len(relativePath) == 0 {
+ return fmt.Errorf("Cannot obtain the relative path of the Android.mk file")
+ }
+ licenseModuleName = strings.Replace(relativePath, "/", "_", -1) + "_license"
+ defaultApplicableLicense = licenseModuleName
+ }
+ }
+
+ //add the package module
+ if hasNonEmptyLiteralListProperty(mod, licenseKindsPropertyName) {
+ licensePatch += "package {\n" +
+ " // See: http://go/android-license-faq\n" +
+ " default_applicable_licenses: [\n" +
+ " \"" + defaultApplicableLicense + "\",\n" +
+ " ],\n" +
+ "}\n" +
+ "\n"
+ }
+
+ // append the license module when necessary
+ // when LOCAL_NOTICE_FILE is not empty and in the current directory, create a new license module
+ // otherwise, use the above default license directly
+ if hasNonEmptyLiteralListProperty(mod, licenseFilesPropertyName) && !hasFileInParentDir {
+ licenseKinds, err := mergeLiteralListPropertyValue(mod, licenseKindsPropertyName)
+ if err != nil {
+ return err
+ }
+ licenseFiles, err := mergeLiteralListPropertyValue(mod, licenseFilesPropertyName)
+ if err != nil {
+ return err
+ }
+ licensePatch += "license {\n" +
+ " name: \"" + licenseModuleName + "\",\n" +
+ " visibility: [\":__subpackages__\"],\n" +
+ " license_kinds: [\n" +
+ licenseKinds +
+ " ],\n" +
+ " license_text: [\n" +
+ licenseFiles +
+ " ],\n" +
+ "}\n" +
+ "\n"
+ }
+
+ // add to the patchList
+ pos := mod.Pos().Offset
+ err := patchList.Add(pos, pos, licensePatch)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// merge the string vaules in a list property of a module into one string with expected format
+func mergeLiteralListPropertyValue(mod *parser.Module, property string) (s string, err error) {
+ listValue, ok := getLiteralListPropertyValue(mod, property)
+ if !ok {
+ // if do not find
+ return "", fmt.Errorf("Cannot retrieve the %s.%s field", mod.Type, property)
+ }
+ for i := 0; i < len(listValue); i++ {
+ s += " \"" + listValue[i] + "\",\n"
+ }
+ return s, nil
+}
+
+// check whether a string list property has any value starting with `../`
+func hasValueStartWithTwoDotsLiteralList(mod *parser.Module, property string) bool {
+ listValue, ok := getLiteralListPropertyValue(mod, property)
+ if ok {
+ for i := 0; i < len(listValue); i++ {
+ if strings.HasPrefix(listValue[i], "../") {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// get the relative path from ANDROID_BUILD_TOP to the Android.mk file to be converted
+func getModuleRelativePath() string {
+ // get the absolute path of the top of the tree
+ rootPath := os.Getenv("ANDROID_BUILD_TOP")
+ // get the absolute path of the `Android.mk` file to be converted
+ absPath := getModuleAbsolutePath()
+ // get the relative path of the `Android.mk` file to top of the tree
+ relModulePath, err := filepath.Rel(rootPath, absPath)
+ if err != nil {
+ return ""
+ }
+ return relModulePath
+}
+
+// get the absolute path of the Android.mk file to be converted
+func getModuleAbsolutePath() string {
+ // get the absolute path at where the `androidmk` commend is executed
+ curAbsPath, err := filepath.Abs(".")
+ if err != nil {
+ return ""
+ }
+ // the argument for the `androidmk` command could be
+ // 1. "./a/b/c/Android.mk"; 2. "a/b/c/Android.mk"; 3. "Android.mk"
+ argPath := flag.Arg(0)
+ if strings.HasPrefix(argPath, "./") {
+ argPath = strings.TrimPrefix(argPath, ".")
+ }
+ argPath = strings.TrimSuffix(argPath, "Android.mk")
+ if strings.HasSuffix(argPath, "/") {
+ argPath = strings.TrimSuffix(argPath, "/")
+ }
+ if len(argPath) > 0 && !strings.HasPrefix(argPath, "/") {
+ argPath = "/" + argPath
+ }
+ // get the absolute path of the `Android.mk` file to be converted
+ absPath := curAbsPath + argPath
+ return absPath
+}
+
+// check whether a file exists in a directory
+func hasFile(dir string, fileName string) error {
+ _, err := os.Stat(dir + fileName)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// get the directory where an `Android.bp` file and the property files are expected to locate
+func getDirFromProperty(mod *parser.Module, property string) (string, error) {
+ listValue, ok := getLiteralListPropertyValue(mod, property)
+ if !ok {
+ // if do not find
+ return "", fmt.Errorf("Cannot retrieve the %s.%s property", mod.Type, property)
+ }
+ if len(listValue) == 0 {
+ // if empty
+ return "", fmt.Errorf("Cannot find the value of the %s.%s property", mod.Type, property)
+ }
+ path := getModuleAbsolutePath()
+ for {
+ if !strings.HasPrefix(listValue[0], "../") {
+ break
+ }
+ path = filepath.Dir(path)
+ listValue[0] = strings.TrimPrefix(listValue[0], "../")
+ }
+ return path, nil
+}
+
+// get the path of the `Android.bp` file at the expected location where the property files locate
+func getPathFromProperty(mod *parser.Module, property string) (string, bool) {
+ dir, err := getDirFromProperty(mod, property)
+ if err != nil {
+ return "", false
+ }
+ err = hasFile(dir, "/Android.bp")
+ if err != nil {
+ return "", false
+ }
+ return dir + "/Android.bp", true
+}
+
+// parse an Android.bp file to get the name of the first module with type of moduleType
+func getModuleName(path string, moduleType string) (string, error) {
+ tree, err := parserPath(path)
+ if err != nil {
+ return "", err
+ }
+ for _, def := range tree.Defs {
+ mod, ok := def.(*parser.Module)
+ if !ok || mod.Type != moduleType {
+ continue
+ }
+ prop, ok := mod.GetProperty("name")
+ if !ok {
+ return "", fmt.Errorf("Cannot get the %s."+"name property", mod.Type)
+ }
+ propVal, ok := prop.Value.(*parser.String)
+ if ok {
+ return propVal.Value, nil
+ }
+ }
+ return "", fmt.Errorf("Cannot find the value of the %s."+"name property", moduleType)
+}
+
+// parse an Android.bp file with the specific path
+func parserPath(path string) (tree *parser.File, err error) {
+ fileContent, _ := os.ReadFile(path)
+ tree, err = parse(path, bytes.NewBufferString(string(fileContent)))
+ if err != nil {
+ return tree, err
+ }
+ return tree, nil
+}
+
+// remove the incorrect property that Soong does not support
+func removeIncorrectProperties(propName string) patchListModFunction {
+ return removeObsoleteProperty(propName)
+}
+
+// the modules on the same Android.mk file are expected to have the same license
+func haveSameLicense(f *Fixer) error {
+ androidLicenseProperties := []string{
+ "android_license_kinds",
+ "android_license_conditions",
+ "android_license_files",
+ }
+
+ var prevModuleName string
+ var prevLicenseKindsVals, prevLicenseConditionsVals, prevLicenseFilesVals []string
+ prevLicenseVals := [][]string{
+ prevLicenseKindsVals,
+ prevLicenseConditionsVals,
+ prevLicenseFilesVals,
+ }
+
+ for _, def := range f.tree.Defs {
+ mod, ok := def.(*parser.Module)
+ if !ok {
+ continue
+ }
+ for idx, property := range androidLicenseProperties {
+ curModuleName, ok := getLiteralStringPropertyValue(mod, "name")
+ // some modules in the existing test cases in the androidmk_test.go do not have name property
+ hasNameProperty := hasProperty(mod, "name")
+ if hasNameProperty && (!ok || len(curModuleName) == 0) {
+ return fmt.Errorf("Cannot retrieve the name property of a module of %s type.", mod.Type)
+ }
+ curVals, ok := getLiteralListPropertyValue(mod, property)
+ // some modules in the existing test cases in the androidmk_test.go do not have license-related property
+ hasLicenseProperty := hasProperty(mod, property)
+ if hasLicenseProperty && (!ok || len(curVals) == 0) {
+ // if do not find the property, or no value is found for the property
+ return fmt.Errorf("Cannot retrieve the %s.%s property", mod.Type, property)
+ }
+ if len(prevLicenseVals[idx]) > 0 {
+ if !reflect.DeepEqual(prevLicenseVals[idx], curVals) {
+ return fmt.Errorf("Modules %s and %s are expected to have the same %s property.",
+ prevModuleName, curModuleName, property)
+ }
+ }
+ sort.Strings(curVals)
+ prevLicenseVals[idx] = curVals
+ prevModuleName = curModuleName
+ }
+ }
+ return nil
+}
+
+func hasProperty(mod *parser.Module, propName string) bool {
+ _, ok := mod.GetProperty(propName)
+ return ok
+}
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index d8772c1..e6b6af5 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -125,34 +125,103 @@
implFilterListTest(t, []string{}, []string{}, []string{})
}
-func runPass(t *testing.T, in, out string, innerTest func(*Fixer) error) {
- expected, err := Reformat(out)
+func checkError(t *testing.T, in, expectedErr string, innerTest func(*Fixer) error) {
+ expected := preProcessOutErr(expectedErr)
+ runTestOnce(t, in, expected, innerTest)
+}
+
+func runTestOnce(t *testing.T, in, expected string, innerTest func(*Fixer) error) {
+ fixer, err := preProcessIn(in)
if err != nil {
t.Fatal(err)
}
+ out, err := runFixerOnce(fixer, innerTest)
+ if err != nil {
+ out = err.Error()
+ }
+
+ compareResult := compareOutExpected(in, out, expected)
+ if len(compareResult) > 0 {
+ t.Errorf(compareResult)
+ }
+}
+
+func preProcessOutErr(expectedErr string) string {
+ expected := strings.TrimSpace(expectedErr)
+ return expected
+}
+
+func preProcessOut(out string) (expected string, err error) {
+ expected, err = Reformat(out)
+ if err != nil {
+ return expected, err
+ }
+ return expected, nil
+}
+
+func preProcessIn(in string) (fixer *Fixer, err error) {
in, err = Reformat(in)
if err != nil {
- t.Fatal(err)
+ return fixer, err
}
tree, errs := parser.Parse("<testcase>", bytes.NewBufferString(in), parser.NewScope(nil))
if errs != nil {
- t.Fatal(errs)
+ return fixer, err
}
- fixer := NewFixer(tree)
+ fixer = NewFixer(tree)
+
+ return fixer, nil
+}
+
+func runFixerOnce(fixer *Fixer, innerTest func(*Fixer) error) (string, error) {
+ err := innerTest(fixer)
+ if err != nil {
+ return "", err
+ }
+
+ out, err := parser.Print(fixer.tree)
+ if err != nil {
+ return "", err
+ }
+ return string(out), nil
+}
+
+func compareOutExpected(in, out, expected string) string {
+ if out != expected {
+ return fmt.Sprintf("output didn't match:\ninput:\n%s\n\nexpected:\n%s\ngot:\n%s\n",
+ in, expected, out)
+ }
+ return ""
+}
+
+func runPassOnce(t *testing.T, in, out string, innerTest func(*Fixer) error) {
+ expected, err := preProcessOut(out)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ runTestOnce(t, in, expected, innerTest)
+}
+
+func runPass(t *testing.T, in, out string, innerTest func(*Fixer) error) {
+ expected, err := preProcessOut(out)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ fixer, err := preProcessIn(in)
+ if err != nil {
+ t.Fatal(err)
+ }
got := ""
prev := "foo"
passes := 0
for got != prev && passes < 10 {
- err := innerTest(fixer)
- if err != nil {
- t.Fatal(err)
- }
-
- out, err := parser.Print(fixer.tree)
+ out, err = runFixerOnce(fixer, innerTest)
if err != nil {
t.Fatal(err)
}
@@ -162,9 +231,9 @@
passes++
}
- if got != expected {
- t.Errorf("output didn't match:\ninput:\n%s\n\nexpected:\n%s\ngot:\n%s\n",
- in, expected, got)
+ compareResult := compareOutExpected(in, out, expected)
+ if len(compareResult) > 0 {
+ t.Errorf(compareResult)
}
}
@@ -1608,3 +1677,157 @@
})
}
}
+
+func TestRewriteLicenseProperties(t *testing.T) {
+ tests := []struct {
+ name string
+ in string
+ out string
+ }{
+ {
+ name: "license rewriting with one module",
+ in: `
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ }
+ `,
+ out: `
+ package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "Android-Apache-2.0",
+ ],
+ }
+
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ }
+ `,
+ },
+ {
+ name: "license rewriting with two modules",
+ in: `
+ android_test {
+ name: "foo1",
+ android_license_kinds: ["license_kind1"],
+ android_license_conditions: ["license_notice1"],
+ }
+
+ android_test {
+ name: "foo2",
+ android_license_kinds: ["license_kind2"],
+ android_license_conditions: ["license_notice2"],
+ }
+ `,
+ out: `
+ package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "Android-Apache-2.0",
+ ],
+ }
+
+ android_test {
+ name: "foo1",
+ android_license_kinds: ["license_kind1"],
+ android_license_conditions: ["license_notice1"],
+ }
+
+ android_test {
+ name: "foo2",
+ android_license_kinds: ["license_kind2"],
+ android_license_conditions: ["license_notice2"],
+ }
+ `,
+ },
+ // TODO(b/205615944): When valid "android_license_files" exists, the test requires an Android.mk
+ // file (and an Android.bp file is required as well if the license files locates outside the current
+ // directory). So plan to use a mock file system to mock the Android.mk and Android.bp files.
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ runPassOnce(t, test.in, test.out, runPatchListMod(rewriteLicenseProperties))
+ })
+ }
+}
+
+func TestHaveSameLicense(t *testing.T) {
+ tests := []struct {
+ name string
+ in string
+ out string
+ }{
+ {
+ name: "two modules with the same license",
+ in: `
+ android_test {
+ name: "foo1",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ }
+
+ android_test {
+ name: "foo2",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ }
+ `,
+ out: `
+ android_test {
+ name: "foo1",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ }
+
+ android_test {
+ name: "foo2",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ }
+ `,
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ runPassOnce(t, test.in, test.out, func(fixer *Fixer) error {
+ return haveSameLicense(fixer)
+ })
+ })
+ }
+ testErrs := []struct {
+ name string
+ in string
+ expectedErr string
+ }{
+ {
+ name: "two modules will different licenses",
+ in: `
+ android_test {
+ name: "foo1",
+ android_license_kinds: ["license_kind1"],
+ android_license_conditions: ["license_notice1"],
+ }
+
+ android_test {
+ name: "foo2",
+ android_license_kinds: ["license_kind2"],
+ android_license_conditions: ["license_notice2"],
+ }
+ `,
+ expectedErr: `
+ Modules foo1 and foo2 are expected to have the same android_license_kinds property.
+ `,
+ },
+ }
+ for _, test := range testErrs {
+ t.Run(test.name, func(t *testing.T) {
+ checkError(t, test.in, test.expectedErr, func(fixer *Fixer) error {
+ return haveSameLicense(fixer)
+ })
+ })
+ }
+}
diff --git a/build_kzip.bash b/build_kzip.bash
index 5655067..aff2d6d 100755
--- a/build_kzip.bash
+++ b/build_kzip.bash
@@ -61,5 +61,5 @@
# Pack
# TODO(asmundak): this should be done by soong.
declare -r allkzip="$KZIP_NAME.kzip"
-"$out/soong/host/linux-x86/bin/merge_zips" "$DIST_DIR/$allkzip" @<(find "$out" -name '*.kzip')
+"$out/host/linux-x86/bin/merge_zips" "$DIST_DIR/$allkzip" @<(find "$out" -name '*.kzip')
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 93283d0..45bb1ca 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -80,7 +80,7 @@
// to be installed. And this is breaking some older devices (like marlin)
// where system.img is small.
Required: c.Properties.AndroidMkRuntimeLibs,
- Include: "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
+ Include: "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
@@ -450,11 +450,6 @@
if installer.path == (android.InstallPath{}) {
return
}
- // Soong installation is only supported for host modules. Have Make
- // installation trigger Soong installation.
- if ctx.Target().Os.Class == android.Host {
- entries.OutputFile = android.OptionalPathForPath(installer.path)
- }
entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
path, file := filepath.Split(installer.path.ToMakePath().String())
@@ -587,8 +582,8 @@
if p.properties.Check_elf_files != nil {
entries.SetBool("LOCAL_CHECK_ELF_FILES", *p.properties.Check_elf_files)
} else {
- // soong_cc_prebuilt.mk does not include check_elf_file.mk by default
- // because cc_library_shared and cc_binary use soong_cc_prebuilt.mk as well.
+ // soong_cc_rust_prebuilt.mk does not include check_elf_file.mk by default
+ // because cc_library_shared and cc_binary use soong_cc_rust_prebuilt.mk as well.
// In order to turn on prebuilt ABI checker, set `LOCAL_CHECK_ELF_FILES` to
// true if `p.properties.Check_elf_files` is not specified.
entries.SetBool("LOCAL_CHECK_ELF_FILES", true)
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 1b13854..dde8dd4 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -320,14 +320,14 @@
"CppFlags": &ca.cppFlags,
}
for propName, attr := range productVarPropNameToAttribute {
- if props, exists := productVariableProps[propName]; exists {
- for _, prop := range props {
- flags, ok := prop.Property.([]string)
+ if productConfigProps, exists := productVariableProps[propName]; exists {
+ for productConfigProp, prop := range productConfigProps {
+ flags, ok := prop.([]string)
if !ok {
ctx.ModuleErrorf("Could not convert product variable %s property", proptools.PropertyNameForField(propName))
}
- newFlags, _ := bazel.TryVariableSubstitutions(flags, prop.ProductConfigVariable)
- attr.SetSelectValue(bazel.ProductVariableConfigurationAxis(prop.FullConfig), prop.FullConfig, newFlags)
+ newFlags, _ := bazel.TryVariableSubstitutions(flags, productConfigProp.Name)
+ attr.SetSelectValue(productConfigProp.ConfigurationAxis(), productConfigProp.SelectKey(), newFlags)
}
}
}
@@ -587,31 +587,35 @@
if !exists && !excludesExists {
continue
}
- // collect all the configurations that an include or exclude property exists for.
- // we want to iterate all configurations rather than either the include or exclude because for a
- // particular configuration we may have only and include or only an exclude to handle
- configs := make(map[string]bool, len(props)+len(excludeProps))
- for config := range props {
- configs[config] = true
+ // Collect all the configurations that an include or exclude property exists for.
+ // We want to iterate all configurations rather than either the include or exclude because, for a
+ // particular configuration, we may have either only an include or an exclude to handle.
+ productConfigProps := make(map[android.ProductConfigProperty]bool, len(props)+len(excludeProps))
+ for p := range props {
+ productConfigProps[p] = true
}
- for config := range excludeProps {
- configs[config] = true
+ for p := range excludeProps {
+ productConfigProps[p] = true
}
- for config := range configs {
- prop, includesExists := props[config]
- excludesProp, excludesExists := excludeProps[config]
+ for productConfigProp := range productConfigProps {
+ prop, includesExists := props[productConfigProp]
+ excludesProp, excludesExists := excludeProps[productConfigProp]
var includes, excludes []string
var ok bool
// if there was no includes/excludes property, casting fails and that's expected
- if includes, ok = prop.Property.([]string); includesExists && !ok {
+ if includes, ok = prop.([]string); includesExists && !ok {
ctx.ModuleErrorf("Could not convert product variable %s property", name)
}
- if excludes, ok = excludesProp.Property.([]string); excludesExists && !ok {
+ if excludes, ok = excludesProp.([]string); excludesExists && !ok {
ctx.ModuleErrorf("Could not convert product variable %s property", dep.excludesField)
}
- dep.attribute.SetSelectValue(bazel.ProductVariableConfigurationAxis(config), config, dep.depResolutionFunc(ctx, android.FirstUniqueStrings(includes), excludes))
+ dep.attribute.SetSelectValue(
+ productConfigProp.ConfigurationAxis(),
+ productConfigProp.SelectKey(),
+ dep.depResolutionFunc(ctx, android.FirstUniqueStrings(includes), excludes),
+ )
}
}
}
diff --git a/cc/builder.go b/cc/builder.go
index abd5f1d..72c2fa5 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -949,8 +949,7 @@
}
// Generate a rule for extracting a table of contents from a shared library (.so)
-func transformSharedObjectToToc(ctx android.ModuleContext, inputFile android.Path,
- outputFile android.WritablePath, flags builderFlags) {
+func TransformSharedObjectToToc(ctx android.ModuleContext, inputFile android.Path, outputFile android.WritablePath) {
var format string
if ctx.Darwin() {
diff --git a/cc/cc.go b/cc/cc.go
index 32652c1..113620c 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1365,6 +1365,8 @@
return c.installer != nil && c.installer.installInRoot()
}
+func (c *Module) InstallBypassMake() bool { return true }
+
type baseModuleContext struct {
android.BaseModuleContext
moduleContextImpl
@@ -1715,7 +1717,7 @@
bazelActionsUsed := false
// Mixed builds mode is disabled for modules outside of device OS.
// TODO(b/200841190): Support non-device OS in mixed builds.
- if c.MixedBuildsEnabled(actx) && c.bazelHandler != nil && actx.Os().Class == android.Device {
+ if c.MixedBuildsEnabled(actx) && c.bazelHandler != nil {
bazelActionsUsed = c.bazelHandler.GenerateBazelBuildActions(actx, bazelModuleLabel)
}
return bazelActionsUsed
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 4c9f579..9ffe48d 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -346,7 +346,7 @@
func checkVndkLibrariesOutput(t *testing.T, ctx *android.TestContext, module string, expected []string) {
t.Helper()
- got := ctx.ModuleForTests(module, "").Module().(*vndkLibrariesTxt).fileNames
+ got := ctx.ModuleForTests(module, "android_common").Module().(*vndkLibrariesTxt).fileNames
assertArrayString(t, got, expected)
}
@@ -532,11 +532,11 @@
CheckSnapshot(t, ctx, snapshotSingleton, "libllndk", "libllndk.so", llndkLib2ndPath, variant2nd)
snapshotConfigsPath := filepath.Join(snapshotVariantPath, "configs")
- CheckSnapshot(t, ctx, snapshotSingleton, "llndk.libraries.txt", "llndk.libraries.txt", snapshotConfigsPath, "")
- CheckSnapshot(t, ctx, snapshotSingleton, "vndkcore.libraries.txt", "vndkcore.libraries.txt", snapshotConfigsPath, "")
- CheckSnapshot(t, ctx, snapshotSingleton, "vndksp.libraries.txt", "vndksp.libraries.txt", snapshotConfigsPath, "")
- CheckSnapshot(t, ctx, snapshotSingleton, "vndkprivate.libraries.txt", "vndkprivate.libraries.txt", snapshotConfigsPath, "")
- CheckSnapshot(t, ctx, snapshotSingleton, "vndkproduct.libraries.txt", "vndkproduct.libraries.txt", snapshotConfigsPath, "")
+ CheckSnapshot(t, ctx, snapshotSingleton, "llndk.libraries.txt", "llndk.libraries.txt", snapshotConfigsPath, "android_common")
+ CheckSnapshot(t, ctx, snapshotSingleton, "vndkcore.libraries.txt", "vndkcore.libraries.txt", snapshotConfigsPath, "android_common")
+ CheckSnapshot(t, ctx, snapshotSingleton, "vndksp.libraries.txt", "vndksp.libraries.txt", snapshotConfigsPath, "android_common")
+ CheckSnapshot(t, ctx, snapshotSingleton, "vndkprivate.libraries.txt", "vndkprivate.libraries.txt", snapshotConfigsPath, "android_common")
+ CheckSnapshot(t, ctx, snapshotSingleton, "vndkproduct.libraries.txt", "vndkproduct.libraries.txt", snapshotConfigsPath, "android_common")
checkVndkOutput(t, ctx, "vndk/vndk.libraries.txt", []string{
"LLNDK: libc.so",
@@ -614,7 +614,7 @@
config.TestProductVariables.Platform_vndk_version = StringPtr("29")
ctx := testCcWithConfig(t, config)
- module := ctx.ModuleForTests("llndk.libraries.txt", "")
+ module := ctx.ModuleForTests("llndk.libraries.txt", "android_common")
entries := android.AndroidMkEntriesForTest(t, ctx, module.Module())[0]
assertArrayString(t, entries.EntryMap["LOCAL_MODULE_STEM"], []string{"llndk.libraries.29.txt"})
}
@@ -730,9 +730,16 @@
gtest: false,
}
+ cc_binary {
+ name: "test_bin",
+ relative_install_path: "foo/bar/baz",
+ compile_multilib: "both",
+ }
+
cc_test {
name: "main_test",
data_libs: ["test_lib"],
+ data_bins: ["test_bin"],
gtest: false,
}
`
@@ -750,10 +757,10 @@
t.Fatalf("Expected cc_test to produce output files, error: %s", err)
}
if len(outputFiles) != 1 {
- t.Errorf("expected exactly one output file. output files: [%s]", outputFiles)
+ t.Fatalf("expected exactly one output file. output files: [%s]", outputFiles)
}
- if len(testBinary.dataPaths()) != 1 {
- t.Errorf("expected exactly one test data file. test data files: [%s]", testBinary.dataPaths())
+ if len(testBinary.dataPaths()) != 2 {
+ t.Fatalf("expected exactly one test data file. test data files: [%s]", testBinary.dataPaths())
}
outputPath := outputFiles[0].String()
@@ -766,6 +773,10 @@
t.Errorf("expected LOCAL_TEST_DATA to end with `:test_lib.so:foo/bar/baz`,"+
" but was '%s'", entries.EntryMap["LOCAL_TEST_DATA"][0])
}
+ if !strings.HasSuffix(entries.EntryMap["LOCAL_TEST_DATA"][1], ":test_bin:foo/bar/baz") {
+ t.Errorf("expected LOCAL_TEST_DATA to end with `:test_bin:foo/bar/baz`,"+
+ " but was '%s'", entries.EntryMap["LOCAL_TEST_DATA"][1])
+ }
}
func TestVndkWhenVndkVersionIsNotSet(t *testing.T) {
@@ -3585,6 +3596,58 @@
}
}
+func TestAidlFlagsWithMinSdkVersion(t *testing.T) {
+ for _, tc := range []struct {
+ name string
+ sdkVersion string
+ variant string
+ expected string
+ }{
+ {
+ name: "default is current",
+ sdkVersion: "",
+ variant: "android_arm64_armv8-a_static",
+ expected: "platform_apis",
+ },
+ {
+ name: "use sdk_version",
+ sdkVersion: `sdk_version: "29"`,
+ variant: "android_arm64_armv8-a_static",
+ expected: "platform_apis",
+ },
+ {
+ name: "use sdk_version(sdk variant)",
+ sdkVersion: `sdk_version: "29"`,
+ variant: "android_arm64_armv8-a_sdk_static",
+ expected: "29",
+ },
+ {
+ name: "use min_sdk_version",
+ sdkVersion: `min_sdk_version: "29"`,
+ variant: "android_arm64_armv8-a_static",
+ expected: "29",
+ },
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ ctx := testCc(t, `
+ cc_library {
+ name: "libfoo",
+ stl: "none",
+ srcs: ["a/Foo.aidl"],
+ `+tc.sdkVersion+`
+ }
+ `)
+ libfoo := ctx.ModuleForTests("libfoo", tc.variant)
+ manifest := android.RuleBuilderSboxProtoForTests(t, libfoo.Output("aidl.sbox.textproto"))
+ aidlCommand := manifest.Commands[0].GetCommand()
+ expectedAidlFlag := "--min_sdk_version=" + tc.expected
+ if !strings.Contains(aidlCommand, expectedAidlFlag) {
+ t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag)
+ }
+ })
+ }
+}
+
func TestMinSdkVersionInClangTriple(t *testing.T) {
ctx := testCc(t, `
cc_library_shared {
diff --git a/cc/ccdeps.go b/cc/ccdeps.go
index b96d8b0..75e1faf 100644
--- a/cc/ccdeps.go
+++ b/cc/ccdeps.go
@@ -44,11 +44,9 @@
var _ android.SingletonMakeVarsProvider = (*ccdepsGeneratorSingleton)(nil)
const (
- // Environment variables used to control the behavior of this singleton.
- envVariableCollectCCDeps = "SOONG_COLLECT_CC_DEPS"
- ccdepsJsonFileName = "module_bp_cc_deps.json"
- cClang = "clang"
- cppClang = "clang++"
+ ccdepsJsonFileName = "module_bp_cc_deps.json"
+ cClang = "clang"
+ cppClang = "clang++"
)
type ccIdeInfo struct {
@@ -83,10 +81,7 @@
}
func (c *ccdepsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) {
- if !ctx.Config().IsEnvTrue(envVariableCollectCCDeps) {
- return
- }
-
+ // (b/204397180) Generate module_bp_cc_deps.json by default.
moduleDeps := ccDeps{}
moduleInfos := map[string]ccIdeInfo{}
diff --git a/cc/compiler.go b/cc/compiler.go
index 00df669..ffe8b2e 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -552,6 +552,12 @@
flags.aidlFlags = append(flags.aidlFlags, "-t")
}
+ aidlMinSdkVersion := ctx.minSdkVersion()
+ if aidlMinSdkVersion == "" {
+ aidlMinSdkVersion = "platform_apis"
+ }
+ flags.aidlFlags = append(flags.aidlFlags, "--min_sdk_version="+aidlMinSdkVersion)
+
flags.Local.CommonFlags = append(flags.Local.CommonFlags,
"-I"+android.PathForModuleGen(ctx, "aidl").String())
}
diff --git a/cc/library.go b/cc/library.go
index c3f7305..dbf927d 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1377,7 +1377,7 @@
// depending on a table of contents file instead of the library itself.
tocFile := outputFile.ReplaceExtension(ctx, flags.Toolchain.ShlibSuffix()[1:]+".toc")
library.tocFile = android.OptionalPathForPath(tocFile)
- transformSharedObjectToToc(ctx, outputFile, tocFile, builderFlags)
+ TransformSharedObjectToToc(ctx, outputFile, tocFile)
stripFlags := flagsToStripFlags(flags)
needsStrip := library.stripper.NeedsStrip(ctx)
@@ -2358,9 +2358,6 @@
if !module.ConvertWithBp2build(ctx) {
return
}
- if ctx.ModuleType() != modType {
- return
- }
ccSharedOrStaticBp2BuildMutatorInternal(ctx, module, modType)
}
@@ -2498,7 +2495,15 @@
}
func CcLibraryStaticBp2Build(ctx android.TopDownMutatorContext) {
- ccSharedOrStaticBp2BuildMutator(ctx, "cc_library_static")
+ isLibraryStatic := ctx.ModuleType() == "cc_library_static"
+ if b, ok := ctx.Module().(android.Bazelable); ok {
+ // This is created by a custom soong config module type, so its ctx.ModuleType() is not
+ // cc_library_static. Check its BaseModuleType.
+ isLibraryStatic = isLibraryStatic || b.BaseModuleType() == "cc_library_static"
+ }
+ if isLibraryStatic {
+ ccSharedOrStaticBp2BuildMutator(ctx, "cc_library_static")
+ }
}
// TODO(b/199902614): Can this be factored to share with the other Attributes?
@@ -2529,5 +2534,13 @@
}
func CcLibrarySharedBp2Build(ctx android.TopDownMutatorContext) {
- ccSharedOrStaticBp2BuildMutator(ctx, "cc_library_shared")
+ isLibraryShared := ctx.ModuleType() == "cc_library_shared"
+ if b, ok := ctx.Module().(android.Bazelable); ok {
+ // This is created by a custom soong config module type, so its ctx.ModuleType() is not
+ // cc_library_shared. Check its BaseModuleType.
+ isLibraryShared = isLibraryShared || b.BaseModuleType() == "cc_library_shared"
+ }
+ if isLibraryShared {
+ ccSharedOrStaticBp2BuildMutator(ctx, "cc_library_shared")
+ }
}
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 3401e36..16945ac 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -114,8 +114,6 @@
// TODO(ccross): verify shared library dependencies
srcs := p.prebuiltSrcs(ctx)
if len(srcs) > 0 {
- builderFlags := flagsToBuilderFlags(flags)
-
if len(srcs) > 1 {
ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
return nil
@@ -152,7 +150,7 @@
// depending on a table of contents file instead of the library itself.
tocFile := android.PathForModuleOut(ctx, libName+".toc")
p.tocFile = android.OptionalPathForPath(tocFile)
- transformSharedObjectToToc(ctx, outputFile, tocFile, builderFlags)
+ TransformSharedObjectToToc(ctx, outputFile, tocFile)
if ctx.Windows() && p.properties.Windows_import_lib != nil {
// Consumers of this library actually links to the import library in build
diff --git a/cc/sanitize.go b/cc/sanitize.go
index c7e8411..93d4b4c 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -88,7 +88,7 @@
intOverflow
scs
Fuzzer
- memtag_heap
+ Memtag_heap
cfi // cfi is last to prevent it running before incompatible mutators
)
@@ -99,7 +99,7 @@
intOverflow,
scs,
Fuzzer,
- memtag_heap,
+ Memtag_heap,
cfi, // cfi is last to prevent it running before incompatible mutators
}
@@ -118,7 +118,7 @@
return "cfi"
case scs:
return "scs"
- case memtag_heap:
+ case Memtag_heap:
return "memtag_heap"
case Fuzzer:
return "fuzzer"
@@ -134,7 +134,7 @@
return "address"
case Hwasan:
return "hwaddress"
- case memtag_heap:
+ case Memtag_heap:
return "memtag_heap"
case tsan:
return "thread"
@@ -156,7 +156,7 @@
case Asan, Hwasan, Fuzzer, scs, tsan, cfi:
ctx.TopDown(t.variationName()+"_deps", sanitizerDepsMutator(t))
ctx.BottomUp(t.variationName(), sanitizerMutator(t))
- case memtag_heap, intOverflow:
+ case Memtag_heap, intOverflow:
// do nothing
default:
panic(fmt.Errorf("unknown SanitizerType %d", t))
@@ -179,6 +179,8 @@
return true
case Fuzzer:
return true
+ case Memtag_heap:
+ return true
default:
return false
}
@@ -467,7 +469,7 @@
s.Scs = nil
}
- // memtag_heap is only implemented on AArch64.
+ // Memtag_heap is only implemented on AArch64.
if ctx.Arch().ArchType != android.Arm64 {
s.Memtag_heap = nil
}
@@ -813,7 +815,7 @@
return sanitize.Properties.Sanitize.Cfi
case scs:
return sanitize.Properties.Sanitize.Scs
- case memtag_heap:
+ case Memtag_heap:
return sanitize.Properties.Sanitize.Memtag_heap
case Fuzzer:
return sanitize.Properties.Sanitize.Fuzzer
@@ -829,7 +831,7 @@
!sanitize.isSanitizerEnabled(tsan) &&
!sanitize.isSanitizerEnabled(cfi) &&
!sanitize.isSanitizerEnabled(scs) &&
- !sanitize.isSanitizerEnabled(memtag_heap) &&
+ !sanitize.isSanitizerEnabled(Memtag_heap) &&
!sanitize.isSanitizerEnabled(Fuzzer)
}
@@ -859,7 +861,7 @@
sanitize.Properties.Sanitize.Cfi = bPtr
case scs:
sanitize.Properties.Sanitize.Scs = bPtr
- case memtag_heap:
+ case Memtag_heap:
sanitize.Properties.Sanitize.Memtag_heap = bPtr
case Fuzzer:
sanitize.Properties.Sanitize.Fuzzer = bPtr
@@ -1148,7 +1150,7 @@
if lib, ok := snapshot.StaticLibs[noteDep]; ok {
noteDep = lib
}
- depTag := libraryDependencyTag{Kind: staticLibraryDependency, wholeStatic: true}
+ depTag := StaticDepTag(true)
variations := append(mctx.Target().Variations(),
blueprint.Variation{Mutator: "link", Variation: "static"})
if c.Device() {
@@ -1318,6 +1320,10 @@
func sanitizerMutator(t SanitizerType) func(android.BottomUpMutatorContext) {
return func(mctx android.BottomUpMutatorContext) {
if c, ok := mctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() {
+
+ // Make sure we're not setting CFI to any value if it's not supported.
+ cfiSupported := mctx.Module().(PlatformSanitizeable).SanitizerSupported(cfi)
+
if c.Binary() && c.IsSanitizerEnabled(t) {
modules := mctx.CreateVariations(t.variationName())
modules[0].(PlatformSanitizeable).SetSanitizer(t, true)
@@ -1338,7 +1344,6 @@
// is redirected to the sanitized variant of the dependent module.
defaultVariation := t.variationName()
// Not all PlatformSanitizeable modules support the CFI sanitizer
- cfiSupported := mctx.Module().(PlatformSanitizeable).SanitizerSupported(cfi)
mctx.SetDefaultDependencyVariation(&defaultVariation)
modules := mctx.CreateVariations("", t.variationName())
@@ -1385,7 +1390,7 @@
modules[0].(PlatformSanitizeable).SetInSanitizerDir()
}
- if mctx.Device() && t.incompatibleWithCfi() {
+ if mctx.Device() && t.incompatibleWithCfi() && cfiSupported {
// TODO: Make sure that cfi mutator runs "after" any of the sanitizers that
// are incompatible with cfi
modules[0].(PlatformSanitizeable).SetSanitizer(cfi, false)
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index 9570664..253a11b 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -66,7 +66,7 @@
// Override existing vendor and recovery snapshot for cc module specific extra functions
var VendorSnapshotImageSingleton vendorSnapshotImage = vendorSnapshotImage{&snapshot.VendorSnapshotImageSingleton}
-var recoverySnapshotImageSingleton recoverySnapshotImage = recoverySnapshotImage{&snapshot.RecoverySnapshotImageSingleton}
+var RecoverySnapshotImageSingleton recoverySnapshotImage = recoverySnapshotImage{&snapshot.RecoverySnapshotImageSingleton}
func RegisterVendorSnapshotModules(ctx android.RegistrationContext) {
ctx.RegisterModuleType("vendor_snapshot", vendorSnapshotFactory)
@@ -231,7 +231,7 @@
}
func recoverySnapshotFactory() android.Module {
- return snapshotFactory(recoverySnapshotImageSingleton)
+ return snapshotFactory(RecoverySnapshotImageSingleton)
}
func snapshotFactory(image SnapshotImage) android.Module {
@@ -326,7 +326,7 @@
return
}
- images := []SnapshotImage{VendorSnapshotImageSingleton, recoverySnapshotImageSingleton}
+ images := []SnapshotImage{VendorSnapshotImageSingleton, RecoverySnapshotImageSingleton}
for _, image := range images {
if p.Image == image {
@@ -476,13 +476,12 @@
if p.shared() {
libName := in.Base()
- builderFlags := flagsToBuilderFlags(flags)
// Optimize out relinking against shared libraries whose interface hasn't changed by
// depending on a table of contents file instead of the library itself.
tocFile := android.PathForModuleOut(ctx, libName+".toc")
p.tocFile = android.OptionalPathForPath(tocFile)
- transformSharedObjectToToc(ctx, in, tocFile, builderFlags)
+ TransformSharedObjectToToc(ctx, in, tocFile)
ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
SharedLibrary: in,
@@ -584,7 +583,7 @@
// overrides the recovery variant of the cc shared library with the same name, if BOARD_VNDK_VERSION
// is set.
func RecoverySnapshotSharedFactory() android.Module {
- module, prebuilt := snapshotLibraryFactory(recoverySnapshotImageSingleton, SnapshotSharedSuffix)
+ module, prebuilt := snapshotLibraryFactory(RecoverySnapshotImageSingleton, SnapshotSharedSuffix)
prebuilt.libraryDecorator.BuildOnlyShared()
return module.Init()
}
@@ -604,7 +603,7 @@
// overrides the recovery variant of the cc static library with the same name, if BOARD_VNDK_VERSION
// is set.
func RecoverySnapshotStaticFactory() android.Module {
- module, prebuilt := snapshotLibraryFactory(recoverySnapshotImageSingleton, SnapshotStaticSuffix)
+ module, prebuilt := snapshotLibraryFactory(RecoverySnapshotImageSingleton, SnapshotStaticSuffix)
prebuilt.libraryDecorator.BuildOnlyStatic()
return module.Init()
}
@@ -624,7 +623,7 @@
// overrides the recovery variant of the cc header library with the same name, if BOARD_VNDK_VERSION
// is set.
func RecoverySnapshotHeaderFactory() android.Module {
- module, prebuilt := snapshotLibraryFactory(recoverySnapshotImageSingleton, snapshotHeaderSuffix)
+ module, prebuilt := snapshotLibraryFactory(RecoverySnapshotImageSingleton, snapshotHeaderSuffix)
prebuilt.libraryDecorator.HeaderOnly()
return module.Init()
}
@@ -699,7 +698,7 @@
// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_binary
// overrides the recovery variant of the cc binary with the same name, if BOARD_VNDK_VERSION is set.
func RecoverySnapshotBinaryFactory() android.Module {
- return snapshotBinaryFactory(recoverySnapshotImageSingleton, snapshotBinarySuffix)
+ return snapshotBinaryFactory(RecoverySnapshotImageSingleton, snapshotBinarySuffix)
}
func snapshotBinaryFactory(image SnapshotImage, moduleSuffix string) android.Module {
@@ -801,7 +800,7 @@
}
module.linker = prebuilt
- prebuilt.Init(module, recoverySnapshotImageSingleton, snapshotObjectSuffix)
+ prebuilt.Init(module, RecoverySnapshotImageSingleton, snapshotObjectSuffix)
module.AddProperties(&prebuilt.properties)
return module.Init()
}
diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go
index 24abcce..de50ef5 100644
--- a/cc/snapshot_utils.go
+++ b/cc/snapshot_utils.go
@@ -113,7 +113,7 @@
return ctx.Config().VndkSnapshotBuildArtifacts()
}
- for _, image := range []SnapshotImage{VendorSnapshotImageSingleton, recoverySnapshotImageSingleton} {
+ for _, image := range []SnapshotImage{VendorSnapshotImageSingleton, RecoverySnapshotImageSingleton} {
if isSnapshotAware(ctx.DeviceConfig(), m, image.IsProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()), apexInfo, image) {
return true
}
diff --git a/cc/test.go b/cc/test.go
index c589165..f37fdae 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -378,31 +378,26 @@
ctx.VisitDirectDepsWithTag(dataLibDepTag, func(dep android.Module) {
depName := ctx.OtherModuleName(dep)
- ccDep, ok := dep.(LinkableInterface)
-
+ linkableDep, ok := dep.(LinkableInterface)
if !ok {
- ctx.ModuleErrorf("data_lib %q is not a linkable cc module", depName)
+ ctx.ModuleErrorf("data_lib %q is not a LinkableInterface module", depName)
}
- ccModule, ok := dep.(*Module)
- if !ok {
- ctx.ModuleErrorf("data_lib %q is not a cc module", depName)
- }
- if ccDep.OutputFile().Valid() {
+ if linkableDep.OutputFile().Valid() {
test.data = append(test.data,
- android.DataPath{SrcPath: ccDep.OutputFile().Path(),
- RelativeInstallPath: ccModule.installer.relativeInstallPath()})
+ android.DataPath{SrcPath: linkableDep.OutputFile().Path(),
+ RelativeInstallPath: linkableDep.RelativeInstallPath()})
}
})
ctx.VisitDirectDepsWithTag(dataBinDepTag, func(dep android.Module) {
depName := ctx.OtherModuleName(dep)
- ccModule, ok := dep.(*Module)
+ linkableDep, ok := dep.(LinkableInterface)
if !ok {
- ctx.ModuleErrorf("data_bin %q is not a cc module", depName)
+ ctx.ModuleErrorf("data_bin %q is not a LinkableInterface module", depName)
}
- if ccModule.OutputFile().Valid() {
+ if linkableDep.OutputFile().Valid() {
test.data = append(test.data,
- android.DataPath{SrcPath: ccModule.OutputFile().Path(),
- RelativeInstallPath: ccModule.installer.relativeInstallPath()})
+ android.DataPath{SrcPath: linkableDep.OutputFile().Path(),
+ RelativeInstallPath: linkableDep.RelativeInstallPath()})
}
})
diff --git a/cc/testing.go b/cc/testing.go
index b0a220c..3bf936d 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -763,3 +763,11 @@
}
return paths
}
+
+func AssertExcludeFromRecoverySnapshotIs(t *testing.T, ctx *android.TestContext, name string, expected bool, variant string) {
+ t.Helper()
+ m := ctx.ModuleForTests(name, variant).Module().(LinkableInterface)
+ if m.ExcludeFromRecoverySnapshot() != expected {
+ t.Errorf("expected %q ExcludeFromRecoverySnapshot to be %t", m.String(), expected)
+ }
+}
diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go
index ca2f569..b5022c8 100644
--- a/cc/vendor_snapshot_test.go
+++ b/cc/vendor_snapshot_test.go
@@ -1020,14 +1020,6 @@
assertString(t, staticCfiModule.outputFile.Path().Base(), "libsnapshot.cfi.a")
}
-func assertExcludeFromRecoverySnapshotIs(t *testing.T, ctx *android.TestContext, name string, expected bool) {
- t.Helper()
- m := ctx.ModuleForTests(name, recoveryVariant).Module().(*Module)
- if m.ExcludeFromRecoverySnapshot() != expected {
- t.Errorf("expected %q ExcludeFromRecoverySnapshot to be %t", m.String(), expected)
- }
-}
-
func TestVendorSnapshotExclude(t *testing.T) {
// This test verifies that the exclude_from_vendor_snapshot property
@@ -1371,13 +1363,13 @@
android.FailIfErrored(t, errs)
// Test an include and exclude framework module.
- assertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude", false)
- assertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude", true)
- assertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude", true)
+ AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude", false, recoveryVariant)
+ AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude", true, recoveryVariant)
+ AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude", true, recoveryVariant)
// A recovery module is excluded, but by its path, not the
// exclude_from_recovery_snapshot property.
- assertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery", false)
+ AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery", false, recoveryVariant)
// Verify the content of the recovery snapshot.
diff --git a/cc/vndk.go b/cc/vndk.go
index 1ae79de..c9c9f2c 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -495,7 +495,7 @@
filterOutFromMakeVar: filter,
}
m.AddProperties(&m.properties)
- android.InitAndroidModule(m)
+ android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
return m
}
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index da34f36..31b6d10 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -144,7 +144,6 @@
// current VNDK prebuilts are only shared libs.
in := p.singleSourcePath(ctx)
- builderFlags := flagsToBuilderFlags(flags)
p.unstrippedOutputFile = in
libName := in.Base()
if p.stripper.NeedsStrip(ctx) {
@@ -158,7 +157,7 @@
// depending on a table of contents file instead of the library itself.
tocFile := android.PathForModuleOut(ctx, libName+".toc")
p.tocFile = android.OptionalPathForPath(tocFile)
- transformSharedObjectToToc(ctx, in, tocFile, builderFlags)
+ TransformSharedObjectToToc(ctx, in, tocFile)
p.androidMkSuffix = p.NameSuffix()
diff --git a/cmd/extract_apks/main.go b/cmd/extract_apks/main.go
index 6e51a28..1cf64de 100644
--- a/cmd/extract_apks/main.go
+++ b/cmd/extract_apks/main.go
@@ -356,7 +356,7 @@
// Writes out selected entries, renaming them as needed
func (apkSet *ApkSet) writeApks(selected SelectionResult, config TargetConfig,
- writer Zip2ZipWriter, partition string) ([]string, error) {
+ outFile io.Writer, zipWriter Zip2ZipWriter, partition string) ([]string, error) {
// Renaming rules:
// splits/MODULE-master.apk to STEM.apk
// else
@@ -406,8 +406,14 @@
origin, inName, outName)
}
entryOrigin[outName] = inName
- if err := writer.CopyFrom(apkFile, outName); err != nil {
- return nil, err
+ if outName == config.stem+".apk" {
+ if err := writeZipEntryToFile(outFile, apkFile); err != nil {
+ return nil, err
+ }
+ } else {
+ if err := zipWriter.CopyFrom(apkFile, outName); err != nil {
+ return nil, err
+ }
}
if partition != "" {
apkcerts = append(apkcerts, fmt.Sprintf(
@@ -426,14 +432,13 @@
if !ok {
return fmt.Errorf("Couldn't find apk path %s", selected.entries[0])
}
- inputReader, _ := apk.Open()
- _, err := io.Copy(outFile, inputReader)
- return err
+ return writeZipEntryToFile(outFile, apk)
}
// Arguments parsing
var (
- outputFile = flag.String("o", "", "output file containing extracted entries")
+ outputFile = flag.String("o", "", "output file for primary entry")
+ zipFile = flag.String("zip", "", "output file containing additional extracted entries")
targetConfig = TargetConfig{
screenDpi: map[android_bundle_proto.ScreenDensity_DensityAlias]bool{},
abis: map[android_bundle_proto.Abi_AbiAlias]int{},
@@ -494,7 +499,8 @@
func processArgs() {
flag.Usage = func() {
- fmt.Fprintln(os.Stderr, `usage: extract_apks -o <output-file> -sdk-version value -abis value `+
+ fmt.Fprintln(os.Stderr, `usage: extract_apks -o <output-file> [-zip <output-zip-file>] `+
+ `-sdk-version value -abis value `+
`-screen-densities value {-stem value | -extract-single} [-allow-prereleased] `+
`[-apkcerts <apkcerts output file> -partition <partition>] <APK set>`)
flag.PrintDefaults()
@@ -510,7 +516,8 @@
flag.StringVar(&targetConfig.stem, "stem", "", "output entries base name in the output zip file")
flag.Parse()
if (*outputFile == "") || len(flag.Args()) != 1 || *version == 0 ||
- (targetConfig.stem == "" && !*extractSingle) || (*apkcertsOutput != "" && *partition == "") {
+ ((targetConfig.stem == "" || *zipFile == "") && !*extractSingle) ||
+ (*apkcertsOutput != "" && *partition == "") {
flag.Usage()
}
targetConfig.sdkVersion = int32(*version)
@@ -542,13 +549,20 @@
if *extractSingle {
err = apkSet.extractAndCopySingle(sel, outFile)
} else {
- writer := zip.NewWriter(outFile)
+ zipOutputFile, err := os.Create(*zipFile)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer zipOutputFile.Close()
+
+ zipWriter := zip.NewWriter(zipOutputFile)
defer func() {
- if err := writer.Close(); err != nil {
+ if err := zipWriter.Close(); err != nil {
log.Fatal(err)
}
}()
- apkcerts, err := apkSet.writeApks(sel, targetConfig, writer, *partition)
+
+ apkcerts, err := apkSet.writeApks(sel, targetConfig, outFile, zipWriter, *partition)
if err == nil && *apkcertsOutput != "" {
apkcertsFile, err := os.Create(*apkcertsOutput)
if err != nil {
@@ -567,3 +581,13 @@
log.Fatal(err)
}
}
+
+func writeZipEntryToFile(outFile io.Writer, zipEntry *zip.File) error {
+ reader, err := zipEntry.Open()
+ if err != nil {
+ return err
+ }
+ defer reader.Close()
+ _, err = io.Copy(outFile, reader)
+ return err
+}
diff --git a/cmd/extract_apks/main_test.go b/cmd/extract_apks/main_test.go
index 9fcf324..f5e4046 100644
--- a/cmd/extract_apks/main_test.go
+++ b/cmd/extract_apks/main_test.go
@@ -15,6 +15,7 @@
package main
import (
+ "bytes"
"fmt"
"reflect"
"testing"
@@ -437,8 +438,8 @@
stem string
partition string
// what we write from what
- expectedZipEntries map[string]string
- expectedApkcerts []string
+ zipEntries map[string]string
+ expectedApkcerts []string
}
func TestWriteApks(t *testing.T) {
@@ -448,7 +449,7 @@
moduleName: "mybase",
stem: "Foo",
partition: "system",
- expectedZipEntries: map[string]string{
+ zipEntries: map[string]string{
"Foo.apk": "splits/mybase-master.apk",
"Foo-xhdpi.apk": "splits/mybase-xhdpi.apk",
},
@@ -462,7 +463,7 @@
moduleName: "base",
stem: "Bar",
partition: "product",
- expectedZipEntries: map[string]string{
+ zipEntries: map[string]string{
"Bar.apk": "universal.apk",
},
expectedApkcerts: []string{
@@ -471,23 +472,46 @@
},
}
for _, testCase := range testCases {
- apkSet := ApkSet{entries: make(map[string]*zip.File)}
- sel := SelectionResult{moduleName: testCase.moduleName}
- for _, in := range testCase.expectedZipEntries {
- apkSet.entries[in] = &zip.File{FileHeader: zip.FileHeader{Name: in}}
- sel.entries = append(sel.entries, in)
- }
- writer := testZip2ZipWriter{make(map[string]string)}
- config := TargetConfig{stem: testCase.stem}
- apkcerts, err := apkSet.writeApks(sel, config, writer, testCase.partition)
- if err != nil {
- t.Error(err)
- }
- if !reflect.DeepEqual(testCase.expectedZipEntries, writer.entries) {
- t.Errorf("expected zip entries %v, got %v", testCase.expectedZipEntries, writer.entries)
- }
- if !reflect.DeepEqual(testCase.expectedApkcerts, apkcerts) {
- t.Errorf("expected apkcerts %v, got %v", testCase.expectedApkcerts, apkcerts)
- }
+ t.Run(testCase.name, func(t *testing.T) {
+ testZipBuf := &bytes.Buffer{}
+ testZip := zip.NewWriter(testZipBuf)
+ for _, in := range testCase.zipEntries {
+ f, _ := testZip.Create(in)
+ f.Write([]byte(in))
+ }
+ testZip.Close()
+
+ zipReader, _ := zip.NewReader(bytes.NewReader(testZipBuf.Bytes()), int64(testZipBuf.Len()))
+
+ apkSet := ApkSet{entries: make(map[string]*zip.File)}
+ sel := SelectionResult{moduleName: testCase.moduleName}
+ for _, f := range zipReader.File {
+ apkSet.entries[f.Name] = f
+ sel.entries = append(sel.entries, f.Name)
+ }
+
+ zipWriter := testZip2ZipWriter{make(map[string]string)}
+ outWriter := &bytes.Buffer{}
+ config := TargetConfig{stem: testCase.stem}
+ apkcerts, err := apkSet.writeApks(sel, config, outWriter, zipWriter, testCase.partition)
+ if err != nil {
+ t.Error(err)
+ }
+ expectedZipEntries := make(map[string]string)
+ for k, v := range testCase.zipEntries {
+ if k != testCase.stem+".apk" {
+ expectedZipEntries[k] = v
+ }
+ }
+ if !reflect.DeepEqual(expectedZipEntries, zipWriter.entries) {
+ t.Errorf("expected zip entries %v, got %v", testCase.zipEntries, zipWriter.entries)
+ }
+ if !reflect.DeepEqual(testCase.expectedApkcerts, apkcerts) {
+ t.Errorf("expected apkcerts %v, got %v", testCase.expectedApkcerts, apkcerts)
+ }
+ if g, w := outWriter.String(), testCase.zipEntries[testCase.stem+".apk"]; !reflect.DeepEqual(g, w) {
+ t.Errorf("expected output file contents %q, got %q", testCase.stem+".apk", outWriter.String())
+ }
+ })
}
}
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index e9eabd3..dfc4eae 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -464,6 +464,11 @@
// conversion for Bazel conversion.
bp2buildCtx := android.NewContext(configuration)
+ // Soong internals like LoadHooks behave differently when running as
+ // bp2build. This is the bit to differentiate between Soong-as-Soong and
+ // Soong-as-bp2build.
+ bp2buildCtx.SetRunningAsBp2build()
+
// Propagate "allow misssing dependencies" bit. This is normally set in
// newContext(), but we create bp2buildCtx without calling that method.
bp2buildCtx.SetAllowMissingDependencies(configuration.AllowMissingDependencies())
diff --git a/compliance/build_license_metadata/build_license_metadata.go b/compliance/build_license_metadata/build_license_metadata.go
index ba3cc3e..8b1fe58 100644
--- a/compliance/build_license_metadata/build_license_metadata.go
+++ b/compliance/build_license_metadata/build_license_metadata.go
@@ -119,7 +119,7 @@
for _, installMap := range installMaps {
components := strings.Split(installMap, ":")
if len(components) != 2 {
- panic(fmt.Errorf("install map entry %q contains %d colons, expected 1", len(components)-1))
+ panic(fmt.Errorf("install map entry %q contains %d colons, expected 1", installMap, len(components)-1))
}
ret = append(ret, &license_metadata_proto.InstallMap{
FromPath: proto.String(components[0]),
@@ -140,7 +140,7 @@
dep := components[0]
components = components[1:]
ad := &license_metadata_proto.AnnotatedDependency{
- File: proto.String(dep),
+ File: proto.String(dep),
Annotations: make([]string, 0, len(components)),
}
for _, ann := range components {
diff --git a/cuj/run_cuj_tests.sh b/cuj/run_cuj_tests.sh
index b4f9f88..a746bd5 100755
--- a/cuj/run_cuj_tests.sh
+++ b/cuj/run_cuj_tests.sh
@@ -18,11 +18,10 @@
cd "$ANDROID_TOP"
export OUT_DIR="${OUT_DIR:-out}"
-readonly SOONG_OUT="${OUT_DIR}/soong"
-build/soong/soong_ui.bash --make-mode "${SOONG_OUT}/host/${OS}-x86/bin/cuj_tests"
+build/soong/soong_ui.bash --make-mode "${OUT_DIR}/host/${OS}-x86/bin/cuj_tests"
-"${SOONG_OUT}/host/${OS}-x86/bin/cuj_tests" || true
+"${OUT_DIR}/host/${OS}-x86/bin/cuj_tests" || true
if [ -n "${DIST_DIR}" ]; then
cp -r "${OUT_DIR}/cuj_tests/logs" "${DIST_DIR}"
diff --git a/dexpreopt/class_loader_context_test.go b/dexpreopt/class_loader_context_test.go
index d81ac2c..4a3d390 100644
--- a/dexpreopt/class_loader_context_test.go
+++ b/dexpreopt/class_loader_context_test.go
@@ -115,16 +115,16 @@
// Test that class loader context structure is correct.
t.Run("string", func(t *testing.T) {
wantStr := " --host-context-for-sdk 29 " +
- "PCL[out/" + AndroidHidlManager + ".jar]#" +
- "PCL[out/" + AndroidHidlBase + ".jar]" +
+ "PCL[out/soong/" + AndroidHidlManager + ".jar]#" +
+ "PCL[out/soong/" + AndroidHidlBase + ".jar]" +
" --target-context-for-sdk 29 " +
"PCL[/system/framework/" + AndroidHidlManager + ".jar]#" +
"PCL[/system/framework/" + AndroidHidlBase + ".jar]" +
" --host-context-for-sdk any " +
- "PCL[out/a.jar]#PCL[out/b.jar]#PCL[out/c.jar]#PCL[out/d.jar]" +
- "{PCL[out/a2.jar]#PCL[out/b2.jar]#PCL[out/c2.jar]" +
- "{PCL[out/a1.jar]#PCL[out/b1.jar]}}#" +
- "PCL[out/f.jar]#PCL[out/a3.jar]#PCL[out/b3.jar]" +
+ "PCL[out/soong/a.jar]#PCL[out/soong/b.jar]#PCL[out/soong/c.jar]#PCL[out/soong/d.jar]" +
+ "{PCL[out/soong/a2.jar]#PCL[out/soong/b2.jar]#PCL[out/soong/c2.jar]" +
+ "{PCL[out/soong/a1.jar]#PCL[out/soong/b1.jar]}}#" +
+ "PCL[out/soong/f.jar]#PCL[out/soong/a3.jar]#PCL[out/soong/b3.jar]" +
" --target-context-for-sdk any " +
"PCL[/system/a.jar]#PCL[/system/b.jar]#PCL[/system/c.jar]#PCL[/system/d.jar]" +
"{PCL[/system/a2.jar]#PCL[/system/b2.jar]#PCL[/system/c2.jar]" +
@@ -138,11 +138,11 @@
// Test that all expected build paths are gathered.
t.Run("paths", func(t *testing.T) {
wantPaths := []string{
- "out/android.hidl.manager-V1.0-java.jar", "out/android.hidl.base-V1.0-java.jar",
- "out/a.jar", "out/b.jar", "out/c.jar", "out/d.jar",
- "out/a2.jar", "out/b2.jar", "out/c2.jar",
- "out/a1.jar", "out/b1.jar",
- "out/f.jar", "out/a3.jar", "out/b3.jar",
+ "out/soong/android.hidl.manager-V1.0-java.jar", "out/soong/android.hidl.base-V1.0-java.jar",
+ "out/soong/a.jar", "out/soong/b.jar", "out/soong/c.jar", "out/soong/d.jar",
+ "out/soong/a2.jar", "out/soong/b2.jar", "out/soong/c2.jar",
+ "out/soong/a1.jar", "out/soong/b1.jar",
+ "out/soong/f.jar", "out/soong/a3.jar", "out/soong/b3.jar",
}
if !reflect.DeepEqual(wantPaths, havePaths.Strings()) {
t.Errorf("\nwant paths: %s\nhave paths: %s", wantPaths, havePaths)
@@ -270,13 +270,13 @@
// Test that class loader context structure is correct.
t.Run("string", func(t *testing.T) {
- wantStr := " --host-context-for-sdk 30 PCL[out/c.jar]" +
+ wantStr := " --host-context-for-sdk 30 PCL[out/soong/c.jar]" +
" --target-context-for-sdk 30 PCL[/system/c.jar]" +
- " --host-context-for-sdk 29 PCL[out/b.jar]" +
+ " --host-context-for-sdk 29 PCL[out/soong/b.jar]" +
" --target-context-for-sdk 29 PCL[/system/b.jar]" +
- " --host-context-for-sdk 28 PCL[out/a.jar]" +
+ " --host-context-for-sdk 28 PCL[out/soong/a.jar]" +
" --target-context-for-sdk 28 PCL[/system/a.jar]" +
- " --host-context-for-sdk any PCL[out/d.jar]" +
+ " --host-context-for-sdk any PCL[out/soong/d.jar]" +
" --target-context-for-sdk any PCL[/system/d.jar]"
if wantStr != haveStr {
t.Errorf("\nwant class loader context: %s\nhave class loader context: %s", wantStr, haveStr)
diff --git a/java/androidmk.go b/java/androidmk.go
index eca5caa..272a4fd 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -47,6 +47,7 @@
if library.dexJarFile.IsSet() {
entries.SetPath("LOCAL_SOONG_DEX_JAR", library.dexJarFile.Path())
}
+ entries.SetPath("LOCAL_SOONG_INSTALLED_MODULE", library.hostdexInstallFile)
entries.SetPath("LOCAL_SOONG_HEADER_JAR", library.headerJarFile)
entries.SetPath("LOCAL_SOONG_CLASSES_JAR", library.implementationAndResourcesJar)
entries.SetString("LOCAL_MODULE_STEM", library.Stem()+"-hostdex")
@@ -285,11 +286,6 @@
}}
} else {
outputFile := binary.wrapperFile
- // Have Make installation trigger Soong installation by using Soong's install path as
- // the output file.
- if binary.Host() {
- outputFile = binary.binaryFile
- }
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "EXECUTABLES",
@@ -700,12 +696,12 @@
return []android.AndroidMkEntries{
android.AndroidMkEntries{
Class: "APPS",
- OutputFile: android.OptionalPathForPath(apkSet.packedOutput),
+ OutputFile: android.OptionalPathForPath(apkSet.primaryOutput),
Include: "$(BUILD_SYSTEM)/soong_android_app_set.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", apkSet.Privileged())
- entries.SetString("LOCAL_APK_SET_INSTALL_FILE", apkSet.InstallFile())
+ entries.SetPath("LOCAL_APK_SET_INSTALL_FILE", apkSet.PackedAdditionalOutputs())
entries.SetPath("LOCAL_APKCERTS_FILE", apkSet.apkcertsFile)
entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", apkSet.properties.Overrides...)
},
diff --git a/java/app.go b/java/app.go
index 6554d66..c08ec06 100755
--- a/java/app.go
+++ b/java/app.go
@@ -471,6 +471,7 @@
a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
a.dexpreopter.classLoaderContexts = a.classLoaderContexts
a.dexpreopter.manifestFile = a.mergedManifestFile
+ a.dexpreopter.preventInstall = a.appProperties.PreventInstall
if ctx.ModuleName() != "framework-res" {
a.Module.compile(ctx, a.aaptSrcJar)
@@ -720,11 +721,15 @@
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
// Install the app package.
- if (Bool(a.Module.properties.Installable) || ctx.Host()) && apexInfo.IsForPlatform() {
- ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile)
+ if (Bool(a.Module.properties.Installable) || ctx.Host()) && apexInfo.IsForPlatform() &&
+ !a.appProperties.PreventInstall {
+
+ var extraInstalledPaths android.Paths
for _, extra := range a.extraOutputFiles {
- ctx.InstallFile(a.installDir, extra.Base(), extra)
+ installed := ctx.InstallFile(a.installDir, extra.Base(), extra)
+ extraInstalledPaths = append(extraInstalledPaths, installed)
}
+ ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile, extraInstalledPaths...)
}
a.buildAppDependencyInfo(ctx)
diff --git a/java/app_import.go b/java/app_import.go
index 3e5f972..4d1969e 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -108,6 +108,8 @@
return true
}
+func (a *AndroidAppImport) InstallBypassMake() bool { return true }
+
// Updates properties with variant-specific values.
func (a *AndroidAppImport) processVariants(ctx android.LoadHookContext) {
config := ctx.Config()
diff --git a/java/app_set.go b/java/app_set.go
index 6b25638..694b167 100644
--- a/java/app_set.go
+++ b/java/app_set.go
@@ -55,10 +55,10 @@
android.DefaultableModuleBase
prebuilt android.Prebuilt
- properties AndroidAppSetProperties
- packedOutput android.WritablePath
- installFile string
- apkcertsFile android.ModuleOutPath
+ properties AndroidAppSetProperties
+ packedOutput android.WritablePath
+ primaryOutput android.WritablePath
+ apkcertsFile android.ModuleOutPath
}
func (as *AndroidAppSet) Name() string {
@@ -78,11 +78,11 @@
}
func (as *AndroidAppSet) OutputFile() android.Path {
- return as.packedOutput
+ return as.primaryOutput
}
-func (as *AndroidAppSet) InstallFile() string {
- return as.installFile
+func (as *AndroidAppSet) PackedAdditionalOutputs() android.Path {
+ return as.packedOutput
}
func (as *AndroidAppSet) APKCertsFile() android.Path {
@@ -114,11 +114,11 @@
func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
as.packedOutput = android.PathForModuleOut(ctx, ctx.ModuleName()+".zip")
+ as.primaryOutput = android.PathForModuleOut(ctx, as.BaseModuleName()+".apk")
as.apkcertsFile = android.PathForModuleOut(ctx, "apkcerts.txt")
// We are assuming here that the install file in the APK
// set has `.apk` suffix. If it doesn't the build will fail.
// APK sets containing APEX files are handled elsewhere.
- as.installFile = as.BaseModuleName() + ".apk"
screenDensities := "all"
if dpis := ctx.Config().ProductAAPTPrebuiltDPI(); len(dpis) > 0 {
screenDensities = strings.ToUpper(strings.Join(dpis, ","))
@@ -127,11 +127,11 @@
// TODO(asmundak): do we support device features
ctx.Build(pctx,
android.BuildParams{
- Rule: extractMatchingApks,
- Description: "Extract APKs from APK set",
- Output: as.packedOutput,
- ImplicitOutput: as.apkcertsFile,
- Inputs: android.Paths{as.prebuilt.SingleSourcePath(ctx)},
+ Rule: extractMatchingApks,
+ Description: "Extract APKs from APK set",
+ Output: as.primaryOutput,
+ ImplicitOutputs: android.WritablePaths{as.packedOutput, as.apkcertsFile},
+ Inputs: android.Paths{as.prebuilt.SingleSourcePath(ctx)},
Args: map[string]string{
"abis": strings.Join(SupportedAbis(ctx), ","),
"allow-prereleased": strconv.FormatBool(proptools.Bool(as.properties.Prerelease)),
@@ -140,10 +140,21 @@
"stem": as.BaseModuleName(),
"apkcerts": as.apkcertsFile.String(),
"partition": as.PartitionTag(ctx.DeviceConfig()),
+ "zip": as.packedOutput.String(),
},
})
+
+ var installDir android.InstallPath
+ if as.Privileged() {
+ installDir = android.PathForModuleInstall(ctx, "priv-app", as.BaseModuleName())
+ } else {
+ installDir = android.PathForModuleInstall(ctx, "app", as.BaseModuleName())
+ }
+ ctx.InstallFileWithExtraFilesZip(installDir, as.BaseModuleName()+".apk", as.primaryOutput, as.packedOutput)
}
+func (as *AndroidAppSet) InstallBypassMake() bool { return true }
+
// android_app_set extracts a set of APKs based on the target device
// configuration and installs this set as "split APKs".
// The extracted set always contains an APK whose name is
diff --git a/java/app_set_test.go b/java/app_set_test.go
index adaf71b..03eb667 100644
--- a/java/app_set_test.go
+++ b/java/app_set_test.go
@@ -17,19 +17,20 @@
import (
"fmt"
"reflect"
+ "strings"
"testing"
"android/soong/android"
)
func TestAndroidAppSet(t *testing.T) {
- ctx, _ := testJava(t, `
+ result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, `
android_app_set {
name: "foo",
set: "prebuilts/apks/app.apks",
prerelease: true,
}`)
- module := ctx.ModuleForTests("foo", "android_common")
+ module := result.ModuleForTests("foo", "android_common")
const packedSplitApks = "foo.zip"
params := module.Output(packedSplitApks)
if params.Rule == nil {
@@ -41,9 +42,22 @@
if s := params.Args["partition"]; s != "system" {
t.Errorf("wrong partition value: '%s', expected 'system'", s)
}
- mkEntries := android.AndroidMkEntriesForTest(t, ctx, module.Module())[0]
+
+ android.AssertPathRelativeToTopEquals(t, "incorrect output path",
+ "out/soong/.intermediates/foo/android_common/foo.apk", params.Output)
+
+ android.AssertPathsRelativeToTopEquals(t, "incorrect implicit output paths",
+ []string{
+ "out/soong/.intermediates/foo/android_common/foo.zip",
+ "out/soong/.intermediates/foo/android_common/apkcerts.txt",
+ },
+ params.ImplicitOutputs.Paths())
+
+ mkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, module.Module())[0]
actualInstallFile := mkEntries.EntryMap["LOCAL_APK_SET_INSTALL_FILE"]
- expectedInstallFile := []string{"foo.apk"}
+ expectedInstallFile := []string{
+ strings.Replace(params.ImplicitOutputs[0].String(), android.OutSoongDir, result.Config.SoongOutDir(), 1),
+ }
if !reflect.DeepEqual(actualInstallFile, expectedInstallFile) {
t.Errorf("Unexpected LOCAL_APK_SET_INSTALL_FILE value: '%s', expected: '%s',",
actualInstallFile, expectedInstallFile)
diff --git a/java/app_test.go b/java/app_test.go
index 07439fc..0aae928 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -144,14 +144,14 @@
}
`)
- testJavaError(t, "platform_apis must be true when sdk_version is empty.", `
+ testJavaError(t, "This module has conflicting settings. sdk_version is empty, which means that this module is build against platform APIs. However platform_apis is not set to true", `
android_app {
name: "bar",
srcs: ["b.java"],
}
`)
- testJavaError(t, "platform_apis must be false when sdk_version is not empty.", `
+ testJavaError(t, "This module has conflicting settings. sdk_version is not empty, which means this module cannot use platform APIs. However platform_apis is set to true.", `
android_app {
name: "bar",
srcs: ["b.java"],
diff --git a/java/base.go b/java/base.go
index ca34f2e..d9b1260 100644
--- a/java/base.go
+++ b/java/base.go
@@ -184,16 +184,21 @@
// Properties that are specific to device modules. Host module factories should not add these when
// constructing a new module.
type DeviceProperties struct {
- // if not blank, set to the version of the sdk to compile against.
+ // If not blank, set to the version of the sdk to compile against.
// Defaults to compiling against the current platform.
+ // Values are of one of the following forms:
+ // 1) numerical API level or "current"
+ // 2) An SDK kind with an API level: "<sdk kind>_<API level>". See
+ // build/soong/android/sdk_version.go for the complete and up to date list of
+ // SDK kinds. If the SDK kind value is empty, it will be set to public.
Sdk_version *string
// if not blank, set the minimum version of the sdk that the compiled artifacts will run against.
- // Defaults to sdk_version if not set.
+ // Defaults to sdk_version if not set. See sdk_version for possible values.
Min_sdk_version *string
// if not blank, set the targetSdkVersion in the AndroidManifest.xml.
- // Defaults to sdk_version if not set.
+ // Defaults to sdk_version if not set. See sdk_version for possible values.
Target_sdk_version *string
// Whether to compile against the platform APIs instead of an SDK.
@@ -407,6 +412,9 @@
// installed file for binary dependency
installFile android.Path
+ // installed file for hostdex copy
+ hostdexInstallFile android.InstallPath
+
// list of .java files and srcjars that was passed to javac
compiledJavaSrcs android.Paths
compiledSrcJars android.Paths
@@ -502,9 +510,9 @@
usePlatformAPI := proptools.Bool(j.deviceProperties.Platform_apis)
sdkVersionSpecified := sc.SdkVersion(ctx).Specified()
if usePlatformAPI && sdkVersionSpecified {
- ctx.PropertyErrorf("platform_apis", "platform_apis must be false when sdk_version is not empty.")
+ ctx.PropertyErrorf("platform_apis", "This module has conflicting settings. sdk_version is not empty, which means this module cannot use platform APIs. However platform_apis is set to true.")
} else if !usePlatformAPI && !sdkVersionSpecified {
- ctx.PropertyErrorf("platform_apis", "platform_apis must be true when sdk_version is empty.")
+ ctx.PropertyErrorf("platform_apis", "This module has conflicting settings. sdk_version is empty, which means that this module is build against platform APIs. However platform_apis is not set to true")
}
}
@@ -784,6 +792,9 @@
flags = append(flags, "--transaction_names")
}
+ aidlMinSdkVersion := j.MinSdkVersion(ctx).ApiLevel.String()
+ flags = append(flags, "--min_sdk_version="+aidlMinSdkVersion)
+
return strings.Join(flags, " "), deps
}
@@ -1055,7 +1066,7 @@
j.compiledSrcJars = srcJars
enableSharding := false
- var headerJarFileWithoutJarjar android.Path
+ var headerJarFileWithoutDepsOrJarjar android.Path
if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") && !deps.disableTurbine {
if j.properties.Javac_shard_size != nil && *(j.properties.Javac_shard_size) > 0 {
enableSharding = true
@@ -1065,7 +1076,7 @@
// allow for the use of annotation processors that do function correctly
// with sharding enabled. See: b/77284273.
}
- headerJarFileWithoutJarjar, j.headerJarFile =
+ headerJarFileWithoutDepsOrJarjar, j.headerJarFile =
j.compileJavaHeader(ctx, uniqueSrcFiles, srcJars, deps, flags, jarName, kotlinJars)
if ctx.Failed() {
return
@@ -1094,7 +1105,9 @@
}
if enableSharding {
- flags.classpath = append(flags.classpath, headerJarFileWithoutJarjar)
+ if headerJarFileWithoutDepsOrJarjar != nil {
+ flags.classpath = append(classpath{headerJarFileWithoutDepsOrJarjar}, flags.classpath...)
+ }
shardSize := int(*(j.properties.Javac_shard_size))
var shardSrcs []android.Paths
if len(uniqueSrcFiles) > 0 {
@@ -1497,7 +1510,7 @@
func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars android.Paths,
deps deps, flags javaBuilderFlags, jarName string,
- extraJars android.Paths) (headerJar, jarjarHeaderJar android.Path) {
+ extraJars android.Paths) (headerJar, jarjarAndDepsHeaderJar android.Path) {
var jars android.Paths
if len(srcFiles) > 0 || len(srcJars) > 0 {
@@ -1508,6 +1521,7 @@
return nil, nil
}
jars = append(jars, turbineJar)
+ headerJar = turbineJar
}
jars = append(jars, extraJars...)
@@ -1521,20 +1535,19 @@
combinedJar := android.PathForModuleOut(ctx, "turbine-combined", jarName)
TransformJarsToJar(ctx, combinedJar, "for turbine", jars, android.OptionalPath{},
false, nil, []string{"META-INF/TRANSITIVE"})
- headerJar = combinedJar
- jarjarHeaderJar = combinedJar
+ jarjarAndDepsHeaderJar = combinedJar
if j.expandJarjarRules != nil {
// Transform classes.jar into classes-jarjar.jar
jarjarFile := android.PathForModuleOut(ctx, "turbine-jarjar", jarName)
- TransformJarJar(ctx, jarjarFile, headerJar, j.expandJarjarRules)
- jarjarHeaderJar = jarjarFile
+ TransformJarJar(ctx, jarjarFile, jarjarAndDepsHeaderJar, j.expandJarjarRules)
+ jarjarAndDepsHeaderJar = jarjarFile
if ctx.Failed() {
return nil, nil
}
}
- return headerJar, jarjarHeaderJar
+ return headerJar, jarjarAndDepsHeaderJar
}
func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
diff --git a/java/builder.go b/java/builder.go
index ae124a3..e64a61f 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -120,14 +120,14 @@
"extractMatchingApks",
blueprint.RuleParams{
Command: `rm -rf "$out" && ` +
- `${config.ExtractApksCmd} -o "${out}" -allow-prereleased=${allow-prereleased} ` +
+ `${config.ExtractApksCmd} -o "${out}" -zip "${zip}" -allow-prereleased=${allow-prereleased} ` +
`-sdk-version=${sdk-version} -abis=${abis} ` +
`--screen-densities=${screen-densities} --stem=${stem} ` +
`-apkcerts=${apkcerts} -partition=${partition} ` +
`${in}`,
CommandDeps: []string{"${config.ExtractApksCmd}"},
},
- "abis", "allow-prereleased", "screen-densities", "sdk-version", "stem", "apkcerts", "partition")
+ "abis", "allow-prereleased", "screen-densities", "sdk-version", "stem", "apkcerts", "partition", "zip")
turbine, turbineRE = pctx.RemoteStaticRules("turbine",
blueprint.RuleParams{
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index e9dc982..7c081b6 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -66,6 +66,7 @@
isApp bool
isTest bool
isPresignedPrebuilt bool
+ preventInstall bool
manifestFile android.Path
statusFile android.WritablePath
@@ -335,17 +336,19 @@
dexpreoptRule.Build("dexpreopt", "dexpreopt")
- if global.ApexSystemServerJars.ContainsJar(moduleName(ctx)) {
- // APEX variants of java libraries are hidden from Make, so their dexpreopt outputs need special
- // handling. Currently, for APEX variants of java libraries, only those in the system server
- // classpath are handled here. Preopting of boot classpath jars in the ART APEX are handled in
- // java/dexpreopt_bootjars.go, and other APEX jars are not preopted.
- for _, install := range dexpreoptRule.Installs() {
- // Remove the "/" prefix because the path should be relative to $ANDROID_PRODUCT_OUT.
- installDir := strings.TrimPrefix(filepath.Dir(install.To), "/")
- installBase := filepath.Base(install.To)
- arch := filepath.Base(installDir)
- installPath := android.PathForModuleInPartitionInstall(ctx, "", installDir)
+ for _, install := range dexpreoptRule.Installs() {
+ // Remove the "/" prefix because the path should be relative to $ANDROID_PRODUCT_OUT.
+ installDir := strings.TrimPrefix(filepath.Dir(install.To), "/")
+ installBase := filepath.Base(install.To)
+ arch := filepath.Base(installDir)
+ installPath := android.PathForModuleInPartitionInstall(ctx, "", installDir)
+
+ if global.ApexSystemServerJars.ContainsJar(moduleName(ctx)) {
+ // APEX variants of java libraries are hidden from Make, so their dexpreopt
+ // outputs need special handling. Currently, for APEX variants of java
+ // libraries, only those in the system server classpath are handled here.
+ // Preopting of boot classpath jars in the ART APEX are handled in
+ // java/dexpreopt_bootjars.go, and other APEX jars are not preopted.
// The installs will be handled by Make as sub-modules of the java library.
d.builtInstalledForApex = append(d.builtInstalledForApex, dexpreopterInstall{
name: arch + "-" + installBase,
@@ -354,10 +357,12 @@
installDirOnDevice: installPath,
installFileOnDevice: installBase,
})
+ } else if !d.preventInstall {
+ ctx.InstallFile(installPath, installBase, install.From)
}
- } else {
- // The installs will be handled by Make as LOCAL_SOONG_BUILT_INSTALLED of the java library
- // module.
+ }
+
+ if !global.ApexSystemServerJars.ContainsJar(moduleName(ctx)) {
d.builtInstalled = dexpreoptRule.Installs().String()
}
}
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 869a598..c84a15c 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -769,8 +769,8 @@
d.Javadoc.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip")
- jsilver := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "jsilver.jar")
- doclava := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "doclava.jar")
+ jsilver := ctx.Config().HostJavaToolPath(ctx, "jsilver.jar")
+ doclava := ctx.Config().HostJavaToolPath(ctx, "doclava.jar")
outDir := android.PathForModuleOut(ctx, "out")
srcJarDir := android.PathForModuleOut(ctx, "srcjars")
diff --git a/java/java.go b/java/java.go
index 854097b..2f9e03a 100644
--- a/java/java.go
+++ b/java/java.go
@@ -265,6 +265,8 @@
return j.kytheFiles
}
+func (j *Module) InstallBypassMake() bool { return true }
+
type dependencyTag struct {
blueprint.BaseDependencyTag
name string
@@ -567,8 +569,23 @@
if j.InstallMixin != nil {
extraInstallDeps = j.InstallMixin(ctx, j.outputFile)
}
- j.installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
- j.Stem()+".jar", j.outputFile, extraInstallDeps...)
+ hostDexNeeded := Bool(j.deviceProperties.Hostdex) && !ctx.Host()
+ if hostDexNeeded {
+ j.hostdexInstallFile = ctx.InstallFile(
+ android.PathForHostDexInstall(ctx, "framework"),
+ j.Stem()+"-hostdex.jar", j.outputFile)
+ }
+ var installDir android.InstallPath
+ if ctx.InstallInTestcases() {
+ var archDir string
+ if !ctx.Host() {
+ archDir = ctx.DeviceConfig().DeviceArch()
+ }
+ installDir = android.PathForModuleInstall(ctx, ctx.ModuleName(), archDir)
+ } else {
+ installDir = android.PathForModuleInstall(ctx, "framework")
+ }
+ j.installFile = ctx.InstallFile(installDir, j.Stem()+".jar", j.outputFile, extraInstallDeps...)
}
}
@@ -842,6 +859,20 @@
dexJarFile android.Path
}
+func (j *Test) InstallInTestcases() bool {
+ // Host java tests install into $(HOST_OUT_JAVA_LIBRARIES), and then are copied into
+ // testcases by base_rules.mk.
+ return !j.Host()
+}
+
+func (j *TestHelperLibrary) InstallInTestcases() bool {
+ return true
+}
+
+func (j *JavaTestImport) InstallInTestcases() bool {
+ return true
+}
+
func (j *TestHost) DepsMutator(ctx android.BottomUpMutatorContext) {
if len(j.testHostProperties.Data_native_bins) > 0 {
for _, target := range ctx.MultiTargets() {
@@ -1376,8 +1407,17 @@
})
if Bool(j.properties.Installable) {
- ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
- jarName, outputFile)
+ var installDir android.InstallPath
+ if ctx.InstallInTestcases() {
+ var archDir string
+ if !ctx.Host() {
+ archDir = ctx.DeviceConfig().DeviceArch()
+ }
+ installDir = android.PathForModuleInstall(ctx, ctx.ModuleName(), archDir)
+ } else {
+ installDir = android.PathForModuleInstall(ctx, "framework")
+ }
+ ctx.InstallFile(installDir, jarName, outputFile)
}
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs)
diff --git a/java/java_test.go b/java/java_test.go
index bc9b409..6e4e673 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -988,11 +988,11 @@
}
`)
- barHeaderJar := filepath.Join("out", "soong", ".intermediates", "bar", "android_common", "turbine-combined", "bar.jar")
+ barHeaderJar := filepath.Join("out", "soong", ".intermediates", "bar", "android_common", "turbine", "bar.jar")
for i := 0; i < 3; i++ {
barJavac := ctx.ModuleForTests("bar", "android_common").Description("javac" + strconv.Itoa(i))
- if !strings.Contains(barJavac.Args["classpath"], barHeaderJar) {
- t.Errorf("bar javac classpath %v does not contain %q", barJavac.Args["classpath"], barHeaderJar)
+ if !strings.HasPrefix(barJavac.Args["classpath"], "-classpath "+barHeaderJar+":") {
+ t.Errorf("bar javac classpath %v does start with %q", barJavac.Args["classpath"], barHeaderJar)
}
}
}
@@ -1357,6 +1357,36 @@
}
}
+func TestAidlFlagsWithMinSdkVersion(t *testing.T) {
+ fixture := android.GroupFixturePreparers(
+ prepareForJavaTest, FixtureWithPrebuiltApis(map[string][]string{"14": {"foo"}}))
+
+ for _, tc := range []struct {
+ name string
+ sdkVersion string
+ expected string
+ }{
+ {"default is current", "", "current"},
+ {"use sdk_version", `sdk_version: "14"`, "14"},
+ {"system_current", `sdk_version: "system_current"`, "current"},
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ ctx := fixture.RunTestWithBp(t, `
+ java_library {
+ name: "foo",
+ srcs: ["aidl/foo/IFoo.aidl"],
+ `+tc.sdkVersion+`
+ }
+ `)
+ aidlCommand := ctx.ModuleForTests("foo", "android_common").Rule("aidl").RuleParams.Command
+ expectedAidlFlag := "--min_sdk_version=" + tc.expected
+ if !strings.Contains(aidlCommand, expectedAidlFlag) {
+ t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag)
+ }
+ })
+ }
+}
+
func TestDataNativeBinaries(t *testing.T) {
ctx, _ := testJava(t, `
java_test_host {
diff --git a/java/jdeps.go b/java/jdeps.go
index 0ab2e42..eff9a31 100644
--- a/java/jdeps.go
+++ b/java/jdeps.go
@@ -40,16 +40,11 @@
var _ android.SingletonMakeVarsProvider = (*jdepsGeneratorSingleton)(nil)
const (
- // Environment variables used to modify behavior of this singleton.
- envVariableCollectJavaDeps = "SOONG_COLLECT_JAVA_DEPS"
- jdepsJsonFileName = "module_bp_java_deps.json"
+ jdepsJsonFileName = "module_bp_java_deps.json"
)
func (j *jdepsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) {
- if !ctx.Config().IsEnvTrue(envVariableCollectJavaDeps) {
- return
- }
-
+ // (b/204397180) Generate module_bp_java_deps.json by default.
moduleInfos := make(map[string]android.IdeInfo)
ctx.VisitAllModules(func(module android.Module) {
diff --git a/licenses/Android.bp b/licenses/Android.bp
index a983b5b..5b764dc 100644
--- a/licenses/Android.bp
+++ b/licenses/Android.bp
@@ -492,36 +492,36 @@
license_kind {
name: "SPDX-license-identifier-CC-BY-ND",
- conditions: ["restricted"],
+ conditions: ["by_exception_only"],
}
license_kind {
name: "SPDX-license-identifier-CC-BY-ND-1.0",
- conditions: ["restricted"],
+ conditions: ["by_exception_only"],
url: "https://spdx.org/licenses/CC-BY-ND-1.0.html",
}
license_kind {
name: "SPDX-license-identifier-CC-BY-ND-2.0",
- conditions: ["restricted"],
+ conditions: ["by_exception_only"],
url: "https://spdx.org/licenses/CC-BY-ND-2.0.html",
}
license_kind {
name: "SPDX-license-identifier-CC-BY-ND-2.5",
- conditions: ["restricted"],
+ conditions: ["by_exception_only"],
url: "https://spdx.org/licenses/CC-BY-ND-2.5.html",
}
license_kind {
name: "SPDX-license-identifier-CC-BY-ND-3.0",
- conditions: ["restricted"],
+ conditions: ["by_exception_only"],
url: "https://spdx.org/licenses/CC-BY-ND-3.0.html",
}
license_kind {
name: "SPDX-license-identifier-CC-BY-ND-4.0",
- conditions: ["restricted"],
+ conditions: ["by_exception_only"],
url: "https://spdx.org/licenses/CC-BY-ND-4.0.html",
}
@@ -562,7 +562,10 @@
license_kind {
name: "SPDX-license-identifier-CC-BY-SA-ND",
- conditions: ["restricted"],
+ conditions: [
+ "restricted",
+ "by_exception_only",
+ ],
}
license_kind {
diff --git a/mk2rbc/cmd/mk2rbc.go b/mk2rbc/cmd/mk2rbc.go
index b089f91..bb5a680 100644
--- a/mk2rbc/cmd/mk2rbc.go
+++ b/mk2rbc/cmd/mk2rbc.go
@@ -46,17 +46,17 @@
dryRun = flag.Bool("dry_run", false, "dry run")
recurse = flag.Bool("convert_dependents", false, "convert all dependent files")
mode = flag.String("mode", "", `"backup" to back up existing files, "write" to overwrite them`)
- warn = flag.Bool("warnings", false, "warn about partially failed conversions")
- verbose = flag.Bool("v", false, "print summary")
errstat = flag.Bool("error_stat", false, "print error statistics")
traceVar = flag.String("trace", "", "comma-separated list of variables to trace")
// TODO(asmundak): this option is for debugging
allInSource = flag.Bool("all", false, "convert all product config makefiles in the tree under //")
outputTop = flag.String("outdir", "", "write output files into this directory hierarchy")
- launcher = flag.String("launcher", "", "generated launcher path. If set, the non-flag argument is _product_name_")
+ launcher = flag.String("launcher", "", "generated launcher path.")
+ boardlauncher = flag.String("boardlauncher", "", "generated board configuration launcher path.")
printProductConfigMap = flag.Bool("print_product_config_map", false, "print product config map and exit")
cpuProfile = flag.String("cpu_profile", "", "write cpu profile to file")
traceCalls = flag.Bool("trace_calls", false, "trace function calls")
+ inputVariables = flag.String("input_variables", "", "starlark file containing product config and global variables")
)
func init() {
@@ -73,13 +73,12 @@
flagAlias("root", "d")
flagAlias("dry_run", "n")
flagAlias("convert_dependents", "r")
- flagAlias("warnings", "w")
flagAlias("error_stat", "e")
}
var backupSuffix string
var tracedVariables []string
-var errorLogger = errorsByType{data: make(map[string]datum)}
+var errorLogger = errorSink{data: make(map[string]datum)}
var makefileFinder = &LinuxMakefileFinder{}
var versionDefaultsMk = filepath.Join("build", "make", "core", "version_defaults.mk")
@@ -87,8 +86,7 @@
flag.Usage = func() {
cmd := filepath.Base(os.Args[0])
fmt.Fprintf(flag.CommandLine.Output(),
- "Usage: %[1]s flags file...\n"+
- "or: %[1]s flags --launcher=PATH PRODUCT\n", cmd)
+ "Usage: %[1]s flags file...\n", cmd)
flag.PrintDefaults()
}
flag.Parse()
@@ -177,21 +175,38 @@
versionDefaultsPath := outputFilePath(versionDefaultsMk)
err = writeGenerated(versionDefaultsPath, versionDefaults)
if err != nil {
- fmt.Fprintf(os.Stderr, "%s:%s", files[0], err)
+ fmt.Fprintf(os.Stderr, "%s: %s", files[0], err)
ok = false
}
err = writeGenerated(*launcher, mk2rbc.Launcher(outputFilePath(files[0]), versionDefaultsPath,
mk2rbc.MakePath2ModuleName(files[0])))
if err != nil {
- fmt.Fprintf(os.Stderr, "%s:%s", files[0], err)
+ fmt.Fprintf(os.Stderr, "%s: %s", files[0], err)
+ ok = false
+ }
+ }
+ if *boardlauncher != "" {
+ if len(files) != 1 {
+ quit(fmt.Errorf("a launcher can be generated only for a single product"))
+ }
+ if *inputVariables == "" {
+ quit(fmt.Errorf("the board launcher requires an input variables file"))
+ }
+ if !convertOne(*inputVariables) {
+ quit(fmt.Errorf("the board launcher input variables file failed to convert"))
+ }
+ err := writeGenerated(*boardlauncher, mk2rbc.BoardLauncher(
+ outputFilePath(files[0]), outputFilePath(*inputVariables)))
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s: %s", files[0], err)
ok = false
}
}
- printStats()
if *errstat {
errorLogger.printStatistics()
+ printStats()
}
if !ok {
os.Exit(1)
@@ -311,19 +326,16 @@
}()
mk2starRequest := mk2rbc.Request{
- MkFile: mkFile,
- Reader: nil,
- RootDir: *rootDir,
- OutputDir: *outputTop,
- OutputSuffix: *suffix,
- TracedVariables: tracedVariables,
- TraceCalls: *traceCalls,
- WarnPartialSuccess: *warn,
- SourceFS: os.DirFS(*rootDir),
- MakefileFinder: makefileFinder,
- }
- if *errstat {
- mk2starRequest.ErrorLogger = errorLogger
+ MkFile: mkFile,
+ Reader: nil,
+ RootDir: *rootDir,
+ OutputDir: *outputTop,
+ OutputSuffix: *suffix,
+ TracedVariables: tracedVariables,
+ TraceCalls: *traceCalls,
+ SourceFS: os.DirFS(*rootDir),
+ MakefileFinder: makefileFinder,
+ ErrorLogger: errorLogger,
}
ss, err := mk2rbc.Convert(mk2starRequest)
if err != nil {
@@ -401,9 +413,6 @@
func printStats() {
var sortedFiles []string
- if !*warn && !*verbose {
- return
- }
for p := range converted {
sortedFiles = append(sortedFiles, p)
}
@@ -419,29 +428,22 @@
nOk++
}
}
- if *warn {
- if nPartial > 0 {
- fmt.Fprintf(os.Stderr, "Conversion was partially successful for:\n")
- for _, f := range sortedFiles {
- if ss := converted[f]; ss != nil && ss.HasErrors() {
- fmt.Fprintln(os.Stderr, " ", f)
- }
- }
- }
-
- if nFailed > 0 {
- fmt.Fprintf(os.Stderr, "Conversion failed for files:\n")
- for _, f := range sortedFiles {
- if converted[f] == nil {
- fmt.Fprintln(os.Stderr, " ", f)
- }
+ if nPartial > 0 {
+ fmt.Fprintf(os.Stderr, "Conversion was partially successful for:\n")
+ for _, f := range sortedFiles {
+ if ss := converted[f]; ss != nil && ss.HasErrors() {
+ fmt.Fprintln(os.Stderr, " ", f)
}
}
}
- if *verbose {
- fmt.Fprintf(os.Stderr, "%-16s%5d\n", "Succeeded:", nOk)
- fmt.Fprintf(os.Stderr, "%-16s%5d\n", "Partial:", nPartial)
- fmt.Fprintf(os.Stderr, "%-16s%5d\n", "Failed:", nFailed)
+
+ if nFailed > 0 {
+ fmt.Fprintf(os.Stderr, "Conversion failed for files:\n")
+ for _, f := range sortedFiles {
+ if converted[f] == nil {
+ fmt.Fprintln(os.Stderr, " ", f)
+ }
+ }
}
}
@@ -450,11 +452,18 @@
formattingArgs []string
}
-type errorsByType struct {
+type errorSink struct {
data map[string]datum
}
-func (ebt errorsByType) NewError(message string, node parser.Node, args ...interface{}) {
+func (ebt errorSink) NewError(el mk2rbc.ErrorLocation, node parser.Node, message string, args ...interface{}) {
+ fmt.Fprint(os.Stderr, el, ": ")
+ fmt.Fprintf(os.Stderr, message, args...)
+ fmt.Fprintln(os.Stderr)
+ if !*errstat {
+ return
+ }
+
v, exists := ebt.data[message]
if exists {
v.count++
@@ -479,7 +488,7 @@
ebt.data[message] = v
}
-func (ebt errorsByType) printStatistics() {
+func (ebt errorSink) printStatistics() {
if len(ebt.data) > 0 {
fmt.Fprintln(os.Stderr, "Error counts:")
}
diff --git a/mk2rbc/expr.go b/mk2rbc/expr.go
index 0bb8b95..ec0b279 100644
--- a/mk2rbc/expr.go
+++ b/mk2rbc/expr.go
@@ -18,8 +18,6 @@
"fmt"
"strconv"
"strings"
-
- mkparser "android/soong/androidmk/parser"
)
// Represents an expression in the Starlark code. An expression has
@@ -106,7 +104,7 @@
format += "%s" + strings.ReplaceAll(chunk, "%", "%%")
}
gctx.writef("%q %% ", format)
- emitarg := func(arg starlarkExpr) {
+ emitArg := func(arg starlarkExpr) {
if arg.typ() == starlarkTypeList {
gctx.write(`" ".join(`)
arg.emit(gctx)
@@ -116,12 +114,12 @@
}
}
if len(xi.args) == 1 {
- emitarg(xi.args[0])
+ emitArg(xi.args[0])
} else {
sep := "("
for _, arg := range xi.args {
gctx.write(sep)
- emitarg(arg)
+ emitArg(arg)
sep = ", "
}
gctx.write(")")
@@ -197,6 +195,51 @@
}
}
+type toStringExpr struct {
+ expr starlarkExpr
+}
+
+func (s *toStringExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
+ if x, same := s.expr.eval(valueMap); same {
+ res = s
+ } else {
+ res = &toStringExpr{expr: x}
+ }
+ return
+}
+
+func (s *toStringExpr) emit(ctx *generationContext) {
+ switch s.expr.typ() {
+ case starlarkTypeString, starlarkTypeUnknown:
+ // Assume unknown types are strings already.
+ s.expr.emit(ctx)
+ case starlarkTypeList:
+ ctx.write(`" ".join(`)
+ s.expr.emit(ctx)
+ ctx.write(")")
+ case starlarkTypeInt:
+ ctx.write(`("%d" % (`)
+ s.expr.emit(ctx)
+ ctx.write("))")
+ case starlarkTypeBool:
+ ctx.write(`("true" if (`)
+ s.expr.emit(ctx)
+ ctx.write(`) else "")`)
+ case starlarkTypeVoid:
+ ctx.write(`""`)
+ default:
+ panic("Unknown starlark type!")
+ }
+}
+
+func (s *toStringExpr) typ() starlarkType {
+ return starlarkTypeString
+}
+
+func (s *toStringExpr) emitListVarCopy(gctx *generationContext) {
+ s.emit(gctx)
+}
+
type notExpr struct {
expr starlarkExpr
}
@@ -240,21 +283,40 @@
}
func (eq *eqExpr) emit(gctx *generationContext) {
- emitSimple := func(expr starlarkExpr) {
- if eq.isEq {
- gctx.write("not ")
- }
- expr.emit(gctx)
+ var stringOperand string
+ var otherOperand starlarkExpr
+ if s, ok := maybeString(eq.left); ok {
+ stringOperand = s
+ otherOperand = eq.right
+ } else if s, ok := maybeString(eq.right); ok {
+ stringOperand = s
+ otherOperand = eq.left
}
- // Are we checking that a variable is empty?
- if isEmptyString(eq.left) {
- emitSimple(eq.right)
- return
- } else if isEmptyString(eq.right) {
- emitSimple(eq.left)
- return
+ // If we've identified one of the operands as being a string literal, check
+ // for some special cases we can do to simplify the resulting expression.
+ if otherOperand != nil {
+ if stringOperand == "" {
+ if eq.isEq {
+ gctx.write("not ")
+ }
+ otherOperand.emit(gctx)
+ return
+ }
+ if stringOperand == "true" && otherOperand.typ() == starlarkTypeBool {
+ if !eq.isEq {
+ gctx.write("not ")
+ }
+ otherOperand.emit(gctx)
+ return
+ }
}
+
+ if eq.left.typ() != eq.right.typ() {
+ eq.left = &toStringExpr{expr: eq.left}
+ eq.right = &toStringExpr{expr: eq.right}
+ }
+
// General case
eq.left.emit(gctx)
if eq.isEq {
@@ -363,7 +425,7 @@
return &v
}
-// concatExpr generates epxr1 + expr2 + ... + exprN in Starlark.
+// concatExpr generates expr1 + expr2 + ... + exprN in Starlark.
type concatExpr struct {
items []starlarkExpr
}
@@ -556,8 +618,8 @@
}
type badExpr struct {
- node mkparser.Node
- message string
+ errorLocation ErrorLocation
+ message string
}
func (b *badExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) {
@@ -566,15 +628,15 @@
return
}
-func (b *badExpr) emit(_ *generationContext) {
- panic("implement me")
+func (b *badExpr) emit(gctx *generationContext) {
+ gctx.emitConversionError(b.errorLocation, b.message)
}
func (_ *badExpr) typ() starlarkType {
return starlarkTypeUnknown
}
-func (b *badExpr) emitListVarCopy(gctx *generationContext) {
+func (_ *badExpr) emitListVarCopy(_ *generationContext) {
panic("implement me")
}
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index 6227164..c55300e 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -52,7 +52,9 @@
// And here are the functions and variables:
cfnGetCfg = baseName + ".cfg"
cfnMain = baseName + ".product_configuration"
+ cfnBoardMain = baseName + ".board_configuration"
cfnPrintVars = baseName + ".printvars"
+ cfnPrintGlobals = baseName + ".printglobals"
cfnWarning = baseName + ".warning"
cfnLocalAppend = baseName + ".local_append"
cfnLocalSetDefault = baseName + ".local_set_default"
@@ -70,6 +72,7 @@
soongConfigVarSetOld = "add_soong_config_var_value"
soongConfigAppend = "soong_config_append"
soongConfigAssign = "soong_config_set"
+ soongConfigGet = "soong_config_get"
wildcardExistsPhony = "$wildcard_exists"
)
@@ -93,11 +96,13 @@
soongConfigVarSetOld: {baseName + ".soong_config_set", starlarkTypeVoid, hiddenArgGlobal},
soongConfigAssign: {baseName + ".soong_config_set", starlarkTypeVoid, hiddenArgGlobal},
soongConfigAppend: {baseName + ".soong_config_append", starlarkTypeVoid, hiddenArgGlobal},
+ soongConfigGet: {baseName + ".soong_config_get", starlarkTypeString, hiddenArgGlobal},
"add-to-product-copy-files-if-exists": {baseName + ".copy_if_exists", starlarkTypeList, hiddenArgNone},
"addprefix": {baseName + ".addprefix", starlarkTypeList, hiddenArgNone},
"addsuffix": {baseName + ".addsuffix", starlarkTypeList, hiddenArgNone},
"copy-files": {baseName + ".copy_files", starlarkTypeList, hiddenArgNone},
"dir": {baseName + ".dir", starlarkTypeList, hiddenArgNone},
+ "dist-for-goals": {baseName + ".mkdist_for_goals", starlarkTypeVoid, hiddenArgGlobal},
"enforce-product-packages-exist": {baseName + ".enforce_product_packages_exist", starlarkTypeVoid, hiddenArgNone},
"error": {baseName + ".mkerror", starlarkTypeVoid, hiddenArgNone},
"findstring": {"!findstring", starlarkTypeInt, hiddenArgNone},
@@ -152,23 +157,31 @@
// Conversion request parameters
type Request struct {
- MkFile string // file to convert
- Reader io.Reader // if set, read input from this stream instead
- RootDir string // root directory path used to resolve included files
- OutputSuffix string // generated Starlark files suffix
- OutputDir string // if set, root of the output hierarchy
- ErrorLogger ErrorMonitorCB
- TracedVariables []string // trace assignment to these variables
- TraceCalls bool
- WarnPartialSuccess bool
- SourceFS fs.FS
- MakefileFinder MakefileFinder
+ MkFile string // file to convert
+ Reader io.Reader // if set, read input from this stream instead
+ RootDir string // root directory path used to resolve included files
+ OutputSuffix string // generated Starlark files suffix
+ OutputDir string // if set, root of the output hierarchy
+ ErrorLogger ErrorLogger
+ TracedVariables []string // trace assignment to these variables
+ TraceCalls bool
+ SourceFS fs.FS
+ MakefileFinder MakefileFinder
}
-// An error sink allowing to gather error statistics.
-// NewError is called on every error encountered during processing.
-type ErrorMonitorCB interface {
- NewError(s string, node mkparser.Node, args ...interface{})
+// ErrorLogger prints errors and gathers error statistics.
+// Its NewError function is called on every error encountered during the conversion.
+type ErrorLogger interface {
+ NewError(el ErrorLocation, node mkparser.Node, text string, args ...interface{})
+}
+
+type ErrorLocation struct {
+ MkFile string
+ MkLine int
+}
+
+func (el ErrorLocation) String() string {
+ return fmt.Sprintf("%s:%d", el.MkFile, el.MkLine)
}
// Derives module name for a given file. It is base name
@@ -244,10 +257,6 @@
node.emit(gctx)
}
- if ss.hasErrors && ss.warnPartialSuccess {
- gctx.newLine()
- gctx.writef("%s(%q, %q)", cfnWarning, filepath.Base(ss.mkFile), "partially successful conversion")
- }
if gctx.starScript.traceCalls {
gctx.newLine()
gctx.writef(`print("<%s")`, gctx.starScript.mkFile)
@@ -302,6 +311,10 @@
gctx.writef("%*s", 2*gctx.indentLevel, "")
}
+func (gctx *generationContext) emitConversionError(el ErrorLocation, message string) {
+ gctx.writef(`rblf.mk2rbc_error("%s", %q)`, el, message)
+}
+
type knownVariable struct {
name string
class varClass
@@ -366,17 +379,17 @@
// Information about the generated Starlark script.
type StarlarkScript struct {
- mkFile string
- moduleName string
- mkPos scanner.Position
- nodes []starlarkNode
- inherited []*moduleInfo
- hasErrors bool
- topDir string
- traceCalls bool // print enter/exit each init function
- warnPartialSuccess bool
- sourceFS fs.FS
- makefileFinder MakefileFinder
+ mkFile string
+ moduleName string
+ mkPos scanner.Position
+ nodes []starlarkNode
+ inherited []*moduleInfo
+ hasErrors bool
+ topDir string
+ traceCalls bool // print enter/exit each init function
+ sourceFS fs.FS
+ makefileFinder MakefileFinder
+ nodeLocator func(pos mkparser.Pos) int
}
func (ss *StarlarkScript) newNode(node starlarkNode) {
@@ -402,7 +415,7 @@
fatalError error
builtinMakeVars map[string]starlarkExpr
outputSuffix string
- errorLogger ErrorMonitorCB
+ errorLogger ErrorLogger
tracedVariables map[string]bool // variables to be traced in the generated script
variables map[string]variable
varAssignments *varAssignmentScope
@@ -536,7 +549,15 @@
return
}
name := a.Name.Strings[0]
- // Soong confuguration
+ // The `override` directive
+ // override FOO :=
+ // is parsed as an assignment to a variable named `override FOO`.
+ // There are very few places where `override` is used, just flag it.
+ if strings.HasPrefix(name, "override ") {
+ ctx.errorf(a, "cannot handle override directive")
+ }
+
+ // Soong configuration
if strings.HasPrefix(name, soongNsPrefix) {
ctx.handleSoongNsAssignment(strings.TrimPrefix(name, soongNsPrefix), a)
return
@@ -547,7 +568,7 @@
return
}
_, isTraced := ctx.tracedVariables[name]
- asgn := &assignmentNode{lhs: lhs, mkValue: a.Value, isTraced: isTraced}
+ asgn := &assignmentNode{lhs: lhs, mkValue: a.Value, isTraced: isTraced, location: ctx.errorLocation(a)}
if lhs.valueType() == starlarkTypeUnknown {
// Try to divine variable type from the RHS
asgn.value = ctx.parseMakeString(a, a.Value)
@@ -637,7 +658,7 @@
// Upon seeing
// SOONG_CONFIG_x_y = v
// find a namespace called `x` and act as if we encountered
- // $(call add_config_var_value(x,y,v)
+ // $(call soong_config_set,x,y,v)
// or check that `x_y` is a namespace, and then add the RHS of this assignment as variables in
// it.
// Emit an error in the ambiguous situation (namespaces `foo_bar` with a variable `baz`
@@ -678,7 +699,7 @@
ctx.errorf(asgn, "no %s variable in %s namespace, please use add_soong_config_var_value instead", varName, namespaceName)
return
}
- fname := soongConfigVarSetOld
+ fname := soongConfigAssign
if asgn.Type == "+=" {
fname = soongConfigAppend
}
@@ -961,25 +982,16 @@
ctx.pushReceiver(&block)
for ctx.hasNodes() {
node := ctx.getNode()
- if ctx.handleSimpleStatement(node) {
- continue
- }
- switch d := node.(type) {
- case *mkparser.Directive:
+ if d, ok := node.(*mkparser.Directive); ok {
switch d.Name {
case "else", "elifdef", "elifndef", "elifeq", "elifneq", "endif":
ctx.popReceiver()
ctx.receiver.newNode(&block)
ctx.backNode()
return
- case "ifdef", "ifndef", "ifeq", "ifneq":
- ctx.handleIfBlock(d)
- default:
- ctx.errorf(d, "unexpected directive %s", d.Name)
}
- default:
- ctx.errorf(node, "unexpected statement")
}
+ ctx.handleSimpleStatement(node)
}
ctx.fatalError = fmt.Errorf("no matching endif for %s", check.Dump())
ctx.popReceiver()
@@ -1019,10 +1031,10 @@
func (ctx *parseContext) newBadExpr(node mkparser.Node, text string, args ...interface{}) starlarkExpr {
message := fmt.Sprintf(text, args...)
if ctx.errorLogger != nil {
- ctx.errorLogger.NewError(text, node, args)
+ ctx.errorLogger.NewError(ctx.errorLocation(node), node, text, args...)
}
ctx.script.hasErrors = true
- return &badExpr{node, message}
+ return &badExpr{errorLocation: ctx.errorLocation(node), message: message}
}
func (ctx *parseContext) parseCompare(cond *mkparser.Directive) starlarkExpr {
@@ -1040,48 +1052,54 @@
args[1].TrimLeftSpaces()
isEq := !strings.HasSuffix(cond.Name, "neq")
- switch xLeft := ctx.parseMakeString(cond, args[0]).(type) {
- case *stringLiteralExpr, *variableRefExpr:
- switch xRight := ctx.parseMakeString(cond, args[1]).(type) {
- case *stringLiteralExpr, *variableRefExpr:
- return &eqExpr{left: xLeft, right: xRight, isEq: isEq}
- case *badExpr:
- return xRight
- default:
- expr, ok := ctx.parseCheckFunctionCallResult(cond, xLeft, args[1])
- if ok {
- return expr
- }
- return ctx.newBadExpr(cond, "right operand is too complex: %s", args[1].Dump())
- }
- case *badExpr:
- return xLeft
- default:
- switch xRight := ctx.parseMakeString(cond, args[1]).(type) {
- case *stringLiteralExpr, *variableRefExpr:
- expr, ok := ctx.parseCheckFunctionCallResult(cond, xRight, args[0])
- if ok {
- return expr
- }
- return ctx.newBadExpr(cond, "left operand is too complex: %s", args[0].Dump())
- case *badExpr:
- return xRight
- default:
- return ctx.newBadExpr(cond, "operands are too complex: (%s,%s)", args[0].Dump(), args[1].Dump())
- }
+ xLeft := ctx.parseMakeString(cond, args[0])
+ xRight := ctx.parseMakeString(cond, args[1])
+ if bad, ok := xLeft.(*badExpr); ok {
+ return bad
}
+ if bad, ok := xRight.(*badExpr); ok {
+ return bad
+ }
+
+ if expr, ok := ctx.parseCompareSpecialCases(cond, xLeft, xRight); ok {
+ return expr
+ }
+
+ return &eqExpr{left: xLeft, right: xRight, isEq: isEq}
}
-func (ctx *parseContext) parseCheckFunctionCallResult(directive *mkparser.Directive, xValue starlarkExpr,
- varArg *mkparser.MakeString) (starlarkExpr, bool) {
- mkSingleVar, ok := varArg.SingleVariable()
- if !ok {
+// Given an if statement's directive and the left/right starlarkExprs,
+// check if the starlarkExprs are one of a few hardcoded special cases
+// that can be converted to a simpler equalify expression than simply comparing
+// the two.
+func (ctx *parseContext) parseCompareSpecialCases(directive *mkparser.Directive, left starlarkExpr,
+ right starlarkExpr) (starlarkExpr, bool) {
+ isEq := !strings.HasSuffix(directive.Name, "neq")
+
+ // All the special cases require a call on one side and a
+ // string literal/variable on the other. Turn the left/right variables into
+ // call/value variables, and return false if that's not possible.
+ var value starlarkExpr = nil
+ call, ok := left.(*callExpr)
+ if ok {
+ switch right.(type) {
+ case *stringLiteralExpr, *variableRefExpr:
+ value = right
+ }
+ } else {
+ call, _ = right.(*callExpr)
+ switch left.(type) {
+ case *stringLiteralExpr, *variableRefExpr:
+ value = left
+ }
+ }
+
+ if call == nil || value == nil {
return nil, false
}
- expr := ctx.parseReference(directive, mkSingleVar)
- negate := strings.HasSuffix(directive.Name, "neq")
+
checkIsSomethingFunction := func(xCall *callExpr) starlarkExpr {
- s, ok := maybeString(xValue)
+ s, ok := maybeString(value)
if !ok || s != "true" {
return ctx.newBadExpr(directive,
fmt.Sprintf("the result of %s can be compared only to 'true'", xCall.name))
@@ -1091,95 +1109,90 @@
}
return nil
}
- switch x := expr.(type) {
- case *callExpr:
- switch x.name {
- case "filter":
- return ctx.parseCompareFilterFuncResult(directive, x, xValue, !negate), true
- case "filter-out":
- return ctx.parseCompareFilterFuncResult(directive, x, xValue, negate), true
- case "wildcard":
- return ctx.parseCompareWildcardFuncResult(directive, x, xValue, negate), true
- case "findstring":
- return ctx.parseCheckFindstringFuncResult(directive, x, xValue, negate), true
- case "strip":
- return ctx.parseCompareStripFuncResult(directive, x, xValue, negate), true
- case "is-board-platform":
- if xBad := checkIsSomethingFunction(x); xBad != nil {
- return xBad, true
- }
- return &eqExpr{
- left: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
- right: x.args[0],
- isEq: !negate,
- }, true
- case "is-board-platform-in-list":
- if xBad := checkIsSomethingFunction(x); xBad != nil {
- return xBad, true
- }
- return &inExpr{
- expr: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
- list: maybeConvertToStringList(x.args[0]),
- isNot: negate,
- }, true
- case "is-product-in-list":
- if xBad := checkIsSomethingFunction(x); xBad != nil {
- return xBad, true
- }
- return &inExpr{
- expr: &variableRefExpr{ctx.addVariable("TARGET_PRODUCT"), true},
- list: maybeConvertToStringList(x.args[0]),
- isNot: negate,
- }, true
- case "is-vendor-board-platform":
- if xBad := checkIsSomethingFunction(x); xBad != nil {
- return xBad, true
- }
- s, ok := maybeString(x.args[0])
- if !ok {
- return ctx.newBadExpr(directive, "cannot handle non-constant argument to is-vendor-board-platform"), true
- }
- return &inExpr{
- expr: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
- list: &variableRefExpr{ctx.addVariable(s + "_BOARD_PLATFORMS"), true},
- isNot: negate,
- }, true
- case "is-board-platform2", "is-board-platform-in-list2":
- if s, ok := maybeString(xValue); !ok || s != "" {
- return ctx.newBadExpr(directive,
- fmt.Sprintf("the result of %s can be compared only to empty", x.name)), true
- }
- if len(x.args) != 1 {
- return ctx.newBadExpr(directive, "%s requires an argument", x.name), true
- }
- cc := &callExpr{
- name: x.name,
- args: []starlarkExpr{x.args[0]},
- returnType: starlarkTypeBool,
- }
- if !negate {
- return ¬Expr{cc}, true
- }
- return cc, true
- case "is-vendor-board-qcom":
- if s, ok := maybeString(xValue); !ok || s != "" {
- return ctx.newBadExpr(directive,
- fmt.Sprintf("the result of %s can be compared only to empty", x.name)), true
- }
- return &inExpr{
- expr: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
- list: &variableRefExpr{ctx.addVariable("QCOM_BOARD_PLATFORMS"), true},
- isNot: negate,
- }, true
- default:
- return ctx.newBadExpr(directive, "Unknown function in ifeq: %s", x.name), true
+ switch call.name {
+ case "filter":
+ return ctx.parseCompareFilterFuncResult(directive, call, value, isEq), true
+ case "filter-out":
+ return ctx.parseCompareFilterFuncResult(directive, call, value, !isEq), true
+ case "wildcard":
+ return ctx.parseCompareWildcardFuncResult(directive, call, value, !isEq), true
+ case "findstring":
+ return ctx.parseCheckFindstringFuncResult(directive, call, value, !isEq), true
+ case "strip":
+ return ctx.parseCompareStripFuncResult(directive, call, value, !isEq), true
+ case "is-board-platform":
+ if xBad := checkIsSomethingFunction(call); xBad != nil {
+ return xBad, true
}
- case *badExpr:
- return x, true
- default:
- return nil, false
+ return &eqExpr{
+ left: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
+ right: call.args[0],
+ isEq: isEq,
+ }, true
+ case "is-board-platform-in-list":
+ if xBad := checkIsSomethingFunction(call); xBad != nil {
+ return xBad, true
+ }
+ return &inExpr{
+ expr: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
+ list: maybeConvertToStringList(call.args[0]),
+ isNot: !isEq,
+ }, true
+ case "is-product-in-list":
+ if xBad := checkIsSomethingFunction(call); xBad != nil {
+ return xBad, true
+ }
+ return &inExpr{
+ expr: &variableRefExpr{ctx.addVariable("TARGET_PRODUCT"), true},
+ list: maybeConvertToStringList(call.args[0]),
+ isNot: !isEq,
+ }, true
+ case "is-vendor-board-platform":
+ if xBad := checkIsSomethingFunction(call); xBad != nil {
+ return xBad, true
+ }
+ s, ok := maybeString(call.args[0])
+ if !ok {
+ return ctx.newBadExpr(directive, "cannot handle non-constant argument to is-vendor-board-platform"), true
+ }
+ return &inExpr{
+ expr: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
+ list: &variableRefExpr{ctx.addVariable(s + "_BOARD_PLATFORMS"), true},
+ isNot: !isEq,
+ }, true
+
+ case "is-board-platform2", "is-board-platform-in-list2":
+ if s, ok := maybeString(value); !ok || s != "" {
+ return ctx.newBadExpr(directive,
+ fmt.Sprintf("the result of %s can be compared only to empty", call.name)), true
+ }
+ if len(call.args) != 1 {
+ return ctx.newBadExpr(directive, "%s requires an argument", call.name), true
+ }
+ cc := &callExpr{
+ name: call.name,
+ args: []starlarkExpr{call.args[0]},
+ returnType: starlarkTypeBool,
+ }
+ if isEq {
+ return ¬Expr{cc}, true
+ }
+ return cc, true
+ case "is-vendor-board-qcom":
+ if s, ok := maybeString(value); !ok || s != "" {
+ return ctx.newBadExpr(directive,
+ fmt.Sprintf("the result of %s can be compared only to empty", call.name)), true
+ }
+ // if the expression is ifneq (,$(call is-vendor-board-platform,...)), negate==true,
+ // so we should set inExpr.isNot to false
+ return &inExpr{
+ expr: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
+ list: &variableRefExpr{ctx.addVariable("QCOM_BOARD_PLATFORMS"), true},
+ isNot: isEq,
+ }, true
}
+ return nil, false
}
func (ctx *parseContext) parseCompareFilterFuncResult(cond *mkparser.Directive,
@@ -1318,7 +1331,7 @@
}
if strings.HasPrefix(refDump, soongNsPrefix) {
// TODO (asmundak): if we find many, maybe handle them.
- return ctx.newBadExpr(node, "SOONG_CONFIG_ variables cannot be referenced: %s", refDump)
+ return ctx.newBadExpr(node, "SOONG_CONFIG_ variables cannot be referenced, use soong_config_get instead: %s", refDump)
}
if v := ctx.addVariable(refDump); v != nil {
return &variableRefExpr{v, ctx.lastAssignment(v.name()) != nil}
@@ -1384,11 +1397,14 @@
if len(words) != 3 {
return ctx.newBadExpr(node, "%s function should have 3 arguments", fname)
}
- if !words[0].Const() || !words[1].Const() {
- return ctx.newBadExpr(node, "%s function's from and to arguments should be constant", fname)
+ from := ctx.parseMakeString(node, words[0])
+ if xBad, ok := from.(*badExpr); ok {
+ return xBad
}
- from := words[0].Strings[0]
- to := words[1].Strings[0]
+ to := ctx.parseMakeString(node, words[1])
+ if xBad, ok := to.(*badExpr); ok {
+ return xBad
+ }
words[2].TrimLeftSpaces()
words[2].TrimRightSpaces()
obj := ctx.parseMakeString(node, words[2])
@@ -1398,13 +1414,13 @@
return &callExpr{
object: obj,
name: "replace",
- args: []starlarkExpr{&stringLiteralExpr{from}, &stringLiteralExpr{to}},
+ args: []starlarkExpr{from, to},
returnType: typ,
}
}
return &callExpr{
name: fname,
- args: []starlarkExpr{&stringLiteralExpr{from}, &stringLiteralExpr{to}, obj},
+ args: []starlarkExpr{from, to, obj},
returnType: obj.typ(),
}
}
@@ -1476,9 +1492,7 @@
// Handles the statements whose treatment is the same in all contexts: comment,
// assignment, variable (which is a macro call in reality) and all constructs that
// do not handle in any context ('define directive and any unrecognized stuff).
-// Return true if we handled it.
-func (ctx *parseContext) handleSimpleStatement(node mkparser.Node) bool {
- handled := true
+func (ctx *parseContext) handleSimpleStatement(node mkparser.Node) {
switch x := node.(type) {
case *mkparser.Comment:
ctx.maybeHandleAnnotation(x)
@@ -1493,13 +1507,14 @@
ctx.handleDefine(x)
case "include", "-include":
ctx.handleInclude(node, ctx.parseMakeString(node, x.Args), x.Name[0] != '-')
+ case "ifeq", "ifneq", "ifdef", "ifndef":
+ ctx.handleIfBlock(x)
default:
- handled = false
+ ctx.errorf(x, "unexpected directive %s", x.Name)
}
default:
ctx.errorf(x, "unsupported line %s", strings.ReplaceAll(x.Dump(), "\n", "\n#"))
}
- return handled
}
// Processes annotation. An annotation is a comment that starts with #RBC# and provides
@@ -1537,17 +1552,14 @@
// records that the given node failed to be converted and includes an explanatory message
func (ctx *parseContext) errorf(failedNode mkparser.Node, message string, args ...interface{}) {
if ctx.errorLogger != nil {
- ctx.errorLogger.NewError(message, failedNode, args...)
+ ctx.errorLogger.NewError(ctx.errorLocation(failedNode), failedNode, message, args...)
}
- message = fmt.Sprintf(message, args...)
- ctx.insertComment(fmt.Sprintf("# MK2RBC TRANSLATION ERROR: %s", message))
- ctx.carryAsComment(failedNode)
+ ctx.receiver.newNode(&exprNode{ctx.newBadExpr(failedNode, message, args...)})
ctx.script.hasErrors = true
}
func (ctx *parseContext) wrapBadExpr(xBad *badExpr) {
- ctx.insertComment(fmt.Sprintf("# MK2RBC TRANSLATION ERROR: %s", xBad.message))
- ctx.carryAsComment(xBad.node)
+ ctx.receiver.newNode(&exprNode{xBad})
}
func (ctx *parseContext) loadedModulePath(path string) string {
@@ -1613,6 +1625,10 @@
return ok
}
+func (ctx *parseContext) errorLocation(node mkparser.Node) ErrorLocation {
+ return ErrorLocation{ctx.script.mkFile, ctx.script.nodeLocator(node.Pos())}
+}
+
func (ss *StarlarkScript) String() string {
return NewGenerateContext(ss).emit()
}
@@ -1651,13 +1667,13 @@
return nil, fmt.Errorf("bad makefile %s", req.MkFile)
}
starScript := &StarlarkScript{
- moduleName: moduleNameForFile(req.MkFile),
- mkFile: req.MkFile,
- topDir: req.RootDir,
- traceCalls: req.TraceCalls,
- warnPartialSuccess: req.WarnPartialSuccess,
- sourceFS: req.SourceFS,
- makefileFinder: req.MakefileFinder,
+ moduleName: moduleNameForFile(req.MkFile),
+ mkFile: req.MkFile,
+ topDir: req.RootDir,
+ traceCalls: req.TraceCalls,
+ sourceFS: req.SourceFS,
+ makefileFinder: req.MakefileFinder,
+ nodeLocator: func(pos mkparser.Pos) int { return parser.Unpack(pos).Line },
}
ctx := newParseContext(starScript, nodes)
ctx.outputSuffix = req.OutputSuffix
@@ -1671,21 +1687,7 @@
}
ctx.pushReceiver(starScript)
for ctx.hasNodes() && ctx.fatalError == nil {
- node := ctx.getNode()
- if ctx.handleSimpleStatement(node) {
- continue
- }
- switch x := node.(type) {
- case *mkparser.Directive:
- switch x.Name {
- case "ifeq", "ifneq", "ifdef", "ifndef":
- ctx.handleIfBlock(x)
- default:
- ctx.errorf(x, "unexpected directive %s", x.Name)
- }
- default:
- ctx.errorf(x, "unsupported line")
- }
+ ctx.handleSimpleStatement(ctx.getNode())
}
if ctx.fatalError != nil {
return nil, ctx.fatalError
@@ -1702,6 +1704,17 @@
return buf.String()
}
+func BoardLauncher(mainModuleUri string, inputVariablesUri string) string {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "load(%q, %q)\n", baseUri, baseName)
+ fmt.Fprintf(&buf, "load(%q, \"init\")\n", mainModuleUri)
+ fmt.Fprintf(&buf, "load(%q, input_variables_init = \"init\")\n", inputVariablesUri)
+ fmt.Fprintf(&buf, "globals, cfg, globals_base = %s(init, input_variables_init)\n", cfnBoardMain)
+ fmt.Fprintf(&buf, "# TODO: Some product config variables need to be printed, but most are readonly so we can't just print cfg here.\n")
+ fmt.Fprintf(&buf, "%s(globals, globals_base)\n", cfnPrintGlobals)
+ return buf.String()
+}
+
func MakePath2ModuleName(mkPath string) string {
return strings.TrimSuffix(mkPath, filepath.Ext(mkPath))
}
diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go
index 511bb0f..dfdf274 100644
--- a/mk2rbc/mk2rbc_test.go
+++ b/mk2rbc/mk2rbc_test.go
@@ -105,15 +105,12 @@
PRODUCT_NAME := $(call foo1, bar)
PRODUCT_NAME := $(call foo0)
`,
- expected: `# MK2RBC TRANSLATION ERROR: cannot handle invoking foo1
-# PRODUCT_NAME := $(call foo1, bar)
-# MK2RBC TRANSLATION ERROR: cannot handle invoking foo0
-# PRODUCT_NAME := $(call foo0)
-load("//build/make/core:product_config.rbc", "rblf")
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
def init(g, handle):
cfg = rblf.cfg(handle)
- rblf.warning("product.mk", "partially successful conversion")
+ rblf.mk2rbc_error("product.mk:2", "cannot handle invoking foo1")
+ rblf.mk2rbc_error("product.mk:3", "cannot handle invoking foo0")
`,
},
{
@@ -207,15 +204,11 @@
$(info foo)
endef
`,
- expected: `# MK2RBC TRANSLATION ERROR: define is not supported: some-macro
-# define some-macro
-# $(info foo)
-# endef
-load("//build/make/core:product_config.rbc", "rblf")
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
def init(g, handle):
cfg = rblf.cfg(handle)
- rblf.warning("product.mk", "partially successful conversion")
+ rblf.mk2rbc_error("product.mk:2", "define is not supported: some-macro")
`,
},
{
@@ -226,6 +219,9 @@
PRODUCT_NAME = gizmo
else
endif
+local_var :=
+ifdef local_var
+endif
`,
expected: `load("//build/make/core:product_config.rbc", "rblf")
@@ -235,6 +231,9 @@
cfg["PRODUCT_NAME"] = "gizmo"
else:
pass
+ _local_var = ""
+ if _local_var:
+ pass
`,
},
{
@@ -276,9 +275,7 @@
# Comment
pass
else:
- # MK2RBC TRANSLATION ERROR: cannot set predefined variable TARGET_COPY_OUT_RECOVERY to "foo", its value should be "recovery"
- pass
- rblf.warning("product.mk", "partially successful conversion")
+ rblf.mk2rbc_error("product.mk:5", "cannot set predefined variable TARGET_COPY_OUT_RECOVERY to \"foo\", its value should be \"recovery\"")
`,
},
{
@@ -347,6 +344,36 @@
`,
},
{
+ desc: "ifeq with soong_config_get",
+ mkname: "product.mk",
+ in: `
+ifeq (true,$(call soong_config_get,art_module,source_build))
+endif
+`,
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ if "true" == rblf.soong_config_get(g, "art_module", "source_build"):
+ pass
+`,
+ },
+ {
+ desc: "ifeq with $(NATIVE_COVERAGE)",
+ mkname: "product.mk",
+ in: `
+ifeq ($(NATIVE_COVERAGE),true)
+endif
+`,
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ if g.get("NATIVE_COVERAGE", False):
+ pass
+`,
+ },
+ {
desc: "Check filter result",
mkname: "product.mk",
in: `
@@ -509,6 +536,21 @@
`,
},
{
+ desc: "if with interpolation",
+ mkname: "product.mk",
+ in: `
+ifeq ($(VARIABLE1)text$(VARIABLE2),true)
+endif
+`,
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ if "%stext%s" % (g.get("VARIABLE1", ""), g.get("VARIABLE2", "")) == "true":
+ pass
+`,
+ },
+ {
desc: "ifneq $(X),true",
mkname: "product.mk",
in: `
@@ -579,7 +621,7 @@
pass
elif not rblf.board_platform_is(g, "copper"):
pass
- elif g.get("TARGET_BOARD_PLATFORM", "") not in g["QCOM_BOARD_PLATFORMS"]:
+ elif g.get("TARGET_BOARD_PLATFORM", "") in g["QCOM_BOARD_PLATFORMS"]:
pass
`,
},
@@ -653,6 +695,7 @@
$(call enforce-product-packages-exist, foo)
$(call require-artifacts-in-path, foo, bar)
$(call require-artifacts-in-path-relaxed, foo, bar)
+$(call dist-for-goals, goal, from:to)
`,
expected: `load("//build/make/core:product_config.rbc", "rblf")
@@ -662,6 +705,7 @@
rblf.enforce_product_packages_exist("foo")
rblf.require_artifacts_in_path("foo", "bar")
rblf.require_artifacts_in_path_relaxed("foo", "bar")
+ rblf.mkdist_for_goals(g, "goal", "from:to")
`,
},
{
@@ -691,7 +735,7 @@
PRODUCT_COPY_FILES := $(addprefix pfx-,a b c)
PRODUCT_COPY_FILES := $(addsuffix .sff, a b c)
PRODUCT_NAME := $(word 1, $(subst ., ,$(TARGET_BOARD_PLATFORM)))
-$(info $(patsubst %.pub,%,$(PRODUCT_ADB_KEYS)))
+$(info $(patsubst %.pub,$(PRODUCT_NAME)%,$(PRODUCT_ADB_KEYS)))
$(info $(dir foo/bar))
$(info $(firstword $(PRODUCT_COPY_FILES)))
$(info $(lastword $(PRODUCT_COPY_FILES)))
@@ -714,7 +758,7 @@
cfg["PRODUCT_COPY_FILES"] = rblf.addprefix("pfx-", "a b c")
cfg["PRODUCT_COPY_FILES"] = rblf.addsuffix(".sff", "a b c")
cfg["PRODUCT_NAME"] = ((g.get("TARGET_BOARD_PLATFORM", "")).replace(".", " ")).split()[0]
- rblf.mkinfo("product.mk", rblf.mkpatsubst("%.pub", "%", g.get("PRODUCT_ADB_KEYS", "")))
+ rblf.mkinfo("product.mk", rblf.mkpatsubst("%.pub", "%s%%" % cfg["PRODUCT_NAME"], g.get("PRODUCT_ADB_KEYS", "")))
rblf.mkinfo("product.mk", rblf.dir("foo/bar"))
rblf.mkinfo("product.mk", cfg["PRODUCT_COPY_FILES"][0])
rblf.mkinfo("product.mk", cfg["PRODUCT_COPY_FILES"][-1])
@@ -821,9 +865,27 @@
rblf.soong_config_namespace(g, "cvd")
rblf.soong_config_set(g, "cvd", "launch_configs", "cvd_config_auto.json")
rblf.soong_config_append(g, "cvd", "grub_config", "grub.cfg")
- # MK2RBC TRANSLATION ERROR: SOONG_CONFIG_ variables cannot be referenced: SOONG_CONFIG_cvd_grub_config
- # x := $(SOONG_CONFIG_cvd_grub_config)
- rblf.warning("product.mk", "partially successful conversion")
+ rblf.mk2rbc_error("product.mk:7", "SOONG_CONFIG_ variables cannot be referenced, use soong_config_get instead: SOONG_CONFIG_cvd_grub_config")
+`,
+ }, {
+ desc: "soong namespace accesses",
+ mkname: "product.mk",
+ in: `
+SOONG_CONFIG_NAMESPACES += cvd
+SOONG_CONFIG_cvd += launch_configs
+SOONG_CONFIG_cvd_launch_configs = cvd_config_auto.json
+SOONG_CONFIG_cvd += grub_config
+SOONG_CONFIG_cvd_grub_config += grub.cfg
+x := $(call soong_config_get,cvd,grub_config)
+`,
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ rblf.soong_config_namespace(g, "cvd")
+ rblf.soong_config_set(g, "cvd", "launch_configs", "cvd_config_auto.json")
+ rblf.soong_config_append(g, "cvd", "grub_config", "grub.cfg")
+ _x = rblf.soong_config_get(g, "cvd", "grub_config")
`,
},
{
@@ -990,15 +1052,39 @@
in: `
foo: foo.c
gcc -o $@ $*`,
- expected: `# MK2RBC TRANSLATION ERROR: unsupported line rule: foo: foo.c
-#gcc -o $@ $*
-# rule: foo: foo.c
-# gcc -o $@ $*
-load("//build/make/core:product_config.rbc", "rblf")
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
def init(g, handle):
cfg = rblf.cfg(handle)
- rblf.warning("product.mk", "partially successful conversion")
+ rblf.mk2rbc_error("product.mk:2", "unsupported line rule: foo: foo.c\n#gcc -o $@ $*")
+`,
+ },
+ {
+ desc: "Flag override",
+ mkname: "product.mk",
+ in: `
+override FOO:=`,
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ rblf.mk2rbc_error("product.mk:2", "cannot handle override directive")
+ g["override FOO"] = ""
+`,
+ },
+ {
+ desc: "Bad expression",
+ mkname: "build/product.mk",
+ in: `
+ifeq (,$(call foobar))
+endif
+`,
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ if rblf.mk2rbc_error("build/product.mk:2", "cannot handle invoking foobar"):
+ pass
`,
},
}
@@ -1008,6 +1094,7 @@
class varClass
starlarkType
}{
+ {"NATIVE_COVERAGE", VarClassSoong, starlarkTypeBool},
{"PRODUCT_NAME", VarClassConfig, starlarkTypeString},
{"PRODUCT_MODEL", VarClassConfig, starlarkTypeString},
{"PRODUCT_PACKAGES", VarClassConfig, starlarkTypeList},
@@ -1069,13 +1156,12 @@
t.Run(test.desc,
func(t *testing.T) {
ss, err := Convert(Request{
- MkFile: test.mkname,
- Reader: bytes.NewBufferString(test.in),
- RootDir: ".",
- OutputSuffix: ".star",
- WarnPartialSuccess: true,
- SourceFS: fs,
- MakefileFinder: &testMakefileFinder{fs: fs},
+ MkFile: test.mkname,
+ Reader: bytes.NewBufferString(test.in),
+ RootDir: ".",
+ OutputSuffix: ".star",
+ SourceFS: fs,
+ MakefileFinder: &testMakefileFinder{fs: fs},
})
if err != nil {
t.Error(err)
diff --git a/mk2rbc/node.go b/mk2rbc/node.go
index 3fe1a17..d38299d 100644
--- a/mk2rbc/node.go
+++ b/mk2rbc/node.go
@@ -183,6 +183,7 @@
value starlarkExpr
mkValue *mkparser.MakeString
flavor assignmentFlavor
+ location ErrorLocation
isTraced bool
previous *assignmentNode
}
@@ -223,18 +224,6 @@
}
gctx.newLine()
- if bad, ok := in.expr.(*badExpr); ok {
- gctx.write("# MK2STAR ERROR converting:")
- gctx.newLine()
- gctx.writef("# %s", bad.node.Dump())
- gctx.newLine()
- gctx.writef("# %s", bad.message)
- gctx.newLine()
- // The init function emits a warning if the conversion was not
- // fullly successful, so here we (arbitrarily) take the false path.
- gctx.writef("%sFalse:", ifElif)
- return
- }
gctx.write(ifElif)
in.expr.emit(gctx)
gctx.write(":")
diff --git a/mk2rbc/variable.go b/mk2rbc/variable.go
index 4bb9ed5..6b67a7c 100644
--- a/mk2rbc/variable.go
+++ b/mk2rbc/variable.go
@@ -177,8 +177,8 @@
baseVariable
}
-func (lv localVariable) emitDefined(_ *generationContext) {
- panic("implement me")
+func (lv localVariable) emitDefined(gctx *generationContext) {
+ gctx.writef(lv.String())
}
func (lv localVariable) String() string {
@@ -228,10 +228,9 @@
if actualValue == expectedValue {
return
}
- gctx.writef("# MK2RBC TRANSLATION ERROR: cannot set predefined variable %s to %q, its value should be %q",
- pv.name(), actualValue, expectedValue)
- gctx.newLine()
- gctx.write("pass")
+ gctx.emitConversionError(asgn.location,
+ fmt.Sprintf("cannot set predefined variable %s to %q, its value should be %q",
+ pv.name(), actualValue, expectedValue))
gctx.starScript.hasErrors = true
return
}
diff --git a/rust/Android.bp b/rust/Android.bp
index 0ee673d..5e14da8 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -38,6 +38,7 @@
"strip.go",
"test.go",
"testing.go",
+ "toolchain_library.go",
],
testSrcs: [
"benchmark_test.go",
@@ -54,6 +55,7 @@
"project_json_test.go",
"protobuf_test.go",
"rust_test.go",
+ "sanitize_test.go",
"source_provider_test.go",
"test_test.go",
"vendor_snapshot_test.go",
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 630805a..1f18b4a 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -50,8 +50,8 @@
}
ret := android.AndroidMkEntries{
- OutputFile: mod.unstrippedOutputFile,
- Include: "$(BUILD_SYSTEM)/soong_rust_prebuilt.mk",
+ OutputFile: android.OptionalPathForPath(mod.UnstrippedOutputFile()),
+ Include: "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.AddStrings("LOCAL_RLIB_LIBRARIES", mod.Properties.AndroidMkRlibs...)
@@ -137,10 +137,15 @@
} else if library.shared() {
ret.Class = "SHARED_LIBRARIES"
}
-
if library.distFile.Valid() {
ret.DistFiles = android.MakeDefaultDistFiles(library.distFile.Path())
}
+ ret.ExtraEntries = append(ret.ExtraEntries,
+ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ if library.tocFile.Valid() {
+ entries.SetString("LOCAL_SOONG_TOC", library.tocFile.String())
+ }
+ })
}
func (procMacro *procMacroDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
@@ -181,18 +186,13 @@
return
}
- var unstrippedOutputFile android.OptionalPath
- // Soong installation is only supported for host modules. Have Make
- // installation trigger Soong installation.
- if ctx.Target().Os.Class == android.Host {
- ret.OutputFile = android.OptionalPathForPath(compiler.path)
- } else if compiler.strippedOutputFile.Valid() {
- unstrippedOutputFile = ret.OutputFile
+ if compiler.strippedOutputFile.Valid() {
ret.OutputFile = compiler.strippedOutputFile
}
+
ret.ExtraEntries = append(ret.ExtraEntries,
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetOptionalPath("LOCAL_SOONG_UNSTRIPPED_BINARY", unstrippedOutputFile)
+ entries.SetPath("LOCAL_SOONG_UNSTRIPPED_BINARY", compiler.unstrippedOutputFile)
path, file := filepath.Split(compiler.path.ToMakePath().String())
stem, suffix, _ := android.SplitFileExt(file)
entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
diff --git a/rust/binary.go b/rust/binary.go
index 7c18730..db91ccb 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -34,6 +34,7 @@
type binaryInterface interface {
binary() bool
staticallyLinked() bool
+ testBinary() bool
}
type binaryDecorator struct {
@@ -122,20 +123,24 @@
fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix()
srcPath, _ := srcPathFromModuleSrcs(ctx, binary.baseCompiler.Properties.Srcs)
outputFile := android.PathForModuleOut(ctx, fileName)
+ ret := outputFile
flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
+ if binary.stripper.NeedsStrip(ctx) {
+ strippedOutputFile := outputFile
+ outputFile = android.PathForModuleOut(ctx, "unstripped", fileName)
+ binary.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile)
+
+ binary.baseCompiler.strippedOutputFile = android.OptionalPathForPath(strippedOutputFile)
+ }
+ binary.baseCompiler.unstrippedOutputFile = outputFile
+
TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile)
- if binary.stripper.NeedsStrip(ctx) {
- strippedOutputFile := android.PathForModuleOut(ctx, "stripped", fileName)
- binary.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile)
- binary.strippedOutputFile = android.OptionalPathForPath(strippedOutputFile)
- }
-
- return outputFile
+ return ret
}
func (binary *binaryDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep {
@@ -168,3 +173,7 @@
func (binary *binaryDecorator) staticallyLinked() bool {
return Bool(binary.Properties.Static_executable)
}
+
+func (binary *binaryDecorator) testBinary() bool {
+ return false
+}
diff --git a/rust/binary_test.go b/rust/binary_test.go
index 968c0c1..7dac249 100644
--- a/rust/binary_test.go
+++ b/rust/binary_test.go
@@ -106,7 +106,7 @@
srcs: ["foo.rs"],
}`)
- fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Output("fizz-buzz")
+ fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustc")
flags := fizzBuzz.Args["rustcFlags"]
if strings.Contains(flags, "--test") {
@@ -139,7 +139,7 @@
static_executable: true,
}`)
- fizzOut := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Output("fizz")
+ fizzOut := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc")
fizzMod := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module)
flags := fizzOut.Args["rustcFlags"]
@@ -173,7 +173,7 @@
name: "libfoo",
}`)
- fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Output("fizz-buzz")
+ fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Rule("rustc")
linkFlags := fizzBuzz.Args["linkFlags"]
if !strings.Contains(linkFlags, "/libfoo.so") {
t.Errorf("missing shared dependency 'libfoo.so' in linkFlags: %#v", linkFlags)
@@ -197,15 +197,17 @@
`)
foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a")
- foo.Output("stripped/foo")
+ foo.Output("unstripped/foo")
+ foo.Output("foo")
+
// Check that the `cp` rules is using the stripped version as input.
cp := foo.Rule("android.Cp")
- if !strings.HasSuffix(cp.Input.String(), "stripped/foo") {
+ if strings.HasSuffix(cp.Input.String(), "unstripped/foo") {
t.Errorf("installed binary not based on stripped version: %v", cp.Input)
}
- fizzBar := ctx.ModuleForTests("bar", "android_arm64_armv8-a").MaybeOutput("stripped/bar")
+ fizzBar := ctx.ModuleForTests("bar", "android_arm64_armv8-a").MaybeOutput("unstripped/bar")
if fizzBar.Rule != nil {
- t.Errorf("stripped version of bar has been generated")
+ t.Errorf("unstripped binary exists, so stripped binary has incorrectly been generated")
}
}
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 845f258..32d02e4 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -15,6 +15,7 @@
package rust
import (
+ "fmt"
"strings"
"github.com/google/blueprint"
@@ -147,6 +148,31 @@
cflags = append(cflags, strings.ReplaceAll(ccToolchain.Cflags(), "${config.", "${cc_config."))
cflags = append(cflags, strings.ReplaceAll(ccToolchain.ToolchainCflags(), "${config.", "${cc_config."))
+ if ctx.RustModule().UseVndk() {
+ cflags = append(cflags, "-D__ANDROID_VNDK__")
+ if ctx.RustModule().InVendor() {
+ cflags = append(cflags, "-D__ANDROID_VENDOR__")
+ } else if ctx.RustModule().InProduct() {
+ cflags = append(cflags, "-D__ANDROID_PRODUCT__")
+ }
+ }
+
+ if ctx.RustModule().InRecovery() {
+ cflags = append(cflags, "-D__ANDROID_RECOVERY__")
+ }
+
+ if mctx, ok := ctx.(*moduleContext); ok && mctx.apexVariationName() != "" {
+ cflags = append(cflags, "-D__ANDROID_APEX__")
+ if ctx.Device() {
+ cflags = append(cflags, fmt.Sprintf("-D__ANDROID_APEX_MIN_SDK_VERSION__=%d",
+ ctx.RustModule().apexSdkVersion.FinalOrFutureInt()))
+ }
+ }
+
+ if ctx.Target().NativeBridge == android.NativeBridgeEnabled {
+ cflags = append(cflags, "-D__ANDROID_NATIVE_BRIDGE__")
+ }
+
// Dependency clang flags and include paths
cflags = append(cflags, deps.depClangFlags...)
for _, include := range deps.depIncludePaths {
diff --git a/rust/builder.go b/rust/builder.go
index f79cf9b..60b5926 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -185,7 +185,7 @@
}
func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, flags Flags,
- outputFile android.WritablePath, crate_type string) buildOutput {
+ outputFile android.WritablePath, crateType string) buildOutput {
var inputs android.Paths
var implicits android.Paths
@@ -204,7 +204,7 @@
// Collect rustc flags
rustcFlags = append(rustcFlags, flags.GlobalRustFlags...)
rustcFlags = append(rustcFlags, flags.RustFlags...)
- rustcFlags = append(rustcFlags, "--crate-type="+crate_type)
+ rustcFlags = append(rustcFlags, "--crate-type="+crateType)
if crateName != "" {
rustcFlags = append(rustcFlags, "--crate-name="+crateName)
}
@@ -361,7 +361,7 @@
Description: "rustdoc " + main.Rel(),
Output: docTimestampFile,
Input: main,
- Implicit: ctx.RustModule().unstrippedOutputFile.Path(),
+ Implicit: ctx.RustModule().UnstrippedOutputFile(),
Args: map[string]string{
"rustdocFlags": strings.Join(rustdocFlags, " "),
"outDir": docDir.String(),
diff --git a/rust/compiler.go b/rust/compiler.go
index cada985..3040e5d 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -181,7 +181,11 @@
sanitize *sanitize
distFile android.OptionalPath
- // Stripped output file. If Valid(), this file will be installed instead of outputFile.
+
+ // unstripped output file.
+ unstrippedOutputFile android.Path
+
+ // stripped output file.
strippedOutputFile android.OptionalPath
// If a crate has a source-generated dependency, a copy of the source file
@@ -340,6 +344,10 @@
return String(compiler.Properties.Cargo_pkg_version)
}
+func (compiler *baseCompiler) unstrippedOutputFilePath() android.Path {
+ return compiler.unstrippedOutputFile
+}
+
func (compiler *baseCompiler) strippedOutputFilePath() android.OptionalPath {
return compiler.strippedOutputFile
}
@@ -355,9 +363,9 @@
if !Bool(compiler.Properties.No_stdlibs) {
for _, stdlib := range config.Stdlibs {
- // If we're building for the primary arch of the build host, use the compiler's stdlibs
+ // If we're building for the build host, use the prebuilt stdlibs
if ctx.Target().Os == ctx.Config().BuildOS {
- stdlib = stdlib + "_" + ctx.toolchain().RustTriple()
+ stdlib = "prebuilt_" + stdlib
}
deps.Stdlibs = append(deps.Stdlibs, stdlib)
}
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index 8182c32..0d0b712 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -11,17 +11,19 @@
"external/crosvm",
"external/libchromeos-rs",
"external/minijail",
+ "external/open-dice",
"external/rust",
"external/selinux/libselinux",
"external/uwb",
"external/vm_tools/p9",
"frameworks/native/libs/binder/rust",
"frameworks/proto_logging/stats",
+ "hardware/interfaces/security",
+ "packages/modules/Bluetooth",
"packages/modules/DnsResolver",
"packages/modules/Uwb",
"packages/modules/Virtualization",
"prebuilts/rust",
- "system/bt",
"system/core/libstats/pull_rust",
"system/extras/profcollectd",
"system/extras/simpleperf",
diff --git a/rust/config/global.go b/rust/config/global.go
index b163bb6..ebddb75 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
var pctx = android.NewPackageContext("android/soong/rust/config")
var (
- RustDefaultVersion = "1.55.0"
+ RustDefaultVersion = "1.56.1"
RustDefaultBase = "prebuilts/rust/"
DefaultEdition = "2018"
Stdlibs = []string{
diff --git a/rust/fuzz.go b/rust/fuzz.go
index a628b61..55921ba 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -36,7 +36,7 @@
fuzzPackagedModule fuzz.FuzzPackagedModule
}
-var _ compiler = (*binaryDecorator)(nil)
+var _ compiler = (*fuzzDecorator)(nil)
// rust_binary produces a binary that is runnable on a device.
func RustFuzzFactory() android.Module {
@@ -147,7 +147,7 @@
files = s.PackageArtifacts(ctx, module, fuzzModule.fuzzPackagedModule, archDir, builder)
// The executable.
- files = append(files, fuzz.FileToZip{rustModule.unstrippedOutputFile.Path(), ""})
+ files = append(files, fuzz.FileToZip{rustModule.UnstrippedOutputFile(), ""})
// Grab the list of required shared libraries.
sharedLibraries := fuzz.CollectAllSharedDependencies(ctx, module, cc.UnstrippedOutputFile, cc.IsValidSharedDependency)
diff --git a/rust/fuzz_test.go b/rust/fuzz_test.go
index 2524f91..98be7c2 100644
--- a/rust/fuzz_test.go
+++ b/rust/fuzz_test.go
@@ -45,7 +45,7 @@
}
// Check that compiler flags are set appropriately .
- fuzz_libtest := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Output("fuzz_libtest")
+ fuzz_libtest := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Rule("rustc")
if !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-Z sanitizer=hwaddress") ||
!strings.Contains(fuzz_libtest.Args["rustcFlags"], "-C passes='sancov'") ||
!strings.Contains(fuzz_libtest.Args["rustcFlags"], "--cfg fuzzing") {
diff --git a/rust/library.go b/rust/library.go
index 38dae4d..07843fe 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -102,6 +102,9 @@
sourceProvider SourceProvider
collectedSnapshotHeaders android.Paths
+
+ // table-of-contents file for cdylib crates to optimize out relinking when possible
+ tocFile android.OptionalPath
}
type libraryInterface interface {
@@ -137,12 +140,18 @@
BuildOnlyDylib()
BuildOnlyStatic()
BuildOnlyShared()
+
+ toc() android.OptionalPath
}
func (library *libraryDecorator) nativeCoverage() bool {
return true
}
+func (library *libraryDecorator) toc() android.OptionalPath {
+ return library.tocFile
+}
+
func (library *libraryDecorator) rlib() bool {
return library.MutatedProperties.VariantIsRlib
}
@@ -460,7 +469,7 @@
}
func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
- var outputFile android.ModuleOutPath
+ var outputFile, ret android.ModuleOutPath
var fileName string
srcPath := library.srcPath(ctx, deps)
@@ -468,6 +477,34 @@
deps.srcProviderFiles = append(deps.srcProviderFiles, library.sourceProvider.Srcs()...)
}
+ // Calculate output filename
+ if library.rlib() {
+ fileName = library.getStem(ctx) + ctx.toolchain().RlibSuffix()
+ outputFile = android.PathForModuleOut(ctx, fileName)
+ ret = outputFile
+ } else if library.dylib() {
+ fileName = library.getStem(ctx) + ctx.toolchain().DylibSuffix()
+ outputFile = android.PathForModuleOut(ctx, fileName)
+ ret = outputFile
+ } else if library.static() {
+ fileName = library.getStem(ctx) + ctx.toolchain().StaticLibSuffix()
+ outputFile = android.PathForModuleOut(ctx, fileName)
+ ret = outputFile
+ } else if library.shared() {
+ fileName = library.sharedLibFilename(ctx)
+ outputFile = android.PathForModuleOut(ctx, fileName)
+ ret = outputFile
+ }
+
+ if !library.rlib() && !library.static() && library.stripper.NeedsStrip(ctx) {
+ strippedOutputFile := outputFile
+ outputFile = android.PathForModuleOut(ctx, "unstripped", fileName)
+ library.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile)
+
+ library.baseCompiler.strippedOutputFile = android.OptionalPathForPath(strippedOutputFile)
+ }
+ library.baseCompiler.unstrippedOutputFile = outputFile
+
flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
@@ -479,34 +516,17 @@
flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic")
}
+ // Call the appropriate builder for this library type
if library.rlib() {
- fileName = library.getStem(ctx) + ctx.toolchain().RlibSuffix()
- outputFile = android.PathForModuleOut(ctx, fileName)
-
TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile)
} else if library.dylib() {
- fileName = library.getStem(ctx) + ctx.toolchain().DylibSuffix()
- outputFile = android.PathForModuleOut(ctx, fileName)
-
TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile)
} else if library.static() {
- fileName = library.getStem(ctx) + ctx.toolchain().StaticLibSuffix()
- outputFile = android.PathForModuleOut(ctx, fileName)
-
TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile)
} else if library.shared() {
- fileName = library.sharedLibFilename(ctx)
- outputFile = android.PathForModuleOut(ctx, fileName)
-
TransformSrctoShared(ctx, srcPath, deps, flags, outputFile)
}
- if !library.rlib() && !library.static() && library.stripper.NeedsStrip(ctx) {
- strippedOutputFile := android.PathForModuleOut(ctx, "stripped", fileName)
- library.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile)
- library.strippedOutputFile = android.OptionalPathForPath(strippedOutputFile)
- }
-
if library.rlib() || library.dylib() {
library.flagExporter.exportLinkDirs(deps.linkDirs...)
library.flagExporter.exportLinkObjects(deps.linkObjects...)
@@ -519,9 +539,16 @@
}
if library.shared() {
+ // Optimize out relinking against shared libraries whose interface hasn't changed by
+ // depending on a table of contents file instead of the library itself.
+ tocFile := outputFile.ReplaceExtension(ctx, flags.Toolchain.SharedLibSuffix()[1:]+".toc")
+ library.tocFile = android.OptionalPathForPath(tocFile)
+ cc.TransformSharedObjectToToc(ctx, outputFile, tocFile)
+
ctx.SetProvider(cc.SharedLibraryInfoProvider, cc.SharedLibraryInfo{
- SharedLibrary: outputFile,
- Target: ctx.Target(),
+ TableOfContents: android.OptionalPathForPath(tocFile),
+ SharedLibrary: outputFile,
+ Target: ctx.Target(),
})
}
@@ -536,7 +563,7 @@
library.flagExporter.setProvider(ctx)
- return outputFile
+ return ret
}
func (library *libraryDecorator) srcPath(ctx ModuleContext, deps PathDeps) android.Path {
diff --git a/rust/library_test.go b/rust/library_test.go
index cb4ef7e..d78dcdd 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -37,10 +37,10 @@
}`)
// Test all variants are being built.
- libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std").Output("libfoo.rlib")
- libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.dylib.so")
- libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static").Output("libfoo.ffi.a")
- libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared").Output("libfoo.ffi.so")
+ libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc")
+ libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
+ libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static").Rule("rustc")
+ libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared").Rule("rustc")
rlibCrateType := "rlib"
dylibCrateType := "dylib"
@@ -78,7 +78,7 @@
crate_name: "foo",
}`)
- libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.dylib.so")
+ libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
if !strings.Contains(libfooDylib.Args["rustcFlags"], "prefer-dynamic") {
t.Errorf("missing prefer-dynamic flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
@@ -94,7 +94,7 @@
crate_name: "foo",
}`)
- libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.dylib.so")
+ libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
if !strings.Contains(libfooDylib.Args["rustcFlags"], "--cfg 'android_dylib'") {
t.Errorf("missing android_dylib cfg flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
@@ -148,7 +148,7 @@
libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared")
- libfooOutput := libfoo.Output("libfoo.so")
+ libfooOutput := libfoo.Rule("rustc")
if !strings.Contains(libfooOutput.Args["linkFlags"], "-Wl,-soname=libfoo.so") {
t.Errorf("missing expected -Wl,-soname linker flag for libfoo shared lib, linkFlags: %#v",
libfooOutput.Args["linkFlags"])
@@ -160,6 +160,26 @@
}
}
+func TestSharedLibraryToc(t *testing.T) {
+ ctx := testRust(t, `
+ rust_ffi_shared {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ }
+ cc_binary {
+ name: "fizzbuzz",
+ shared_libs: ["libfoo"],
+ }`)
+
+ fizzbuzz := ctx.ModuleForTests("fizzbuzz", "android_arm64_armv8-a").Rule("ld")
+
+ if !android.SuffixInList(fizzbuzz.Implicits.Strings(), "libfoo.so.toc") {
+ t.Errorf("missing expected libfoo.so.toc implicit dependency, instead found: %#v",
+ fizzbuzz.Implicits.Strings())
+ }
+}
+
func TestStaticLibraryLinkage(t *testing.T) {
ctx := testRust(t, `
rust_ffi_static {
@@ -242,16 +262,17 @@
`)
foo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib")
- foo.Output("stripped/libfoo.dylib.so")
+ foo.Output("libfoo.dylib.so")
+ foo.Output("unstripped/libfoo.dylib.so")
// Check that the `cp` rule is using the stripped version as input.
cp := foo.Rule("android.Cp")
- if !strings.HasSuffix(cp.Input.String(), "stripped/libfoo.dylib.so") {
- t.Errorf("installed binary not based on stripped version: %v", cp.Input)
+ if strings.HasSuffix(cp.Input.String(), "unstripped/libfoo.dylib.so") {
+ t.Errorf("installed library not based on stripped version: %v", cp.Input)
}
- fizzBar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeOutput("stripped/libbar.dylib.so")
+ fizzBar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeOutput("unstripped/libbar.dylib.so")
if fizzBar.Rule != nil {
- t.Errorf("stripped version of bar has been generated")
+ t.Errorf("unstripped library exists, so stripped library has incorrectly been generated")
}
}
diff --git a/rust/prebuilt.go b/rust/prebuilt.go
index 49f3c0f..6f17272 100644
--- a/rust/prebuilt.go
+++ b/rust/prebuilt.go
@@ -32,6 +32,8 @@
}
type prebuiltLibraryDecorator struct {
+ android.Prebuilt
+
*libraryDecorator
Properties PrebuiltProperties
}
@@ -54,6 +56,13 @@
return module.Init()
}
+func addSrcSupplier(module android.PrebuiltInterface, prebuilt *prebuiltLibraryDecorator) {
+ srcsSupplier := func(_ android.BaseModuleContext, _ android.Module) []string {
+ return prebuilt.prebuiltSrcs()
+ }
+ android.InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "srcs")
+}
+
func NewPrebuiltLibrary(hod android.HostOrDeviceSupported) (*Module, *prebuiltLibraryDecorator) {
module, library := NewRustLibrary(hod)
library.BuildOnlyRust()
@@ -62,6 +71,9 @@
libraryDecorator: library,
}
module.compiler = prebuilt
+
+ addSrcSupplier(module, prebuilt)
+
return module, prebuilt
}
@@ -73,6 +85,9 @@
libraryDecorator: library,
}
module.compiler = prebuilt
+
+ addSrcSupplier(module, prebuilt)
+
return module, prebuilt
}
@@ -84,6 +99,9 @@
libraryDecorator: library,
}
module.compiler = prebuilt
+
+ addSrcSupplier(module, prebuilt)
+
return module, prebuilt
}
@@ -100,6 +118,7 @@
if len(paths) > 0 {
ctx.PropertyErrorf("srcs", "prebuilt libraries can only have one entry in srcs (the prebuilt path)")
}
+ prebuilt.baseCompiler.unstrippedOutputFile = srcPath
return srcPath
}
@@ -129,3 +148,7 @@
return srcs
}
+
+func (prebuilt *prebuiltLibraryDecorator) prebuilt() *android.Prebuilt {
+ return &prebuilt.Prebuilt
+}
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index 804d79f..974c096 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -75,6 +75,7 @@
srcPath, _ := srcPathFromModuleSrcs(ctx, procMacro.baseCompiler.Properties.Srcs)
TransformSrctoProcMacro(ctx, srcPath, deps, flags, outputFile)
+ procMacro.baseCompiler.unstrippedOutputFile = outputFile
return outputFile
}
diff --git a/rust/rust.go b/rust/rust.go
index c465cb6..b575c7a 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -156,13 +156,15 @@
sourceProvider SourceProvider
subAndroidMkOnce map[SubAndroidMkProvider]bool
- // Unstripped output. This is usually used when this module is linked to another module
- // as a library. The stripped output which is used for installation can be found via
- // compiler.strippedOutputFile if it exists.
- unstrippedOutputFile android.OptionalPath
- docTimestampFile android.OptionalPath
+ // Output file to be installed, may be stripped or unstripped.
+ outputFile android.OptionalPath
+
+ docTimestampFile android.OptionalPath
hideApexVariantFromMake bool
+
+ // For apex variants, this is set as apex.min_sdk_version
+ apexSdkVersion android.ApiLevel
}
func (mod *Module) Header() bool {
@@ -281,8 +283,8 @@
func (mod *Module) Toc() android.OptionalPath {
if mod.compiler != nil {
- if _, ok := mod.compiler.(libraryInterface); ok {
- return android.OptionalPath{}
+ if lib, ok := mod.compiler.(libraryInterface); ok {
+ return lib.toc()
}
}
panic(fmt.Errorf("Toc() called on non-library module: %q", mod.BaseModuleName()))
@@ -391,6 +393,10 @@
WholeStaticLibs []string
HeaderLibs []string
+ // Used for data dependencies adjacent to tests
+ DataLibs []string
+ DataBins []string
+
CrtBegin, CrtEnd string
}
@@ -465,6 +471,7 @@
stdLinkage(ctx *depsContext) RustLinkage
+ unstrippedOutputFilePath() android.Path
strippedOutputFilePath() android.OptionalPath
}
@@ -574,7 +581,7 @@
func (mod *Module) CcLibrary() bool {
if mod.compiler != nil {
- if _, ok := mod.compiler.(*libraryDecorator); ok {
+ if _, ok := mod.compiler.(libraryInterface); ok {
return true
}
}
@@ -593,8 +600,8 @@
}
func (mod *Module) UnstrippedOutputFile() android.Path {
- if mod.unstrippedOutputFile.Valid() {
- return mod.unstrippedOutputFile.Path()
+ if mod.compiler != nil {
+ return mod.compiler.unstrippedOutputFilePath()
}
return nil
}
@@ -651,10 +658,7 @@
}
func (mod *Module) OutputFile() android.OptionalPath {
- if mod.compiler != nil && mod.compiler.strippedOutputFilePath().Valid() {
- return mod.compiler.strippedOutputFilePath()
- }
- return mod.unstrippedOutputFile
+ return mod.outputFile
}
func (mod *Module) CoverageFiles() android.Paths {
@@ -678,6 +682,10 @@
return mod.OutputFile().Valid() && !mod.Properties.PreventInstall
}
+func (ctx moduleContext) apexVariationName() string {
+ return ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).ApexVariationName
+}
+
var _ cc.LinkableInterface = (*Module)(nil)
func (mod *Module) Init() android.Module {
@@ -885,9 +893,12 @@
if mod.compiler != nil && !mod.compiler.Disabled() {
mod.compiler.initialize(ctx)
- unstrippedOutputFile := mod.compiler.compile(ctx, flags, deps)
- mod.unstrippedOutputFile = android.OptionalPathForPath(unstrippedOutputFile)
- bloaty.MeasureSizeForPaths(ctx, mod.compiler.strippedOutputFilePath(), mod.unstrippedOutputFile)
+ outputFile := mod.compiler.compile(ctx, flags, deps)
+ if ctx.Failed() {
+ return
+ }
+ mod.outputFile = android.OptionalPathForPath(outputFile)
+ bloaty.MeasureSizeForPaths(ctx, mod.compiler.strippedOutputFilePath(), android.OptionalPathForPath(mod.compiler.unstrippedOutputFilePath()))
mod.docTimestampFile = mod.compiler.rustdoc(ctx, flags, deps)
@@ -975,6 +986,8 @@
procMacroDepTag = dependencyTag{name: "procMacro", procMacro: true}
testPerSrcDepTag = dependencyTag{name: "rust_unit_tests"}
sourceDepTag = dependencyTag{name: "source"}
+ dataLibDepTag = dependencyTag{name: "data lib"}
+ dataBinDepTag = dependencyTag{name: "data bin"}
)
func IsDylibDepTag(depTag blueprint.DependencyTag) bool {
@@ -1012,6 +1025,13 @@
}
}
+func (mod *Module) Prebuilt() *android.Prebuilt {
+ if p, ok := mod.compiler.(*prebuiltLibraryDecorator); ok {
+ return p.prebuilt()
+ }
+ return nil
+}
+
func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
var depPaths PathDeps
@@ -1023,6 +1043,20 @@
directSrcProvidersDeps := []*Module{}
directSrcDeps := [](android.SourceFileProducer){}
+ // For the dependency from platform to apex, use the latest stubs
+ mod.apexSdkVersion = android.FutureApiLevel
+ apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ if !apexInfo.IsForPlatform() {
+ mod.apexSdkVersion = apexInfo.MinSdkVersion
+ }
+
+ if android.InList("hwaddress", ctx.Config().SanitizeDevice()) {
+ // In hwasan build, we override apexSdkVersion to the FutureApiLevel(10000)
+ // so that even Q(29/Android10) apexes could use the dynamic unwinder by linking the newer stubs(e.g libc(R+)).
+ // (b/144430859)
+ mod.apexSdkVersion = android.FutureApiLevel
+ }
+
ctx.VisitDirectDeps(func(dep android.Module) {
depName := ctx.OtherModuleName(dep)
depTag := ctx.OtherModuleDependencyTag(dep)
@@ -1083,13 +1117,8 @@
}
if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
- linkFile := rustDep.unstrippedOutputFile
- if !linkFile.Valid() {
- ctx.ModuleErrorf("Invalid output file when adding dep %q to %q",
- depName, ctx.ModuleName())
- return
- }
- linkDir := linkPathFromFilePath(linkFile.Path())
+ linkFile := rustDep.UnstrippedOutputFile()
+ linkDir := linkPathFromFilePath(linkFile)
if lib, ok := mod.compiler.(exportedFlagsProducer); ok {
lib.exportLinkDirs(linkDir)
}
@@ -1198,15 +1227,15 @@
var rlibDepFiles RustLibraries
for _, dep := range directRlibDeps {
- rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.unstrippedOutputFile.Path(), CrateName: dep.CrateName()})
+ rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
}
var dylibDepFiles RustLibraries
for _, dep := range directDylibDeps {
- dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.unstrippedOutputFile.Path(), CrateName: dep.CrateName()})
+ dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
}
var procMacroDepFiles RustLibraries
for _, dep := range directProcMacroDeps {
- procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.unstrippedOutputFile.Path(), CrateName: dep.CrateName()})
+ procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
}
var staticLibDepFiles android.Paths
@@ -1273,6 +1302,10 @@
return mod.InRecovery()
}
+func (mod *Module) InstallBypassMake() bool {
+ return true
+}
+
func linkPathFromFilePath(filepath android.Path) string {
return strings.Split(filepath.String(), filepath.Base())[0]
}
@@ -1401,6 +1434,12 @@
}
}
+ actx.AddVariationDependencies([]blueprint.Variation{
+ {Mutator: "link", Variation: "shared"},
+ }, dataLibDepTag, deps.DataLibs...)
+
+ actx.AddVariationDependencies(nil, dataBinDepTag, deps.DataBins...)
+
// proc_macros are compiler plugins, and so we need the host arch variant as a dependendcy.
actx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), procMacroDepTag, deps.ProcMacros...)
}
@@ -1515,7 +1554,7 @@
// Overrides ApexModule.IsInstallabeToApex()
func (mod *Module) IsInstallableToApex() bool {
if mod.compiler != nil {
- if lib, ok := mod.compiler.(*libraryDecorator); ok && (lib.shared() || lib.dylib()) {
+ if lib, ok := mod.compiler.(libraryInterface); ok && (lib.shared() || lib.dylib()) {
return true
}
if _, ok := mod.compiler.(*binaryDecorator); ok {
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 80f693e..97bd541 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -79,8 +79,10 @@
}
const (
- sharedVendorVariant = "android_vendor.29_arm64_armv8-a_shared"
- rlibVendorVariant = "android_vendor.29_arm64_armv8-a_rlib_rlib-std"
+ sharedVendorVariant = "android_vendor.29_arm64_armv8-a_shared"
+ rlibVendorVariant = "android_vendor.29_arm64_armv8-a_rlib_rlib-std"
+ sharedRecoveryVariant = "android_recovery_arm64_armv8-a_shared"
+ rlibRecoveryVariant = "android_recovery_arm64_armv8-a_rlib_rlib-std"
)
func testRustVndkFs(t *testing.T, bp string, fs android.MockFS) *android.TestContext {
@@ -101,7 +103,22 @@
),
).RunTestWithBp(t, bp)
return result.TestContext
+}
+func testRustRecoveryFsVersions(t *testing.T, bp string, fs android.MockFS, device_version, vndk_version, recovery_version string) *android.TestContext {
+ skipTestIfOsNotSupported(t)
+ result := android.GroupFixturePreparers(
+ prepareForRustTest,
+ fs.AddToFixture(),
+ android.FixtureModifyProductVariables(
+ func(variables android.FixtureProductVariables) {
+ variables.DeviceVndkVersion = StringPtr(device_version)
+ variables.RecoverySnapshotVersion = StringPtr(recovery_version)
+ variables.Platform_vndk_version = StringPtr(vndk_version)
+ },
+ ),
+ ).RunTestWithBp(t, bp)
+ return result.TestContext
}
// testRustCov returns a TestContext in which a basic environment has been
@@ -439,6 +456,13 @@
}`)
m := ctx.SingletonForTests("file_metrics")
+ m.Output("unstripped/libwaldo.dylib.so.bloaty.csv")
m.Output("libwaldo.dylib.so.bloaty.csv")
- m.Output("stripped/libwaldo.dylib.so.bloaty.csv")
+}
+
+func assertString(t *testing.T, got, expected string) {
+ t.Helper()
+ if got != expected {
+ t.Errorf("expected %q got %q", expected, got)
+ }
}
diff --git a/rust/sanitize.go b/rust/sanitize.go
index baa383d..be9dc42 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -15,20 +15,39 @@
package rust
import (
+ "fmt"
+ "strings"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+
"android/soong/android"
"android/soong/cc"
"android/soong/rust/config"
- "fmt"
- "github.com/google/blueprint"
)
+// TODO: When Rust has sanitizer-parity with CC, deduplicate this struct
type SanitizeProperties struct {
// enable AddressSanitizer, HWAddressSanitizer, and others.
Sanitize struct {
Address *bool `android:"arch_variant"`
Hwaddress *bool `android:"arch_variant"`
- Fuzzer *bool `android:"arch_variant"`
- Never *bool `android:"arch_variant"`
+
+ // Memory-tagging, only available on arm64
+ // if diag.memtag unset or false, enables async memory tagging
+ Memtag_heap *bool `android:"arch_variant"`
+ Fuzzer *bool `android:"arch_variant"`
+ Never *bool `android:"arch_variant"`
+
+ // Sanitizers to run in the diagnostic mode (as opposed to the release mode).
+ // Replaces abort() on error with a human-readable error message.
+ // Address and Thread sanitizers always run in diagnostic mode.
+ Diag struct {
+ // Memory-tagging, only available on arm64
+ // requires sanitizer.memtag: true
+ // if set, enables sync memory tagging
+ Memtag_heap *bool `android:"arch_variant"`
+ }
}
SanitizerEnabled bool `blueprint:"mutated"`
SanitizeDep bool `blueprint:"mutated"`
@@ -59,9 +78,18 @@
"-Z sanitizer=address",
}
+// See cc/sanitize.go's hwasanGlobalOptions for global hwasan options.
var hwasanFlags = []string{
"-Z sanitizer=hwaddress",
"-C target-feature=+tagged-globals",
+
+ // Flags from cc/sanitize.go hwasanFlags
+ "-C llvm-args=--aarch64-enable-global-isel-at-O=-1",
+ "-C llvm-args=-fast-isel=false",
+ "-C llvm-args=-instcombine-lower-dbg-declare=0",
+
+ // Additional flags for HWASAN-ified Rust/C interop
+ "-C llvm-args=--hwasan-with-ifunc",
}
func boolPtr(v bool) *bool {
@@ -79,7 +107,88 @@
}
func (sanitize *sanitize) begin(ctx BaseModuleContext) {
- s := sanitize.Properties.Sanitize
+ s := &sanitize.Properties.Sanitize
+
+ // Never always wins.
+ if Bool(s.Never) {
+ return
+ }
+
+ // rust_test targets default to SYNC MemTag unless explicitly set to ASYNC (via diag: {Memtag_heap}).
+ if binary, ok := ctx.RustModule().compiler.(binaryInterface); ok && binary.testBinary() {
+ if s.Memtag_heap == nil {
+ s.Memtag_heap = proptools.BoolPtr(true)
+ }
+ if s.Diag.Memtag_heap == nil {
+ s.Diag.Memtag_heap = proptools.BoolPtr(true)
+ }
+ }
+
+ var globalSanitizers []string
+ var globalSanitizersDiag []string
+
+ if ctx.Host() {
+ if !ctx.Windows() {
+ globalSanitizers = ctx.Config().SanitizeHost()
+ }
+ } else {
+ arches := ctx.Config().SanitizeDeviceArch()
+ if len(arches) == 0 || android.InList(ctx.Arch().ArchType.Name, arches) {
+ globalSanitizers = ctx.Config().SanitizeDevice()
+ globalSanitizersDiag = ctx.Config().SanitizeDeviceDiag()
+ }
+ }
+
+ if len(globalSanitizers) > 0 {
+ var found bool
+
+ // Global Sanitizers
+ if found, globalSanitizers = android.RemoveFromList("hwaddress", globalSanitizers); found && s.Hwaddress == nil {
+ // TODO(b/204776996): HWASan for static Rust binaries isn't supported yet.
+ if !ctx.RustModule().StaticExecutable() {
+ s.Hwaddress = proptools.BoolPtr(true)
+ }
+ }
+
+ if found, globalSanitizers = android.RemoveFromList("memtag_heap", globalSanitizers); found && s.Memtag_heap == nil {
+ if !ctx.Config().MemtagHeapDisabledForPath(ctx.ModuleDir()) {
+ s.Memtag_heap = proptools.BoolPtr(true)
+ }
+ }
+
+ if found, globalSanitizers = android.RemoveFromList("address", globalSanitizers); found && s.Address == nil {
+ s.Address = proptools.BoolPtr(true)
+ }
+
+ if found, globalSanitizers = android.RemoveFromList("fuzzer", globalSanitizers); found && s.Fuzzer == nil {
+ // TODO(b/204776996): HWASan for static Rust binaries isn't supported yet, and fuzzer enables HWAsan
+ if !ctx.RustModule().StaticExecutable() {
+ s.Fuzzer = proptools.BoolPtr(true)
+ }
+ }
+
+ // Global Diag Sanitizers
+ if found, globalSanitizersDiag = android.RemoveFromList("memtag_heap", globalSanitizersDiag); found &&
+ s.Diag.Memtag_heap == nil && Bool(s.Memtag_heap) {
+ s.Diag.Memtag_heap = proptools.BoolPtr(true)
+ }
+ }
+
+ // Enable Memtag for all components in the include paths (for Aarch64 only)
+ if ctx.Arch().ArchType == android.Arm64 {
+ if ctx.Config().MemtagHeapSyncEnabledForPath(ctx.ModuleDir()) {
+ if s.Memtag_heap == nil {
+ s.Memtag_heap = proptools.BoolPtr(true)
+ }
+ if s.Diag.Memtag_heap == nil {
+ s.Diag.Memtag_heap = proptools.BoolPtr(true)
+ }
+ } else if ctx.Config().MemtagHeapAsyncEnabledForPath(ctx.ModuleDir()) {
+ if s.Memtag_heap == nil {
+ s.Memtag_heap = proptools.BoolPtr(true)
+ }
+ }
+ }
// TODO:(b/178369775)
// For now sanitizing is only supported on devices
@@ -96,7 +205,22 @@
s.Hwaddress = nil
}
- if ctx.Os() == android.Android && Bool(s.Hwaddress) {
+ // HWASan ramdisk (which is built from recovery) goes over some bootloader limit.
+ // Keep libc instrumented so that ramdisk / vendor_ramdisk / recovery can run hwasan-instrumented code if necessary.
+ if (ctx.RustModule().InRamdisk() || ctx.RustModule().InVendorRamdisk() || ctx.RustModule().InRecovery()) && !strings.HasPrefix(ctx.ModuleDir(), "bionic/libc") {
+ s.Hwaddress = nil
+ }
+
+ if Bool(s.Hwaddress) {
+ s.Address = nil
+ }
+
+ // Memtag_heap is only implemented on AArch64.
+ if ctx.Arch().ArchType != android.Arm64 {
+ s.Memtag_heap = nil
+ }
+
+ if ctx.Os() == android.Android && (Bool(s.Hwaddress) || Bool(s.Address) || Bool(s.Memtag_heap)) {
sanitize.Properties.SanitizerEnabled = true
}
}
@@ -116,12 +240,10 @@
} else {
flags.RustFlags = append(flags.RustFlags, asanFlags...)
}
- }
- if Bool(sanitize.Properties.Sanitize.Address) {
- flags.RustFlags = append(flags.RustFlags, asanFlags...)
- }
- if Bool(sanitize.Properties.Sanitize.Hwaddress) {
+ } else if Bool(sanitize.Properties.Sanitize.Hwaddress) {
flags.RustFlags = append(flags.RustFlags, hwasanFlags...)
+ } else if Bool(sanitize.Properties.Sanitize.Address) {
+ flags.RustFlags = append(flags.RustFlags, asanFlags...)
}
return flags, deps
}
@@ -136,6 +258,26 @@
return
}
+ if Bool(mod.sanitize.Properties.Sanitize.Memtag_heap) && mod.Binary() {
+ noteDep := "note_memtag_heap_async"
+ if Bool(mod.sanitize.Properties.Sanitize.Diag.Memtag_heap) {
+ noteDep = "note_memtag_heap_sync"
+ }
+ // If we're using snapshots, redirect to snapshot whenever possible
+ // TODO(b/178470649): clean manual snapshot redirections
+ snapshot := mctx.Provider(cc.SnapshotInfoProvider).(cc.SnapshotInfo)
+ if lib, ok := snapshot.StaticLibs[noteDep]; ok {
+ noteDep = lib
+ }
+ depTag := cc.StaticDepTag(true)
+ variations := append(mctx.Target().Variations(),
+ blueprint.Variation{Mutator: "link", Variation: "static"})
+ if mod.Device() {
+ variations = append(variations, mod.ImageVariation())
+ }
+ mctx.AddFarVariationDependencies(variations, depTag, noteDep)
+ }
+
variations := mctx.Target().Variations()
var depTag blueprint.DependencyTag
var deps []string
@@ -148,27 +290,24 @@
deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan")}
} else if mod.IsSanitizerEnabled(cc.Hwasan) ||
(mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType == android.Arm64) {
- // TODO(b/180495975): HWASan for static Rust binaries isn't supported yet.
- if binary, ok := mod.compiler.(*binaryDecorator); ok {
- if Bool(binary.Properties.Static_executable) {
+ // TODO(b/204776996): HWASan for static Rust binaries isn't supported yet.
+ if binary, ok := mod.compiler.(binaryInterface); ok {
+ if binary.staticallyLinked() {
mctx.ModuleErrorf("HWASan is not supported for static Rust executables yet.")
}
}
- if mod.StaticallyLinked() {
- variations = append(variations,
- blueprint.Variation{Mutator: "link", Variation: "static"})
- depTag = cc.StaticDepTag(false)
- deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan_static")}
- } else {
- variations = append(variations,
- blueprint.Variation{Mutator: "link", Variation: "shared"})
- depTag = cc.SharedDepTag()
- deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan")}
- }
+ // Always link against the shared library -- static binaries will pull in the static
+ // library during final link if necessary
+ variations = append(variations,
+ blueprint.Variation{Mutator: "link", Variation: "shared"})
+ depTag = cc.SharedDepTag()
+ deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan")}
}
- mctx.AddFarVariationDependencies(variations, depTag, deps...)
+ if len(deps) > 0 {
+ mctx.AddFarVariationDependencies(variations, depTag, deps...)
+ }
}
}
@@ -184,6 +323,9 @@
case cc.Hwasan:
sanitize.Properties.Sanitize.Hwaddress = boolPtr(b)
sanitizerSet = true
+ case cc.Memtag_heap:
+ sanitize.Properties.Sanitize.Memtag_heap = boolPtr(b)
+ sanitizerSet = true
default:
panic(fmt.Errorf("setting unsupported sanitizerType %d", t))
}
@@ -243,6 +385,8 @@
return sanitize.Properties.Sanitize.Address
case cc.Hwasan:
return sanitize.Properties.Sanitize.Hwaddress
+ case cc.Memtag_heap:
+ return sanitize.Properties.Sanitize.Memtag_heap
default:
return nil
}
@@ -268,6 +412,12 @@
case cc.Asan:
return true
case cc.Hwasan:
+ // TODO(b/180495975): HWASan for static Rust binaries isn't supported yet.
+ if mod.StaticExecutable() {
+ return false
+ }
+ return true
+ case cc.Memtag_heap:
return true
default:
return false
diff --git a/rust/sanitize_test.go b/rust/sanitize_test.go
new file mode 100644
index 0000000..d6a14b2
--- /dev/null
+++ b/rust/sanitize_test.go
@@ -0,0 +1,365 @@
+package rust
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+
+ "android/soong/android"
+)
+
+type MemtagNoteType int
+
+const (
+ None MemtagNoteType = iota + 1
+ Sync
+ Async
+)
+
+func (t MemtagNoteType) str() string {
+ switch t {
+ case None:
+ return "none"
+ case Sync:
+ return "sync"
+ case Async:
+ return "async"
+ default:
+ panic("type_note_invalid")
+ }
+}
+
+func checkHasMemtagNote(t *testing.T, m android.TestingModule, expected MemtagNoteType) {
+ t.Helper()
+ note_async := "note_memtag_heap_async"
+ note_sync := "note_memtag_heap_sync"
+
+ found := None
+ implicits := m.Rule("rustc").Implicits
+ for _, lib := range implicits {
+ if strings.Contains(lib.Rel(), note_async) {
+ found = Async
+ break
+ } else if strings.Contains(lib.Rel(), note_sync) {
+ found = Sync
+ break
+ }
+ }
+
+ if found != expected {
+ t.Errorf("Wrong Memtag note in target %q: found %q, expected %q", m.Module().(*Module).Name(), found.str(), expected.str())
+ }
+}
+
+var prepareForTestWithMemtagHeap = android.GroupFixturePreparers(
+ android.FixtureModifyMockFS(func(fs android.MockFS) {
+ templateBp := `
+ rust_test {
+ name: "unset_test_%[1]s",
+ srcs: ["foo.rs"],
+ }
+
+ rust_test {
+ name: "no_memtag_test_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: false },
+ }
+
+ rust_test {
+ name: "set_memtag_test_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: true },
+ }
+
+ rust_test {
+ name: "set_memtag_set_async_test_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: true, diag: { memtag_heap: false } },
+ }
+
+ rust_test {
+ name: "set_memtag_set_sync_test_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: true, diag: { memtag_heap: true } },
+ }
+
+ rust_test {
+ name: "unset_memtag_set_sync_test_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { diag: { memtag_heap: true } },
+ }
+
+ rust_binary {
+ name: "unset_binary_%[1]s",
+ srcs: ["foo.rs"],
+ }
+
+ rust_binary {
+ name: "no_memtag_binary_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: false },
+ }
+
+ rust_binary {
+ name: "set_memtag_binary_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: true },
+ }
+
+ rust_binary {
+ name: "set_memtag_set_async_binary_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: true, diag: { memtag_heap: false } },
+ }
+
+ rust_binary {
+ name: "set_memtag_set_sync_binary_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: true, diag: { memtag_heap: true } },
+ }
+
+ rust_binary {
+ name: "unset_memtag_set_sync_binary_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { diag: { memtag_heap: true } },
+ }
+ `
+ subdirNoOverrideBp := fmt.Sprintf(templateBp, "no_override")
+ subdirOverrideDefaultDisableBp := fmt.Sprintf(templateBp, "override_default_disable")
+ subdirSyncBp := fmt.Sprintf(templateBp, "override_default_sync")
+ subdirAsyncBp := fmt.Sprintf(templateBp, "override_default_async")
+
+ fs.Merge(android.MockFS{
+ "subdir_no_override/Android.bp": []byte(subdirNoOverrideBp),
+ "subdir_override_default_disable/Android.bp": []byte(subdirOverrideDefaultDisableBp),
+ "subdir_sync/Android.bp": []byte(subdirSyncBp),
+ "subdir_async/Android.bp": []byte(subdirAsyncBp),
+ })
+ }),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.MemtagHeapExcludePaths = []string{"subdir_override_default_disable"}
+ // "subdir_override_default_disable" is covered by both include and override_default_disable paths. override_default_disable wins.
+ variables.MemtagHeapSyncIncludePaths = []string{"subdir_sync", "subdir_override_default_disable"}
+ variables.MemtagHeapAsyncIncludePaths = []string{"subdir_async", "subdir_override_default_disable"}
+ }),
+)
+
+func TestSanitizeMemtagHeap(t *testing.T) {
+ variant := "android_arm64_armv8-a"
+
+ result := android.GroupFixturePreparers(
+ prepareForRustTest,
+ prepareForTestWithMemtagHeap,
+ ).RunTest(t)
+ ctx := result.TestContext
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_async", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_sync", variant), None)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_async", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_sync", variant), None)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_sync", variant), Async)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_sync", variant), Async)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync)
+}
+
+func TestSanitizeMemtagHeapWithSanitizeDevice(t *testing.T) {
+ variant := "android_arm64_armv8-a"
+
+ result := android.GroupFixturePreparers(
+ prepareForRustTest,
+ prepareForTestWithMemtagHeap,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.SanitizeDevice = []string{"memtag_heap"}
+ }),
+ ).RunTest(t)
+ ctx := result.TestContext
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_async", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_sync", variant), None)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_async", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_sync", variant), None)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_sync", variant), Async)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_sync", variant), Async)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_sync", variant), Sync)
+
+ // should sanitize: { diag: { memtag: true } } result in Sync instead of None here?
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_async", variant), Sync)
+ // should sanitize: { diag: { memtag: true } } result in Sync instead of None here?
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync)
+}
+
+func TestSanitizeMemtagHeapWithSanitizeDeviceDiag(t *testing.T) {
+ variant := "android_arm64_armv8-a"
+
+ result := android.GroupFixturePreparers(
+ prepareForRustTest,
+ prepareForTestWithMemtagHeap,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.SanitizeDevice = []string{"memtag_heap"}
+ variables.SanitizeDeviceDiag = []string{"memtag_heap"}
+ }),
+ ).RunTest(t)
+ ctx := result.TestContext
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_async", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_sync", variant), None)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_async", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_sync", variant), None)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_sync", variant), Async)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_sync", variant), Async)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_async", variant), Sync)
+ // should sanitize: { diag: { memtag: true } } result in Sync instead of None here?
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync)
+}
diff --git a/rust/snapshot_prebuilt.go b/rust/snapshot_prebuilt.go
index 79eaab3..dfbc1d1 100644
--- a/rust/snapshot_prebuilt.go
+++ b/rust/snapshot_prebuilt.go
@@ -44,6 +44,8 @@
func registerRustSnapshotModules(ctx android.RegistrationContext) {
cc.VendorSnapshotImageSingleton.RegisterAdditionalModule(ctx,
"vendor_snapshot_rlib", VendorSnapshotRlibFactory)
+ cc.RecoverySnapshotImageSingleton.RegisterAdditionalModule(ctx,
+ "recovery_snapshot_rlib", RecoverySnapshotRlibFactory)
}
func snapshotLibraryFactory(image cc.SnapshotImage, moduleSuffix string) (*Module, *snapshotLibraryDecorator) {
@@ -85,8 +87,9 @@
if !library.MatchesWithDevice(ctx.DeviceConfig()) {
return nil
}
-
- return android.PathForModuleSrc(ctx, *library.properties.Src)
+ outputFile := android.PathForModuleSrc(ctx, *library.properties.Src)
+ library.unstrippedOutputFile = outputFile
+ return outputFile
}
func (library *snapshotLibraryDecorator) rustdoc(ctx ModuleContext, flags Flags, deps PathDeps) android.OptionalPath {
@@ -104,6 +107,13 @@
return module.Init()
}
+func RecoverySnapshotRlibFactory() android.Module {
+ module, prebuilt := snapshotLibraryFactory(cc.RecoverySnapshotImageSingleton, cc.SnapshotRlibSuffix)
+ prebuilt.libraryDecorator.BuildOnlyRlib()
+ prebuilt.libraryDecorator.setNoStdlibs()
+ return module.Init()
+}
+
func (library *snapshotLibraryDecorator) MatchesWithDevice(config android.DeviceConfig) bool {
arches := config.Arches()
if len(arches) == 0 || arches[0].ArchType.String() != library.Arch() {
diff --git a/rust/test.go b/rust/test.go
index 56da509..3eea0ad 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -18,6 +18,7 @@
"github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/cc"
"android/soong/tradefed"
)
@@ -49,6 +50,12 @@
// the test
Data []string `android:"path,arch_variant"`
+ // list of shared library modules that should be installed alongside the test
+ Data_libs []string `android:"arch_variant"`
+
+ // list of binary modules that should be installed alongside the test
+ Data_bins []string `android:"arch_variant"`
+
// Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
// doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
// explicitly.
@@ -137,6 +144,32 @@
dataSrcPaths := android.PathsForModuleSrc(ctx, test.Properties.Data)
+ ctx.VisitDirectDepsWithTag(dataLibDepTag, func(dep android.Module) {
+ depName := ctx.OtherModuleName(dep)
+ linkableDep, ok := dep.(cc.LinkableInterface)
+ if !ok {
+ ctx.ModuleErrorf("data_lib %q is not a linkable module", depName)
+ }
+ if linkableDep.OutputFile().Valid() {
+ test.data = append(test.data,
+ android.DataPath{SrcPath: linkableDep.OutputFile().Path(),
+ RelativeInstallPath: linkableDep.RelativeInstallPath()})
+ }
+ })
+
+ ctx.VisitDirectDepsWithTag(dataBinDepTag, func(dep android.Module) {
+ depName := ctx.OtherModuleName(dep)
+ linkableDep, ok := dep.(cc.LinkableInterface)
+ if !ok {
+ ctx.ModuleErrorf("data_bin %q is not a linkable module", depName)
+ }
+ if linkableDep.OutputFile().Valid() {
+ test.data = append(test.data,
+ android.DataPath{SrcPath: linkableDep.OutputFile().Path(),
+ RelativeInstallPath: linkableDep.RelativeInstallPath()})
+ }
+ })
+
for _, dataSrcPath := range dataSrcPaths {
test.data = append(test.data, android.DataPath{SrcPath: dataSrcPath})
}
@@ -194,5 +227,12 @@
deps.Rustlibs = append(deps.Rustlibs, "libtest")
+ deps.DataLibs = append(deps.DataLibs, test.Properties.Data_libs...)
+ deps.DataBins = append(deps.DataBins, test.Properties.Data_bins...)
+
return deps
}
+
+func (test *testDecorator) testBinary() bool {
+ return true
+}
diff --git a/rust/test_test.go b/rust/test_test.go
index 892761a..1124176 100644
--- a/rust/test_test.go
+++ b/rust/test_test.go
@@ -74,3 +74,129 @@
t.Errorf("Device rust_test module 'my_test' does not link libstd as an rlib")
}
}
+
+func TestDataLibs(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "test_lib",
+ srcs: ["test_lib.cpp"],
+ }
+
+ rust_binary {
+ name: "rusty",
+ srcs: ["foo.rs"],
+ compile_multilib: "both",
+ }
+
+ rust_ffi {
+ name: "librust_test_lib",
+ crate_name: "rust_test_lib",
+ srcs: ["test_lib.rs"],
+ relative_install_path: "foo/bar/baz",
+ compile_multilib: "64",
+ }
+
+ rust_test {
+ name: "main_test",
+ srcs: ["foo.rs"],
+ data_libs: ["test_lib"],
+ data_bins: ["rusty"],
+ }
+ `
+
+ ctx := testRust(t, bp)
+
+ module := ctx.ModuleForTests("main_test", "android_arm64_armv8-a").Module()
+ testBinary := module.(*Module).compiler.(*testDecorator)
+ outputFiles, err := module.(android.OutputFileProducer).OutputFiles("")
+ if err != nil {
+ t.Fatalf("Expected rust_test to produce output files, error: %s", err)
+ }
+ if len(outputFiles) != 1 {
+ t.Fatalf("expected exactly one output file. output files: [%s]", outputFiles)
+ }
+ if len(testBinary.dataPaths()) != 2 {
+ t.Fatalf("expected exactly two test data files. test data files: [%s]", testBinary.dataPaths())
+ }
+
+ outputPath := outputFiles[0].String()
+ dataLibraryPath := testBinary.dataPaths()[0].SrcPath.String()
+ dataBinaryPath := testBinary.dataPaths()[1].SrcPath.String()
+
+ if !strings.HasSuffix(outputPath, "/main_test") {
+ t.Errorf("expected test output file to be 'main_test', but was '%s'", outputPath)
+ }
+ if !strings.HasSuffix(dataLibraryPath, "/test_lib.so") {
+ t.Errorf("expected test data file to be 'test_lib.so', but was '%s'", dataLibraryPath)
+ }
+ if !strings.HasSuffix(dataBinaryPath, "/rusty") {
+ t.Errorf("expected test data file to be 'test_lib.so', but was '%s'", dataBinaryPath)
+ }
+}
+
+func TestDataLibsRelativeInstallPath(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "test_lib",
+ srcs: ["test_lib.cpp"],
+ relative_install_path: "foo/bar/baz",
+ compile_multilib: "64",
+ }
+
+ rust_ffi {
+ name: "librust_test_lib",
+ crate_name: "rust_test_lib",
+ srcs: ["test_lib.rs"],
+ relative_install_path: "foo/bar/baz",
+ compile_multilib: "64",
+ }
+
+ rust_binary {
+ name: "rusty",
+ srcs: ["foo.rs"],
+ relative_install_path: "foo/bar/baz",
+ compile_multilib: "64",
+ }
+
+ rust_test {
+ name: "main_test",
+ srcs: ["foo.rs"],
+ data_libs: ["test_lib", "librust_test_lib"],
+ data_bins: ["rusty"],
+ compile_multilib: "64",
+ }
+ `
+
+ ctx := testRust(t, bp)
+ module := ctx.ModuleForTests("main_test", "android_arm64_armv8-a").Module()
+ testBinary := module.(*Module).compiler.(*testDecorator)
+ outputFiles, err := module.(android.OutputFileProducer).OutputFiles("")
+ if err != nil {
+ t.Fatalf("Expected rust_test to produce output files, error: %s", err)
+ }
+ if len(outputFiles) != 1 {
+ t.Fatalf("expected exactly one output file. output files: [%s]", outputFiles)
+ }
+ if len(testBinary.dataPaths()) != 3 {
+ t.Fatalf("expected exactly two test data files. test data files: [%s]", testBinary.dataPaths())
+ }
+
+ outputPath := outputFiles[0].String()
+
+ if !strings.HasSuffix(outputPath, "/main_test") {
+ t.Errorf("expected test output file to be 'main_test', but was '%s'", outputPath)
+ }
+ entries := android.AndroidMkEntriesForTest(t, ctx, module)[0]
+ if !strings.HasSuffix(entries.EntryMap["LOCAL_TEST_DATA"][0], ":test_lib.so:foo/bar/baz") {
+ t.Errorf("expected LOCAL_TEST_DATA to end with `:test_lib.so:foo/bar/baz`,"+
+ " but was '%s'", entries.EntryMap["LOCAL_TEST_DATA"][0])
+ }
+ if !strings.HasSuffix(entries.EntryMap["LOCAL_TEST_DATA"][1], ":librust_test_lib.so:foo/bar/baz") {
+ t.Errorf("expected LOCAL_TEST_DATA to end with `:librust_test_lib.so:foo/bar/baz`,"+
+ " but was '%s'", entries.EntryMap["LOCAL_TEST_DATA"][1])
+ }
+ if !strings.HasSuffix(entries.EntryMap["LOCAL_TEST_DATA"][2], ":rusty:foo/bar/baz") {
+ t.Errorf("expected LOCAL_TEST_DATA to end with `:rusty:foo/bar/baz`,"+
+ " but was '%s'", entries.EntryMap["LOCAL_TEST_DATA"][2])
+ }
+}
diff --git a/rust/testing.go b/rust/testing.go
index 94cdd9d..1b34dfe 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -53,74 +53,14 @@
func GatherRequiredDepsForTest() string {
bp := `
rust_prebuilt_library {
- name: "libstd_x86_64-unknown-linux-gnu",
- crate_name: "std",
- rlib: {
- srcs: ["libstd.rlib"],
- },
- dylib: {
- srcs: ["libstd.so"],
- },
- host_supported: true,
- sysroot: true,
- }
- rust_prebuilt_library {
- name: "libtest_x86_64-unknown-linux-gnu",
- crate_name: "test",
- rlib: {
- srcs: ["libtest.rlib"],
- },
- dylib: {
- srcs: ["libtest.so"],
- },
- host_supported: true,
- sysroot: true,
- }
- rust_prebuilt_library {
- name: "libstd_i686-unknown-linux-gnu",
- crate_name: "std",
- rlib: {
- srcs: ["libstd.rlib"],
- },
- dylib: {
- srcs: ["libstd.so"],
- },
- host_supported: true,
- sysroot: true,
- }
- rust_prebuilt_library {
- name: "libtest_i686-unknown-linux-gnu",
- crate_name: "test",
- rlib: {
- srcs: ["libtest.rlib"],
- },
- dylib: {
- srcs: ["libtest.so"],
- },
- host_supported: true,
- sysroot: true,
- }
- rust_prebuilt_library {
- name: "libstd_x86_64-apple-darwin",
- crate_name: "std",
- rlib: {
- srcs: ["libstd.rlib"],
- },
- dylib: {
- srcs: ["libstd.so"],
- },
- host_supported: true,
- sysroot: true,
- }
- rust_prebuilt_library {
- name: "libtest_x86_64-apple-darwin",
- crate_name: "test",
- rlib: {
- srcs: ["libtest.rlib"],
- },
- dylib: {
- srcs: ["libtest.so"],
- },
+ name: "libstd",
+ crate_name: "std",
+ rlib: {
+ srcs: ["libstd.rlib"],
+ },
+ dylib: {
+ srcs: ["libstd.so"],
+ },
host_supported: true,
sysroot: true,
}
@@ -135,6 +75,7 @@
apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
min_sdk_version: "29",
vendor_available: true,
+ recovery_available: true,
llndk: {
symbol_file: "liblog.map.txt",
},
@@ -151,7 +92,12 @@
no_libcrt: true,
nocrt: true,
system_shared_libs: [],
- export_include_dirs: ["libprotobuf-cpp-full-includes"],
+ }
+ cc_library {
+ name: "libclang_rt.hwasan_static-aarch64-android",
+ no_libcrt: true,
+ nocrt: true,
+ system_shared_libs: [],
}
rust_library {
name: "libstd",
@@ -161,6 +107,7 @@
host_supported: true,
vendor_available: true,
vendor_ramdisk_available: true,
+ recovery_available: true,
native_coverage: false,
sysroot: true,
apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
@@ -173,6 +120,7 @@
host_supported: true,
vendor_available: true,
vendor_ramdisk_available: true,
+ recovery_available: true,
native_coverage: false,
apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
min_sdk_version: "29",
@@ -246,5 +194,8 @@
ctx.BottomUp("rust_begin", BeginMutator).Parallel()
})
ctx.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton)
+ ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("rust_sanitizers", rustSanitizerRuntimeMutator).Parallel()
+ })
registerRustSnapshotModules(ctx)
}
diff --git a/rust/toolchain_library.go b/rust/toolchain_library.go
new file mode 100644
index 0000000..326d529
--- /dev/null
+++ b/rust/toolchain_library.go
@@ -0,0 +1,103 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package rust
+
+import (
+ "path"
+
+ "android/soong/android"
+ "android/soong/rust/config"
+)
+
+// This module is used to compile the rust toolchain libraries
+// When RUST_PREBUILTS_VERSION is set, the library will generated
+// from the given Rust version.
+func init() {
+ android.RegisterModuleType("rust_toolchain_library",
+ rustToolchainLibraryFactory)
+ android.RegisterModuleType("rust_toolchain_library_rlib",
+ rustToolchainLibraryRlibFactory)
+ android.RegisterModuleType("rust_toolchain_library_dylib",
+ rustToolchainLibraryDylibFactory)
+}
+
+type toolchainLibraryProperties struct {
+ // path to the toolchain source, relative to the top of the toolchain source
+ Toolchain_src *string `android:"arch_variant"`
+}
+
+type toolchainLibraryDecorator struct {
+ *libraryDecorator
+ Properties toolchainLibraryProperties
+}
+
+// rust_toolchain_library produces all rust variants.
+func rustToolchainLibraryFactory() android.Module {
+ module, library := NewRustLibrary(android.HostAndDeviceSupported)
+ library.BuildOnlyRust()
+
+ return initToolchainLibrary(module, library)
+}
+
+// rust_toolchain_library_dylib produces a dylib.
+func rustToolchainLibraryDylibFactory() android.Module {
+ module, library := NewRustLibrary(android.HostAndDeviceSupported)
+ library.BuildOnlyDylib()
+
+ return initToolchainLibrary(module, library)
+}
+
+// rust_toolchain_library_rlib produces an rlib.
+func rustToolchainLibraryRlibFactory() android.Module {
+ module, library := NewRustLibrary(android.HostAndDeviceSupported)
+ library.BuildOnlyRlib()
+
+ return initToolchainLibrary(module, library)
+}
+
+func initToolchainLibrary(module *Module, library *libraryDecorator) android.Module {
+ toolchainLibrary := &toolchainLibraryDecorator{
+ libraryDecorator: library,
+ }
+ module.compiler = toolchainLibrary
+ module.AddProperties(&toolchainLibrary.Properties)
+ android.AddLoadHook(module, rustSetToolchainSource)
+
+ return module.Init()
+}
+
+func rustSetToolchainSource(ctx android.LoadHookContext) {
+ if toolchainLib, ok := ctx.Module().(*Module).compiler.(*toolchainLibraryDecorator); ok {
+ prefix := "linux-x86/" + GetRustPrebuiltVersion(ctx)
+ newSrcs := []string{path.Join(prefix, android.String(toolchainLib.Properties.Toolchain_src))}
+
+ type props struct {
+ Srcs []string
+ }
+ p := &props{}
+ p.Srcs = newSrcs
+ ctx.AppendProperties(p)
+
+ } else {
+ ctx.ModuleErrorf("Called rustSetToolchainSource on a non-Rust Module.")
+ }
+}
+
+// GetRustPrebuiltVersion returns the RUST_PREBUILTS_VERSION env var, or the default version if it is not defined.
+func GetRustPrebuiltVersion(ctx android.LoadHookContext) string {
+ return ctx.AConfig().GetenvWithDefault("RUST_PREBUILTS_VERSION", config.RustDefaultVersion)
+}
diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go
index 60ddb65..03bd867 100644
--- a/rust/vendor_snapshot_test.go
+++ b/rust/vendor_snapshot_test.go
@@ -562,6 +562,7 @@
"libvendor",
"libvndk",
"libclang_rt.builtins-aarch64-android",
+ "note_memtag_heap_sync",
],
shared_libs: [
"libvendor_available",
@@ -853,6 +854,20 @@
},
}
+ // Test sanitizers use the snapshot libraries
+ rust_binary {
+ name: "memtag_binary",
+ srcs: ["vendor/bin.rs"],
+ vendor: true,
+ compile_multilib: "64",
+ sanitize: {
+ memtag_heap: true,
+ diag: {
+ memtag_heap: true,
+ }
+ },
+ }
+
// old snapshot module which has to be ignored
vendor_snapshot_binary {
name: "bin",
@@ -880,11 +895,25 @@
},
},
}
+
+ vendor_snapshot_static {
+ name: "note_memtag_heap_sync",
+ vendor: true,
+ target_arch: "arm64",
+ version: "30",
+ arch: {
+ arm64: {
+ src: "note_memtag_heap_sync.a",
+ },
+ },
+ }
+
`
mockFS := android.MockFS{
"framework/Android.bp": []byte(frameworkBp),
"framework/bin.rs": nil,
+ "note_memtag_heap_sync.a": nil,
"vendor/Android.bp": []byte(vendorProprietaryBp),
"vendor/bin": nil,
"vendor/bin32": nil,
@@ -993,4 +1022,360 @@
if android.InList(binaryVariant, binVariants) {
t.Errorf("bin must not have variant %#v, but it does", sharedVariant)
}
+
+ memtagStaticLibs := ctx.ModuleForTests("memtag_binary", "android_vendor.30_arm64_armv8-a").Module().(*Module).Properties.AndroidMkStaticLibs
+ if g, w := memtagStaticLibs, []string{"libclang_rt.builtins-aarch64-android.vendor", "note_memtag_heap_sync.vendor"}; !reflect.DeepEqual(g, w) {
+ t.Errorf("wanted memtag_binary AndroidMkStaticLibs %q, got %q", w, g)
+ }
+}
+
+func TestRecoverySnapshotCapture(t *testing.T) {
+ bp := `
+ rust_ffi {
+ name: "librecovery",
+ recovery: true,
+ srcs: ["foo.rs"],
+ crate_name: "recovery",
+ }
+
+ rust_ffi {
+ name: "librecovery_available",
+ recovery_available: true,
+ srcs: ["foo.rs"],
+ crate_name: "recovery_available",
+ }
+
+ rust_library_rlib {
+ name: "librecovery_rlib",
+ recovery: true,
+ srcs: ["foo.rs"],
+ crate_name: "recovery_rlib",
+ }
+
+ rust_library_rlib {
+ name: "librecovery_available_rlib",
+ recovery_available: true,
+ srcs: ["foo.rs"],
+ crate_name: "recovery_available_rlib",
+ }
+
+ rust_binary {
+ name: "recovery_bin",
+ recovery: true,
+ srcs: ["foo.rs"],
+ }
+
+ rust_binary {
+ name: "recovery_available_bin",
+ recovery_available: true,
+ srcs: ["foo.rs"],
+ }
+
+`
+ // Check Recovery snapshot output.
+
+ ctx := testRustRecoveryFsVersions(t, bp, rustMockedFiles, "", "29", "current")
+ snapshotDir := "recovery-snapshot"
+ snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
+ snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
+
+ var jsonFiles []string
+
+ for _, arch := range [][]string{
+ []string{"arm64", "armv8-a"},
+ } {
+ archType := arch[0]
+ archVariant := arch[1]
+ archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
+
+ // For shared libraries, all recovery:true and recovery_available modules are captured.
+ sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
+ sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant)
+ jsonFiles = append(jsonFiles,
+ filepath.Join(sharedDir, "librecovery.so.json"),
+ filepath.Join(sharedDir, "librecovery_available.so.json"))
+
+ // For static libraries, all recovery:true and recovery_available modules are captured.
+ staticVariant := fmt.Sprintf("android_recovery_%s_%s_static", archType, archVariant)
+ staticDir := filepath.Join(snapshotVariantPath, archDir, "static")
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.a", staticDir, staticVariant)
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.a", staticDir, staticVariant)
+ jsonFiles = append(jsonFiles,
+ filepath.Join(staticDir, "librecovery.a.json"),
+ filepath.Join(staticDir, "librecovery_available.a.json"))
+
+ // For rlib libraries, all recovery:true and recovery_available modules are captured.
+ rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_rlib-std", archType, archVariant)
+ rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib")
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rlib", "librecovery_rlib.rlib", rlibDir, rlibVariant)
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available_rlib", "librecovery_available_rlib.rlib", rlibDir, rlibVariant)
+ jsonFiles = append(jsonFiles,
+ filepath.Join(rlibDir, "librecovery_rlib.rlib.json"),
+ filepath.Join(rlibDir, "librecovery_available_rlib.rlib.json"))
+
+ // For binary executables, all recovery:true and recovery_available modules are captured.
+ if archType == "arm64" {
+ binaryVariant := fmt.Sprintf("android_recovery_%s_%s", archType, archVariant)
+ binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary")
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "recovery_bin", "recovery_bin", binaryDir, binaryVariant)
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "recovery_available_bin", "recovery_available_bin", binaryDir, binaryVariant)
+ jsonFiles = append(jsonFiles,
+ filepath.Join(binaryDir, "recovery_bin.json"),
+ filepath.Join(binaryDir, "recovery_available_bin.json"))
+ }
+ }
+
+ for _, jsonFile := range jsonFiles {
+ // verify all json files exist
+ if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
+ t.Errorf("%q expected but not found", jsonFile)
+ }
+ }
+}
+
+func TestRecoverySnapshotExclude(t *testing.T) {
+ // This test verifies that the exclude_from_recovery_snapshot property
+ // makes its way from the Android.bp source file into the module data
+ // structure. It also verifies that modules are correctly included or
+ // excluded in the recovery snapshot based on their path (framework or
+ // vendor) and the exclude_from_recovery_snapshot property.
+
+ frameworkBp := `
+ rust_ffi_shared {
+ name: "libinclude",
+ srcs: ["src/include.rs"],
+ recovery_available: true,
+ crate_name: "include",
+ }
+ rust_ffi_shared {
+ name: "libexclude",
+ srcs: ["src/exclude.rs"],
+ recovery: true,
+ exclude_from_recovery_snapshot: true,
+ crate_name: "exclude",
+ }
+ rust_ffi_shared {
+ name: "libavailable_exclude",
+ srcs: ["src/exclude.rs"],
+ recovery_available: true,
+ exclude_from_recovery_snapshot: true,
+ crate_name: "available_exclude",
+ }
+ rust_library_rlib {
+ name: "libinclude_rlib",
+ srcs: ["src/include.rs"],
+ recovery_available: true,
+ crate_name: "include_rlib",
+ }
+ rust_library_rlib {
+ name: "libexclude_rlib",
+ srcs: ["src/exclude.rs"],
+ recovery: true,
+ exclude_from_recovery_snapshot: true,
+ crate_name: "exclude_rlib",
+ }
+ rust_library_rlib {
+ name: "libavailable_exclude_rlib",
+ srcs: ["src/exclude.rs"],
+ recovery_available: true,
+ exclude_from_recovery_snapshot: true,
+ crate_name: "available_exclude_rlib",
+ }
+ `
+
+ vendorProprietaryBp := `
+ rust_ffi_shared {
+ name: "librecovery",
+ srcs: ["recovery.rs"],
+ recovery: true,
+ crate_name: "recovery",
+ }
+ rust_library_rlib {
+ name: "librecovery_rlib",
+ srcs: ["recovery.rs"],
+ recovery: true,
+ crate_name: "recovery_rlib",
+ }
+ `
+
+ mockFS := map[string][]byte{
+ "framework/Android.bp": []byte(frameworkBp),
+ "framework/include.rs": nil,
+ "framework/exclude.rs": nil,
+ "device/Android.bp": []byte(vendorProprietaryBp),
+ "device/recovery.rs": nil,
+ }
+
+ ctx := testRustRecoveryFsVersions(t, "", mockFS, "", "29", "current")
+
+ // Test an include and exclude framework module.
+ cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude", false, sharedRecoveryVariant)
+ cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude", true, sharedRecoveryVariant)
+ cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude", true, sharedRecoveryVariant)
+ cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude_rlib", false, rlibRecoveryVariant)
+ cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude_rlib", true, rlibRecoveryVariant)
+ cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude_rlib", true, rlibRecoveryVariant)
+
+ // A recovery module is excluded, but by its path not the exclude_from_recovery_snapshot property
+ // ('device/' and 'vendor/' are default excluded). See snapshot/recovery_snapshot.go for more detail.
+ cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery", false, sharedRecoveryVariant)
+ cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery_rlib", false, rlibRecoveryVariant)
+
+ // Verify the content of the recovery snapshot.
+
+ snapshotDir := "recovery-snapshot"
+ snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
+ snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
+
+ var includeJsonFiles []string
+ var excludeJsonFiles []string
+
+ for _, arch := range [][]string{
+ []string{"arm64", "armv8-a"},
+ } {
+ archType := arch[0]
+ archVariant := arch[1]
+ archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
+
+ sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
+ rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_rlib-std", archType, archVariant)
+ sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
+ rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib")
+
+ // Included modules
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant)
+ includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json"))
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "libinclude_rlib", "libinclude_rlib.rlib", rlibDir, rlibVariant)
+ includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "libinclude_rlib.rlib.json"))
+
+ // Excluded modules
+ cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant)
+ excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json"))
+ cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
+ excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json"))
+ cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant)
+ excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json"))
+ cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude_rlib", "libexclude_rlib.rlib", rlibDir, rlibVariant)
+ excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libexclude_rlib.rlib.json"))
+ cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librecovery_rlib", "librecovery_rlib.rlib", rlibDir, rlibVariant)
+ excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librecovery_rlib.rlib.json"))
+ cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude_rlib", "libavailable_exclude_rlib.rlib", rlibDir, rlibVariant)
+ excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libavailable_exclude_rlib.rlib.json"))
+ }
+
+ // Verify that each json file for an included module has a rule.
+ for _, jsonFile := range includeJsonFiles {
+ if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
+ t.Errorf("include json file %q not found", jsonFile)
+ }
+ }
+
+ // Verify that each json file for an excluded module has no rule.
+ for _, jsonFile := range excludeJsonFiles {
+ if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil {
+ t.Errorf("exclude json file %q found", jsonFile)
+ }
+ }
+}
+
+func TestRecoverySnapshotDirected(t *testing.T) {
+ bp := `
+ rust_ffi_shared {
+ name: "librecovery",
+ recovery: true,
+ crate_name: "recovery",
+ srcs: ["foo.rs"],
+ }
+
+ rust_ffi_shared {
+ name: "librecovery_available",
+ recovery_available: true,
+ crate_name: "recovery_available",
+ srcs: ["foo.rs"],
+ }
+
+ rust_library_rlib {
+ name: "librecovery_rlib",
+ recovery: true,
+ crate_name: "recovery",
+ srcs: ["foo.rs"],
+ }
+
+ rust_library_rlib {
+ name: "librecovery_available_rlib",
+ recovery_available: true,
+ crate_name: "recovery_available",
+ srcs: ["foo.rs"],
+ }
+
+ /* TODO: Uncomment when Rust supports the "prefer" property for prebuilts
+ rust_library_rlib {
+ name: "libfoo_rlib",
+ recovery: true,
+ crate_name: "foo",
+ }
+
+ rust_prebuilt_rlib {
+ name: "libfoo_rlib",
+ recovery: true,
+ prefer: true,
+ srcs: ["libfoo.rlib"],
+ crate_name: "foo",
+ }
+ */
+`
+ ctx := testRustRecoveryFsVersions(t, bp, rustMockedFiles, "current", "29", "current")
+ ctx.Config().TestProductVariables.RecoverySnapshotModules = make(map[string]bool)
+ ctx.Config().TestProductVariables.RecoverySnapshotModules["librecovery"] = true
+ ctx.Config().TestProductVariables.RecoverySnapshotModules["librecovery_rlib"] = true
+ ctx.Config().TestProductVariables.DirectedRecoverySnapshot = true
+
+ // Check recovery snapshot output.
+ snapshotDir := "recovery-snapshot"
+ snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
+ snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
+
+ var includeJsonFiles []string
+
+ for _, arch := range [][]string{
+ []string{"arm64", "armv8-a"},
+ } {
+ archType := arch[0]
+ archVariant := arch[1]
+ archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
+
+ sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
+ rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_rlib-std", archType, archVariant)
+ sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
+ rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib")
+
+ // Included modules
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
+ includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json"))
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rlib", "librecovery_rlib.rlib", rlibDir, rlibVariant)
+ includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librecovery_rlib.rlib.json"))
+
+ // TODO: When Rust supports the "prefer" property for prebuilts, perform this check.
+ /*
+ // Check that snapshot captures "prefer: true" prebuilt
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo_rlib", "libfoo_rlib.rlib", rlibDir, rlibVariant)
+ includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo_rlib.rlib.json"))
+ */
+
+ // Excluded modules. Modules not included in the directed recovery snapshot
+ // are still included as fake modules.
+ cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant)
+ includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery_available.so.json"))
+ cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available_rlib", "librecovery_available_rlib.rlib", rlibDir, rlibVariant)
+ includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librecovery_available_rlib.rlib.json"))
+ }
+
+ // Verify that each json file for an included module has a rule.
+ for _, jsonFile := range includeJsonFiles {
+ if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
+ t.Errorf("include json file %q not found, %#v", jsonFile, includeJsonFiles)
+ }
+ }
}
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 635be10..730d756 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -1,5 +1,6 @@
package {
default_applicable_licenses: ["Android-Apache-2.0"],
+ default_visibility: ["//build/soong:__subpackages__"],
}
python_binary_host {
@@ -8,14 +9,6 @@
srcs: [
"check_boot_jars/check_boot_jars.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
}
python_binary_host {
@@ -24,14 +17,6 @@
srcs: [
"manifest_fixer.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
libs: [
"manifest_utils",
],
@@ -45,11 +30,8 @@
"manifest_fixer.py",
],
version: {
- py2: {
- enabled: true,
- },
py3: {
- enabled: false,
+ embedded_launcher: true,
},
},
libs: [
@@ -67,12 +49,14 @@
],
version: {
py2: {
+ // TODO(b/203436762) Remove when system/apex/apexer/apexer.py is converted
enabled: true,
},
py3: {
- enabled: false,
+ enabled: true,
},
},
+ visibility: ["//system/apex/apexer:__pkg__"],
}
python_binary_host {
@@ -81,14 +65,6 @@
srcs: [
"manifest_check.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
libs: [
"manifest_utils",
],
@@ -101,14 +77,6 @@
"manifest_check_test.py",
"manifest_check.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
libs: [
"manifest_utils",
],
@@ -123,14 +91,6 @@
srcs: [
"jsonmodify.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
}
python_binary_host {
@@ -139,14 +99,6 @@
srcs: [
"test_config_fixer.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
libs: [
"manifest_utils",
],
@@ -159,14 +111,6 @@
"test_config_fixer_test.py",
"test_config_fixer.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
libs: [
"manifest_utils",
],
@@ -179,14 +123,6 @@
srcs: [
"construct_context.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
libs: [
"manifest_utils",
],
@@ -199,14 +135,6 @@
"construct_context_test.py",
"construct_context.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
libs: [
"manifest_utils",
],
@@ -253,11 +181,7 @@
"conv_linker_config.py",
],
version: {
- py2: {
- enabled: false,
- },
py3: {
- enabled: true,
embedded_launcher: true,
},
},
@@ -272,12 +196,4 @@
srcs: [
"get_clang_version.py",
],
- version: {
- py2: {
- enabled: false,
- },
- py3: {
- enabled: true,
- },
- },
}
diff --git a/scripts/OWNERS b/scripts/OWNERS
index 1830a18..88787cd 100644
--- a/scripts/OWNERS
+++ b/scripts/OWNERS
@@ -3,4 +3,4 @@
per-file build-aml-prebuilts.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com
per-file construct_context.py = ngeoffray@google.com,calin@google.com,skvadrik@google.com
per-file conv_linker_config.py = kiyoungkim@google.com, jiyong@google.com, jooyung@google.com
-per-file gen_ndk*.sh = sophiez@google.com, allenhair@google.com
+per-file gen_ndk*.sh,gen_java*.sh = sophiez@google.com, allenhair@google.com
\ No newline at end of file
diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh
index f183c05..1e3f6ce 100755
--- a/scripts/build-mainline-modules.sh
+++ b/scripts/build-mainline-modules.sh
@@ -17,7 +17,6 @@
MODULES_SDK_AND_EXPORTS=(
art-module-sdk
art-module-test-exports
- compos-module-sdk
conscrypt-module-host-exports
conscrypt-module-sdk
conscrypt-module-test-exports
diff --git a/scripts/diff_build_graphs.sh b/scripts/diff_build_graphs.sh
index 81010f3..8d01124 100755
--- a/scripts/diff_build_graphs.sh
+++ b/scripts/diff_build_graphs.sh
@@ -98,7 +98,7 @@
# or in case it is affected by some of the changes we're testing
make blueprint_tools
# find multiproduct_kati and have it build the ninja files for each product
- builder="$(echo $OUT_DIR/soong/host/*/bin/multiproduct_kati)"
+ builder="$(echo $OUT_DIR/host/*/bin/multiproduct_kati)"
BUILD_NUMBER=sample "$builder" $PRODUCTS_ARG --keep --out "$OUT_DIR_TEMP" || true
echo
}
diff --git a/scripts/gen_java_usedby_apex.sh b/scripts/gen_java_usedby_apex.sh
new file mode 100755
index 0000000..251d7aa
--- /dev/null
+++ b/scripts/gen_java_usedby_apex.sh
@@ -0,0 +1,46 @@
+#!/bin/bash -e
+
+# Copyright 2020 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.
+
+printHelp() {
+ echo "**************************** Usage Instructions ****************************"
+ echo "This script is used to generate the Mainline modules used-by Java symbols."
+ echo ""
+ echo "To run this script use: ./gen_java_usedby_apex.sh \$BINARY_DEXDEPS_PATH \$OUTPUT_FILE_PATH \$JAR_AND_APK_LIST"
+ echo "For example: If all jar and apk files are '/myJar.jar /myApk.apk' and output write to /myModule.txt then the command would be:"
+ echo "./gen_java_usedby_apex.sh \$BINARY_DEXDEPS_PATH /myModule.txt /myJar.jar /myApk.apk"
+}
+
+genUsedByList() {
+ dexdeps="$1"
+ shift
+ out="$1"
+ shift
+ rm -f "$out"
+ touch "$out"
+ for x in "$@"; do
+ "$dexdeps" "$x" >> "$out" || true
+ done
+}
+
+if [[ "$1" == "help" ]]
+then
+ printHelp
+elif [[ "$#" -lt 2 ]]
+then
+ echo "Wrong argument length. Expecting at least 2 argument representing dexdeps path, output path, followed by a list of jar or apk files in the Mainline module."
+else
+ genUsedByList "$@"
+fi
\ No newline at end of file
diff --git a/scripts/manifest.py b/scripts/manifest.py
index 04f7405..81f9c61 100755
--- a/scripts/manifest.py
+++ b/scripts/manifest.py
@@ -123,4 +123,4 @@
def write_xml(f, doc):
f.write('<?xml version="1.0" encoding="utf-8"?>\n')
for node in doc.childNodes:
- f.write(node.toxml(encoding='utf-8') + '\n')
+ f.write(node.toxml() + '\n')
diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py
index 8bed52a..c8d4f76 100755
--- a/scripts/manifest_check.py
+++ b/scripts/manifest_check.py
@@ -335,7 +335,7 @@
if is_apk:
aapt = args.aapt if args.aapt is not None else 'aapt'
manifest = subprocess.check_output(
- [aapt, 'dump', 'badging', args.input])
+ [aapt, 'dump', 'badging', args.input]).decode('utf-8')
else:
manifest = minidom.parse(args.input)
@@ -381,7 +381,7 @@
if is_apk:
raise RuntimeError('cannot save APK manifest as XML')
- with open(args.output, 'wb') as f:
+ with open(args.output, 'w') as f:
write_xml(f, manifest)
# pylint: disable=broad-except
diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py
index 55d0fd1..d80a617 100755
--- a/scripts/manifest_fixer.py
+++ b/scripts/manifest_fixer.py
@@ -352,7 +352,7 @@
if args.extract_native_libs is not None:
add_extract_native_libs(doc, args.extract_native_libs)
- with open(args.output, 'wb') as f:
+ with open(args.output, 'w') as f:
write_xml(f, doc)
# pylint: disable=broad-except
diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py
index 3a0a25d..f6fcaaf 100755
--- a/scripts/manifest_fixer_test.py
+++ b/scripts/manifest_fixer_test.py
@@ -16,16 +16,16 @@
#
"""Unit tests for manifest_fixer.py."""
-import StringIO
+import io
import sys
import unittest
from xml.dom import minidom
+import xml.etree.ElementTree as ET
import manifest_fixer
sys.dont_write_bytecode = True
-
class CompareVersionGtTest(unittest.TestCase):
"""Unit tests for compare_version_gt function."""
@@ -59,7 +59,7 @@
doc = minidom.parseString(input_manifest)
manifest_fixer.raise_min_sdk_version(doc, min_sdk_version,
target_sdk_version, library)
- output = StringIO.StringIO()
+ output = io.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -80,13 +80,16 @@
attrs += ' ' + extra
return ' <uses-sdk%s/>\n' % (attrs)
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
def test_no_uses_sdk(self):
"""Tests inserting a uses-sdk element into a manifest."""
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28')
output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_no_min(self):
"""Tests inserting a minSdkVersion attribute into a uses-sdk element."""
@@ -95,7 +98,7 @@
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28',
extra='extra="foo"')
output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_raise_min(self):
"""Tests inserting a minSdkVersion attribute into a uses-sdk element."""
@@ -103,7 +106,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28')
output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_raise(self):
"""Tests raising a minSdkVersion attribute."""
@@ -111,7 +114,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28')
output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_no_raise_min(self):
"""Tests a minSdkVersion that doesn't need raising."""
@@ -119,7 +122,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='28')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
output = self.raise_min_sdk_version_test(manifest_input, '27', '27', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_raise_codename(self):
"""Tests raising a minSdkVersion attribute to a codename."""
@@ -127,7 +130,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='28')
expected = self.manifest_tmpl % self.uses_sdk(min='P', target='P')
output = self.raise_min_sdk_version_test(manifest_input, 'P', 'P', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_no_raise_codename(self):
"""Tests a minSdkVersion codename that doesn't need raising."""
@@ -135,7 +138,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='P')
expected = self.manifest_tmpl % self.uses_sdk(min='P', target='28')
output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_target(self):
"""Tests an existing targetSdkVersion is preserved."""
@@ -143,7 +146,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='26', target='27')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_no_target(self):
"""Tests inserting targetSdkVersion when minSdkVersion exists."""
@@ -151,7 +154,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='29')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_target_no_min(self):
""""Tests inserting targetSdkVersion when minSdkVersion exists."""
@@ -159,7 +162,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(target='27')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_no_target_no_min(self):
"""Tests inserting targetSdkVersion when minSdkVersion does not exist."""
@@ -167,7 +170,7 @@
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='29')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_library_no_target(self):
"""Tests inserting targetSdkVersion when minSdkVersion exists."""
@@ -175,7 +178,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='16')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_library_target_no_min(self):
"""Tests inserting targetSdkVersion when minSdkVersion exists."""
@@ -183,7 +186,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(target='27')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_library_no_target_no_min(self):
"""Tests inserting targetSdkVersion when minSdkVersion does not exist."""
@@ -191,7 +194,7 @@
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='16')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_extra(self):
"""Tests that extra attributes and elements are maintained."""
@@ -204,12 +207,12 @@
# pylint: disable=line-too-long
expected = self.manifest_tmpl % (
' <!-- comment -->\n'
- ' <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="29" extra="foo"/>\n'
+ ' <uses-sdk android:minSdkVersion="28" extra="foo" android:targetSdkVersion="29"/>\n'
' <application/>\n')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_indent(self):
"""Tests that an inserted element copies the existing indentation."""
@@ -223,17 +226,20 @@
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
class AddLoggingParentTest(unittest.TestCase):
"""Unit tests for add_logging_parent function."""
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
def add_logging_parent_test(self, input_manifest, logging_parent=None):
doc = minidom.parseString(input_manifest)
if logging_parent:
manifest_fixer.add_logging_parent(doc, logging_parent)
- output = StringIO.StringIO()
+ output = io.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -257,23 +263,26 @@
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.uses_logging_parent()
output = self.add_logging_parent_test(manifest_input)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_logging_parent(self):
"""Tests manifest_fixer with no logging_parent."""
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.uses_logging_parent('FOO')
output = self.add_logging_parent_test(manifest_input, 'FOO')
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
class AddUsesLibrariesTest(unittest.TestCase):
"""Unit tests for add_uses_libraries function."""
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
def run_test(self, input_manifest, new_uses_libraries):
doc = minidom.parseString(input_manifest)
manifest_fixer.add_uses_libraries(doc, new_uses_libraries, True)
- output = StringIO.StringIO()
+ output = io.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -301,7 +310,7 @@
('bar', 'false')])
expected = manifest_input
output = self.run_test(manifest_input, [])
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_not_overwrite(self):
"""new_uses_libraries must not overwrite existing tags."""
@@ -310,7 +319,7 @@
('bar', 'false')])
expected = manifest_input
output = self.run_test(manifest_input, ['foo', 'bar'])
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_add(self):
"""New names are added with 'required:true'."""
@@ -323,7 +332,7 @@
('baz', 'true'),
('qux', 'true')])
output = self.run_test(manifest_input, ['bar', 'baz', 'qux'])
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_no_application(self):
"""When there is no <application> tag, the tag is added."""
@@ -336,7 +345,7 @@
('foo', 'true'),
('bar', 'true')])
output = self.run_test(manifest_input, ['foo', 'bar'])
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_empty_application(self):
"""Even when here is an empty <application/> tag, the libs are added."""
@@ -350,16 +359,19 @@
('foo', 'true'),
('bar', 'true')])
output = self.run_test(manifest_input, ['foo', 'bar'])
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
class AddUsesNonSdkApiTest(unittest.TestCase):
"""Unit tests for add_uses_libraries function."""
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
def run_test(self, input_manifest):
doc = minidom.parseString(input_manifest)
manifest_fixer.add_uses_non_sdk_api(doc)
- output = StringIO.StringIO()
+ output = io.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -377,23 +389,26 @@
manifest_input = self.manifest_tmpl % self.uses_non_sdk_api(False)
expected = self.manifest_tmpl % self.uses_non_sdk_api(True)
output = self.run_test(manifest_input)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_already_set(self):
"""new_uses_libraries must not overwrite existing tags."""
manifest_input = self.manifest_tmpl % self.uses_non_sdk_api(True)
expected = manifest_input
output = self.run_test(manifest_input)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
class UseEmbeddedDexTest(unittest.TestCase):
"""Unit tests for add_use_embedded_dex function."""
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
def run_test(self, input_manifest):
doc = minidom.parseString(input_manifest)
manifest_fixer.add_use_embedded_dex(doc)
- output = StringIO.StringIO()
+ output = io.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -410,13 +425,13 @@
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.use_embedded_dex('true')
output = self.run_test(manifest_input)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_manifest_with_use_embedded_dex(self):
manifest_input = self.manifest_tmpl % self.use_embedded_dex('true')
expected = manifest_input
output = self.run_test(manifest_input)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_manifest_with_not_use_embedded_dex(self):
manifest_input = self.manifest_tmpl % self.use_embedded_dex('false')
@@ -426,10 +441,13 @@
class AddExtractNativeLibsTest(unittest.TestCase):
"""Unit tests for add_extract_native_libs function."""
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
def run_test(self, input_manifest, value):
doc = minidom.parseString(input_manifest)
manifest_fixer.add_extract_native_libs(doc, value)
- output = StringIO.StringIO()
+ output = io.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -446,19 +464,19 @@
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.extract_native_libs('true')
output = self.run_test(manifest_input, True)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_set_false(self):
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.extract_native_libs('false')
output = self.run_test(manifest_input, False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_match(self):
manifest_input = self.manifest_tmpl % self.extract_native_libs('true')
expected = manifest_input
output = self.run_test(manifest_input, True)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_conflict(self):
manifest_input = self.manifest_tmpl % self.extract_native_libs('true')
@@ -468,10 +486,13 @@
class AddNoCodeApplicationTest(unittest.TestCase):
"""Unit tests for set_has_code_to_false function."""
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
def run_test(self, input_manifest):
doc = minidom.parseString(input_manifest)
manifest_fixer.set_has_code_to_false(doc)
- output = StringIO.StringIO()
+ output = io.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -485,26 +506,26 @@
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % ' <application android:hasCode="false"/>\n'
output = self.run_test(manifest_input)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_has_application_no_has_code(self):
manifest_input = self.manifest_tmpl % ' <application/>\n'
expected = self.manifest_tmpl % ' <application android:hasCode="false"/>\n'
output = self.run_test(manifest_input)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_has_application_has_code_false(self):
""" Do nothing if there's already an application elemeent. """
manifest_input = self.manifest_tmpl % ' <application android:hasCode="false"/>\n'
output = self.run_test(manifest_input)
- self.assertEqual(output, manifest_input)
+ self.assert_xml_equal(output, manifest_input)
def test_has_application_has_code_true(self):
""" Do nothing if there's already an application elemeent even if its
hasCode attribute is true. """
manifest_input = self.manifest_tmpl % ' <application android:hasCode="true"/>\n'
output = self.run_test(manifest_input)
- self.assertEqual(output, manifest_input)
+ self.assert_xml_equal(output, manifest_input)
if __name__ == '__main__':
diff --git a/scripts/rbc-run b/scripts/rbc-run
index ecc6edd..235da75 100755
--- a/scripts/rbc-run
+++ b/scripts/rbc-run
@@ -8,9 +8,9 @@
declare -r output_root="${OUT_DIR:-out}"
declare -r runner="${output_root}/soong/rbcrun"
declare -r converter="${output_root}/soong/mk2rbc"
-declare -r launcher="${output_root}/launchers/run.rbc"
+declare -r launcher="${output_root}/rbc/launcher.rbc"
declare -r makefile="$1"
shift
-"${converter}" -mode=write -r --outdir "${output_root}" --launcher="${launcher}" "${makefile}"
+"${converter}" -mode=write -r --outdir "${output_root}/rbc" --launcher="${launcher}" "${makefile}"
"${runner}" RBC_OUT="make,global" RBC_DEBUG="${RBC_DEBUG:-}" $@ "${launcher}"
diff --git a/scripts/test_config_fixer.py b/scripts/test_config_fixer.py
index 32d5b17..c150e8c 100644
--- a/scripts/test_config_fixer.py
+++ b/scripts/test_config_fixer.py
@@ -86,7 +86,7 @@
if args.test_file_name:
overwrite_test_file_name(doc, args.test_file_name)
- with open(args.output, 'wb') as f:
+ with open(args.output, 'w') as f:
write_xml(f, doc)
# pylint: disable=broad-except
diff --git a/scripts/test_config_fixer_test.py b/scripts/test_config_fixer_test.py
index 1272c6b..d00a593 100644
--- a/scripts/test_config_fixer_test.py
+++ b/scripts/test_config_fixer_test.py
@@ -16,7 +16,7 @@
#
"""Unit tests for test_config_fixer.py."""
-import StringIO
+import io
import sys
import unittest
from xml.dom import minidom
@@ -59,7 +59,7 @@
manifest = minidom.parseString(self.manifest)
test_config_fixer.overwrite_package_name(doc, manifest, "com.soong.foo")
- output = StringIO.StringIO()
+ output = io.StringIO()
test_config_fixer.write_xml(output, doc)
# Only the matching package name in a test node should be updated.
@@ -86,7 +86,7 @@
doc = minidom.parseString(self.test_config % ("foo.apk"))
test_config_fixer.overwrite_test_file_name(doc, "bar.apk")
- output = StringIO.StringIO()
+ output = io.StringIO()
test_config_fixer.write_xml(output, doc)
# Only the matching package name in a test node should be updated.
diff --git a/scripts/update_out b/scripts/update_out
new file mode 100755
index 0000000..d3950cf
--- /dev/null
+++ b/scripts/update_out
@@ -0,0 +1,21 @@
+#! /bin/bash
+# Run given command application and update the contents of a given file.
+# Will not change the file if its contents has not changed.
+[[ $# -gt 1 ]] || { echo "Usage: ${0##*/} FILE COMMAND" >&2; exit 1; }
+set -u
+declare -r outfile="$1"
+shift
+if [[ ! -f $outfile ]]; then
+ $@ >$outfile
+ exit
+fi
+
+declare -r newout=${outfile}.new
+$@ >$newout
+rc=$?
+if cmp -s $newout $outfile; then
+ rm $newout
+else
+ mv -f $newout $outfile
+fi
+exit $rc
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index b22a5b7..c32cde0 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -168,6 +168,10 @@
var _ android.HostToolProvider = (*ShBinary)(nil)
+func (s *ShBinary) InstallBypassMake() bool {
+ return true
+}
+
type ShTest struct {
ShBinary
@@ -271,13 +275,16 @@
s.generateAndroidBuildActions(ctx)
installDir := android.PathForModuleInstall(ctx, "bin", proptools.String(s.properties.Sub_dir))
s.installedFile = ctx.InstallExecutable(installDir, s.outputFilePath.Base(), s.outputFilePath)
+ for _, symlink := range s.Symlinks() {
+ ctx.InstallSymlink(installDir, symlink, s.installedFile)
+ }
}
func (s *ShBinary) AndroidMkEntries() []android.AndroidMkEntries {
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "EXECUTABLES",
OutputFile: android.OptionalPathForPath(s.outputFilePath),
- Include: "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
+ Include: "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
s.customAndroidMkEntries(entries)
@@ -426,7 +433,7 @@
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "NATIVE_TESTS",
OutputFile: android.OptionalPathForPath(s.outputFilePath),
- Include: "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
+ Include: "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
s.customAndroidMkEntries(entries)
diff --git a/snapshot/recovery_snapshot.go b/snapshot/recovery_snapshot.go
index 9b3919c..f1e31ca 100644
--- a/snapshot/recovery_snapshot.go
+++ b/snapshot/recovery_snapshot.go
@@ -71,6 +71,10 @@
ctx.RegisterSingletonType("recovery-snapshot", RecoverySnapshotSingleton)
}
+func (RecoverySnapshotImage) RegisterAdditionalModule(ctx android.RegistrationContext, name string, factory android.ModuleFactory) {
+ ctx.RegisterModuleType(name, factory)
+}
+
func (RecoverySnapshotImage) shouldGenerateSnapshot(ctx android.SingletonContext) bool {
// RECOVERY_SNAPSHOT_VERSION must be set to 'current' in order to generate a
// snapshot.
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index 01b4760..4f37c2b 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -105,7 +105,7 @@
# NOTE: We don't actually use the extra BUILD file for anything here
run_bazel build --package_path=out/soong/workspace //foo/...
- local the_answer_file="bazel-out/k8-fastbuild/bin/foo/convertible_soong_module/the_answer.txt"
+ local the_answer_file="bazel-out/android_target-fastbuild/bin/foo/convertible_soong_module/the_answer.txt"
if [[ ! -f "${the_answer_file}" ]]; then
fail "Expected '${the_answer_file}' to be generated, but was missing"
fi
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index 6304a11..a376e06 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -7,3 +7,4 @@
"$TOP/build/soong/tests/mixed_mode_test.sh"
"$TOP/build/soong/tests/bp2build_bazel_test.sh"
"$TOP/build/soong/tests/soong_test.sh"
+"$TOP/build/bazel/ci/rbc_product_config.sh" aosp_arm64-userdebug
diff --git a/ui/build/config.go b/ui/build/config.go
index e0fa503..c306633 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -786,7 +786,11 @@
}
func (c *configImpl) HostToolDir() string {
- return filepath.Join(c.SoongOutDir(), "host", c.PrebuiltOS(), "bin")
+ if c.SkipKatiNinja() {
+ return filepath.Join(c.SoongOutDir(), "host", c.PrebuiltOS(), "bin")
+ } else {
+ return filepath.Join(c.OutDir(), "host", c.PrebuiltOS(), "bin")
+ }
}
func (c *configImpl) NamedGlobFile(name string) string {
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
index 83007be..86c8568 100644
--- a/ui/build/test_build.go
+++ b/ui/build/test_build.go
@@ -76,6 +76,9 @@
// out/build_date.txt is considered a "source file"
buildDatetimeFilePath := filepath.Join(outDir, "build_date.txt")
+ // bpglob is built explicitly using Microfactory
+ bpglob := filepath.Join(config.SoongOutDir(), "bpglob")
+
danglingRules := make(map[string]bool)
scanner := bufio.NewScanner(stdout)
@@ -88,7 +91,8 @@
if strings.HasPrefix(line, modulePathsDir) ||
line == variablesFilePath ||
line == dexpreoptConfigFilePath ||
- line == buildDatetimeFilePath {
+ line == buildDatetimeFilePath ||
+ line == bpglob {
// Leaf node is in one of Soong's bootstrap directories, which do not have
// full build rules in the primary build.ninja file.
continue
diff --git a/ui/metrics/Android.bp b/ui/metrics/Android.bp
index 1590ab0..96f6389 100644
--- a/ui/metrics/Android.bp
+++ b/ui/metrics/Android.bp
@@ -23,6 +23,7 @@
"golang-protobuf-proto",
"soong-ui-metrics_upload_proto",
"soong-ui-metrics_proto",
+ "soong-ui-bp2build_metrics_proto",
"soong-ui-tracer",
],
srcs: [
@@ -57,3 +58,15 @@
"upload_proto/upload.pb.go",
],
}
+
+bootstrap_go_package {
+ name: "soong-ui-bp2build_metrics_proto",
+ pkgPath: "android/soong/ui/metrics/bp2build_metrics_proto",
+ deps: [
+ "golang-protobuf-reflect-protoreflect",
+ "golang-protobuf-runtime-protoimpl",
+ ],
+ srcs: [
+ "bp2build_metrics_proto/bp2build_metrics.pb.go",
+ ],
+}
diff --git a/ui/metrics/bp2build_metrics_proto/bp2build_metrics.pb.go b/ui/metrics/bp2build_metrics_proto/bp2build_metrics.pb.go
new file mode 100644
index 0000000..11177e4
--- /dev/null
+++ b/ui/metrics/bp2build_metrics_proto/bp2build_metrics.pb.go
@@ -0,0 +1,222 @@
+// Copyright 2021 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.27.1
+// protoc v3.9.1
+// source: bp2build_metrics.proto
+
+package bp2build_metrics_proto
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Bp2BuildMetrics struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Total number of Soong modules converted to generated targets
+ GeneratedModuleCount uint64 `protobuf:"varint,1,opt,name=generatedModuleCount,proto3" json:"generatedModuleCount,omitempty"`
+ // Total number of Soong modules converted to handcrafted targets
+ HandCraftedModuleCount uint64 `protobuf:"varint,2,opt,name=handCraftedModuleCount,proto3" json:"handCraftedModuleCount,omitempty"`
+ // Total number of unconverted Soong modules
+ UnconvertedModuleCount uint64 `protobuf:"varint,3,opt,name=unconvertedModuleCount,proto3" json:"unconvertedModuleCount,omitempty"`
+ // Counts of generated Bazel targets per Bazel rule class
+ RuleClassCount map[string]uint64 `protobuf:"bytes,4,rep,name=ruleClassCount,proto3" json:"ruleClassCount,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
+ // List of converted modules
+ ConvertedModules []string `protobuf:"bytes,5,rep,name=convertedModules,proto3" json:"convertedModules,omitempty"`
+}
+
+func (x *Bp2BuildMetrics) Reset() {
+ *x = Bp2BuildMetrics{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_bp2build_metrics_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Bp2BuildMetrics) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Bp2BuildMetrics) ProtoMessage() {}
+
+func (x *Bp2BuildMetrics) ProtoReflect() protoreflect.Message {
+ mi := &file_bp2build_metrics_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Bp2BuildMetrics.ProtoReflect.Descriptor instead.
+func (*Bp2BuildMetrics) Descriptor() ([]byte, []int) {
+ return file_bp2build_metrics_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Bp2BuildMetrics) GetGeneratedModuleCount() uint64 {
+ if x != nil {
+ return x.GeneratedModuleCount
+ }
+ return 0
+}
+
+func (x *Bp2BuildMetrics) GetHandCraftedModuleCount() uint64 {
+ if x != nil {
+ return x.HandCraftedModuleCount
+ }
+ return 0
+}
+
+func (x *Bp2BuildMetrics) GetUnconvertedModuleCount() uint64 {
+ if x != nil {
+ return x.UnconvertedModuleCount
+ }
+ return 0
+}
+
+func (x *Bp2BuildMetrics) GetRuleClassCount() map[string]uint64 {
+ if x != nil {
+ return x.RuleClassCount
+ }
+ return nil
+}
+
+func (x *Bp2BuildMetrics) GetConvertedModules() []string {
+ if x != nil {
+ return x.ConvertedModules
+ }
+ return nil
+}
+
+var File_bp2build_metrics_proto protoreflect.FileDescriptor
+
+var file_bp2build_metrics_proto_rawDesc = []byte{
+ 0x0a, 0x16, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
+ 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f,
+ 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d,
+ 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x8f, 0x03, 0x0a, 0x0f, 0x42, 0x70, 0x32, 0x42, 0x75,
+ 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x67, 0x65,
+ 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x6f, 0x75,
+ 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x14, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61,
+ 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x36,
+ 0x0a, 0x16, 0x68, 0x61, 0x6e, 0x64, 0x43, 0x72, 0x61, 0x66, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64,
+ 0x75, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16,
+ 0x68, 0x61, 0x6e, 0x64, 0x43, 0x72, 0x61, 0x66, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c,
+ 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x36, 0x0a, 0x16, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x76,
+ 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72,
+ 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x69,
+ 0x0a, 0x0e, 0x72, 0x75, 0x6c, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74,
+ 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62,
+ 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65,
+ 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x70, 0x32, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65,
+ 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43,
+ 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x72, 0x75, 0x6c, 0x65, 0x43,
+ 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x6f, 0x6e,
+ 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20,
+ 0x03, 0x28, 0x09, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f,
+ 0x64, 0x75, 0x6c, 0x65, 0x73, 0x1a, 0x41, 0x0a, 0x13, 0x52, 0x75, 0x6c, 0x65, 0x43, 0x6c, 0x61,
+ 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
+ 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14,
+ 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76,
+ 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x31, 0x5a, 0x2f, 0x61, 0x6e, 0x64, 0x72,
+ 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74,
+ 0x72, 0x69, 0x63, 0x73, 0x2f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65,
+ 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x33,
+}
+
+var (
+ file_bp2build_metrics_proto_rawDescOnce sync.Once
+ file_bp2build_metrics_proto_rawDescData = file_bp2build_metrics_proto_rawDesc
+)
+
+func file_bp2build_metrics_proto_rawDescGZIP() []byte {
+ file_bp2build_metrics_proto_rawDescOnce.Do(func() {
+ file_bp2build_metrics_proto_rawDescData = protoimpl.X.CompressGZIP(file_bp2build_metrics_proto_rawDescData)
+ })
+ return file_bp2build_metrics_proto_rawDescData
+}
+
+var file_bp2build_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_bp2build_metrics_proto_goTypes = []interface{}{
+ (*Bp2BuildMetrics)(nil), // 0: soong_build_bp2build_metrics.Bp2BuildMetrics
+ nil, // 1: soong_build_bp2build_metrics.Bp2BuildMetrics.RuleClassCountEntry
+}
+var file_bp2build_metrics_proto_depIdxs = []int32{
+ 1, // 0: soong_build_bp2build_metrics.Bp2BuildMetrics.ruleClassCount:type_name -> soong_build_bp2build_metrics.Bp2BuildMetrics.RuleClassCountEntry
+ 1, // [1:1] is the sub-list for method output_type
+ 1, // [1:1] is the sub-list for method input_type
+ 1, // [1:1] is the sub-list for extension type_name
+ 1, // [1:1] is the sub-list for extension extendee
+ 0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_bp2build_metrics_proto_init() }
+func file_bp2build_metrics_proto_init() {
+ if File_bp2build_metrics_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_bp2build_metrics_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Bp2BuildMetrics); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_bp2build_metrics_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 2,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_bp2build_metrics_proto_goTypes,
+ DependencyIndexes: file_bp2build_metrics_proto_depIdxs,
+ MessageInfos: file_bp2build_metrics_proto_msgTypes,
+ }.Build()
+ File_bp2build_metrics_proto = out.File
+ file_bp2build_metrics_proto_rawDesc = nil
+ file_bp2build_metrics_proto_goTypes = nil
+ file_bp2build_metrics_proto_depIdxs = nil
+}
diff --git a/ui/metrics/bp2build_metrics_proto/bp2build_metrics.proto b/ui/metrics/bp2build_metrics_proto/bp2build_metrics.proto
new file mode 100644
index 0000000..5e88966
--- /dev/null
+++ b/ui/metrics/bp2build_metrics_proto/bp2build_metrics.proto
@@ -0,0 +1,35 @@
+// Copyright 2021 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package soong_build_bp2build_metrics;
+option go_package = "android/soong/ui/metrics/bp2build_metrics_proto";
+
+message Bp2BuildMetrics {
+ // Total number of Soong modules converted to generated targets
+ uint64 generatedModuleCount = 1;
+
+ // Total number of Soong modules converted to handcrafted targets
+ uint64 handCraftedModuleCount = 2;
+
+ // Total number of unconverted Soong modules
+ uint64 unconvertedModuleCount = 3;
+
+ // Counts of generated Bazel targets per Bazel rule class
+ map<string, uint64> ruleClassCount = 4;
+
+ // List of converted modules
+ repeated string convertedModules = 5;
+}
diff --git a/ui/metrics/bp2build_metrics_proto/regen.sh b/ui/metrics/bp2build_metrics_proto/regen.sh
new file mode 100755
index 0000000..bfe4294
--- /dev/null
+++ b/ui/metrics/bp2build_metrics_proto/regen.sh
@@ -0,0 +1,29 @@
+#!/bin/bash -e
+
+# Copyright 2021 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Generates the golang source file of bp2build_metrics.proto protobuf file.
+
+function die() { echo "ERROR: $1" >&2; exit 1; }
+
+readonly error_msg="Maybe you need to run 'lunch aosp_arm-eng && m aprotoc blueprint_tools'?"
+
+if ! hash aprotoc &>/dev/null; then
+ die "could not find aprotoc. ${error_msg}"
+fi
+
+if ! aprotoc --go_out=paths=source_relative:. bp2build_metrics.proto; then
+ die "build failed. ${error_msg}"
+fi