Merge "Remove InstallBypassMake and ToMakePath"
diff --git a/android/bazel.go b/android/bazel.go
index 4114f37..9a966b6 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -245,6 +245,7 @@
"build/soong/cc/libbuildversion": Bp2BuildDefaultTrue, // Skip tests subdir
"build/soong/cc/ndkstubgen": Bp2BuildDefaultTrue,
"build/soong/cc/symbolfile": Bp2BuildDefaultTrue,
+ "build/soong/scripts": Bp2BuildDefaultTrueRecursively,
"cts/common/device-side/nativetesthelper/jni": Bp2BuildDefaultTrueRecursively,
"development/apps/DevelopmentSettings": Bp2BuildDefaultTrue,
"development/apps/Fallback": Bp2BuildDefaultTrue,
@@ -296,6 +297,7 @@
"external/libcxx": Bp2BuildDefaultTrueRecursively,
"external/libcxxabi": Bp2BuildDefaultTrueRecursively,
"external/libevent": Bp2BuildDefaultTrueRecursively,
+ "external/libpng": Bp2BuildDefaultTrueRecursively,
"external/lz4/lib": Bp2BuildDefaultTrue,
"external/lzma/C": Bp2BuildDefaultTrueRecursively,
"external/mdnsresponder": Bp2BuildDefaultTrueRecursively,
@@ -303,9 +305,9 @@
"external/pcre": Bp2BuildDefaultTrueRecursively,
"external/protobuf": Bp2BuildDefaultTrueRecursively,
"external/python/six": Bp2BuildDefaultTrueRecursively,
- "external/selinux/libsepol": Bp2BuildDefaultTrueRecursively,
"external/scudo": Bp2BuildDefaultTrueRecursively,
"external/selinux/libselinux": Bp2BuildDefaultTrueRecursively,
+ "external/selinux/libsepol": Bp2BuildDefaultTrueRecursively,
"external/zlib": Bp2BuildDefaultTrueRecursively,
"external/zstd": Bp2BuildDefaultTrueRecursively,
"frameworks/base/media/tests/MediaDump": Bp2BuildDefaultTrue,
@@ -322,6 +324,7 @@
"packages/apps/HTMLViewer": Bp2BuildDefaultTrue,
"packages/apps/Protips": Bp2BuildDefaultTrue,
"packages/modules/adb": Bp2BuildDefaultTrue,
+ "packages/modules/adb/apex": Bp2BuildDefaultTrue,
"packages/modules/adb/crypto": Bp2BuildDefaultTrueRecursively,
"packages/modules/adb/libs": Bp2BuildDefaultTrueRecursively,
"packages/modules/adb/pairing_auth": Bp2BuildDefaultTrueRecursively,
@@ -361,8 +364,7 @@
// Per-module denylist to always opt modules out of both bp2build and mixed builds.
bp2buildModuleDoNotConvertList = []string{
- "libnativehelper_compat_libc++", // Broken compile: implicit declaration of function 'strerror_r' is invalid in C99
- "art_libdexfile_dex_instruction_list_header", // breaks libart_mterp.armng, header not found
+ "libnativehelper_compat_libc", // Broken compile: implicit declaration of function 'strerror_r' is invalid in C99
"libandroid_runtime_lazy", // depends on unconverted modules: libbinder_headers
"libcmd", // depends on unconverted modules: libbinder
@@ -371,14 +373,13 @@
"libsepol", // TODO(b/207408632): Unsupported case of .l sources in cc library rules
- "get_clang_version_test", // depends on unconverted module: get_clang_version
+ "gen-kotlin-build-file.py", // module has same name as source
"libbinder", // TODO(b/188503688): Disabled for some archs,
"libactivitymanager_aidl", // TODO(b/207426160): Depends on activity_manager_procstate_aidl, which is an aidl filegroup.
- "libnativehelper_lazy_mts_jni", // depends on unconverted modules: libgmock_ndk
- "libnativehelper_mts_jni", // depends on unconverted modules: libgmock_ndk
- "libnativetesthelper_jni", // depends on unconverted modules: libgtest_ndk_c++
+ "libnativehelper_lazy_mts_jni", "libnativehelper_mts_jni", // depends on unconverted modules: libgmock_ndk
+ "libnativetesthelper_jni", "libgmock_main_ndk", "libgmock_ndk", // depends on unconverted module: libgtest_ndk_c++
"statslog-framework-java-gen", "statslog.cpp", "statslog.h", "statslog.rs", "statslog_header.rs", // depends on unconverted modules: stats-log-api-gen
@@ -386,8 +387,6 @@
"libstatslog", // depends on unconverted modules: statslog.cpp, statslog.h, ...
- "libgmock_main_ndk", "libgmock_ndk", // depends on unconverted module: libgtest_ndk_c++
-
"cmd", // depends on unconverted module packagemanager_aidl-cpp, of unsupported type aidl_interface
"servicedispatcher", // depends on unconverted module android.debug_aidl, of unsupported type aidl_interface
"libutilscallstack", // depends on unconverted module libbacktrace
@@ -398,18 +397,11 @@
"libdebuggerd", // depends on unconverted modules libdexfile_support, libunwindstack, gwp_asan_crash_handler, libtombstone_proto, libprotobuf-cpp-lite
"libdexfile_static", // depends on libartpalette, libartbase, libdexfile, which are of unsupported type: art_cc_library.
- "crasher", // depends on unconverted modules: libseccomp_policy
- "static_crasher", // depends on unconverted modules: libdebuggerd_handler, libseccomp_policy
-
"host_bionic_linker_asm", // depends on extract_linker, a go binary.
"host_bionic_linker_script", // depends on extract_linker, a go binary.
+ "static_crasher", // depends on unconverted modules: libdebuggerd_handler
- "pbtombstone", // depends on libprotobuf-cpp-lite, libtombstone_proto
- "crash_dump", // depends on unconverted module libprotobuf-cpp-lite
-
- "libunwindstack_local", "libunwindstack_utils", // depends on unconverted module libunwindstack
- "libunwindstack", // depends on libdexfile_support, of unsupported module type art_cc_library_static
- "libc_malloc_debug", // depends on unconverted module libunwindstack
+ "pbtombstone", "crash_dump", // depends on libdebuggerd, libunwindstack
"libbase_ndk", // http://b/186826477, fails to link libctscamera2_jni for device (required for CtsCameraTestCases)
@@ -420,10 +412,7 @@
"libprotobuf-java-util-full", // b/210751803, we don't handle path property for filegroups
"conscrypt", // b/210751803, we don't handle path property for filegroups
- "libseccomp_policy", // b/201094425: depends on func_to_syscall_nrs, which depends on py_binary, which is unsupported in mixed builds.
- "libfdtrack", // depends on unconverted module libunwindstack
-
- "gwp_asan_crash_handler", // cc_library, ld.lld: error: undefined symbol: memset
+ "conv_linker_config", // depends on linker_config_proto, a python lib with proto sources
"brotli-fuzzer-corpus", // b/202015218: outputs are in location incompatible with bazel genrule handling.
@@ -432,14 +421,8 @@
"platform_tools_properties",
"build_tools_source_properties",
- // Tests. Handle later.
- "libbionic_tests_headers_posix", // http://b/186024507, cc_library_static, sched.h, time.h not found
- "libjemalloc5_integrationtest",
- "libjemalloc5_stresstestlib",
- "libjemalloc5_unittest",
-
// APEX support
- "com.android.runtime", // http://b/194746715, apex, depends on 'libc_malloc_debug'
+ "com.android.runtime", // depends on unconverted modules: bionic-linker-config, linkerconfig
"libgtest_ndk_c++", // b/201816222: Requires sdk_version support.
"libgtest_main_ndk_c++", // b/201816222: Requires sdk_version support.
@@ -469,6 +452,8 @@
// Per-module denylist to opt modules out of mixed builds. Such modules will
// still be generated via bp2build.
mixedBuildsDisabledList = []string{
+ "art_libdexfile_dex_instruction_list_header", // breaks libart_mterp.armng, header not found
+
"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.
diff --git a/android/defaults.go b/android/defaults.go
index 0953f95..5677638 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -92,6 +92,7 @@
if module.base().module == nil {
panic("InitAndroidModule must be called before InitDefaultableModule")
}
+
module.setProperties(module.GetProperties(), module.base().variableProperties)
module.AddProperties(module.defaults())
@@ -118,6 +119,11 @@
type DefaultsModuleBase struct {
DefaultableModuleBase
+
+ // Included to support setting bazel_module.label for multiple Soong modules to the same Bazel
+ // target. This is primarily useful for modules that were architecture specific and instead are
+ // handled in Bazel as a select().
+ BazelModuleBase
}
// The common pattern for defaults modules is to register separate instances of
@@ -160,6 +166,7 @@
type DefaultsModule interface {
Module
Defaults
+ Bazelable
}
func (d *DefaultsModuleBase) properties() []interface{} {
@@ -170,8 +177,7 @@
return d.defaultableVariableProperties
}
-func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) {
-}
+func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) {}
// ConvertWithBp2build to fulfill Bazelable interface; however, at this time defaults module are
// *NOT* converted with bp2build
@@ -186,6 +192,8 @@
&ApexProperties{},
&distProperties{})
+ // Bazel module must be initialized _before_ Defaults to be included in cc_defaults module.
+ InitBazelModule(module)
initAndroidModuleBase(module)
initProductVariableModule(module)
initArchModule(module)
diff --git a/android/util.go b/android/util.go
index a0394f6..0ee253e 100644
--- a/android/util.go
+++ b/android/util.go
@@ -65,22 +65,6 @@
return buf.String()
}
-// SortedIntKeys returns the keys of the given integer-keyed map in the ascending order
-// TODO(asmundak): once Go has generics, combine this with SortedStringKeys below.
-func SortedIntKeys(m interface{}) []int {
- v := reflect.ValueOf(m)
- if v.Kind() != reflect.Map {
- panic(fmt.Sprintf("%#v is not a map", m))
- }
- keys := v.MapKeys()
- s := make([]int, 0, len(keys))
- for _, key := range keys {
- s = append(s, int(key.Int()))
- }
- sort.Ints(s)
- return s
-}
-
// SorterStringKeys returns the keys of the given string-keyed map in the ascending order
func SortedStringKeys(m interface{}) []string {
v := reflect.ValueOf(m)
@@ -96,21 +80,6 @@
return s
}
-// SortedStringMapValues returns the values of the string-values map in the ascending order
-func SortedStringMapValues(m interface{}) []string {
- v := reflect.ValueOf(m)
- if v.Kind() != reflect.Map {
- panic(fmt.Sprintf("%#v is not a map", m))
- }
- keys := v.MapKeys()
- s := make([]string, 0, len(keys))
- for _, key := range keys {
- s = append(s, v.MapIndex(key).String())
- }
- sort.Strings(s)
- return s
-}
-
// IndexList returns the index of the first occurrence of the given string in the list or -1
func IndexList(s string, list []string) int {
for i, l := range list {
diff --git a/apex/apex.go b/apex/apex.go
index 09b6daa..635ff30 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2643,7 +2643,7 @@
//
// Module separator
//
- m["com.android.bluetooth.updatable"] = []string{
+ m["com.android.bluetooth"] = []string{
"android.hardware.audio.common@5.0",
"android.hardware.bluetooth.a2dp@1.0",
"android.hardware.bluetooth.audio@2.0",
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index 7ecf9b2..ce828e1 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -16,6 +16,7 @@
import (
"fmt"
+ "path"
"sort"
"strings"
"testing"
@@ -442,6 +443,24 @@
checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
})
+ t.Run("boot image disable generate profile", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ commonPreparer,
+
+ // Configure some libraries in the art bootclasspath_fragment that match the source
+ // bootclasspath_fragment's contents property.
+ java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
+ addSource("foo", "bar"),
+ dexpreopt.FixtureDisableGenerateProfile(true),
+ ).RunTest(t)
+
+ files := getFiles(t, result.TestContext, "com.android.art", "android_common_com.android.art_image")
+ for _, file := range files {
+ matched, _ := path.Match("etc/boot-image.prof", file.path)
+ android.AssertBoolEquals(t, "\"etc/boot-image.prof\" should not be in the APEX", matched, false)
+ }
+ })
+
t.Run("boot image files with preferred prebuilt", func(t *testing.T) {
result := android.GroupFixturePreparers(
commonPreparer,
diff --git a/cc/builder.go b/cc/builder.go
index 8af2255..fa7f7a3 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -529,6 +529,14 @@
cppflags += " ${config.NoOverrideGlobalCflags}"
toolingCppflags += " ${config.NoOverrideGlobalCflags}"
+ modulePath := android.PathForModuleSrc(ctx).String()
+ if android.IsThirdPartyPath(modulePath) {
+ cflags += " ${config.NoOverrideExternalGlobalCflags}"
+ toolingCflags += " ${config.NoOverrideExternalGlobalCflags}"
+ cppflags += " ${config.NoOverrideExternalGlobalCflags}"
+ toolingCppflags += " ${config.NoOverrideExternalGlobalCflags}"
+ }
+
// Multiple source files have build rules usually share the same cFlags or tidyFlags.
// Define only one version in this module and share it in multiple build rules.
// To simplify the code, the shared variables are all named as $flags<nnn>.
diff --git a/cc/cc.go b/cc/cc.go
index 730041c..22baf30 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -3494,10 +3494,6 @@
type Defaults struct {
android.ModuleBase
android.DefaultsModuleBase
- // Included to support setting bazel_module.label for multiple Soong modules to the same Bazel
- // target. This is primarily useful for modules that were architecture specific and instead are
- // handled in Bazel as a select().
- android.BazelModuleBase
android.ApexModuleBase
}
@@ -3545,8 +3541,6 @@
&prebuiltLinkerProperties{},
)
- // Bazel module must be initialized _before_ Defaults to be included in cc_defaults module.
- android.InitBazelModule(module)
android.InitDefaultsModule(module)
return module
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 9ffe48d..bcc6fcd 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -4005,12 +4005,12 @@
{
name: "c",
src: "foo.c",
- expected: combineSlices(baseExpectedFlags, conly, expectedIncludes, cflags, cstd, lastIncludes, []string{"${config.NoOverrideGlobalCflags}"}),
+ expected: combineSlices(baseExpectedFlags, conly, expectedIncludes, cflags, cstd, lastIncludes, []string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"}),
},
{
name: "cc",
src: "foo.cc",
- expected: combineSlices(baseExpectedFlags, cppOnly, expectedIncludes, cflags, cppstd, lastIncludes, []string{"${config.NoOverrideGlobalCflags}"}),
+ expected: combineSlices(baseExpectedFlags, cppOnly, expectedIncludes, cflags, cppstd, lastIncludes, []string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"}),
},
{
name: "assemble",
diff --git a/cc/config/global.go b/cc/config/global.go
index a340e46..7f2c23e 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -224,8 +224,6 @@
"-Wno-pessimizing-move", // http://b/154270751
// New warnings to be fixed after clang-r399163
"-Wno-non-c-typedef-for-linkage", // http://b/161304145
- // New warnings to be fixed after clang-r407598
- "-Wno-string-concatenation", // http://b/175068488
// New warnings to be fixed after clang-r428724
"-Wno-align-mismatch", // http://b/193679946
// New warnings to be fixed after clang-r433403
@@ -233,6 +231,12 @@
"-Wno-error=unused-but-set-parameter", // http://b/197240255
}
+ noOverrideExternalGlobalCflags = []string{
+ // http://b/197240255
+ "-Wno-unused-but-set-variable",
+ "-Wno-unused-but-set-parameter",
+ }
+
// Extra cflags for external third-party projects to disable warnings that
// are infeasible to fix in all the external projects and their upstream repos.
extraExternalCflags = []string{
@@ -259,6 +263,9 @@
// http://b/199369603
"-Wno-null-pointer-subtraction",
+
+ // http://b/175068488
+ "-Wno-string-concatenation",
}
IllegalFlags = []string{
@@ -346,6 +353,7 @@
exportStringListStaticVariable("HostGlobalCflags", hostGlobalCflags)
exportStringListStaticVariable("NoOverrideGlobalCflags", noOverrideGlobalCflags)
+ exportStringListStaticVariable("NoOverrideExternalGlobalCflags", noOverrideExternalGlobalCflags)
exportStringListStaticVariable("CommonGlobalCppflags", commonGlobalCppflags)
exportStringListStaticVariable("ExternalCflags", extraExternalCflags)
diff --git a/cc/makevars.go b/cc/makevars.go
index 8d7a163..b7aaaad 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -95,6 +95,7 @@
ctx.Strict("CLANG_EXTERNAL_CFLAGS", "${config.ExternalCflags}")
ctx.Strict("GLOBAL_CLANG_CFLAGS_NO_OVERRIDE", "${config.NoOverrideGlobalCflags}")
ctx.Strict("GLOBAL_CLANG_CPPFLAGS_NO_OVERRIDE", "")
+ ctx.Strict("GLOBAL_CLANG_EXTERNAL_CFLAGS_NO_OVERRIDE", "${config.NoOverrideExternalGlobalCflags}")
ctx.Strict("BOARD_VNDK_VERSION", ctx.DeviceConfig().VndkVersion())
ctx.Strict("RECOVERY_SNAPSHOT_VERSION", ctx.DeviceConfig().RecoverySnapshotVersion())
diff --git a/dexpreopt/testing.go b/dexpreopt/testing.go
index 5131cd3..47ae494 100644
--- a/dexpreopt/testing.go
+++ b/dexpreopt/testing.go
@@ -167,3 +167,10 @@
dexpreoptConfig.BootImageProfiles = android.PathsForSource(ctx, profiles)
})
}
+
+// FixtureDisableGenerateProfile sets the DisableGenerateProfile property in the global config.
+func FixtureDisableGenerateProfile(disable bool) android.FixturePreparer {
+ return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) {
+ dexpreoptConfig.DisableGenerateProfile = disable
+ })
+}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 75083e8..c599c4d 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -506,8 +506,18 @@
dst := dstBootJarsByModule[name]
if src == nil {
+ // A dex boot jar should be provided by the source java module. It needs to be installable or
+ // have compile_dex=true - cf. assignments to java.Module.dexJarFile.
+ //
+ // However, the source java module may be either replaced or overridden (using prefer:true) by
+ // a prebuilt java module with the same name. In that case the dex boot jar needs to be
+ // provided by the corresponding prebuilt APEX module. That APEX is the one that refers
+ // through a exported_(boot|systemserver)classpath_fragments property to a
+ // prebuilt_(boot|systemserver)classpath_fragment module, which in turn lists the prebuilt
+ // java module in the contents property. If that chain is broken then this dependency will
+ // fail.
if !ctx.Config().AllowMissingDependencies() {
- ctx.ModuleErrorf("module %s does not provide a dex boot jar", name)
+ ctx.ModuleErrorf("module %s does not provide a dex boot jar (see comment next to this message in Soong for details)", name)
} else {
ctx.AddMissingDependencies([]string{name})
}
diff --git a/mk2rbc/expr.go b/mk2rbc/expr.go
index 81b31c7..7cd4899 100644
--- a/mk2rbc/expr.go
+++ b/mk2rbc/expr.go
@@ -16,21 +16,22 @@
import (
"fmt"
- "strconv"
"strings"
)
-// Represents an expression in the Starlark code. An expression has
-// a type, and it can be evaluated.
+// Represents an expression in the Starlark code. An expression has a type.
type starlarkExpr interface {
starlarkNode
typ() starlarkType
- // Try to substitute variable values. Return substitution result
- // and whether it is the same as the original expression.
- eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool)
// Emit the code to copy the expression, otherwise we will end up
// with source and target pointing to the same list.
emitListVarCopy(gctx *generationContext)
+ // Return the expression, calling the transformer func for
+ // every expression in the tree. If the transformer func returns non-nil,
+ // its result is used in place of the expression it was called with in the
+ // resulting expression. The resulting starlarkExpr will contain as many
+ // of the same objects from the original expression as possible.
+ transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr
}
func maybeString(expr starlarkExpr) (string, bool) {
@@ -44,12 +45,6 @@
literal string
}
-func (s *stringLiteralExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) {
- res = s
- same = true
- return
-}
-
func (s *stringLiteralExpr) emit(gctx *generationContext) {
gctx.writef("%q", s.literal)
}
@@ -62,17 +57,19 @@
s.emit(gctx)
}
+func (s *stringLiteralExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ if replacement := transformer(s); replacement != nil {
+ return replacement
+ } else {
+ return s
+ }
+}
+
// Integer literal
type intLiteralExpr struct {
literal int
}
-func (s *intLiteralExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) {
- res = s
- same = true
- return
-}
-
func (s *intLiteralExpr) emit(gctx *generationContext) {
gctx.writef("%d", s.literal)
}
@@ -85,15 +82,19 @@
s.emit(gctx)
}
+func (s *intLiteralExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ if replacement := transformer(s); replacement != nil {
+ return replacement
+ } else {
+ return s
+ }
+}
+
// Boolean literal
type boolLiteralExpr struct {
literal bool
}
-func (b *boolLiteralExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) {
- return b, true
-}
-
func (b *boolLiteralExpr) emit(gctx *generationContext) {
if b.literal {
gctx.write("True")
@@ -110,6 +111,14 @@
b.emit(gctx)
}
+func (b *boolLiteralExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ if replacement := transformer(b); replacement != nil {
+ return replacement
+ } else {
+ return b
+ }
+}
+
// interpolateExpr represents Starlark's interpolation operator <string> % list
// we break <string> into a list of chunks, i.e., "first%second%third" % (X, Y)
// will have chunks = ["first", "second", "third"] and args = [X, Y]
@@ -118,6 +127,35 @@
args []starlarkExpr
}
+func NewInterpolateExpr(parts []starlarkExpr) starlarkExpr {
+ result := &interpolateExpr{}
+ needString := true
+ for _, part := range parts {
+ if needString {
+ if strLit, ok := part.(*stringLiteralExpr); ok {
+ result.chunks = append(result.chunks, strLit.literal)
+ } else {
+ result.chunks = append(result.chunks, "")
+ }
+ needString = false
+ } else {
+ if strLit, ok := part.(*stringLiteralExpr); ok {
+ result.chunks[len(result.chunks)-1] += strLit.literal
+ } else {
+ result.args = append(result.args, part)
+ needString = true
+ }
+ }
+ }
+ if len(result.chunks) == len(result.args) {
+ result.chunks = append(result.chunks, "")
+ }
+ if len(result.args) == 0 {
+ return &stringLiteralExpr{literal: strings.Join(result.chunks, "")}
+ }
+ return result
+}
+
func (xi *interpolateExpr) emit(gctx *generationContext) {
if len(xi.chunks) != len(xi.args)+1 {
panic(fmt.Errorf("malformed interpolateExpr: #chunks(%d) != #args(%d)+1",
@@ -151,37 +189,6 @@
}
}
-func (xi *interpolateExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
- same = true
- newChunks := []string{xi.chunks[0]}
- var newArgs []starlarkExpr
- for i, arg := range xi.args {
- newArg, sameArg := arg.eval(valueMap)
- same = same && sameArg
- switch x := newArg.(type) {
- case *stringLiteralExpr:
- newChunks[len(newChunks)-1] += x.literal + xi.chunks[i+1]
- same = false
- continue
- case *intLiteralExpr:
- newChunks[len(newChunks)-1] += strconv.Itoa(x.literal) + xi.chunks[i+1]
- same = false
- continue
- default:
- newChunks = append(newChunks, xi.chunks[i+1])
- newArgs = append(newArgs, newArg)
- }
- }
- if same {
- res = xi
- } else if len(newChunks) == 1 {
- res = &stringLiteralExpr{newChunks[0]}
- } else {
- res = &interpolateExpr{chunks: newChunks, args: newArgs}
- }
- return
-}
-
func (_ *interpolateExpr) typ() starlarkType {
return starlarkTypeString
}
@@ -190,19 +197,29 @@
xi.emit(gctx)
}
+func (xi *interpolateExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ argsCopy := make([]starlarkExpr, len(xi.args))
+ for i, arg := range xi.args {
+ argsCopy[i] = arg.transform(transformer)
+ }
+ xi.args = argsCopy
+ if replacement := transformer(xi); replacement != nil {
+ return replacement
+ } else {
+ return xi
+ }
+}
+
type variableRefExpr struct {
ref variable
isDefined bool
}
-func (v *variableRefExpr) eval(map[string]starlarkExpr) (res starlarkExpr, same bool) {
- predefined, ok := v.ref.(*predefinedVariable)
- if same = !ok; same {
- res = v
- } else {
- res = predefined.value
+func NewVariableRefExpr(ref variable, isDefined bool) starlarkExpr {
+ if predefined, ok := ref.(*predefinedVariable); ok {
+ return predefined.value
}
- return
+ return &variableRefExpr{ref, isDefined}
}
func (v *variableRefExpr) emit(gctx *generationContext) {
@@ -220,17 +237,16 @@
}
}
-type toStringExpr struct {
- expr starlarkExpr
+func (v *variableRefExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ if replacement := transformer(v); replacement != nil {
+ return replacement
+ } else {
+ return v
+ }
}
-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
+type toStringExpr struct {
+ expr starlarkExpr
}
func (s *toStringExpr) emit(ctx *generationContext) {
@@ -265,17 +281,17 @@
s.emit(gctx)
}
-type notExpr struct {
- expr starlarkExpr
+func (s *toStringExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ s.expr = s.expr.transform(transformer)
+ if replacement := transformer(s); replacement != nil {
+ return replacement
+ } else {
+ return s
+ }
}
-func (n *notExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
- if x, same := n.expr.eval(valueMap); same {
- res = n
- } else {
- res = ¬Expr{expr: x}
- }
- return
+type notExpr struct {
+ expr starlarkExpr
}
func (n *notExpr) emit(ctx *generationContext) {
@@ -291,22 +307,20 @@
n.emit(gctx)
}
+func (n *notExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ n.expr = n.expr.transform(transformer)
+ if replacement := transformer(n); replacement != nil {
+ return replacement
+ } else {
+ return n
+ }
+}
+
type eqExpr struct {
left, right starlarkExpr
isEq bool // if false, it's !=
}
-func (eq *eqExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
- xLeft, sameLeft := eq.left.eval(valueMap)
- xRight, sameRight := eq.right.eval(valueMap)
- if same = sameLeft && sameRight; same {
- res = eq
- } else {
- res = &eqExpr{left: xLeft, right: xRight, isEq: eq.isEq}
- }
- return
-}
-
func (eq *eqExpr) emit(gctx *generationContext) {
var stringOperand string
var otherOperand starlarkExpr
@@ -360,18 +374,21 @@
eq.emit(gctx)
}
+func (eq *eqExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ eq.left = eq.left.transform(transformer)
+ eq.right = eq.right.transform(transformer)
+ if replacement := transformer(eq); replacement != nil {
+ return replacement
+ } else {
+ return eq
+ }
+}
+
// variableDefinedExpr corresponds to Make's ifdef VAR
type variableDefinedExpr struct {
v variable
}
-func (v *variableDefinedExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) {
- res = v
- same = true
- return
-
-}
-
func (v *variableDefinedExpr) emit(gctx *generationContext) {
if v.v != nil {
v.v.emitDefined(gctx)
@@ -388,24 +405,13 @@
v.emit(gctx)
}
-type listExpr struct {
- items []starlarkExpr
+func (v *variableDefinedExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ // TODO: VariableDefinedExpr isn't really an expression?
+ return v
}
-func (l *listExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
- newItems := make([]starlarkExpr, len(l.items))
- same = true
- for i, item := range l.items {
- var sameItem bool
- newItems[i], sameItem = item.eval(valueMap)
- same = same && sameItem
- }
- if same {
- res = l
- } else {
- res = &listExpr{newItems}
- }
- return
+type listExpr struct {
+ items []starlarkExpr
}
func (l *listExpr) emit(gctx *generationContext) {
@@ -442,6 +448,19 @@
l.emit(gctx)
}
+func (l *listExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ itemsCopy := make([]starlarkExpr, len(l.items))
+ for i, item := range l.items {
+ itemsCopy[i] = item.transform(transformer)
+ }
+ l.items = itemsCopy
+ if replacement := transformer(l); replacement != nil {
+ return replacement
+ } else {
+ return l
+ }
+}
+
func newStringListExpr(items []string) *listExpr {
v := listExpr{}
for _, item := range items {
@@ -481,22 +500,6 @@
gctx.indentLevel -= 2
}
-func (c *concatExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
- same = true
- xConcat := &concatExpr{items: make([]starlarkExpr, len(c.items))}
- for i, item := range c.items {
- var sameItem bool
- xConcat.items[i], sameItem = item.eval(valueMap)
- same = same && sameItem
- }
- if same {
- res = c
- } else {
- res = xConcat
- }
- return
-}
-
func (_ *concatExpr) typ() starlarkType {
return starlarkTypeList
}
@@ -505,6 +508,19 @@
c.emit(gctx)
}
+func (c *concatExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ itemsCopy := make([]starlarkExpr, len(c.items))
+ for i, item := range c.items {
+ itemsCopy[i] = item.transform(transformer)
+ }
+ c.items = itemsCopy
+ if replacement := transformer(c); replacement != nil {
+ return replacement
+ } else {
+ return c
+ }
+}
+
// inExpr generates <expr> [not] in <list>
type inExpr struct {
expr starlarkExpr
@@ -512,19 +528,6 @@
isNot bool
}
-func (i *inExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
- x := &inExpr{isNot: i.isNot}
- var sameExpr, sameList bool
- x.expr, sameExpr = i.expr.eval(valueMap)
- x.list, sameList = i.list.eval(valueMap)
- if same = sameExpr && sameList; same {
- res = i
- } else {
- res = x
- }
- return
-}
-
func (i *inExpr) emit(gctx *generationContext) {
i.expr.emit(gctx)
if i.isNot {
@@ -543,35 +546,44 @@
i.emit(gctx)
}
+func (i *inExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ i.expr = i.expr.transform(transformer)
+ i.list = i.list.transform(transformer)
+ if replacement := transformer(i); replacement != nil {
+ return replacement
+ } else {
+ return i
+ }
+}
+
type indexExpr struct {
array starlarkExpr
index starlarkExpr
}
-func (ix indexExpr) emit(gctx *generationContext) {
+func (ix *indexExpr) emit(gctx *generationContext) {
ix.array.emit(gctx)
gctx.write("[")
ix.index.emit(gctx)
gctx.write("]")
}
-func (ix indexExpr) typ() starlarkType {
+func (ix *indexExpr) typ() starlarkType {
return starlarkTypeString
}
-func (ix indexExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
- newArray, isSameArray := ix.array.eval(valueMap)
- newIndex, isSameIndex := ix.index.eval(valueMap)
- if same = isSameArray && isSameIndex; same {
- res = ix
- } else {
- res = &indexExpr{newArray, newIndex}
- }
- return
+func (ix *indexExpr) emitListVarCopy(gctx *generationContext) {
+ ix.emit(gctx)
}
-func (ix indexExpr) emitListVarCopy(gctx *generationContext) {
- ix.emit(gctx)
+func (ix *indexExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ ix.array = ix.array.transform(transformer)
+ ix.index = ix.index.transform(transformer)
+ if replacement := transformer(ix); replacement != nil {
+ return replacement
+ } else {
+ return ix
+ }
}
type callExpr struct {
@@ -581,27 +593,6 @@
returnType starlarkType
}
-func (cx *callExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
- newCallExpr := &callExpr{name: cx.name, args: make([]starlarkExpr, len(cx.args)),
- returnType: cx.returnType}
- if cx.object != nil {
- newCallExpr.object, same = cx.object.eval(valueMap)
- } else {
- same = true
- }
- for i, args := range cx.args {
- var s bool
- newCallExpr.args[i], s = args.eval(valueMap)
- same = same && s
- }
- if same {
- res = cx
- } else {
- res = newCallExpr
- }
- return
-}
-
func (cx *callExpr) emit(gctx *generationContext) {
sep := ""
if cx.object != nil {
@@ -642,28 +633,27 @@
cx.emit(gctx)
}
+func (cx *callExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ if cx.object != nil {
+ cx.object = cx.object.transform(transformer)
+ }
+ argsCopy := make([]starlarkExpr, len(cx.args))
+ for i, arg := range cx.args {
+ argsCopy[i] = arg.transform(transformer)
+ }
+ if replacement := transformer(cx); replacement != nil {
+ return replacement
+ } else {
+ return cx
+ }
+}
+
type ifExpr struct {
condition starlarkExpr
ifTrue starlarkExpr
ifFalse starlarkExpr
}
-func (i *ifExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
- cond, condSame := i.condition.eval(valueMap)
- t, tSame := i.ifTrue.eval(valueMap)
- f, fSame := i.ifFalse.eval(valueMap)
- same = condSame && tSame && fSame
- if same {
- return i, same
- } else {
- return &ifExpr{
- condition: cond,
- ifTrue: t,
- ifFalse: f,
- }, same
- }
-}
-
func (i *ifExpr) emit(gctx *generationContext) {
gctx.write("(")
i.ifTrue.emit(gctx)
@@ -691,17 +681,78 @@
i.emit(gctx)
}
+func (i *ifExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ i.condition = i.condition.transform(transformer)
+ i.ifTrue = i.ifTrue.transform(transformer)
+ i.ifFalse = i.ifFalse.transform(transformer)
+ if replacement := transformer(i); replacement != nil {
+ return replacement
+ } else {
+ return i
+ }
+}
+
+type identifierExpr struct {
+ name string
+}
+
+func (i *identifierExpr) emit(gctx *generationContext) {
+ gctx.write(i.name)
+}
+
+func (i *identifierExpr) typ() starlarkType {
+ return starlarkTypeUnknown
+}
+
+func (i *identifierExpr) emitListVarCopy(gctx *generationContext) {
+ i.emit(gctx)
+}
+
+func (i *identifierExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ if replacement := transformer(i); replacement != nil {
+ return replacement
+ } else {
+ return i
+ }
+}
+
+type foreachExpr struct {
+ varName string
+ list starlarkExpr
+ action starlarkExpr
+}
+
+func (f *foreachExpr) emit(gctx *generationContext) {
+ gctx.write("[")
+ f.action.emit(gctx)
+ gctx.write(" for " + f.varName + " in ")
+ f.list.emit(gctx)
+ gctx.write("]")
+}
+
+func (f *foreachExpr) typ() starlarkType {
+ return starlarkTypeList
+}
+
+func (f *foreachExpr) emitListVarCopy(gctx *generationContext) {
+ f.emit(gctx)
+}
+
+func (f *foreachExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ f.list = f.list.transform(transformer)
+ f.action = f.action.transform(transformer)
+ if replacement := transformer(f); replacement != nil {
+ return replacement
+ } else {
+ return f
+ }
+}
+
type badExpr struct {
errorLocation ErrorLocation
message string
}
-func (b *badExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) {
- res = b
- same = true
- return
-}
-
func (b *badExpr) emit(gctx *generationContext) {
gctx.emitConversionError(b.errorLocation, b.message)
}
@@ -714,6 +765,14 @@
panic("implement me")
}
+func (b *badExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ if replacement := transformer(b); replacement != nil {
+ return replacement
+ } else {
+ return b
+ }
+}
+
func maybeConvertToStringList(expr starlarkExpr) starlarkExpr {
if xString, ok := expr.(*stringLiteralExpr); ok {
return newStringListExpr(strings.Fields(xString.literal))
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index 839dea2..024311e 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -111,6 +111,7 @@
"filter": {baseName + ".filter", starlarkTypeList, hiddenArgNone},
"filter-out": {baseName + ".filter_out", starlarkTypeList, hiddenArgNone},
"firstword": {"!firstword", starlarkTypeString, hiddenArgNone},
+ "foreach": {"!foreach", starlarkTypeList, hiddenArgNone},
"get-vendor-board-platforms": {"!get-vendor-board-platforms", starlarkTypeList, hiddenArgNone}, // internal macro, used by is-board-platform, etc.
"if": {"!if", starlarkTypeUnknown, hiddenArgNone},
"info": {baseName + ".mkinfo", starlarkTypeVoid, hiddenArgNone},
@@ -147,14 +148,10 @@
"warning": {baseName + ".mkwarning", starlarkTypeVoid, hiddenArgNone},
"word": {baseName + "!word", starlarkTypeString, hiddenArgNone},
"wildcard": {baseName + ".expand_wildcard", starlarkTypeList, hiddenArgNone},
+ "words": {baseName + ".words", starlarkTypeList, hiddenArgNone},
}
-var builtinFuncRex = regexp.MustCompile(
- "^(addprefix|addsuffix|abspath|and|basename|call|dir|error|eval" +
- "|flavor|foreach|file|filter|filter-out|findstring|firstword|guile" +
- "|if|info|join|lastword|notdir|or|origin|patsubst|realpath" +
- "|shell|sort|strip|subst|suffix|value|warning|word|wordlist|words" +
- "|wildcard)")
+var identifierFullMatchRegex = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$")
// Conversion request parameters
type Request struct {
@@ -414,7 +411,6 @@
ifNestLevel int
moduleNameCount map[string]int // count of imported modules with given basename
fatalError error
- builtinMakeVars map[string]starlarkExpr
outputSuffix string
errorLogger ErrorLogger
tracedVariables map[string]bool // variables to be traced in the generated script
@@ -467,7 +463,6 @@
currentNodeIndex: 0,
ifNestLevel: 0,
moduleNameCount: make(map[string]int),
- builtinMakeVars: map[string]starlarkExpr{},
variables: make(map[string]variable),
dependentModules: make(map[string]*moduleInfo),
soongNamespaces: make(map[string]map[string]bool),
@@ -603,9 +598,6 @@
}
}
- // TODO(asmundak): move evaluation to a separate pass
- asgn.value, _ = asgn.value.eval(ctx.builtinMakeVars)
-
asgn.previous = ctx.lastAssignment(name)
ctx.setLastAssignment(name, asgn)
switch a.Type {
@@ -632,7 +624,6 @@
ctx.wrapBadExpr(xBad)
return
}
- val, _ = val.eval(ctx.builtinMakeVars)
// Unfortunately, Soong namespaces can be set up by directly setting corresponding Make
// variables instead of via add_soong_config_namespace + add_soong_config_var_value.
@@ -788,7 +779,6 @@
func (ctx *parseContext) handleSubConfig(
v mkparser.Node, pathExpr starlarkExpr, loadAlways bool, processModule func(inheritedModule)) {
- pathExpr, _ = pathExpr.eval(ctx.builtinMakeVars)
// In a simple case, the name of a module to inherit/include is known statically.
if path, ok := maybeString(pathExpr); ok {
@@ -1125,7 +1115,7 @@
return xBad, true
}
return &eqExpr{
- left: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
+ left: NewVariableRefExpr(ctx.addVariable("TARGET_BOARD_PLATFORM"), false),
right: call.args[0],
isEq: isEq,
}, true
@@ -1134,7 +1124,7 @@
return xBad, true
}
return &inExpr{
- expr: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
+ expr: NewVariableRefExpr(ctx.addVariable("TARGET_BOARD_PLATFORM"), false),
list: maybeConvertToStringList(call.args[0]),
isNot: !isEq,
}, true
@@ -1143,7 +1133,7 @@
return xBad, true
}
return &inExpr{
- expr: &variableRefExpr{ctx.addVariable("TARGET_PRODUCT"), true},
+ expr: NewVariableRefExpr(ctx.addVariable("TARGET_PRODUCT"), true),
list: maybeConvertToStringList(call.args[0]),
isNot: !isEq,
}, true
@@ -1156,8 +1146,8 @@
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},
+ expr: NewVariableRefExpr(ctx.addVariable("TARGET_BOARD_PLATFORM"), false),
+ list: NewVariableRefExpr(ctx.addVariable(s+"_BOARD_PLATFORMS"), true),
isNot: !isEq,
}, true
@@ -1186,8 +1176,8 @@
// 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},
+ expr: NewVariableRefExpr(ctx.addVariable("TARGET_BOARD_PLATFORM"), false),
+ list: NewVariableRefExpr(ctx.addVariable("QCOM_BOARD_PLATFORMS"), true),
isNot: isEq,
}, true
}
@@ -1369,12 +1359,12 @@
args: []starlarkExpr{
&stringLiteralExpr{literal: substParts[0]},
&stringLiteralExpr{literal: substParts[1]},
- &variableRefExpr{v, ctx.lastAssignment(v.name()) != nil},
+ NewVariableRefExpr(v, ctx.lastAssignment(v.name()) != nil),
},
}
}
if v := ctx.addVariable(refDump); v != nil {
- return &variableRefExpr{v, ctx.lastAssignment(v.name()) != nil}
+ return NewVariableRefExpr(v, ctx.lastAssignment(v.name()) != nil)
}
return ctx.newBadExpr(node, "unknown variable %s", refDump)
}
@@ -1412,12 +1402,14 @@
switch expr.name {
case "if":
return ctx.parseIfFunc(node, args)
+ case "foreach":
+ return ctx.parseForeachFunc(node, args)
case "word":
return ctx.parseWordFunc(node, args)
case "firstword", "lastword":
return ctx.parseFirstOrLastwordFunc(node, expr.name, args)
case "my-dir":
- return &variableRefExpr{ctx.addVariable("LOCAL_PATH"), true}
+ return NewVariableRefExpr(ctx.addVariable("LOCAL_PATH"), true)
case "subst", "patsubst":
return ctx.parseSubstFunc(node, expr.name, args)
default:
@@ -1496,6 +1488,38 @@
}
}
+func (ctx *parseContext) parseForeachFunc(node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
+ words := args.Split(",")
+ if len(words) != 3 {
+ return ctx.newBadExpr(node, "foreach function should have 3 arguments, found "+strconv.Itoa(len(words)))
+ }
+ if !words[0].Const() || words[0].Empty() || !identifierFullMatchRegex.MatchString(words[0].Strings[0]) {
+ return ctx.newBadExpr(node, "first argument to foreach function must be a simple string identifier")
+ }
+ loopVarName := words[0].Strings[0]
+ list := ctx.parseMakeString(node, words[1])
+ action := ctx.parseMakeString(node, words[2]).transform(func(expr starlarkExpr) starlarkExpr {
+ if varRefExpr, ok := expr.(*variableRefExpr); ok && varRefExpr.ref.name() == loopVarName {
+ return &identifierExpr{loopVarName}
+ }
+ return nil
+ })
+
+ if list.typ() != starlarkTypeList {
+ list = &callExpr{
+ name: "words",
+ returnType: knownFunctions["words"].returnType,
+ args: []starlarkExpr{list},
+ }
+ }
+
+ return &foreachExpr{
+ varName: loopVarName,
+ list: list,
+ action: action,
+ }
+}
+
func (ctx *parseContext) parseWordFunc(node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
words := args.Split(",")
if len(words) != 2 {
@@ -1517,7 +1541,7 @@
if array.typ() != starlarkTypeList {
array = &callExpr{object: array, name: "split", returnType: starlarkTypeList}
}
- return indexExpr{array, &intLiteralExpr{int(index - 1)}}
+ return &indexExpr{array, &intLiteralExpr{int(index - 1)}}
}
func (ctx *parseContext) parseFirstOrLastwordFunc(node mkparser.Node, name string, args *mkparser.MakeString) starlarkExpr {
@@ -1548,16 +1572,18 @@
// If we reached here, it's neither string literal nor a simple variable,
// we need a full-blown interpolation node that will generate
// "a%b%c" % (X, Y) for a$(X)b$(Y)c
- xInterp := &interpolateExpr{args: make([]starlarkExpr, len(mk.Variables))}
- for i, ref := range mk.Variables {
- arg := ctx.parseReference(node, ref.Name)
- if x, ok := arg.(*badExpr); ok {
- return x
+ parts := make([]starlarkExpr, len(mk.Variables)+len(mk.Strings))
+ for i := 0; i < len(parts); i++ {
+ if i%2 == 0 {
+ parts[i] = &stringLiteralExpr{literal: mk.Strings[i/2]}
+ } else {
+ parts[i] = ctx.parseReference(node, mk.Variables[i/2].Name)
+ if x, ok := parts[i].(*badExpr); ok {
+ return x
+ }
}
- xInterp.args[i] = arg
}
- xInterp.chunks = append(xInterp.chunks, mk.Strings...)
- return xInterp
+ return NewInterpolateExpr(parts)
}
// Handles the statements whose treatment is the same in all contexts: comment,
diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go
index a1731a2..94c4fe6 100644
--- a/mk2rbc/mk2rbc_test.go
+++ b/mk2rbc/mk2rbc_test.go
@@ -1158,6 +1158,28 @@
g["OBJECTS2"] = rblf.mkpatsubst("%.c", "%.o", g["SOURCES"])
`,
},
+ {
+ desc: "foreach expressions",
+ mkname: "product.mk",
+ in: `
+BOOT_KERNEL_MODULES := foo.ko bar.ko
+BOOT_KERNEL_MODULES_FILTER := $(foreach m,$(BOOT_KERNEL_MODULES),%/$(m))
+BOOT_KERNEL_MODULES_LIST := foo.ko
+BOOT_KERNEL_MODULES_LIST += bar.ko
+BOOT_KERNEL_MODULES_FILTER_2 := $(foreach m,$(BOOT_KERNEL_MODULES_LIST),%/$(m))
+
+`,
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ g["BOOT_KERNEL_MODULES"] = "foo.ko bar.ko"
+ g["BOOT_KERNEL_MODULES_FILTER"] = ["%%/%s" % m for m in rblf.words(g["BOOT_KERNEL_MODULES"])]
+ g["BOOT_KERNEL_MODULES_LIST"] = ["foo.ko"]
+ g["BOOT_KERNEL_MODULES_LIST"] += ["bar.ko"]
+ g["BOOT_KERNEL_MODULES_FILTER_2"] = ["%%/%s" % m for m in g["BOOT_KERNEL_MODULES_LIST"]]
+`,
+ },
}
var known_variables = []struct {
diff --git a/scripts/OWNERS b/scripts/OWNERS
index 88787cd..3f4f9c0 100644
--- a/scripts/OWNERS
+++ b/scripts/OWNERS
@@ -1,5 +1,4 @@
per-file system-clang-format,system-clang-format-2 = enh@google.com,smoreland@google.com
-per-file build-mainline-modules.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com
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
diff --git a/ui/build/config.go b/ui/build/config.go
index 4c26d3e..b6d0d27 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -721,10 +721,6 @@
}
func (c *configImpl) SoongBuildInvocationNeeded() bool {
- if c.Dist() {
- return true
- }
-
if len(c.Arguments()) > 0 {
// Explicit targets requested that are not special targets like b2pbuild
// or the JSON module graph
@@ -736,6 +732,11 @@
return true
}
+ // bp2build + dist may be used to dist bp2build logs but does not require SoongBuildInvocation
+ if c.Dist() && !c.Bp2Build() {
+ return true
+ }
+
// build.ninja doesn't need to be generated
return false
}