Merge changes I5c7f1fc1,I6015581c into main
* changes:
Fix comment for Bp2buildDepsMutator config.
Use parameter name hint for BazelLabelModuleDepsWithFn's markAsDeps.
diff --git a/README.md b/README.md
index 22daa95..5e9e04a 100644
--- a/README.md
+++ b/README.md
@@ -648,8 +648,8 @@
SOONG_DELVE=2345 SOONG_DELVE_STEPS='build,modulegraph' m
```
results in only `build` (main build step) and `modulegraph` being run in the debugger.
-The allowed step names are `api_bp2build`, `bp2build_files`, `bp2build_workspace`,
-`build`, `modulegraph`, `queryview`, `soong_docs`.
+The allowed step names are `bp2build_files`, `bp2build_workspace`, `build`,
+`modulegraph`, `queryview`, `soong_docs`.
Note setting or unsetting `SOONG_DELVE` causes a recompilation of `soong_build`. This
is because in order to debug the binary, it needs to be built with debug
diff --git a/android/api_domain.go b/android/api_domain.go
index 38f48e3..0a66c3d 100644
--- a/android/api_domain.go
+++ b/android/api_domain.go
@@ -14,14 +14,6 @@
package android
-func init() {
- RegisterApiDomainBuildComponents(InitRegistrationContext)
-}
-
-func RegisterApiDomainBuildComponents(ctx RegistrationContext) {
- ctx.RegisterModuleType("api_domain", ApiDomainFactory)
-}
-
type ApiSurface int
// TODO(b/246656800): Reconcile with android.SdkKind
@@ -44,50 +36,3 @@
return "invalid"
}
}
-
-type apiDomain struct {
- ModuleBase
- BazelModuleBase
-
- properties apiDomainProperties
-}
-
-type apiDomainProperties struct {
- // cc library contributions (.h files/.map.txt) of this API domain
- // This dependency is a no-op in Soong, but the corresponding Bazel target in the api_bp2build workspace
- // will provide a `CcApiContributionInfo` provider
- Cc_api_contributions []string
-
- // java library contributions (as .txt) of this API domain
- // This dependency is a no-op in Soong, but the corresponding Bazel target in the api_bp2build workspace
- // will provide a `JavaApiContributionInfo` provider
- Java_api_contributions []string
-}
-
-func ApiDomainFactory() Module {
- m := &apiDomain{}
- m.AddProperties(&m.properties)
- InitAndroidArchModule(m, DeviceSupported, MultilibBoth)
- return m
-}
-
-// Do not create any dependency edges in Soong for now to skip visibility checks for some systemapi libraries.
-// Currently, all api_domain modules reside in build/orchestrator/apis/Android.bp
-// However, cc libraries like libsigchain (com.android.art) restrict their visibility to art/*
-// When the api_domain module types are collocated with their contributions, this dependency edge can be restored
-func (a *apiDomain) DepsMutator(ctx BottomUpMutatorContext) {
-}
-
-// API domain does not have any builld actions yet
-func (a *apiDomain) GenerateAndroidBuildActions(ctx ModuleContext) {
-}
-
-const (
- apiContributionSuffix = ".contribution"
-)
-
-// ApiContributionTargetName returns the name of the bp2build target (e.g. cc_api_contribution) of contribution modules (e.g. ndk_library)
-// A suffix is necessary to prevent a name collision with the base target in the same bp2build bazel package
-func ApiContributionTargetName(moduleName string) string {
- return moduleName + apiContributionSuffix
-}
diff --git a/android/register.go b/android/register.go
index f1c2986..6182159 100644
--- a/android/register.go
+++ b/android/register.go
@@ -181,8 +181,7 @@
return ctx
}
-// Helper function to register the module types used in bp2build and
-// api_bp2build.
+// Helper function to register the module types used in bp2build.
func registerModuleTypes(ctx *Context) {
for _, t := range moduleTypes {
t.register(ctx)
diff --git a/android/test_asserts.go b/android/test_asserts.go
index 3a2cb1a..c33ade5 100644
--- a/android/test_asserts.go
+++ b/android/test_asserts.go
@@ -148,7 +148,7 @@
return
}
if !ok {
- t.Errorf("%s does not match regular expression %s", s, expectedRex)
+ t.Errorf("%s: %s does not match regular expression %s", message, s, expectedRex)
}
}
diff --git a/cc/Android.bp b/cc/Android.bp
index c32d854..8fa0fbe 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -18,6 +18,7 @@
"soong-genrule",
"soong-multitree",
"soong-snapshot",
+ "soong-sysprop-bp2build",
"soong-tradefed",
],
srcs: [
@@ -49,7 +50,6 @@
"snapshot_utils.go",
"stl.go",
"strip.go",
- "sysprop.go",
"tidy.go",
"util.go",
"vendor_snapshot.go",
diff --git a/cc/config/riscv64_device.go b/cc/config/riscv64_device.go
index e048622..d5bc760 100644
--- a/cc/config/riscv64_device.go
+++ b/cc/config/riscv64_device.go
@@ -27,6 +27,9 @@
"-Werror=implicit-function-declaration",
"-fno-emulated-tls",
"-march=rv64gcv_zba_zbb_zbs",
+ // Equivalent to "-munaligned-access", but our clang doesn't have that yet.
+ "-Xclang -target-feature -Xclang +unaligned-scalar-mem",
+ "-Xclang -target-feature -Xclang +unaligned-vector-mem",
}
riscv64ArchVariantCflags = map[string][]string{}
@@ -34,6 +37,9 @@
riscv64Ldflags = []string{
"-Wl,--hash-style=gnu",
"-march=rv64gcv_zba_zbb_zbs",
+ // Equivalent to "-munaligned-access", but our clang doesn't have that yet.
+ "-Xclang -target-feature -Xclang +unaligned-scalar-mem",
+ "-Xclang -target-feature -Xclang +unaligned-vector-mem",
}
riscv64Lldflags = append(riscv64Ldflags,
diff --git a/cc/gen.go b/cc/gen.go
index b15f164..151f23d 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -20,6 +20,7 @@
"android/soong/aidl_library"
"android/soong/bazel"
+ "android/soong/sysprop/bp2build"
"github.com/google/blueprint"
@@ -240,12 +241,13 @@
}
func bp2buildCcSysprop(ctx android.Bp2buildMutatorContext, moduleName string, minSdkVersion *string, srcs bazel.LabelListAttribute) *bazel.LabelAttribute {
- labels := SyspropLibraryLabels{
- SyspropLibraryLabel: moduleName + "_sysprop_library",
- StaticLibraryLabel: moduleName + "_cc_sysprop_library_static",
+ labels := bp2build.SyspropLibraryLabels{
+ SyspropLibraryLabel: moduleName + "_sysprop_library",
+ CcStaticLibraryLabel: moduleName + "_cc_sysprop_library_static",
}
- Bp2buildSysprop(ctx, labels, srcs, minSdkVersion)
- return createLabelAttributeCorrespondingToSrcs(":"+labels.StaticLibraryLabel, srcs)
+ bp2build.Bp2buildBaseSyspropLibrary(ctx, labels.SyspropLibraryLabel, srcs)
+ bp2build.Bp2buildSyspropCc(ctx, labels, minSdkVersion)
+ return createLabelAttributeCorrespondingToSrcs(":"+labels.CcStaticLibraryLabel, srcs)
}
// Creates a LabelAttribute for a given label where the value is only set for
diff --git a/cc/library_headers.go b/cc/library_headers.go
index fccdf99..4da2b48 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -161,18 +161,3 @@
Tags: tags,
}, attrs)
}
-
-// Append .contribution suffix to input labels
-func apiBazelTargets(ll bazel.LabelList) bazel.LabelList {
- labels := make([]bazel.Label, 0)
- for _, l := range ll.Includes {
- labels = append(labels, bazel.Label{
- Label: android.ApiContributionTargetName(l.Label),
- })
- }
- return bazel.MakeLabelList(labels)
-}
-
-var (
- allArches = []string{"arm", "arm64", "x86", "x86_64"}
-)
diff --git a/cc/sysprop.go b/cc/sysprop.go
deleted file mode 100644
index be03004..0000000
--- a/cc/sysprop.go
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright (C) 2019 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 cc
-
-import (
- "android/soong/android"
- "android/soong/bazel"
-)
-
-// TODO(b/240463568): Additional properties will be added for API validation
-type bazelSyspropLibraryAttributes struct {
- Srcs bazel.LabelListAttribute
- Tags bazel.StringListAttribute
-}
-
-type bazelCcSyspropLibraryAttributes struct {
- Dep bazel.LabelAttribute
- Min_sdk_version *string
- Tags bazel.StringListAttribute
-}
-
-type SyspropLibraryLabels struct {
- SyspropLibraryLabel string
- SharedLibraryLabel string
- StaticLibraryLabel string
-}
-
-func Bp2buildSysprop(ctx android.Bp2buildMutatorContext, labels SyspropLibraryLabels, srcs bazel.LabelListAttribute, minSdkVersion *string) {
- apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx, ctx.Module())
- ctx.CreateBazelTargetModule(
- bazel.BazelTargetModuleProperties{
- Rule_class: "sysprop_library",
- Bzl_load_location: "//build/bazel/rules/sysprop:sysprop_library.bzl",
- },
- android.CommonAttributes{Name: labels.SyspropLibraryLabel},
- &bazelSyspropLibraryAttributes{
- Srcs: srcs,
- Tags: apexAvailableTags,
- },
- )
-
- attrs := &bazelCcSyspropLibraryAttributes{
- Dep: *bazel.MakeLabelAttribute(":" + labels.SyspropLibraryLabel),
- Min_sdk_version: minSdkVersion,
- Tags: apexAvailableTags,
- }
-
- if labels.SharedLibraryLabel != "" {
- ctx.CreateBazelTargetModule(
- bazel.BazelTargetModuleProperties{
- Rule_class: "cc_sysprop_library_shared",
- Bzl_load_location: "//build/bazel/rules/cc:cc_sysprop_library.bzl",
- },
- android.CommonAttributes{Name: labels.SharedLibraryLabel},
- attrs)
- }
-
- ctx.CreateBazelTargetModule(
- bazel.BazelTargetModuleProperties{
- Rule_class: "cc_sysprop_library_static",
- Bzl_load_location: "//build/bazel/rules/cc:cc_sysprop_library.bzl",
- },
- android.CommonAttributes{Name: labels.StaticLibraryLabel},
- attrs)
-}
diff --git a/sysprop/Android.bp b/sysprop/Android.bp
index e5263fe..7f51000 100644
--- a/sysprop/Android.bp
+++ b/sysprop/Android.bp
@@ -12,6 +12,7 @@
"soong-bp2build",
"soong-cc",
"soong-java",
+ "soong-sysprop-bp2build",
],
srcs: [
"sysprop_library.go",
diff --git a/sysprop/bp2build/Android.bp b/sysprop/bp2build/Android.bp
new file mode 100644
index 0000000..1b9eda8
--- /dev/null
+++ b/sysprop/bp2build/Android.bp
@@ -0,0 +1,16 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+ name: "soong-sysprop-bp2build",
+ pkgPath: "android/soong/sysprop/bp2build",
+ deps: [
+ "soong-android",
+ "soong-bazel",
+ ],
+ srcs: [
+ "bp2build.go",
+ ],
+ pluginFor: ["soong_build"],
+}
diff --git a/sysprop/bp2build/bp2build.go b/sysprop/bp2build/bp2build.go
new file mode 100644
index 0000000..18991de
--- /dev/null
+++ b/sysprop/bp2build/bp2build.go
@@ -0,0 +1,106 @@
+// Copyright (C) 2019 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 bp2build
+
+import (
+ "android/soong/android"
+ "android/soong/bazel"
+)
+
+type SyspropLibraryLabels struct {
+ SyspropLibraryLabel string
+ CcSharedLibraryLabel string
+ CcStaticLibraryLabel string
+ JavaLibraryLabel string
+}
+
+// TODO(b/240463568): Additional properties will be added for API validation
+type bazelSyspropLibraryAttributes struct {
+ Srcs bazel.LabelListAttribute
+ Tags bazel.StringListAttribute
+}
+
+func Bp2buildBaseSyspropLibrary(ctx android.Bp2buildMutatorContext, name string, srcs bazel.LabelListAttribute) {
+ apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.Bp2buildMutatorContext), ctx.Module())
+
+ ctx.CreateBazelTargetModule(
+ bazel.BazelTargetModuleProperties{
+ Rule_class: "sysprop_library",
+ Bzl_load_location: "//build/bazel/rules/sysprop:sysprop_library.bzl",
+ },
+ android.CommonAttributes{Name: name},
+ &bazelSyspropLibraryAttributes{
+ Srcs: srcs,
+ Tags: apexAvailableTags,
+ },
+ )
+}
+
+type bazelCcSyspropLibraryAttributes struct {
+ Dep bazel.LabelAttribute
+ Min_sdk_version *string
+ Tags bazel.StringListAttribute
+}
+
+func Bp2buildSyspropCc(ctx android.Bp2buildMutatorContext, labels SyspropLibraryLabels, minSdkVersion *string) {
+ apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.Bp2buildMutatorContext), ctx.Module())
+
+ attrs := &bazelCcSyspropLibraryAttributes{
+ Dep: *bazel.MakeLabelAttribute(":" + labels.SyspropLibraryLabel),
+ Min_sdk_version: minSdkVersion,
+ Tags: apexAvailableTags,
+ }
+
+ if labels.CcSharedLibraryLabel != "" {
+ ctx.CreateBazelTargetModule(
+ bazel.BazelTargetModuleProperties{
+ Rule_class: "cc_sysprop_library_shared",
+ Bzl_load_location: "//build/bazel/rules/cc:cc_sysprop_library.bzl",
+ },
+ android.CommonAttributes{Name: labels.CcSharedLibraryLabel},
+ attrs)
+ }
+ if labels.CcStaticLibraryLabel != "" {
+ ctx.CreateBazelTargetModule(
+ bazel.BazelTargetModuleProperties{
+ Rule_class: "cc_sysprop_library_static",
+ Bzl_load_location: "//build/bazel/rules/cc:cc_sysprop_library.bzl",
+ },
+ android.CommonAttributes{Name: labels.CcStaticLibraryLabel},
+ attrs)
+ }
+}
+
+type bazelJavaLibraryAttributes struct {
+ Dep bazel.LabelAttribute
+ Min_sdk_version *string
+ Tags bazel.StringListAttribute
+}
+
+func Bp2buildSyspropJava(ctx android.Bp2buildMutatorContext, labels SyspropLibraryLabels, minSdkVersion *string) {
+ apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.Bp2buildMutatorContext), ctx.Module())
+
+ ctx.CreateBazelTargetModule(
+ bazel.BazelTargetModuleProperties{
+ Rule_class: "java_sysprop_library",
+ Bzl_load_location: "//build/bazel/rules/java:java_sysprop_library.bzl",
+ },
+ android.CommonAttributes{Name: labels.JavaLibraryLabel},
+ &bazelJavaLibraryAttributes{
+ Dep: *bazel.MakeLabelAttribute(":" + labels.SyspropLibraryLabel),
+ Min_sdk_version: minSdkVersion,
+ Tags: apexAvailableTags,
+ })
+}
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index d16bf32..13cf68f 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -24,6 +24,8 @@
"sync"
"android/soong/bazel"
+ "android/soong/sysprop/bp2build"
+ "android/soong/ui/metrics/bp2build_metrics_proto"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -230,6 +232,10 @@
return m.BaseModuleName() + "_java_gen_public"
}
+func (m *syspropLibrary) bp2buildJavaImplementationModuleName() string {
+ return m.BaseModuleName() + "_java_library"
+}
+
func (m *syspropLibrary) BaseModuleName() string {
return m.ModuleBase.Name()
}
@@ -431,6 +437,7 @@
Min_sdk_version *string
Bazel_module struct {
Bp2build_available *bool
+ Label *string
}
}
@@ -551,8 +558,10 @@
Min_sdk_version: m.properties.Java.Min_sdk_version,
Bazel_module: struct {
Bp2build_available *bool
+ Label *string
}{
- Bp2build_available: proptools.BoolPtr(false),
+ Label: proptools.StringPtr(
+ fmt.Sprintf("//%s:%s", ctx.ModuleDir(), m.bp2buildJavaImplementationModuleName())),
},
})
@@ -573,6 +582,7 @@
Stem: proptools.StringPtr(m.BaseModuleName()),
Bazel_module: struct {
Bp2build_available *bool
+ Label *string
}{
Bp2build_available: proptools.BoolPtr(false),
},
@@ -592,13 +602,17 @@
// TODO(b/240463568): Additional properties will be added for API validation
func (m *syspropLibrary) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
- labels := cc.SyspropLibraryLabels{
- SyspropLibraryLabel: m.BaseModuleName(),
- SharedLibraryLabel: m.CcImplementationModuleName(),
- StaticLibraryLabel: cc.BazelLabelNameForStaticModule(m.CcImplementationModuleName()),
+ if m.Owner() != "Platform" {
+ ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_UNSUPPORTED, "Only sysprop libraries owned by platform are supported at this time")
+ return
}
- cc.Bp2buildSysprop(ctx,
- labels,
- bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.properties.Srcs)),
- m.properties.Cpp.Min_sdk_version)
+ labels := bp2build.SyspropLibraryLabels{
+ SyspropLibraryLabel: m.BaseModuleName(),
+ CcSharedLibraryLabel: m.CcImplementationModuleName(),
+ CcStaticLibraryLabel: cc.BazelLabelNameForStaticModule(m.CcImplementationModuleName()),
+ JavaLibraryLabel: m.bp2buildJavaImplementationModuleName(),
+ }
+ bp2build.Bp2buildBaseSyspropLibrary(ctx, labels.SyspropLibraryLabel, bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.properties.Srcs)))
+ bp2build.Bp2buildSyspropCc(ctx, labels, m.properties.Cpp.Min_sdk_version)
+ bp2build.Bp2buildSyspropJava(ctx, labels, m.properties.Java.Min_sdk_version)
}
diff --git a/sysprop/sysprop_library_conversion_test.go b/sysprop/sysprop_library_conversion_test.go
index 89adf7d..dabcc92 100644
--- a/sysprop/sysprop_library_conversion_test.go
+++ b/sysprop/sysprop_library_conversion_test.go
@@ -58,13 +58,18 @@
bp2build.AttrNameToString{
"dep": `":sysprop_foo"`,
}),
+ bp2build.MakeBazelTargetNoRestrictions("java_sysprop_library",
+ "sysprop_foo_java_library",
+ bp2build.AttrNameToString{
+ "dep": `":sysprop_foo"`,
+ }),
},
})
}
func TestSyspropLibraryCppMinSdkVersion(t *testing.T) {
bp2build.RunBp2BuildTestCaseSimple(t, bp2build.Bp2buildTestCase{
- Description: "sysprop_library with min_sdk_version",
+ Description: "sysprop_library with cpp min_sdk_version",
ModuleTypeUnderTest: "sysprop_library",
ModuleTypeUnderTestFactory: syspropLibraryFactory,
Filesystem: map[string]string{
@@ -105,6 +110,86 @@
"dep": `":sysprop_foo"`,
"min_sdk_version": `"5"`,
}),
+ bp2build.MakeBazelTargetNoRestrictions("java_sysprop_library",
+ "sysprop_foo_java_library",
+ bp2build.AttrNameToString{
+ "dep": `":sysprop_foo"`,
+ }),
},
})
}
+
+func TestSyspropLibraryJavaMinSdkVersion(t *testing.T) {
+ bp2build.RunBp2BuildTestCaseSimple(t, bp2build.Bp2buildTestCase{
+ Description: "sysprop_library with java min_sdk_version",
+ ModuleTypeUnderTest: "sysprop_library",
+ ModuleTypeUnderTestFactory: syspropLibraryFactory,
+ Filesystem: map[string]string{
+ "foo.sysprop": "",
+ "bar.sysprop": "",
+ },
+ Blueprint: `
+sysprop_library {
+ name: "sysprop_foo",
+ srcs: [
+ "foo.sysprop",
+ "bar.sysprop",
+ ],
+ java: {
+ min_sdk_version: "5",
+ },
+ property_owner: "Platform",
+}
+`,
+ ExpectedBazelTargets: []string{
+ bp2build.MakeBazelTargetNoRestrictions("sysprop_library",
+ "sysprop_foo",
+ bp2build.AttrNameToString{
+ "srcs": `[
+ "foo.sysprop",
+ "bar.sysprop",
+ ]`,
+ }),
+ bp2build.MakeBazelTargetNoRestrictions("cc_sysprop_library_shared",
+ "libsysprop_foo",
+ bp2build.AttrNameToString{
+ "dep": `":sysprop_foo"`,
+ }),
+ bp2build.MakeBazelTargetNoRestrictions("cc_sysprop_library_static",
+ "libsysprop_foo_bp2build_cc_library_static",
+ bp2build.AttrNameToString{
+ "dep": `":sysprop_foo"`,
+ }),
+ bp2build.MakeBazelTargetNoRestrictions("java_sysprop_library",
+ "sysprop_foo_java_library",
+ bp2build.AttrNameToString{
+ "dep": `":sysprop_foo"`,
+ "min_sdk_version": `"5"`,
+ }),
+ },
+ })
+}
+
+func TestSyspropLibraryOwnerNotPlatformUnconvertible(t *testing.T) {
+ bp2build.RunBp2BuildTestCaseSimple(t, bp2build.Bp2buildTestCase{
+ Description: "sysprop_library simple",
+ ModuleTypeUnderTest: "sysprop_library",
+ ModuleTypeUnderTestFactory: syspropLibraryFactory,
+ Filesystem: map[string]string{
+ "foo.sysprop": "",
+ "bar.sysprop": "",
+ },
+ Blueprint: `
+sysprop_library {
+ name: "sysprop_foo",
+ srcs: [
+ "foo.sysprop",
+ "bar.sysprop",
+ ],
+ property_owner: "Vendor",
+ device_specific: true,
+}
+`,
+ ExpectedBazelTargets: []string{},
+ })
+}
diff --git a/tests/lib.sh b/tests/lib.sh
index dbb10b7..fb3b374 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -8,6 +8,11 @@
REAL_TOP="$(readlink -f "$(dirname "$0")"/../../..)"
+function make_mock_top {
+ mock=$(mktemp -t -d st.XXXXX)
+ echo "$mock"
+}
+
if [[ -n "$HARDWIRED_MOCK_TOP" ]]; then
MOCK_TOP="$HARDWIRED_MOCK_TOP"
else
@@ -198,3 +203,11 @@
info "Completed test case \e[96;1m$f\e[0m"
done
}
+
+function move_mock_top {
+ MOCK_TOP2=$(make_mock_top)
+ rm -rf $MOCK_TOP2
+ mv $MOCK_TOP $MOCK_TOP2
+ MOCK_TOP=$MOCK_TOP2
+ trap cleanup_mock_top EXIT
+}
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index 6b9ff8b..223baa4 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -23,4 +23,4 @@
"$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_cf_arm64_phone" "armv8-a" "cortex-a53"
"$TOP/build/bazel/ci/b_test.sh"
-
+"$TOP/build/soong/tests/symlinks_path_test.sh"
diff --git a/tests/symlinks_path_test.sh b/tests/symlinks_path_test.sh
new file mode 100755
index 0000000..ed42911
--- /dev/null
+++ b/tests/symlinks_path_test.sh
@@ -0,0 +1,51 @@
+#!/bin/bash -eu
+
+set -o pipefail
+
+# Test that relative symlinks work by recreating the bug in b/259191764
+# In some cases, developers prefer to move their checkouts. This causes
+# issues in that symlinked files (namely, the bazel wrapper script)
+# cannot be found. As such, we implemented relative symlinks so that a
+# moved checkout doesn't need a full clean before rebuilding.
+# The bazel output base will still need to be removed, as Starlark
+# doesn't seem to support relative symlinks yet.
+
+source "$(dirname "$0")/lib.sh"
+
+function check_link_has_mock_top_prefix {
+ input_link=$1
+ link_target=`readlink $input_link`
+ if [[ $link_target != "$MOCK_TOP"* ]]; then
+ echo "Symlink for file $input_link -> $link_target doesn't start with $MOCK_TOP"
+ exit 1
+ fi
+}
+
+function test_symlinks_updated_when_top_dir_changed {
+ setup
+
+ mkdir -p a
+ touch a/g.txt
+ cat > a/Android.bp <<'EOF'
+filegroup {
+ name: "g",
+ srcs: ["g.txt"],
+ bazel_module: {bp2build_available: true},
+}
+EOF
+ # A directory under $MOCK_TOP
+ outdir=out2
+
+ # Modify OUT_DIR in a subshell so it doesn't affect the top level one.
+ (export OUT_DIR=$MOCK_TOP/$outdir; run_soong bp2build && run_bazel build --config=bp2build --config=ci //a:g)
+
+ g_txt="out2/soong/workspace/a/g.txt"
+ check_link_has_mock_top_prefix "$g_txt"
+
+ move_mock_top
+
+ (export OUT_DIR=$MOCK_TOP/$outdir; run_soong bp2build && run_bazel build --config=bp2build --config=ci //a:g)
+ check_link_has_mock_top_prefix "$g_txt"
+}
+
+scan_and_run_tests
\ No newline at end of file
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 44c20a0..ac9bf3a 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -16,10 +16,13 @@
import (
"fmt"
+ "io/fs"
"os"
"path/filepath"
"strconv"
"strings"
+ "sync"
+ "sync/atomic"
"android/soong/bazel"
"android/soong/ui/metrics"
@@ -50,6 +53,13 @@
bootstrapEpoch = 1
)
+var (
+ // Used during parallel update of symlinks in out directory to reflect new
+ // TOP dir.
+ symlinkWg sync.WaitGroup
+ numFound, numUpdated uint32
+)
+
func writeEnvironmentFile(_ Context, envFile string, envDeps map[string]string) error {
data, err := shared.EnvFileContents(envDeps)
if err != nil {
@@ -465,10 +475,118 @@
}
}
+func updateSymlinks(ctx Context, dir, prevCWD, cwd string) error {
+ defer symlinkWg.Done()
+
+ visit := func(path string, d fs.DirEntry, err error) error {
+ if d.IsDir() && path != dir {
+ symlinkWg.Add(1)
+ go updateSymlinks(ctx, path, prevCWD, cwd)
+ return filepath.SkipDir
+ }
+ f, err := d.Info()
+ if err != nil {
+ return err
+ }
+ // If the file is not a symlink, we don't have to update it.
+ if f.Mode()&os.ModeSymlink != os.ModeSymlink {
+ return nil
+ }
+
+ atomic.AddUint32(&numFound, 1)
+ target, err := os.Readlink(path)
+ if err != nil {
+ return err
+ }
+ if strings.HasPrefix(target, prevCWD) &&
+ (len(target) == len(prevCWD) || target[len(prevCWD)] == '/') {
+ target = filepath.Join(cwd, target[len(prevCWD):])
+ if err := os.Remove(path); err != nil {
+ return err
+ }
+ if err := os.Symlink(target, path); err != nil {
+ return err
+ }
+ atomic.AddUint32(&numUpdated, 1)
+ }
+ return nil
+ }
+
+ if err := filepath.WalkDir(dir, visit); err != nil {
+ return err
+ }
+ return nil
+}
+
+func fixOutDirSymlinks(ctx Context, config Config, outDir string) error {
+ cwd, err := os.Getwd()
+ if err != nil {
+ return err
+ }
+
+ // Record the .top as the very last thing in the function.
+ tf := filepath.Join(outDir, ".top")
+ defer func() {
+ if err := os.WriteFile(tf, []byte(cwd), 0644); err != nil {
+ fmt.Fprintf(os.Stderr, fmt.Sprintf("Unable to log CWD: %v", err))
+ }
+ }()
+
+ // Find the previous working directory if it was recorded.
+ var prevCWD string
+ pcwd, err := os.ReadFile(tf)
+ if err != nil {
+ if os.IsNotExist(err) {
+ // No previous working directory recorded, nothing to do.
+ return nil
+ }
+ return err
+ }
+ prevCWD = strings.Trim(string(pcwd), "\n")
+
+ if prevCWD == cwd {
+ // We are in the same source dir, nothing to update.
+ return nil
+ }
+
+ symlinkWg.Add(1)
+ if err := updateSymlinks(ctx, outDir, prevCWD, cwd); err != nil {
+ return err
+ }
+ symlinkWg.Wait()
+ ctx.Println(fmt.Sprintf("Updated %d/%d symlinks in dir %v", numUpdated, numFound, outDir))
+ return nil
+}
+
+func migrateOutputSymlinks(ctx Context, config Config) error {
+ // Figure out the real out directory ("out" could be a symlink).
+ outDir := config.OutDir()
+ s, err := os.Lstat(outDir)
+ if err != nil {
+ if os.IsNotExist(err) {
+ // No out dir exists, no symlinks to migrate.
+ return nil
+ }
+ return err
+ }
+ if s.Mode()&os.ModeSymlink == os.ModeSymlink {
+ target, err := filepath.EvalSymlinks(outDir)
+ if err != nil {
+ return err
+ }
+ outDir = target
+ }
+ return fixOutDirSymlinks(ctx, config, outDir)
+}
+
func runSoong(ctx Context, config Config) {
ctx.BeginTrace(metrics.RunSoong, "soong")
defer ctx.EndTrace()
+ if err := migrateOutputSymlinks(ctx, config); err != nil {
+ ctx.Fatalf("failed to migrate output directory to current TOP dir: %v", err)
+ }
+
// We have two environment files: .available is the one with every variable,
// .used with the ones that were actually used. The latter is used to
// determine whether Soong needs to be re-run since why re-run it if only