Merge "Get rid of DeviceName() from path related to dexpreopt"
diff --git a/OWNERS b/OWNERS
index 964e27a..0234f27 100644
--- a/OWNERS
+++ b/OWNERS
@@ -3,7 +3,6 @@
# AMER
agespino@google.com
-alexmarquez@google.com
ccross@android.com
colefaust@google.com
cparsons@google.com
diff --git a/android/Android.bp b/android/Android.bp
index 641c438..118087d 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -17,6 +17,7 @@
"soong-remoteexec",
"soong-response",
"soong-shared",
+ "soong-starlark",
"soong-starlark-format",
"soong-ui-metrics_proto",
"soong-android-allowlists",
@@ -60,7 +61,6 @@
"license_metadata.go",
"license_sdk_member.go",
"licenses.go",
- "makefile_goal.go",
"makevars.go",
"metrics.go",
"module.go",
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 7f3dd2d..6bd4e26 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -183,6 +183,7 @@
"external/selinux/libselinux": Bp2BuildDefaultTrueRecursively,
"external/selinux/libsepol": Bp2BuildDefaultTrueRecursively,
"external/speex": Bp2BuildDefaultTrueRecursively,
+ "external/sqlite": Bp2BuildDefaultTrueRecursively,
"external/tinyalsa": Bp2BuildDefaultTrueRecursively,
"external/tinyalsa_new": Bp2BuildDefaultTrueRecursively,
"external/toybox": Bp2BuildDefaultTrueRecursively,
@@ -191,16 +192,18 @@
"external/zstd": Bp2BuildDefaultTrueRecursively,
"frameworks/av": Bp2BuildDefaultTrue,
+ "frameworks/av/media/audioaidlconversion": Bp2BuildDefaultTrueRecursively,
"frameworks/av/media/codec2/components/aom": Bp2BuildDefaultTrueRecursively,
"frameworks/av/media/codecs": Bp2BuildDefaultTrueRecursively,
"frameworks/av/media/liberror": Bp2BuildDefaultTrueRecursively,
+ "frameworks/av/media/libmediahelper": Bp2BuildDefaultTrue,
"frameworks/av/media/libshmem": Bp2BuildDefaultTrueRecursively,
- "frameworks/av/media/audioaidlconversion": Bp2BuildDefaultTrueRecursively,
"frameworks/av/media/module/minijail": Bp2BuildDefaultTrueRecursively,
"frameworks/av/services/minijail": Bp2BuildDefaultTrueRecursively,
"frameworks/base/libs/androidfw": Bp2BuildDefaultTrue,
"frameworks/base/media/tests/MediaDump": Bp2BuildDefaultTrue,
"frameworks/base/services/tests/servicestests/aidl": Bp2BuildDefaultTrue,
+ "frameworks/base/proto": Bp2BuildDefaultTrue,
"frameworks/base/startop/apps/test": Bp2BuildDefaultTrue,
"frameworks/base/tests/appwidgets/AppWidgetHostTest": Bp2BuildDefaultTrueRecursively,
"frameworks/base/tools/aapt2": Bp2BuildDefaultTrue,
@@ -212,13 +215,13 @@
"frameworks/native/libs/gui": Bp2BuildDefaultTrue,
"frameworks/native/libs/math": Bp2BuildDefaultTrueRecursively,
"frameworks/native/libs/nativebase": Bp2BuildDefaultTrueRecursively,
+ "frameworks/native/libs/permission": Bp2BuildDefaultTrueRecursively,
"frameworks/native/libs/vr": Bp2BuildDefaultTrueRecursively,
"frameworks/native/opengl/tests/gl2_cameraeye": Bp2BuildDefaultTrue,
"frameworks/native/opengl/tests/gl2_java": Bp2BuildDefaultTrue,
"frameworks/native/opengl/tests/testLatency": Bp2BuildDefaultTrue,
"frameworks/native/opengl/tests/testPauseResume": Bp2BuildDefaultTrue,
"frameworks/native/opengl/tests/testViewport": Bp2BuildDefaultTrue,
- "frameworks/native/libs/permission": Bp2BuildDefaultTrue,
"frameworks/native/services/batteryservice": Bp2BuildDefaultTrue,
"frameworks/proto_logging/stats": Bp2BuildDefaultTrueRecursively,
@@ -290,20 +293,24 @@
"packages/modules/Gki/libkver": Bp2BuildDefaultTrue,
"packages/modules/NetworkStack/common/captiveportal": Bp2BuildDefaultTrue,
"packages/modules/NeuralNetworks/apex": Bp2BuildDefaultTrue,
+ "packages/modules/NeuralNetworks/apex/testing": Bp2BuildDefaultTrue,
"packages/providers/MediaProvider/tools/dialogs": Bp2BuildDefaultFalse, // TODO(b/242834374)
"packages/screensavers/Basic": Bp2BuildDefaultTrue,
"packages/services/Car/tests/SampleRearViewCamera": Bp2BuildDefaultFalse, // TODO(b/242834321)
"platform_testing/tests/example": Bp2BuildDefaultTrueRecursively,
- "prebuilts/clang/host/linux-x86": Bp2BuildDefaultTrueRecursively,
- "prebuilts/gradle-plugin": Bp2BuildDefaultTrueRecursively,
- "prebuilts/runtime/mainline/platform/sdk": Bp2BuildDefaultTrueRecursively,
- "prebuilts/sdk/current/androidx": Bp2BuildDefaultTrue,
- "prebuilts/sdk/current/extras/app-toolkit": Bp2BuildDefaultTrue,
- "prebuilts/sdk/current/support": Bp2BuildDefaultTrue,
- "prebuilts/tools": Bp2BuildDefaultTrue,
- "prebuilts/tools/common/m2": Bp2BuildDefaultTrue,
+ "prebuilts/clang/host/linux-x86": Bp2BuildDefaultTrueRecursively,
+ "prebuilts/gradle-plugin": Bp2BuildDefaultTrueRecursively,
+ "prebuilts/runtime/mainline/platform/sdk": Bp2BuildDefaultTrueRecursively,
+ "prebuilts/sdk/current/androidx": Bp2BuildDefaultTrue,
+ "prebuilts/sdk/current/androidx-legacy": Bp2BuildDefaultTrue,
+ "prebuilts/sdk/current/extras/constraint-layout-x": Bp2BuildDefaultTrue,
+ "prebuilts/sdk/current/extras/material-design-x": Bp2BuildDefaultTrue,
+ "prebuilts/sdk/current/extras/app-toolkit": Bp2BuildDefaultTrue,
+ "prebuilts/sdk/current/support": Bp2BuildDefaultTrue,
+ "prebuilts/tools": Bp2BuildDefaultTrue,
+ "prebuilts/tools/common/m2": Bp2BuildDefaultTrue,
"sdk/dumpeventlog": Bp2BuildDefaultTrue,
"sdk/eventanalyzer": Bp2BuildDefaultTrue,
@@ -375,8 +382,10 @@
"system/tools/xsdc/utils": Bp2BuildDefaultTrueRecursively,
"system/unwinding/libunwindstack": Bp2BuildDefaultTrueRecursively,
- "tools/apksig": Bp2BuildDefaultTrue,
- "tools/metalava": Bp2BuildDefaultTrue,
+ "tools/apifinder": Bp2BuildDefaultTrue,
+ "tools/apksig": Bp2BuildDefaultTrue,
+ "tools/external_updater": Bp2BuildDefaultTrueRecursively,
+ "tools/metalava": Bp2BuildDefaultTrue,
"tools/platform-compat/java/android/compat": Bp2BuildDefaultTrueRecursively,
"tools/tradefederation/prebuilts/filegroups": Bp2BuildDefaultTrueRecursively,
}
@@ -408,8 +417,6 @@
// this BUILD file is globbed by //external/icu/icu4c/source:icu4c_test_data's "data/**/*".
"external/icu/icu4c/source/data/unidata/norm2":/* recursive = */ false,
- "frameworks/ex/common":/* recursive = */ true,
-
// Building manually due to b/179889880: resource files cross package boundary
"packages/apps/Music":/* recursive = */ true,
@@ -455,7 +462,6 @@
"framework-connectivity-protos",
"gemmlowp_headers",
"gl_headers",
- "ipconnectivity-proto-src",
"libandroid_runtime_lazy",
"libandroid_runtime_vm_headers",
"libaudioclient_aidl_conversion_util",
@@ -475,6 +481,7 @@
"libgralloctypes",
"libnativewindow",
"libneuralnetworks",
+ "libneuralnetworks_static",
"libgraphicsenv",
"libhardware",
"libhardware_headers",
@@ -541,6 +548,14 @@
"liblp",
"libstorage_literals_headers",
+ "PluginCoreLib",
+ "dagger2",
+ "dagger2-android-annotation-stubs",
+ "dagger2-bootstrap-compiler",
+ "dagger2-producers",
+ "okio-lib",
+ "setupdesign-strings",
+
//external/avb
"avbtool",
"libavb",
@@ -689,7 +704,6 @@
"libcodec2_soft_common",
// kotlin srcs in java libs
- "CtsPkgInstallerConstants",
"kotlinx_atomicfu",
// kotlin srcs in java binary
@@ -702,6 +716,9 @@
//kotlin srcs in android_binary
"MusicKotlin",
+ // java_library with prebuilt sdk_version
+ "android-common",
+
// checked in current.txt for merged_txts
"non-updatable-current.txt",
"non-updatable-system-current.txt",
@@ -712,11 +729,12 @@
"api_fingerprint",
// allowlisting for kotlinx_coroutines
+ "annotations",
+ "kotlinx-coroutines-android-annotation-stubs",
+ "kotlinx-coroutines-core",
"kotlinx_coroutines",
"kotlinx_coroutines-device",
"kotlinx_coroutines-host",
- "annotations",
- "kotlinx-coroutines-android-annotation-stubs",
// for building com.android.neuralnetworks
"libimapper_stablec",
@@ -724,7 +742,11 @@
// min_sdk_version in android_app
"CtsShimUpgrade",
- "fake-framework",
+
+ "art_cmdlineparser_headers",
+
+ // Mainline Module Apps
+ "CaptivePortalLogin",
}
Bp2buildModuleTypeAlwaysConvertList = []string{
@@ -756,7 +778,6 @@
"buffer_hub_queue_producer-test",
// cc bugs
- "libactivitymanager_aidl", // TODO(b/207426160): Unsupported use of aidl sources (via Dactivity_manager_procstate_aidl) in a cc_library
// TODO(b/198619163) module has same name as source
"logtagd.rc",
@@ -769,16 +790,16 @@
"libcutils_test_static",
"KernelLibcutilsTest",
- "linker", // TODO(b/228316882): cc_binary uses link_crt
- "versioner", // TODO(b/228313961): depends on prebuilt shared library libclang-cpp_host as a shared library, which does not supply expected providers for a shared library
- "art_libartbase_headers", // TODO(b/236268577): Header libraries do not support export_shared_libs_headers
- "apexer_test", // Requires aapt2
- "apexer_test_host_tools",
- "host_apex_verifier",
- "tjbench", // TODO(b/240563612): Stem property
+ "linker", // TODO(b/228316882): cc_binary uses link_crt
+ "versioner", // TODO(b/228313961): depends on prebuilt shared library libclang-cpp_host as a shared library, which does not supply expected providers for a shared library
+ "tjbench", // TODO(b/240563612): Stem property
+
+ // requires host tools for apexer
+ "apexer_test", "apexer_test_host_tools", "host_apex_verifier",
// java bugs
- "libbase_ndk", // TODO(b/186826477): fails to link libctscamera2_jni for device (required for CtsCameraTestCases)
+ "libbase_ndk", // TODO(b/186826477): fails to link libctscamera2_jni for device (required for CtsCameraTestCases)
+ "bouncycastle", // TODO(b/274474005): Need support for custom system_modules.
// python protos
"libprotobuf-python", // Has a handcrafted alternative
@@ -804,6 +825,7 @@
// go deps:
"analyze_bcpf", // depends on bpmodify a blueprint_go_binary.
+ "analyze_bcpf_test", // depends on bpmodify a blueprint_go_binary.
"host_bionic_linker_asm", // depends on extract_linker, a go binary.
"host_bionic_linker_script", // depends on extract_linker, a go binary.
@@ -814,13 +836,15 @@
"libtombstoned_client_rust_bridge_code", "libtombstoned_client_wrapper", // rust conversions are not supported
// unconverted deps
- "CarHTMLViewer", // depends on unconverted modules android.car-stubs, car-ui-lib
+ "apexer_with_DCLA_preprocessing_test", // depends on unconverted modules: apexer_test_host_tools, com.android.example.apex
"adb", // depends on unconverted modules: AdbWinApi, libandroidfw, libopenscreen-discovery, libopenscreen-platform-impl, libusb, bin2c_fastdeployagent, AdbWinUsbApi
"android_icu4j_srcgen", // depends on unconverted modules: currysrc
"android_icu4j_srcgen_binary", // depends on unconverted modules: android_icu4j_srcgen, currysrc
+ "apex_compression_test", // depends on unconverted modules: soong_zip, com.android.example.apex
"apex_manifest_proto_java", // b/210751803, depends on libprotobuf-java-full
"art-script", // depends on unconverted modules: dalvikvm, dex2oat
"bin2c_fastdeployagent", // depends on unconverted modules: deployagent
+ "CarHTMLViewer", // depends on unconverted modules android.car-stubs, car-ui-lib
"com.android.runtime", // depends on unconverted modules: bionic-linker-config, linkerconfig
"currysrc", // depends on unconverted modules: currysrc_org.eclipse, guavalib, jopt-simple-4.9
"dex2oat-script", // depends on unconverted modules: dex2oat
@@ -845,12 +869,12 @@
"libgmock_ndk", // depends on unconverted modules: libgtest_ndk_c++
"libnativehelper_lazy_mts_jni", "libnativehelper_mts_jni", // depends on unconverted modules: libnativetesthelper_jni, libgmock_ndk
"libnativetesthelper_jni", // depends on unconverted modules: libgtest_ndk_c++
- "libprotobuf-java-nano", // b/220869005, depends on non-public_current SDK
"libstatslog", // depends on unconverted modules: libstatspull, statsd-aidl-ndk
"libstatslog_art", // depends on unconverted modules: statslog_art.cpp, statslog_art.h
"linker_reloc_bench_main", // depends on unconverted modules: liblinker_reloc_bench_*
"malloc-rss-benchmark", // depends on unconverted modules: libmeminfo
"pbtombstone", "crash_dump", // depends on libdebuggerd, libunwindstack
+ "releasetools_test", // depends on unconverted modules: com.android.apex.compressed.v1
"robolectric-sqlite4java-0.282", // depends on unconverted modules: robolectric-sqlite4java-import, robolectric-sqlite4java-native
"static_crasher", // depends on unconverted modules: libdebuggerd_handler
"test_fips", // depends on unconverted modules: adb
@@ -927,6 +951,11 @@
"libandroidfw_tests", "aapt2_tests", // failing due to data path issues
+ // error: overriding commands for target
+ // `out/host/linux-x86/nativetest64/gmock_tests/gmock_tests__cc_runner_test',
+ // previously defined at out/soong/installs-aosp_arm.mk:64919`
+ "gmock_tests",
+
// cc_test with unconverted deps, or are device-only (and not verified to pass yet)
"AMRWBEncTest",
"AmrnbDecoderTest", // depends on unconverted modules: libaudioutils, libsndfile
@@ -1053,7 +1082,7 @@
"libcfi-test",
"libcfi-test-bad",
"libcrash_test",
- // "libcrypto_fuzz_unsafe",
+ "libcrypto_fuzz_unsafe",
"libdl_preempt_test_1",
"libdl_preempt_test_2",
"libdl_test_df_1_global",
@@ -1264,7 +1293,7 @@
"librelocations-fat",
"libsegment_gap_inner",
"libsegment_gap_outer",
- // "libssl_fuzz_unsafe",
+ "libssl_fuzz_unsafe",
"libstatssocket_private",
"libsysv-hash-table-library",
"libtest_atexit",
@@ -1395,6 +1424,26 @@
// TODO(b/266459895): depends on libunwindstack
"libutils_test",
+
+ // Has dependencies on other tools like ziptool, bp2build'd data properties don't work with these tests atm
+ "ziparchive_tests_large",
+ "mkbootimg_test",
+ "certify_bootimg_test",
+
+ // Despite being _host module types, these require devices to run
+ "logd_integration_test",
+ "mobly-hello-world-test",
+ "mobly-multidevice-test",
+
+ // TODO(b/274805756): Support core_platform and current java APIs
+ "fake-framework",
+
+ // TODO(b/277616982): These modules depend on private java APIs, but maybe they don't need to.
+ "StreamingProtoTest",
+ "textclassifierprotoslite",
+ "styleprotoslite",
+ "CtsPkgInstallerConstants",
+ "guava-android-testlib",
}
MixedBuildsDisabledList = []string{
@@ -1484,6 +1533,11 @@
"adb_tls_connection_test",
// M9: mixed builds for mainline trains launch
"api_fingerprint",
+ // M11: neuralnetworks launch
+ "com.android.neuralnetworks",
+ "test_com.android.neuralnetworks",
+ "libneuralnetworks",
+ "libneuralnetworks_static",
}
// Staging-mode allowlist. Modules in this list are only built
@@ -1491,9 +1545,7 @@
// which will soon be added to the prod allowlist.
// It is implicit that all modules in ProdMixedBuildsEnabledList will
// also be built - do not add them to this list.
- StagingMixedBuildsEnabledList = []string{
- "com.android.neuralnetworks",
- }
+ StagingMixedBuildsEnabledList = []string{}
// These should be the libs that are included by the apexes in the ProdMixedBuildsEnabledList
ProdDclaMixedBuildsEnabledList = []string{
diff --git a/android/apex.go b/android/apex.go
index 87bff74..6119b08 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -84,6 +84,9 @@
//
// See Prebuilt.ApexInfoMutator for more information.
ForPrebuiltApex bool
+
+ // Returns the name of the test apexes that this module is included in.
+ TestApexes []string
}
var ApexInfoProvider = blueprint.NewMutatorProvider(ApexInfo{}, "apex")
@@ -287,6 +290,9 @@
// See ApexModule.UniqueApexVariants()
UniqueApexVariationsForDeps bool `blueprint:"mutated"`
+
+ // The test apexes that includes this apex variant
+ TestApexes []string `blueprint:"mutated"`
}
// Marker interface that identifies dependencies that are excluded from APEX contents.
@@ -356,9 +362,18 @@
return m
}
+var (
+ availableToPlatformList = []string{AvailableToPlatform}
+)
+
// Implements ApexModule
func (m *ApexModuleBase) ApexAvailable() []string {
- return m.ApexProperties.Apex_available
+ aa := m.ApexProperties.Apex_available
+ if len(aa) > 0 {
+ return aa
+ }
+ // Default is availability to platform
+ return CopyOf(availableToPlatformList)
}
// Implements ApexModule
@@ -420,6 +435,11 @@
return nil
}
+// Returns the test apexes that this module is included in.
+func (m *ApexModuleBase) TestApexes() []string {
+ return m.ApexProperties.TestApexes
+}
+
// Implements ApexModule
func (m *ApexModuleBase) UniqueApexVariations() bool {
// If needed, this will bel overridden by concrete types inheriting
@@ -442,6 +462,14 @@
AvailableToGkiApex = "com.android.gki.*"
)
+var (
+ AvailableToRecognziedWildcards = []string{
+ AvailableToPlatform,
+ AvailableToAnyApex,
+ AvailableToGkiApex,
+ }
+)
+
// CheckAvailableForApex provides the default algorithm for checking the apex availability. When the
// availability is empty, it defaults to ["//apex_available:platform"] which means "available to the
// platform but not available to any APEX". When the list is not empty, `what` is matched against
@@ -540,12 +568,14 @@
// Platform APIs is allowed for this module only when all APEXes containing
// the module are with `use_platform_apis: true`.
merged[index].UsePlatformApis = merged[index].UsePlatformApis && apexInfo.UsePlatformApis
+ merged[index].TestApexes = append(merged[index].TestApexes, apexInfo.TestApexes...)
} else {
seen[mergedName] = len(merged)
apexInfo.ApexVariationName = mergedName
apexInfo.InApexVariants = CopyOf(apexInfo.InApexVariants)
apexInfo.InApexModules = CopyOf(apexInfo.InApexModules)
apexInfo.ApexContents = append([]*ApexContents(nil), apexInfo.ApexContents...)
+ apexInfo.TestApexes = CopyOf(apexInfo.TestApexes)
merged = append(merged, apexInfo)
}
aliases = append(aliases, [2]string{variantName, mergedName})
@@ -593,8 +623,10 @@
mctx.SetDefaultDependencyVariation(&defaultVariation)
variations := []string{defaultVariation}
+ testApexes := []string{}
for _, a := range apexInfos {
variations = append(variations, a.ApexVariationName)
+ testApexes = append(testApexes, a.TestApexes...)
}
modules := mctx.CreateVariations(variations...)
for i, mod := range modules {
@@ -608,6 +640,9 @@
if !platformVariation {
mctx.SetVariationProvider(mod, ApexInfoProvider, apexInfos[i-1])
}
+ // Set the value of TestApexes in every single apex variant.
+ // This allows each apex variant to be aware of the test apexes in the user provided apex_available.
+ mod.(ApexModule).apexModuleBase().ApexProperties.TestApexes = testApexes
}
for _, alias := range aliases {
@@ -898,3 +933,9 @@
return true
})
}
+
+// Implemented by apexBundle.
+type ApexTestInterface interface {
+ // Return true if the apex bundle is an apex_test
+ IsTestApex() bool
+}
diff --git a/android/apex_test.go b/android/apex_test.go
index 0bf4c9c..ddc730d 100644
--- a/android/apex_test.go
+++ b/android/apex_test.go
@@ -33,10 +33,10 @@
{
name: "single",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
},
wantMerged: []ApexInfo{
- {"apex10000", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"apex10000", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
},
wantAliases: [][2]string{
{"foo", "apex10000"},
@@ -45,11 +45,11 @@
{
name: "merge",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+ {"bar", FutureApiLevel, false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
},
wantMerged: []ApexInfo{
- {"apex10000", FutureApiLevel, false, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, false}},
+ {"apex10000", FutureApiLevel, false, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, false, nil}},
wantAliases: [][2]string{
{"bar", "apex10000"},
{"foo", "apex10000"},
@@ -58,12 +58,12 @@
{
name: "don't merge version",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", uncheckedFinalApiLevel(30), false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+ {"bar", uncheckedFinalApiLevel(30), false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
},
wantMerged: []ApexInfo{
- {"apex30", uncheckedFinalApiLevel(30), false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
- {"apex10000", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"apex30", uncheckedFinalApiLevel(30), false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
+ {"apex10000", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
},
wantAliases: [][2]string{
{"bar", "apex30"},
@@ -73,11 +73,11 @@
{
name: "merge updatable",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, true, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+ {"bar", FutureApiLevel, true, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
},
wantMerged: []ApexInfo{
- {"apex10000", FutureApiLevel, true, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+ {"apex10000", FutureApiLevel, true, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil},
},
wantAliases: [][2]string{
{"bar", "apex10000"},
@@ -87,15 +87,15 @@
{
name: "don't merge when for prebuilt_apex",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, true, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+ {"bar", FutureApiLevel, true, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
// This one should not be merged in with the others because it is for
// a prebuilt_apex.
- {"baz", FutureApiLevel, true, false, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex},
+ {"baz", FutureApiLevel, true, false, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex, nil},
},
wantMerged: []ApexInfo{
- {"apex10000", FutureApiLevel, true, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
- {"baz", FutureApiLevel, true, false, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex},
+ {"apex10000", FutureApiLevel, true, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil},
+ {"baz", FutureApiLevel, true, false, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex, nil},
},
wantAliases: [][2]string{
{"bar", "apex10000"},
@@ -105,11 +105,11 @@
{
name: "merge different UsePlatformApis but don't allow using platform api",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, false, true, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+ {"bar", FutureApiLevel, false, true, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
},
wantMerged: []ApexInfo{
- {"apex10000", FutureApiLevel, false, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+ {"apex10000", FutureApiLevel, false, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil},
},
wantAliases: [][2]string{
{"bar", "apex10000"},
@@ -119,11 +119,11 @@
{
name: "merge same UsePlatformApis and allow using platform api",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, true, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, false, true, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, true, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+ {"bar", FutureApiLevel, false, true, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
},
wantMerged: []ApexInfo{
- {"apex10000", FutureApiLevel, false, true, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+ {"apex10000", FutureApiLevel, false, true, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil},
},
wantAliases: [][2]string{
{"bar", "apex10000"},
diff --git a/android/bazel.go b/android/bazel.go
index 1646883..58d9d87 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -32,6 +32,22 @@
Bp2BuildTopLevel = "."
)
+type MixedBuildEnabledStatus int
+
+const (
+ // This module can be mixed_built.
+ MixedBuildEnabled = iota
+
+ // There is a technical incompatibility preventing this module from being
+ // bazel-analyzed. Note: the module might also be incompatible.
+ TechnicalIncompatibility
+
+ // This module cannot be mixed_built due to some incompatibility with it
+ // that is not a platform incompatibility. Example: the module-type is not
+ // enabled, or is not bp2build-converted.
+ ModuleIncompatibility
+)
+
// FileGroupAsLibrary describes a filegroup module that is converted to some library
// such as aidl_library or proto_library.
type FileGroupAsLibrary interface {
@@ -346,24 +362,31 @@
}).(Bp2BuildConversionAllowlist)
}
-// MixedBuildsEnabled returns true if a module is ready to be replaced by a
-// converted or handcrafted Bazel target. As a side effect, calling this
-// method will also log whether this module is mixed build enabled for
-// metrics reporting.
-func MixedBuildsEnabled(ctx BaseModuleContext) bool {
+// MixedBuildsEnabled returns a MixedBuildEnabledStatus regarding whether
+// a module is ready to be replaced by a converted or handcrafted Bazel target.
+// As a side effect, calling this method will also log whether this module is
+// mixed build enabled for metrics reporting.
+func MixedBuildsEnabled(ctx BaseModuleContext) MixedBuildEnabledStatus {
module := ctx.Module()
apexInfo := ctx.Provider(ApexInfoProvider).(ApexInfo)
withinApex := !apexInfo.IsForPlatform()
+
+ platformIncompatible := isPlatformIncompatible(ctx.Os(), ctx.Arch().ArchType)
+ if platformIncompatible {
+ ctx.Config().LogMixedBuild(ctx, false)
+ return TechnicalIncompatibility
+ }
+
mixedBuildEnabled := ctx.Config().IsMixedBuildsEnabled() &&
- ctx.Os() != Windows && // Windows toolchains are not currently supported.
- ctx.Os() != LinuxBionic && // Linux Bionic toolchains are not currently supported.
- ctx.Os() != LinuxMusl && // Linux musl toolchains are not currently supported (b/259266326).
- ctx.Arch().ArchType != Riscv64 && // TODO(b/262192655) Riscv64 toolchains are not currently supported.
module.Enabled() &&
convertedToBazel(ctx, module) &&
ctx.Config().BazelContext.IsModuleNameAllowed(module.Name(), withinApex)
ctx.Config().LogMixedBuild(ctx, mixedBuildEnabled)
- return mixedBuildEnabled
+
+ if mixedBuildEnabled {
+ return MixedBuildEnabled
+ }
+ return ModuleIncompatibility
}
// ConvertedToBazel returns whether this module has been converted (with bp2build or manually) to Bazel.
@@ -388,6 +411,13 @@
OtherModuleDir(m blueprint.Module) string
}
+func isPlatformIncompatible(osType OsType, arch ArchType) bool {
+ return osType == Windows || // Windows toolchains are not currently supported.
+ osType == LinuxBionic || // Linux Bionic toolchains are not currently supported.
+ osType == LinuxMusl || // Linux musl toolchains are not currently supported (b/259266326).
+ arch == Riscv64 // TODO(b/262192655) Riscv64 toolchains are not currently supported.
+}
+
func (b *BazelModuleBase) shouldConvertWithBp2build(ctx bazelOtherModuleContext, module blueprint.Module) bool {
if !b.bazelProps().Bazel_module.CanConvertToBazel {
return false
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 44dc055..5291eca 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -18,7 +18,6 @@
"bytes"
"fmt"
"os"
- "os/exec"
"path"
"path/filepath"
"runtime"
@@ -30,7 +29,6 @@
"android/soong/bazel/cquery"
"android/soong/shared"
"android/soong/starlark_fmt"
-
"github.com/google/blueprint"
"github.com/google/blueprint/metrics"
@@ -61,8 +59,12 @@
"AUTO_UNINITIALIZE",
"USE_CCACHE",
"LLVM_NEXT",
+ "LLVM_PREBUILTS_VERSION",
+ "LLVM_RELEASE_VERSION",
"ALLOW_UNKNOWN_WARNING_OPTION",
+ "UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT",
+
// Overrides the version in the apex_manifest.json. The version is unique for
// each branch (internal, aosp, mainline releases, dessert releases). This
// enables modules built on an older branch to be installed against a newer
@@ -84,7 +86,9 @@
func mixedBuildsPrepareMutator(ctx BottomUpMutatorContext) {
if m := ctx.Module(); m.Enabled() {
if mixedBuildMod, ok := m.(MixedBuildBuildable); ok {
- if mixedBuildMod.IsMixedBuildSupported(ctx) && MixedBuildsEnabled(ctx) {
+ mixedBuildEnabled := MixedBuildsEnabled(ctx)
+ queueMixedBuild := mixedBuildMod.IsMixedBuildSupported(ctx) && mixedBuildEnabled == MixedBuildEnabled
+ if queueMixedBuild {
mixedBuildMod.QueueBazelCall(ctx)
}
}
@@ -214,8 +218,7 @@
}
type bazelRunner interface {
- createBazelCommand(config Config, paths *bazelPaths, runName bazel.RunName, command bazelCommand, extraFlags ...string) *exec.Cmd
- issueBazelCommand(bazelCmd *exec.Cmd, eventHandler *metrics.EventHandler) (output string, errorMessage string, error error)
+ issueBazelCommand(cmdRequest bazel.CmdRequest, paths *bazelPaths, eventHandler *metrics.EventHandler) (output string, errorMessage string, error error)
}
type bazelPaths struct {
@@ -654,36 +657,6 @@
expression string
}
-type mockBazelRunner struct {
- bazelCommandResults map[bazelCommand]string
- // use *exec.Cmd as a key to get the bazelCommand, the map will be used in issueBazelCommand()
- // Register createBazelCommand() invocations. Later, an
- // issueBazelCommand() invocation can be mapped to the *exec.Cmd instance
- // and then to the expected result via bazelCommandResults
- tokens map[*exec.Cmd]bazelCommand
- commands []bazelCommand
- extraFlags []string
-}
-
-func (r *mockBazelRunner) createBazelCommand(_ Config, _ *bazelPaths, _ bazel.RunName,
- command bazelCommand, extraFlags ...string) *exec.Cmd {
- r.commands = append(r.commands, command)
- r.extraFlags = append(r.extraFlags, strings.Join(extraFlags, " "))
- cmd := &exec.Cmd{}
- if r.tokens == nil {
- r.tokens = make(map[*exec.Cmd]bazelCommand)
- }
- r.tokens[cmd] = command
- return cmd
-}
-
-func (r *mockBazelRunner) issueBazelCommand(bazelCmd *exec.Cmd, _ *metrics.EventHandler) (string, string, error) {
- if command, ok := r.tokens[bazelCmd]; ok {
- return r.bazelCommandResults[command], "", nil
- }
- return "", "", nil
-}
-
type builtinBazelRunner struct {
useBazelProxy bool
outDir string
@@ -693,17 +666,12 @@
// Returns (stdout, stderr, error). The first and second return values are strings
// containing the stdout and stderr of the run command, and an error is returned if
// the invocation returned an error code.
-func (r *builtinBazelRunner) issueBazelCommand(bazelCmd *exec.Cmd, eventHandler *metrics.EventHandler) (string, string, error) {
+func (r *builtinBazelRunner) issueBazelCommand(cmdRequest bazel.CmdRequest, paths *bazelPaths, eventHandler *metrics.EventHandler) (string, string, error) {
if r.useBazelProxy {
eventHandler.Begin("client_proxy")
defer eventHandler.End("client_proxy")
proxyClient := bazel.NewProxyClient(r.outDir)
- // Omit the arg containing the Bazel binary, as that is handled by the proxy
- // server.
- bazelFlags := bazelCmd.Args[1:]
- // TODO(b/270989498): Refactor these functions to not take exec.Cmd, as its
- // not actually executed for client proxying.
- resp, err := proxyClient.IssueCommand(bazel.CmdRequest{bazelFlags, bazelCmd.Env})
+ resp, err := proxyClient.IssueCommand(cmdRequest)
if err != nil {
return "", "", err
@@ -715,26 +683,19 @@
} else {
eventHandler.Begin("bazel command")
defer eventHandler.End("bazel command")
- stderr := &bytes.Buffer{}
- bazelCmd.Stderr = stderr
- if output, err := bazelCmd.Output(); err != nil {
- return "", string(stderr.Bytes()),
- fmt.Errorf("bazel command failed: %s\n---command---\n%s\n---env---\n%s\n---stderr---\n%s---",
- err, bazelCmd, strings.Join(bazelCmd.Env, "\n"), stderr)
- } else {
- return string(output), string(stderr.Bytes()), nil
- }
+
+ stdout, stderr, err := bazel.ExecBazel(paths.bazelPath, absolutePath(paths.syntheticWorkspaceDir()), cmdRequest)
+ return string(stdout), string(stderr), err
}
}
-func (r *builtinBazelRunner) createBazelCommand(config Config, paths *bazelPaths, runName bazel.RunName, command bazelCommand,
- extraFlags ...string) *exec.Cmd {
+func (context *mixedBuildBazelContext) createBazelCommand(config Config, runName bazel.RunName, command bazelCommand,
+ extraFlags ...string) bazel.CmdRequest {
cmdFlags := []string{
- "--output_base=" + absolutePath(paths.outputBase),
+ "--output_base=" + absolutePath(context.paths.outputBase),
command.command,
command.expression,
- // TODO(asmundak): is it needed in every build?
- "--profile=" + shared.BazelMetricsFilename(paths, runName),
+ "--profile=" + shared.BazelMetricsFilename(context.paths, runName),
// We don't need to set --host_platforms because it's set in bazelrc files
// that the bazel shell script wrapper passes
@@ -749,15 +710,13 @@
}
cmdFlags = append(cmdFlags, extraFlags...)
- bazelCmd := exec.Command(paths.bazelPath, cmdFlags...)
- bazelCmd.Dir = absolutePath(paths.syntheticWorkspaceDir())
extraEnv := []string{
- "HOME=" + paths.homeDir,
+ "HOME=" + context.paths.homeDir,
pwdPrefix(),
- "BUILD_DIR=" + absolutePath(paths.soongOutDir),
+ "BUILD_DIR=" + absolutePath(context.paths.soongOutDir),
// Make OUT_DIR absolute here so build/bazel/bin/bazel uses the correct
// OUT_DIR at <root>/out, instead of <root>/out/soong/workspace/out.
- "OUT_DIR=" + absolutePath(paths.outDir()),
+ "OUT_DIR=" + absolutePath(context.paths.outDir()),
// Disables local host detection of gcc; toolchain information is defined
// explicitly in BUILD files.
"BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1",
@@ -769,15 +728,15 @@
}
extraEnv = append(extraEnv, fmt.Sprintf("%s=%s", envvar, val))
}
- bazelCmd.Env = append(os.Environ(), extraEnv...)
+ envVars := append(os.Environ(), extraEnv...)
- return bazelCmd
+ return bazel.CmdRequest{cmdFlags, envVars}
}
-func printableCqueryCommand(bazelCmd *exec.Cmd) string {
- outputString := strings.Join(bazelCmd.Env, " ") + " \"" + strings.Join(bazelCmd.Args, "\" \"") + "\""
+func (context *mixedBuildBazelContext) printableCqueryCommand(bazelCmd bazel.CmdRequest) string {
+ args := append([]string{context.paths.bazelPath}, bazelCmd.Argv...)
+ outputString := strings.Join(bazelCmd.Env, " ") + " \"" + strings.Join(args, "\" \"") + "\""
return outputString
-
}
func (context *mixedBuildBazelContext) mainBzlFileContents() []byte {
@@ -960,9 +919,13 @@
// request type.
func (context *mixedBuildBazelContext) cqueryStarlarkFileContents() []byte {
requestTypeToCqueryIdEntries := map[cqueryRequest][]string{}
+ requestTypes := []cqueryRequest{}
for _, val := range context.requests {
cqueryId := getCqueryId(val)
mapEntryString := fmt.Sprintf("%q : True", cqueryId)
+ if _, seenKey := requestTypeToCqueryIdEntries[val.requestType]; !seenKey {
+ requestTypes = append(requestTypes, val.requestType)
+ }
requestTypeToCqueryIdEntries[val.requestType] =
append(requestTypeToCqueryIdEntries[val.requestType], mapEntryString)
}
@@ -984,7 +947,7 @@
return id_string + ">>" + %s(target, id_string)
`
- for requestType := range requestTypeToCqueryIdEntries {
+ for _, requestType := range requestTypes {
labelMapName := requestType.Name() + "_Labels"
functionName := requestType.Name() + "_Fn"
labelRegistrationMapSection += fmt.Sprintf(mapDeclarationFormatString,
@@ -1096,9 +1059,10 @@
const buildrootLabel = "@soong_injection//mixed_builds:buildroot"
var (
- cqueryCmd = bazelCommand{"cquery", fmt.Sprintf("deps(%s, 2)", buildrootLabel)}
- aqueryCmd = bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)}
- buildCmd = bazelCommand{"build", "@soong_injection//mixed_builds:phonyroot"}
+ cqueryCmd = bazelCommand{"cquery", fmt.Sprintf("deps(%s, 2)", buildrootLabel)}
+ aqueryCmd = bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)}
+ buildCmd = bazelCommand{"build", "@soong_injection//mixed_builds:phonyroot"}
+ allBazelCommands = []bazelCommand{aqueryCmd, cqueryCmd, buildCmd}
)
// Issues commands to Bazel to receive results for all cquery requests
@@ -1160,12 +1124,12 @@
extraFlags = append(extraFlags, "--collect_code_coverage")
}
- cqueryCommandWithFlag := context.createBazelCommand(config, context.paths, bazel.CqueryBuildRootRunName, cqueryCmd, extraFlags...)
- cqueryOutput, cqueryErrorMessage, cqueryErr := context.issueBazelCommand(cqueryCommandWithFlag, eventHandler)
+ cqueryCmdRequest := context.createBazelCommand(config, bazel.CqueryBuildRootRunName, cqueryCmd, extraFlags...)
+ cqueryOutput, cqueryErrorMessage, cqueryErr := context.issueBazelCommand(cqueryCmdRequest, context.paths, eventHandler)
if cqueryErr != nil {
return cqueryErr
}
- cqueryCommandPrint := fmt.Sprintf("cquery command line:\n %s \n\n\n", printableCqueryCommand(cqueryCommandWithFlag))
+ cqueryCommandPrint := fmt.Sprintf("cquery command line:\n %s \n\n\n", context.printableCqueryCommand(cqueryCmdRequest))
if err := os.WriteFile(filepath.Join(soongInjectionPath, "cquery.out"), []byte(cqueryCommandPrint+cqueryOutput), 0666); err != nil {
return err
}
@@ -1223,8 +1187,8 @@
extraFlags = append(extraFlags, "--instrumentation_filter="+strings.Join(paths, ","))
}
}
- aqueryOutput, _, err := context.issueBazelCommand(context.createBazelCommand(config, context.paths, bazel.AqueryBuildRootRunName, aqueryCmd,
- extraFlags...), eventHandler)
+ aqueryOutput, _, err := context.issueBazelCommand(context.createBazelCommand(config, bazel.AqueryBuildRootRunName, aqueryCmd,
+ extraFlags...), context.paths, eventHandler)
if err != nil {
return err
}
@@ -1239,7 +1203,7 @@
// Issue a build command of the phony root to generate symlink forests for dependencies of the
// Bazel build. This is necessary because aquery invocations do not generate this symlink forest,
// but some of symlinks may be required to resolve source dependencies of the build.
- _, _, err := context.issueBazelCommand(context.createBazelCommand(config, context.paths, bazel.BazelBuildPhonyRootRunName, buildCmd), eventHandler)
+ _, _, err := context.issueBazelCommand(context.createBazelCommand(config, bazel.BazelBuildPhonyRootRunName, buildCmd), context.paths, eventHandler)
return err
}
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index c67d7fb..b17b765 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -8,6 +8,7 @@
"strings"
"testing"
+ "android/soong/bazel"
"android/soong/bazel/cquery"
analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
@@ -19,6 +20,34 @@
type testInvokeBazelContext struct{}
+type mockBazelRunner struct {
+ testHelper *testing.T
+ // Stores mock behavior. If an issueBazelCommand request is made for command
+ // k, and {k:v} is present in this map, then the mock will return v.
+ bazelCommandResults map[bazelCommand]string
+ // Requests actually made of the mockBazelRunner with issueBazelCommand,
+ // keyed by the command they represent.
+ bazelCommandRequests map[bazelCommand]bazel.CmdRequest
+}
+
+func (r *mockBazelRunner) bazelCommandForRequest(cmdRequest bazel.CmdRequest) bazelCommand {
+ for _, arg := range cmdRequest.Argv {
+ for _, cmdType := range allBazelCommands {
+ if arg == cmdType.command {
+ return cmdType
+ }
+ }
+ }
+ r.testHelper.Fatalf("Unrecognized bazel request: %s", cmdRequest)
+ return cqueryCmd
+}
+
+func (r *mockBazelRunner) issueBazelCommand(cmdRequest bazel.CmdRequest, paths *bazelPaths, eventHandler *metrics.EventHandler) (string, string, error) {
+ command := r.bazelCommandForRequest(cmdRequest)
+ r.bazelCommandRequests[command] = cmdRequest
+ return r.bazelCommandResults[command], "", nil
+}
+
func (t *testInvokeBazelContext) GetEventHandler() *metrics.EventHandler {
return &metrics.EventHandler{}
}
@@ -36,9 +65,7 @@
`@//foo:foo|arm64_armv8-a|android|within_apex|29>>out/foo/foo.txt`,
`@//foo:bar|arm64_armv8-a|android>>out/foo/bar.txt`,
}
- bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
- bazelCommand{command: "cquery", expression: "deps(@soong_injection//mixed_builds:buildroot, 2)"}: strings.Join(cmd_results, "\n"),
- })
+ bazelContext, _ := testBazelContext(t, map[bazelCommand]string{cqueryCmd: strings.Join(cmd_results, "\n")})
bazelContext.QueueBazelRequest(label_foo, cquery.GetOutputFiles, cfg_foo)
bazelContext.QueueBazelRequest(label_bar, cquery.GetOutputFiles, cfg_bar)
@@ -139,8 +166,7 @@
if err != nil {
t.Error(err)
}
- bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
- bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}: string(data)})
+ bazelContext, _ := testBazelContext(t, map[bazelCommand]string{aqueryCmd: string(data)})
err = bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{})
if err != nil {
@@ -166,30 +192,26 @@
testConfig.productVariables.NativeCoveragePaths = []string{"foo1", "foo2"}
testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1", "bar2"}
- verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+foo1,+foo2,-bar1,-bar2`)
+ verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+foo1,+foo2,-bar1,-bar2")
testConfig.productVariables.NativeCoveragePaths = []string{"foo1"}
testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1"}
- verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+foo1,-bar1`)
+ verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+foo1,-bar1")
testConfig.productVariables.NativeCoveragePaths = []string{"foo1"}
testConfig.productVariables.NativeCoverageExcludePaths = nil
- verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+foo1`)
+ verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+foo1")
testConfig.productVariables.NativeCoveragePaths = nil
testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1"}
- verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=-bar1`)
+ verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=-bar1")
testConfig.productVariables.NativeCoveragePaths = []string{"*"}
testConfig.productVariables.NativeCoverageExcludePaths = nil
- verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+.*`)
+ verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+.*")
testConfig.productVariables.ClangCoverage = boolPtr(false)
- actual := verifyExtraFlags(t, testConfig, ``)
- if strings.Contains(actual, "--collect_code_coverage") ||
- strings.Contains(actual, "--instrumentation_filter=") {
- t.Errorf("Expected code coverage disabled, but got %#v", actual)
- }
+ verifyAqueryDoesNotContainSubstrings(t, testConfig, "collect_code_coverage", "instrumentation_filter")
}
func TestBazelRequestsSorted(t *testing.T) {
@@ -268,7 +290,8 @@
}
}
-func verifyExtraFlags(t *testing.T, config Config, expected string) string {
+func verifyAqueryContainsFlags(t *testing.T, config Config, expected ...string) {
+ t.Helper()
bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
err := bazelContext.InvokeBazel(config, &testInvokeBazelContext{})
@@ -276,17 +299,49 @@
t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
}
- flags := bazelContext.bazelRunner.(*mockBazelRunner).extraFlags
- if expected := 3; len(flags) != expected {
- t.Errorf("Expected %d extra flags got %#v", expected, flags)
+ sliceContains := func(slice []string, x string) bool {
+ for _, s := range slice {
+ if s == x {
+ return true
+ }
+ }
+ return false
}
- actual := flags[1]
- if !strings.Contains(actual, expected) {
- t.Errorf("Expected %#v got %#v", expected, actual)
+ aqueryArgv := bazelContext.bazelRunner.(*mockBazelRunner).bazelCommandRequests[aqueryCmd].Argv
+
+ for _, expectedFlag := range expected {
+ if !sliceContains(aqueryArgv, expectedFlag) {
+ t.Errorf("aquery does not contain expected flag %#v. Argv was: %#v", expectedFlag, aqueryArgv)
+ }
+ }
+}
+
+func verifyAqueryDoesNotContainSubstrings(t *testing.T, config Config, substrings ...string) {
+ t.Helper()
+ bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
+
+ err := bazelContext.InvokeBazel(config, &testInvokeBazelContext{})
+ if err != nil {
+ t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
}
- return actual
+ sliceContainsSubstring := func(slice []string, substring string) bool {
+ for _, s := range slice {
+ if strings.Contains(s, substring) {
+ return true
+ }
+ }
+ return false
+ }
+
+ aqueryArgv := bazelContext.bazelRunner.(*mockBazelRunner).bazelCommandRequests[aqueryCmd].Argv
+
+ for _, substring := range substrings {
+ if sliceContainsSubstring(aqueryArgv, substring) {
+ t.Errorf("aquery contains unexpected substring %#v. Argv was: %#v", substring, aqueryArgv)
+ }
+ }
}
func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) (*mixedBuildBazelContext, string) {
@@ -296,11 +351,14 @@
outputBase: "outputbase",
workspaceDir: "workspace_dir",
}
- aqueryCommand := bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}
- if _, exists := bazelCommandResults[aqueryCommand]; !exists {
- bazelCommandResults[aqueryCommand] = ""
+ if _, exists := bazelCommandResults[aqueryCmd]; !exists {
+ bazelCommandResults[aqueryCmd] = ""
}
- runner := &mockBazelRunner{bazelCommandResults: bazelCommandResults}
+ runner := &mockBazelRunner{
+ testHelper: t,
+ bazelCommandResults: bazelCommandResults,
+ bazelCommandRequests: map[bazelCommand]bazel.CmdRequest{},
+ }
return &mixedBuildBazelContext{
bazelRunner: runner,
paths: &p,
diff --git a/android/config.go b/android/config.go
index 2ccb732..0b54ed9 100644
--- a/android/config.go
+++ b/android/config.go
@@ -102,6 +102,8 @@
UseBazelProxy bool
BuildFromTextStub bool
+
+ EnsureAllowlistIntegrity bool
}
// Build modes that soong_build can run as.
@@ -174,6 +176,13 @@
return c.config.TestProductVariables != nil
}
+// MaxPageSizeSupported returns the max page size supported by the device. This
+// value will define the ELF segment alignment for binaries (executables and
+// shared libraries).
+func (c Config) MaxPageSizeSupported() string {
+ return String(c.config.productVariables.DeviceMaxPageSizeSupported)
+}
+
// A DeviceConfig object represents the configuration for a particular device
// being built. For now there will only be one of these, but in the future there
// may be multiple devices being built.
@@ -278,6 +287,11 @@
// If buildFromTextStub is true then the Java API stubs are
// built from the signature text files, not the source Java files.
buildFromTextStub bool
+
+ // If ensureAllowlistIntegrity is true, then the presence of any allowlisted
+ // modules that aren't mixed-built for at least one variant will cause a build
+ // failure
+ ensureAllowlistIntegrity bool
}
type deviceConfig struct {
@@ -592,12 +606,11 @@
setBazelMode(cmdArgs.BazelMode, "--bazel-mode", BazelProdMode)
setBazelMode(cmdArgs.BazelModeStaging, "--bazel-mode-staging", BazelStagingMode)
- config.BazelContext, err = NewBazelContext(config)
- config.Bp2buildPackageConfig = GetBp2BuildAllowList()
-
for _, module := range strings.Split(cmdArgs.BazelForceEnabledModules, ",") {
config.bazelForceEnabledModules[module] = struct{}{}
}
+ config.BazelContext, err = NewBazelContext(config)
+ config.Bp2buildPackageConfig = GetBp2BuildAllowList()
return Config{config}, err
}
@@ -833,6 +846,10 @@
return uncheckedFinalApiLevel(*c.productVariables.Platform_sdk_version)
}
+func (c *config) RawPlatformSdkVersion() *int {
+ return c.productVariables.Platform_sdk_version
+}
+
func (c *config) PlatformSdkFinal() bool {
return Bool(c.productVariables.Platform_sdk_final)
}
@@ -1554,6 +1571,13 @@
return HasAnyPrefix(path, c.productVariables.MemtagHeapSyncIncludePaths) && !c.MemtagHeapDisabledForPath(path)
}
+func (c *config) HWASanEnabledForPath(path string) bool {
+ if len(c.productVariables.HWASanIncludePaths) == 0 {
+ return false
+ }
+ return HasAnyPrefix(path, c.productVariables.HWASanIncludePaths)
+}
+
func (c *config) VendorConfig(name string) VendorConfig {
return soongconfig.Config(c.productVariables.VendorVars[name])
}
@@ -1901,6 +1925,10 @@
return Bool(c.productVariables.HostMusl)
}
+func (c *config) GetMixedBuildsEnabledModules() map[string]struct{} {
+ return c.mixedBuildEnabledModules
+}
+
func (c *config) LogMixedBuild(ctx BaseModuleContext, useBazel bool) {
moduleName := ctx.Module().Name()
c.mixedBuildsLock.Lock()
@@ -1930,3 +1958,8 @@
func (c *config) SetBuildFromTextStub(b bool) {
c.buildFromTextStub = b
}
+func (c *config) AddForceEnabledModules(forceEnabled []string) {
+ for _, forceEnabledModule := range forceEnabled {
+ c.bazelForceEnabledModules[forceEnabledModule] = struct{}{}
+ }
+}
diff --git a/android/config_bp2build.go b/android/config_bp2build.go
index 830890d..2beeb51 100644
--- a/android/config_bp2build.go
+++ b/android/config_bp2build.go
@@ -95,15 +95,6 @@
return ev.pctx.VariableConfigMethod(name, method)
}
-func (ev ExportedVariables) ExportStringStaticVariableWithEnvOverride(name, envVar, defaultVal string) {
- ev.ExportVariableConfigMethod(name, func(config Config) string {
- if override := config.Getenv(envVar); override != "" {
- return override
- }
- return defaultVal
- })
-}
-
// ExportSourcePathVariable declares a static "source path" variable and exports
// it to Bazel's toolchain.
func (ev ExportedVariables) ExportSourcePathVariable(name string, value string) {
diff --git a/android/filegroup.go b/android/filegroup.go
index c259f21..0ca5dc5 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -81,6 +81,7 @@
type bazelAidlLibraryAttributes struct {
Srcs bazel.LabelListAttribute
Strip_import_prefix *string
+ Deps bazel.LabelListAttribute
}
// api srcs can be contained in filegroups.
@@ -119,9 +120,12 @@
// and then convert
if fg.ShouldConvertToAidlLibrary(ctx) {
tags := []string{"apex_available=//apex_available:anyapex"}
+ deps := bazel.MakeLabelListAttribute(BazelLabelForModuleDeps(ctx, fg.properties.Aidl.Deps))
+
attrs := &bazelAidlLibraryAttributes{
Srcs: srcs,
Strip_import_prefix: fg.properties.Path,
+ Deps: deps,
}
props := bazel.BazelTargetModuleProperties{
@@ -187,6 +191,14 @@
// Create a make variable with the specified name that contains the list of files in the
// filegroup, relative to the root of the source tree.
Export_to_make_var *string
+
+ // aidl is explicitly provided for implicit aidl dependencies
+ // TODO(b/278298615): aidl prop is a no-op in Soong and is an escape hatch
+ // to include implicit aidl dependencies for bazel migration compatibility
+ Aidl struct {
+ // List of aidl files or filegroup depended on by srcs
+ Deps []string `android:"path"`
+ }
}
type fileGroup struct {
diff --git a/android/makefile_goal.go b/android/makefile_goal.go
deleted file mode 100644
index 07354a6..0000000
--- a/android/makefile_goal.go
+++ /dev/null
@@ -1,98 +0,0 @@
-// 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.
-
-package android
-
-import (
- "fmt"
- "io"
- "path/filepath"
-
- "github.com/google/blueprint/proptools"
-)
-
-func init() {
- RegisterModuleType("makefile_goal", MakefileGoalFactory)
-}
-
-type makefileGoalProperties struct {
- // Sources.
-
- // Makefile goal output file path, relative to PRODUCT_OUT.
- Product_out_path *string
-}
-
-type makefileGoal struct {
- ModuleBase
-
- properties makefileGoalProperties
-
- // Destination. Output file path of this module.
- outputFilePath OutputPath
-}
-
-var _ AndroidMkEntriesProvider = (*makefileGoal)(nil)
-var _ OutputFileProducer = (*makefileGoal)(nil)
-
-// Input file of this makefile_goal module. Nil if none specified. May use variable names in makefiles.
-func (p *makefileGoal) inputPath() *string {
- if p.properties.Product_out_path != nil {
- return proptools.StringPtr(filepath.Join("$(PRODUCT_OUT)", proptools.String(p.properties.Product_out_path)))
- }
- return nil
-}
-
-// OutputFileProducer
-func (p *makefileGoal) OutputFiles(tag string) (Paths, error) {
- if tag != "" {
- return nil, fmt.Errorf("unsupported tag %q", tag)
- }
- return Paths{p.outputFilePath}, nil
-}
-
-// AndroidMkEntriesProvider
-func (p *makefileGoal) DepsMutator(ctx BottomUpMutatorContext) {
- if p.inputPath() == nil {
- ctx.PropertyErrorf("product_out_path", "Path relative to PRODUCT_OUT required")
- }
-}
-
-func (p *makefileGoal) GenerateAndroidBuildActions(ctx ModuleContext) {
- filename := filepath.Base(proptools.String(p.inputPath()))
- p.outputFilePath = PathForModuleOut(ctx, filename).OutputPath
-
- ctx.InstallFile(PathForModuleInstall(ctx, "etc"), ctx.ModuleName(), p.outputFilePath)
-}
-
-func (p *makefileGoal) AndroidMkEntries() []AndroidMkEntries {
- return []AndroidMkEntries{AndroidMkEntries{
- Class: "ETC",
- OutputFile: OptionalPathForPath(p.outputFilePath),
- ExtraFooters: []AndroidMkExtraFootersFunc{
- func(w io.Writer, name, prefix, moduleDir string) {
- // Can't use Cp because inputPath() is not a valid Path.
- fmt.Fprintf(w, "$(eval $(call copy-one-file,%s,%s))\n", proptools.String(p.inputPath()), p.outputFilePath)
- },
- },
- }}
-}
-
-// Import a Makefile goal to Soong by copying the file built by
-// the goal to a path visible to Soong. This rule only works on boot images.
-func MakefileGoalFactory() Module {
- module := &makefileGoal{}
- module.AddProperties(&module.properties)
- InitAndroidModule(module)
- return module
-}
diff --git a/android/module.go b/android/module.go
index ba47453..c8670c3 100644
--- a/android/module.go
+++ b/android/module.go
@@ -2438,7 +2438,7 @@
func (m *ModuleBase) isHandledByBazel(ctx ModuleContext) (MixedBuildBuildable, bool) {
if mixedBuildMod, ok := m.module.(MixedBuildBuildable); ok {
- if mixedBuildMod.IsMixedBuildSupported(ctx) && MixedBuildsEnabled(ctx) {
+ if mixedBuildMod.IsMixedBuildSupported(ctx) && (MixedBuildsEnabled(ctx) == MixedBuildEnabled) {
return mixedBuildMod, true
}
}
diff --git a/android/mutator.go b/android/mutator.go
index 676f8a5..0a091eb 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -273,6 +273,12 @@
// This function can be used to create alias definitions in a directory that is different
// from the directory of the visited Soong module.
CreateBazelTargetAliasInDir(dir string, name string, actual bazel.Label)
+
+ // CreateBazelConfigSetting creates a config_setting in <dir>/BUILD.bazel
+ // build/bazel has several static config_setting(s) that are used in Bazel builds.
+ // This function can be used to createa additional config_setting(s) based on the build graph
+ // (e.g. a config_setting specific to an apex variant)
+ CreateBazelConfigSetting(csa bazel.ConfigSettingAttributes, ca CommonAttributes, dir string)
}
type topDownMutatorContext struct {
@@ -738,6 +744,23 @@
mod.base().addBp2buildInfo(info)
}
+func (t *topDownMutatorContext) CreateBazelConfigSetting(
+ csa bazel.ConfigSettingAttributes,
+ ca CommonAttributes,
+ dir string) {
+ mod := t.Module()
+ info := bp2buildInfo{
+ Dir: dir,
+ BazelProps: bazel.BazelTargetModuleProperties{
+ Rule_class: "config_setting",
+ },
+ CommonAttrs: ca,
+ ConstraintAttrs: constraintAttributes{},
+ Attrs: &csa,
+ }
+ mod.base().addBp2buildInfo(info)
+}
+
// ApexAvailableTags converts the apex_available property value of an ApexModule
// module and returns it as a list of keyed tags.
func ApexAvailableTags(mod Module) bazel.StringListAttribute {
@@ -747,11 +770,46 @@
// TODO(b/218841706): hidl_interface has the apex_available prop, but it's
// defined directly as a prop and not via ApexModule, so this doesn't
// pick those props up.
- attr.Value = ConvertApexAvailableToTags(am.apexModuleBase().ApexAvailable())
+ apexAvailable := am.apexModuleBase().ApexAvailable()
+ // If a user does not specify apex_available in Android.bp, then soong provides a default.
+ // To avoid verbosity of BUILD files, remove this default from user-facing BUILD files.
+ if len(am.apexModuleBase().ApexProperties.Apex_available) == 0 {
+ apexAvailable = []string{}
+ }
+ attr.Value = ConvertApexAvailableToTags(apexAvailable)
}
return attr
}
+func ApexAvailableTagsWithoutTestApexes(ctx BaseModuleContext, mod Module) bazel.StringListAttribute {
+ attr := bazel.StringListAttribute{}
+ if am, ok := mod.(ApexModule); ok {
+ apexAvailableWithoutTestApexes := removeTestApexes(ctx, am.apexModuleBase().ApexAvailable())
+ // If a user does not specify apex_available in Android.bp, then soong provides a default.
+ // To avoid verbosity of BUILD files, remove this default from user-facing BUILD files.
+ if len(am.apexModuleBase().ApexProperties.Apex_available) == 0 {
+ apexAvailableWithoutTestApexes = []string{}
+ }
+ attr.Value = ConvertApexAvailableToTags(apexAvailableWithoutTestApexes)
+ }
+ return attr
+}
+
+func removeTestApexes(ctx BaseModuleContext, apex_available []string) []string {
+ testApexes := []string{}
+ for _, aa := range apex_available {
+ // ignore the wildcards
+ if InList(aa, AvailableToRecognziedWildcards) {
+ continue
+ }
+ mod, _ := ctx.ModuleFromName(aa)
+ if apex, ok := mod.(ApexTestInterface); ok && apex.IsTestApex() {
+ testApexes = append(testApexes, aa)
+ }
+ }
+ return RemoveListFromList(CopyOf(apex_available), testApexes)
+}
+
func ConvertApexAvailableToTags(apexAvailable []string) []string {
if len(apexAvailable) == 0 {
// We need nil specifically to make bp2build not add the tags property at all,
@@ -765,6 +823,13 @@
return result
}
+// ConvertApexAvailableToTagsWithoutTestApexes converts a list of apex names to a list of bazel tags
+// This function drops any test apexes from the input.
+func ConvertApexAvailableToTagsWithoutTestApexes(ctx BaseModuleContext, apexAvailable []string) []string {
+ noTestApexes := removeTestApexes(ctx, apexAvailable)
+ return ConvertApexAvailableToTags(noTestApexes)
+}
+
func (t *topDownMutatorContext) createBazelTargetModule(
bazelProps bazel.BazelTargetModuleProperties,
commonAttrs CommonAttributes,
diff --git a/android/neverallow.go b/android/neverallow.go
index 2139c3c..5b5e613 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -55,7 +55,6 @@
AddNeverAllowRules(createJavaDeviceForHostRules()...)
AddNeverAllowRules(createCcSdkVariantRules()...)
AddNeverAllowRules(createUncompressDexRules()...)
- AddNeverAllowRules(createMakefileGoalRules()...)
AddNeverAllowRules(createInitFirstStageRules()...)
AddNeverAllowRules(createProhibitFrameworkAccessRules()...)
AddNeverAllowRules(createBp2BuildRule())
@@ -236,20 +235,6 @@
}
}
-func createMakefileGoalRules() []Rule {
- allowlist := []string{
- // libwifi_hal uses makefile_goal for its dependencies
- "frameworks/opt/net/wifi/libwifi_hal",
- }
- return []Rule{
- NeverAllow().
- ModuleType("makefile_goal").
- WithoutMatcher("product_out_path", Regexp("^boot[0-9a-zA-Z.-]*[.]img$")).
- NotIn(allowlist...).
- Because("Only boot images may be imported as a makefile goal if not in allowed projects"),
- }
-}
-
func createInitFirstStageRules() []Rule {
return []Rule{
NeverAllow().
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 5f5f9a1..ddd982d 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -313,45 +313,6 @@
"module \"outside_art_libraries\": violates neverallow",
},
},
- {
- name: "disallowed makefile_goal",
- fs: map[string][]byte{
- "Android.bp": []byte(`
- makefile_goal {
- name: "foo",
- product_out_path: "boot/trap.img"
- }
- `),
- },
- expectedErrors: []string{
- "Only boot images.* may be imported as a makefile goal",
- },
- },
- {
- name: "disallowed makefile_goal outside external",
- fs: map[string][]byte{
- "project/Android.bp": []byte(`
- makefile_goal {
- name: "foo",
- product_out_path: "obj/EXE/foo",
- }
- `),
- },
- expectedErrors: []string{
- "not in allowed projects",
- },
- },
- {
- name: "allow makefile_goal within external",
- fs: map[string][]byte{
- "frameworks/opt/net/wifi/libwifi_hal/Android.bp": []byte(`
- makefile_goal {
- name: "foo",
- product_out_path: "obj/EXE/foo",
- }
- `),
- },
- },
// Tests for the rule prohibiting the use of framework
{
name: "prohibit framework",
@@ -391,7 +352,6 @@
ctx.RegisterModuleType("java_library", newMockJavaLibraryModule)
ctx.RegisterModuleType("java_library_host", newMockJavaLibraryModule)
ctx.RegisterModuleType("java_device_for_host", newMockJavaLibraryModule)
- ctx.RegisterModuleType("makefile_goal", newMockMakefileGoalModule)
}),
)
@@ -489,22 +449,3 @@
func (p *mockJavaLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
}
-
-type mockMakefileGoalProperties struct {
- Product_out_path *string
-}
-
-type mockMakefileGoalModule struct {
- ModuleBase
- properties mockMakefileGoalProperties
-}
-
-func newMockMakefileGoalModule() Module {
- m := &mockMakefileGoalModule{}
- m.AddProperties(&m.properties)
- InitAndroidModule(m)
- return m
-}
-
-func (p *mockMakefileGoalModule) GenerateAndroidBuildActions(ModuleContext) {
-}
diff --git a/android/ninja_deps.go b/android/ninja_deps.go
index 2f442d5..1d50a47 100644
--- a/android/ninja_deps.go
+++ b/android/ninja_deps.go
@@ -14,7 +14,10 @@
package android
-import "sort"
+import (
+ "android/soong/starlark_import"
+ "sort"
+)
func (c *config) addNinjaFileDeps(deps ...string) {
for _, dep := range deps {
@@ -40,4 +43,11 @@
func (ninjaDepsSingleton) GenerateBuildActions(ctx SingletonContext) {
ctx.AddNinjaFileDeps(ctx.Config().ninjaFileDeps()...)
+
+ deps, err := starlark_import.GetNinjaDeps()
+ if err != nil {
+ ctx.Errorf("Error running starlark code: %s", err)
+ } else {
+ ctx.AddNinjaFileDeps(deps...)
+ }
}
diff --git a/android/override_module.go b/android/override_module.go
index 2d30a85..86f582b 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -304,8 +304,9 @@
for i, o := range overrides {
mods[i+1].(OverridableModule).override(ctx, o)
if o.getOverriddenByPrebuilt() {
- // The overriding module itself, too, is overridden by a prebuilt. Skip its installation.
- mods[i+1].HideFromMake()
+ // The overriding module itself, too, is overridden by a prebuilt.
+ // Copy the flag and hide it in make
+ mods[i+1].ReplacedByPrebuilt()
}
}
} else if o, ok := ctx.Module().(OverrideModule); ok {
diff --git a/android/proto.go b/android/proto.go
index 09e50c8..cebbd59 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -234,7 +234,7 @@
}
}
- tags := ApexAvailableTags(ctx.Module())
+ tags := ApexAvailableTagsWithoutTestApexes(ctx.(TopDownMutatorContext), ctx.Module())
ctx.CreateBazelTargetModule(
bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
diff --git a/android/sdk_version.go b/android/sdk_version.go
index 0ae8073..08762ef 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -100,6 +100,15 @@
return name
}
+// JavaApiLibraryNames applies JavaApiLibraryName to the list of java_library names.
+func JavaApiLibraryNames(c Config, names []string) []string {
+ apiLibs := make([]string, len(names))
+ for i, name := range names {
+ apiLibs[i] = JavaApiLibraryName(c, name)
+ }
+ return apiLibs
+}
+
func (k SdkKind) DefaultJavaLibraryName() string {
switch k {
case SdkPublic:
diff --git a/android/test_config.go b/android/test_config.go
index 07ca33d..28d9ec4 100644
--- a/android/test_config.go
+++ b/android/test_config.go
@@ -65,6 +65,7 @@
BuildMode: BazelProdMode,
mixedBuildDisabledModules: make(map[string]struct{}),
mixedBuildEnabledModules: make(map[string]struct{}),
+ bazelForceEnabledModules: make(map[string]struct{}),
}
config.deviceConfig = &deviceConfig{
config: config,
diff --git a/android/util.go b/android/util.go
index 38e0a4d..08a3521 100644
--- a/android/util.go
+++ b/android/util.go
@@ -26,7 +26,11 @@
// CopyOf returns a new slice that has the same contents as s.
func CopyOf(s []string) []string {
- return append([]string(nil), s...)
+ // If the input is nil, return nil and not an empty list
+ if s == nil {
+ return s
+ }
+ return append([]string{}, s...)
}
// Concat returns a new slice concatenated from the two input slices. It does not change the input
@@ -276,6 +280,8 @@
// FirstUniqueStrings returns all unique elements of a slice of strings, keeping the first copy of
// each. It modifies the slice contents in place, and returns a subslice of the original slice.
func FirstUniqueStrings(list []string) []string {
+ // Do not moodify the input in-place, operate on a copy instead.
+ list = CopyOf(list)
// 128 was chosen based on BenchmarkFirstUniqueStrings results.
if len(list) > 128 {
return firstUniqueStringsMap(list)
@@ -332,6 +338,7 @@
// SortedUniqueStrings returns what the name says
func SortedUniqueStrings(list []string) []string {
+ // FirstUniqueStrings creates a copy of `list`, so the input remains untouched.
unique := FirstUniqueStrings(list)
sort.Strings(unique)
return unique
diff --git a/android/util_test.go b/android/util_test.go
index 5584b38..a2ef589 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -381,6 +381,14 @@
}
}
+func TestCopyOfEmptyAndNil(t *testing.T) {
+ emptyList := []string{}
+ copyOfEmptyList := CopyOf(emptyList)
+ AssertBoolEquals(t, "Copy of an empty list should be an empty list and not nil", true, copyOfEmptyList != nil)
+ copyOfNilList := CopyOf(nil)
+ AssertBoolEquals(t, "Copy of a nil list should be a nil list and not an empty list", true, copyOfNilList == nil)
+}
+
func ExampleCopyOf() {
a := []string{"1", "2", "3"}
b := CopyOf(a)
diff --git a/android/variable.go b/android/variable.go
index 249d53b..496f523 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -218,6 +218,7 @@
DeviceVndkVersion *string `json:",omitempty"`
DeviceCurrentApiLevelForVendorModules *string `json:",omitempty"`
DeviceSystemSdkVersions []string `json:",omitempty"`
+ DeviceMaxPageSizeSupported *string `json:",omitempty"`
RecoverySnapshotVersion *string `json:",omitempty"`
@@ -306,6 +307,8 @@
MemtagHeapAsyncIncludePaths []string `json:",omitempty"`
MemtagHeapSyncIncludePaths []string `json:",omitempty"`
+ HWASanIncludePaths []string `json:",omitempty"`
+
VendorPath *string `json:",omitempty"`
OdmPath *string `json:",omitempty"`
ProductPath *string `json:",omitempty"`
@@ -505,6 +508,7 @@
DeviceSecondaryArchVariant: stringPtr("armv8-a"),
DeviceSecondaryCpuVariant: stringPtr("generic"),
DeviceSecondaryAbi: []string{"armeabi-v7a", "armeabi"},
+ DeviceMaxPageSizeSupported: stringPtr("4096"),
AAPTConfig: []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
AAPTPreferredConfig: stringPtr("xhdpi"),
diff --git a/apex/apex.go b/apex/apex.go
index 5451a04..69547c3 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1064,6 +1064,10 @@
apexVariationName := mctx.ModuleName() // could be com.android.foo
a.properties.ApexVariationName = apexVariationName
+ testApexes := []string{}
+ if a.testApex {
+ testApexes = []string{apexVariationName}
+ }
apexInfo := android.ApexInfo{
ApexVariationName: apexVariationName,
MinSdkVersion: minSdkVersion,
@@ -1072,6 +1076,7 @@
InApexVariants: []string{apexVariationName},
InApexModules: []string{a.Name()}, // could be com.mycompany.android.foo
ApexContents: []*android.ApexContents{apexContents},
+ TestApexes: testApexes,
}
mctx.WalkDeps(func(child, parent android.Module) bool {
if !continueApexDepsWalk(child, parent) {
@@ -1659,7 +1664,6 @@
if ccMod.Target().NativeBridge == android.NativeBridgeEnabled {
dirInApex = filepath.Join(dirInApex, ccMod.Target().NativeBridgeRelativePath)
}
- dirInApex = filepath.Join(dirInApex, ccMod.RelativeInstallPath())
if handleSpecialLibs && cc.InstallToBootstrap(ccMod.BaseModuleName(), ctx.Config()) {
// Special case for Bionic libs and other libs installed with them. This is to
// prevent those libs from being included in the search path
@@ -1672,6 +1676,10 @@
// loading of them, which isn't supported.
dirInApex = filepath.Join(dirInApex, "bionic")
}
+ // This needs to go after the runtime APEX handling because otherwise we would get
+ // weird paths like lib64/rel_install_path/bionic rather than
+ // lib64/bionic/rel_install_path.
+ dirInApex = filepath.Join(dirInApex, ccMod.RelativeInstallPath())
fileToCopy := android.OutputFileForModule(ctx, ccMod, "")
androidMkModuleName := ccMod.BaseModuleName() + ccMod.Properties.SubName
@@ -3803,3 +3811,7 @@
func invalidCompileMultilib(ctx android.TopDownMutatorContext, value string) {
ctx.PropertyErrorf("compile_multilib", "Invalid value: %s", value)
}
+
+func (a *apexBundle) IsTestApex() bool {
+ return a.testApex
+}
diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go
index 1581949..ebc35cf 100644
--- a/apex/apex_singleton.go
+++ b/apex/apex_singleton.go
@@ -23,7 +23,11 @@
)
func init() {
- android.RegisterSingletonType("apex_depsinfo_singleton", apexDepsInfoSingletonFactory)
+ registerApexDepsInfoComponents(android.InitRegistrationContext)
+}
+
+func registerApexDepsInfoComponents(ctx android.RegistrationContext) {
+ ctx.RegisterSingletonType("apex_depsinfo_singleton", apexDepsInfoSingletonFactory)
}
type apexDepsInfoSingleton struct {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 8a02a4a..3ba4d8d 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -1001,7 +1001,7 @@
// Ensure that stub dependency from a rust module is not included
ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.shared_from_rust.so")
// The rust module is linked to the stub cc library
- rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").Args["linkFlags"]
+ rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustLink").Args["linkFlags"]
ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so")
ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so")
@@ -1077,7 +1077,7 @@
mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_current/mylib2.so")
ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so")
- rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").Args["linkFlags"]
+ rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustLink").Args["linkFlags"]
ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so")
ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so")
}
@@ -1980,6 +1980,93 @@
android.AssertStringDoesContain(t, "cflags", cflags, "-target aarch64-linux-android29")
}
+func TestTrackAllowedDeps(t *testing.T) {
+ ctx := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ updatable: true,
+ native_shared_libs: [
+ "mylib",
+ "yourlib",
+ ],
+ min_sdk_version: "29",
+ }
+
+ apex {
+ name: "myapex2",
+ key: "myapex.key",
+ updatable: false,
+ native_shared_libs: ["yourlib"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["libbar"],
+ min_sdk_version: "29",
+ apex_available: ["myapex"],
+ }
+
+ cc_library {
+ name: "libbar",
+ stubs: { versions: ["29", "30"] },
+ }
+
+ cc_library {
+ name: "yourlib",
+ srcs: ["mylib.cpp"],
+ min_sdk_version: "29",
+ apex_available: ["myapex", "myapex2", "//apex_available:platform"],
+ }
+ `, withFiles(android.MockFS{
+ "packages/modules/common/build/allowed_deps.txt": nil,
+ }))
+
+ depsinfo := ctx.SingletonForTests("apex_depsinfo_singleton")
+ inputs := depsinfo.Rule("generateApexDepsInfoFilesRule").BuildParams.Inputs.Strings()
+ android.AssertStringListContains(t, "updatable myapex should generate depsinfo file", inputs,
+ "out/soong/.intermediates/myapex/android_common_myapex_image/depsinfo/flatlist.txt")
+ android.AssertStringListDoesNotContain(t, "non-updatable myapex2 should not generate depsinfo file", inputs,
+ "out/soong/.intermediates/myapex2/android_common_myapex2_image/depsinfo/flatlist.txt")
+
+ myapex := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+ flatlist := strings.Split(myapex.Output("depsinfo/flatlist.txt").BuildParams.Args["content"], "\\n")
+ android.AssertStringListContains(t, "deps with stubs should be tracked in depsinfo as external dep",
+ flatlist, "libbar(minSdkVersion:(no version)) (external)")
+ android.AssertStringListDoesNotContain(t, "do not track if not available for platform",
+ flatlist, "mylib:(minSdkVersion:29)")
+ android.AssertStringListContains(t, "track platform-available lib",
+ flatlist, "yourlib(minSdkVersion:29)")
+}
+
+func TestTrackAllowedDeps_SkipWithoutAllowedDepsTxt(t *testing.T) {
+ ctx := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ updatable: true,
+ min_sdk_version: "29",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `)
+ depsinfo := ctx.SingletonForTests("apex_depsinfo_singleton")
+ if nil != depsinfo.MaybeRule("generateApexDepsInfoFilesRule").Output {
+ t.Error("apex_depsinfo_singleton shouldn't run when allowed_deps.txt doesn't exist")
+ }
+}
+
func TestPlatformUsesLatestStubsFromApexes(t *testing.T) {
ctx := testApex(t, `
apex {
@@ -3131,10 +3218,7 @@
stubs: {
versions: ["1", "2", "3"],
},
- apex_available: [
- "//apex_available:platform",
- "myapex",
- ],
+ apex_available: ["myapex"],
}
cc_binary {
@@ -4134,7 +4218,7 @@
apex {
name: "myapex_selfcontained",
key: "myapex.key",
- native_shared_libs: ["lib_dep", "libfoo"],
+ native_shared_libs: ["lib_dep_on_bar", "libbar"],
compile_multilib: "both",
file_contexts: ":myapex-file_contexts",
updatable: false,
@@ -4168,6 +4252,18 @@
}
cc_library {
+ name: "lib_dep_on_bar",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["libbar"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [
+ "myapex_selfcontained",
+ ],
+ }
+
+
+ cc_library {
name: "libfoo",
srcs: ["mytest.cpp"],
stubs: {
@@ -4177,9 +4273,22 @@
stl: "none",
apex_available: [
"myapex_provider",
+ ],
+ }
+
+ cc_library {
+ name: "libbar",
+ srcs: ["mytest.cpp"],
+ stubs: {
+ versions: ["1"],
+ },
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [
"myapex_selfcontained",
],
}
+
`)
var apexManifestRule android.TestingBuildParams
@@ -4206,7 +4315,7 @@
apexManifestRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained_image").Rule("apexManifestRule")
provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
- ensureListContains(t, provideNativeLibs, "libfoo.so")
+ ensureListContains(t, provideNativeLibs, "libbar.so")
ensureListEmpty(t, requireNativeLibs)
}
@@ -5281,7 +5390,16 @@
apex_set {
name: "myapex",
set: "myapex.apks",
+ exported_java_libs: ["myjavalib"],
exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
+ exported_systemserverclasspath_fragments: ["my-systemserverclasspath-fragment"],
+ }
+
+ java_import {
+ name: "myjavalib",
+ jars: ["myjavalib.jar"],
+ apex_available: ["myapex"],
+ permitted_packages: ["javalib"],
}
prebuilt_bootclasspath_fragment {
@@ -5298,6 +5416,12 @@
},
}
+ prebuilt_systemserverclasspath_fragment {
+ name: "my-systemserverclasspath-fragment",
+ contents: ["libbaz"],
+ apex_available: ["myapex"],
+ }
+
java_import {
name: "libfoo",
jars: ["libfoo.jar"],
@@ -5314,6 +5438,16 @@
shared_library: false,
permitted_packages: ["bar"],
}
+
+ java_sdk_library_import {
+ name: "libbaz",
+ public: {
+ jars: ["libbaz.jar"],
+ },
+ apex_available: ["myapex"],
+ shared_library: false,
+ permitted_packages: ["baz"],
+ }
`
ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
@@ -5326,6 +5460,24 @@
my-bootclasspath-fragment/index.csv
out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv
`)
+
+ myApex := ctx.ModuleForTests("myapex", "android_common_myapex").Module()
+
+ overrideNames := []string{
+ "",
+ "myjavalib.myapex",
+ "libfoo.myapex",
+ "libbar.myapex",
+ "libbaz.myapex",
+ }
+ mkEntries := android.AndroidMkEntriesForTest(t, ctx, myApex)
+ for i, e := range mkEntries {
+ g := e.OverrideName
+ if w := overrideNames[i]; w != g {
+ t.Errorf("Expected override name %q, got %q", w, g)
+ }
+ }
+
})
t.Run("prebuilt with source library preferred", func(t *testing.T) {
@@ -7515,6 +7667,7 @@
"some-updatable-apex",
],
permitted_packages: ["some.updatable.apex.lib"],
+ min_sdk_version: "33",
}
java_library {
@@ -7554,6 +7707,7 @@
],
hostdex: true,
compile_dex: true,
+ min_sdk_version: "33",
}
apex {
@@ -7561,7 +7715,7 @@
key: "some-updatable-apex.key",
java_libs: ["some-updatable-apex-lib"],
updatable: true,
- min_sdk_version: "current",
+ min_sdk_version: "33",
}
apex {
@@ -7584,7 +7738,7 @@
key: "com.android.art.debug.key",
bootclasspath_fragments: ["art-bootclasspath-fragment"],
updatable: true,
- min_sdk_version: "current",
+ min_sdk_version: "33",
}
bootclasspath_fragment {
@@ -8443,14 +8597,14 @@
apex {
name: "com.android.art",
key: "myapex.key",
- native_shared_libs: ["mylib"],
+ native_shared_libs: ["libnativebridge"],
updatable: false,
}
apex {
name: "com.android.art.debug",
key: "myapex.key",
- native_shared_libs: ["mylib", "mytestlib"],
+ native_shared_libs: ["libnativebridge", "libnativebrdige_test"],
updatable: false,
}
@@ -8461,8 +8615,8 @@
}
cc_library {
- name: "mylib",
- srcs: ["mylib.cpp"],
+ name: "libnativebridge",
+ srcs: ["libnativebridge.cpp"],
system_shared_libs: [],
stl: "none",
stubs: {
@@ -8472,10 +8626,10 @@
}
cc_library {
- name: "mytestlib",
+ name: "libnativebrdige_test",
srcs: ["mylib.cpp"],
system_shared_libs: [],
- shared_libs: ["mylib"],
+ shared_libs: ["libnativebridge"],
stl: "none",
apex_available: ["com.android.art.debug"],
test_for: ["com.android.art"],
@@ -10147,3 +10301,77 @@
// Ensure that canned_fs_config has "cat my_config" at the end
ensureContains(t, cmd, `( echo '/ 1000 1000 0755'; echo '/apex_manifest.json 1000 1000 0644'; echo '/apex_manifest.pb 1000 1000 0644'; cat my_config ) >`)
}
+
+func TestStubLibrariesMultipleApexViolation(t *testing.T) {
+ testCases := []struct {
+ desc string
+ hasStubs bool
+ apexAvailable string
+ expectedError string
+ }{
+ {
+ desc: "non-stub library can have multiple apex_available",
+ hasStubs: false,
+ apexAvailable: `["myapex", "otherapex"]`,
+ },
+ {
+ desc: "stub library should not be available to anyapex",
+ hasStubs: true,
+ apexAvailable: `["//apex_available:anyapex"]`,
+ expectedError: "Stub libraries should have a single apex_available.*anyapex",
+ },
+ {
+ desc: "stub library should not be available to multiple apexes",
+ hasStubs: true,
+ apexAvailable: `["myapex", "otherapex"]`,
+ expectedError: "Stub libraries should have a single apex_available.*myapex.*otherapex",
+ },
+ {
+ desc: "stub library can be available to a core apex and a test apex",
+ hasStubs: true,
+ apexAvailable: `["myapex", "test_myapex"]`,
+ },
+ }
+ bpTemplate := `
+ cc_library {
+ name: "libfoo",
+ %v
+ apex_available: %v,
+ }
+ apex {
+ name: "myapex",
+ key: "apex.key",
+ updatable: false,
+ native_shared_libs: ["libfoo"],
+ }
+ apex {
+ name: "otherapex",
+ key: "apex.key",
+ updatable: false,
+ }
+ apex_test {
+ name: "test_myapex",
+ key: "apex.key",
+ updatable: false,
+ native_shared_libs: ["libfoo"],
+ }
+ apex_key {
+ name: "apex.key",
+ }
+ `
+ for _, tc := range testCases {
+ stubs := ""
+ if tc.hasStubs {
+ stubs = `stubs: {symbol_file: "libfoo.map.txt"},`
+ }
+ bp := fmt.Sprintf(bpTemplate, stubs, tc.apexAvailable)
+ mockFsFixturePreparer := android.FixtureModifyMockFS(func(fs android.MockFS) {
+ fs["system/sepolicy/apex/test_myapex-file_contexts"] = nil
+ })
+ if tc.expectedError == "" {
+ testApex(t, bp, mockFsFixturePreparer)
+ } else {
+ testApexError(t, tc.expectedError, bp, mockFsFixturePreparer)
+ }
+ }
+}
diff --git a/apex/builder.go b/apex/builder.go
index 94aef49..7c6522d 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -231,7 +231,7 @@
apexSepolicyTestsRule = pctx.StaticRule("apexSepolicyTestsRule", blueprint.RuleParams{
Command: `${deapexer} --debugfs_path ${debugfs_static} list -Z ${in} > ${out}.fc` +
- `&& ${apex_sepolicy_tests} -f ${out}.fc && touch ${out}`,
+ ` && ${apex_sepolicy_tests} -f ${out}.fc && touch ${out}`,
CommandDeps: []string{"${apex_sepolicy_tests}", "${deapexer}", "${debugfs_static}"},
Description: "run apex_sepolicy_tests",
})
@@ -513,9 +513,6 @@
}
}
implicitInputs = append(implicitInputs, fi.builtFile)
- if installSymbolFiles {
- implicitInputs = append(implicitInputs, installedPath)
- }
// Create additional symlinks pointing the file inside the APEX (if any). Note that
// this is independent from the symlink optimization.
@@ -523,8 +520,7 @@
symlinkDest := imageDir.Join(ctx, symlinkPath).String()
copyCommands = append(copyCommands, "ln -sfn "+filepath.Base(destPath)+" "+symlinkDest)
if installSymbolFiles {
- installedSymlink := ctx.InstallSymlink(apexDir.Join(ctx, filepath.Dir(symlinkPath)), filepath.Base(symlinkPath), installedPath)
- implicitInputs = append(implicitInputs, installedSymlink)
+ ctx.InstallSymlink(apexDir.Join(ctx, filepath.Dir(symlinkPath)), filepath.Base(symlinkPath), installedPath)
}
}
@@ -549,11 +545,6 @@
installMapSet[installMapPath.String()+":"+fi.installDir+"/"+fi.builtFile.Base()] = true
}
implicitInputs = append(implicitInputs, a.manifestPbOut)
- if installSymbolFiles {
- installedManifest := ctx.InstallFile(apexDir, "apex_manifest.pb", a.manifestPbOut)
- installedKey := ctx.InstallFile(apexDir, "apex_pubkey", a.publicKeyFile)
- implicitInputs = append(implicitInputs, installedManifest, installedKey)
- }
if len(installMapSet) > 0 {
var installs []string
@@ -881,7 +872,8 @@
args["outCommaList"] = signedOutputFile.String()
}
var validations android.Paths
- if suffix == imageApexSuffix {
+ // TODO(b/279688635) deapexer supports [ext4]
+ if suffix == imageApexSuffix && ext4 == a.payloadFsType {
validations = append(validations, runApexSepolicyTests(ctx, unsignedOutputFile.OutputPath))
}
ctx.Build(pctx, android.BuildParams{
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index cae507e..31cecf1 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -316,31 +316,29 @@
}
}
-func (p *prebuiltCommon) getExportedDependencies() map[string]exportedDependencyTag {
- dependencies := make(map[string]exportedDependencyTag)
-
- for _, dep := range p.prebuiltCommonProperties.Exported_java_libs {
- dependencies[dep] = exportedJavaLibTag
- }
-
- for _, dep := range p.prebuiltCommonProperties.Exported_bootclasspath_fragments {
- dependencies[dep] = exportedBootclasspathFragmentTag
- }
-
- for _, dep := range p.prebuiltCommonProperties.Exported_systemserverclasspath_fragments {
- dependencies[dep] = exportedSystemserverclasspathFragmentTag
- }
-
- return dependencies
+func (p *prebuiltCommon) hasExportedDeps() bool {
+ return len(p.prebuiltCommonProperties.Exported_java_libs) > 0 ||
+ len(p.prebuiltCommonProperties.Exported_bootclasspath_fragments) > 0 ||
+ len(p.prebuiltCommonProperties.Exported_systemserverclasspath_fragments) > 0
}
// prebuiltApexContentsDeps adds dependencies onto the prebuilt apex module's contents.
func (p *prebuiltCommon) prebuiltApexContentsDeps(ctx android.BottomUpMutatorContext) {
module := ctx.Module()
- for dep, tag := range p.getExportedDependencies() {
+ for _, dep := range p.prebuiltCommonProperties.Exported_java_libs {
prebuiltDep := android.PrebuiltNameFromSource(dep)
- ctx.AddDependency(module, tag, prebuiltDep)
+ ctx.AddDependency(module, exportedJavaLibTag, prebuiltDep)
+ }
+
+ for _, dep := range p.prebuiltCommonProperties.Exported_bootclasspath_fragments {
+ prebuiltDep := android.PrebuiltNameFromSource(dep)
+ ctx.AddDependency(module, exportedBootclasspathFragmentTag, prebuiltDep)
+ }
+
+ for _, dep := range p.prebuiltCommonProperties.Exported_systemserverclasspath_fragments {
+ prebuiltDep := android.PrebuiltNameFromSource(dep)
+ ctx.AddDependency(module, exportedSystemserverclasspathFragmentTag, prebuiltDep)
}
}
@@ -608,7 +606,7 @@
// the listed modules need access to files from within the prebuilt .apex file.
func (p *prebuiltCommon) createDeapexerModuleIfNeeded(ctx android.TopDownMutatorContext, deapexerName string, apexFileSource string) {
// Only create the deapexer module if it is needed.
- if len(p.getExportedDependencies()) == 0 {
+ if !p.hasExportedDeps() {
return
}
diff --git a/apex/testing.go b/apex/testing.go
index 69bd73e..3b200f0 100644
--- a/apex/testing.go
+++ b/apex/testing.go
@@ -19,6 +19,7 @@
var PrepareForTestWithApexBuildComponents = android.GroupFixturePreparers(
android.FixtureRegisterWithContext(registerApexBuildComponents),
android.FixtureRegisterWithContext(registerApexKeyBuildComponents),
+ android.FixtureRegisterWithContext(registerApexDepsInfoComponents),
// Additional files needed in tests that disallow non-existent source files.
// This includes files that are needed by all, or at least most, instances of an apex module type.
android.MockFS{
diff --git a/bazel/bazel_proxy.go b/bazel/bazel_proxy.go
index d7f5e64..2940b99 100644
--- a/bazel/bazel_proxy.go
+++ b/bazel/bazel_proxy.go
@@ -128,6 +128,24 @@
}
}
+func ExecBazel(bazelPath string, workspaceDir string, request CmdRequest) (stdout []byte, stderr []byte, cmdErr error) {
+ bazelCmd := exec.Command(bazelPath, request.Argv...)
+ bazelCmd.Dir = workspaceDir
+ bazelCmd.Env = request.Env
+
+ stderrBuffer := &bytes.Buffer{}
+ bazelCmd.Stderr = stderrBuffer
+
+ if output, err := bazelCmd.Output(); err != nil {
+ cmdErr = fmt.Errorf("bazel command failed: %s\n---command---\n%s\n---env---\n%s\n---stderr---\n%s---",
+ err, bazelCmd, strings.Join(bazelCmd.Env, "\n"), stderrBuffer)
+ } else {
+ stdout = output
+ }
+ stderr = stderrBuffer.Bytes()
+ return
+}
+
func (b *ProxyServer) handleRequest(conn net.Conn) error {
defer conn.Close()
@@ -137,23 +155,13 @@
return fmt.Errorf("Error decoding request: %s", err)
}
- bazelCmd := exec.Command("./build/bazel/bin/bazel", req.Argv...)
- bazelCmd.Dir = b.workspaceDir
- bazelCmd.Env = req.Env
-
- stderr := &bytes.Buffer{}
- bazelCmd.Stderr = stderr
- var stdout string
- var bazelErrString string
-
- if output, err := bazelCmd.Output(); err != nil {
- bazelErrString = fmt.Sprintf("bazel command failed: %s\n---command---\n%s\n---env---\n%s\n---stderr---\n%s---",
- err, bazelCmd, strings.Join(bazelCmd.Env, "\n"), stderr)
- } else {
- stdout = string(output)
+ stdout, stderr, cmdErr := ExecBazel("./build/bazel/bin/bazel", b.workspaceDir, req)
+ errorString := ""
+ if cmdErr != nil {
+ errorString = cmdErr.Error()
}
- resp := CmdResponse{stdout, string(stderr.Bytes()), bazelErrString}
+ resp := CmdResponse{string(stdout), string(stderr), errorString}
enc := gob.NewEncoder(conn)
if err := enc.Encode(&resp); err != nil {
return fmt.Errorf("Error encoding response: %s", err)
diff --git a/bazel/configurability.go b/bazel/configurability.go
index 4680256..d01877d 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -268,9 +268,8 @@
case productVariables:
// do nothing
case osAndInApex:
- if _, ok := osAndInApexMap[config]; !ok {
- panic(fmt.Errorf("Unknown os+in_apex config: %s", config))
- }
+ // do nothing
+ // this axis can contain additional per-apex keys
case inApex:
if _, ok := inApexMap[config]; !ok {
panic(fmt.Errorf("Unknown in_apex config: %s", config))
@@ -299,7 +298,10 @@
}
return fmt.Sprintf("%s:%s", productVariableBazelPackage, config)
case osAndInApex:
- return osAndInApexMap[config]
+ if ret, exists := osAndInApexMap[config]; exists {
+ return ret
+ }
+ return config
case inApex:
return inApexMap[config]
default:
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index bf3a6b5..6a3b3c8 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -149,6 +149,7 @@
rootSharedLibraries = []
shared_info_tag = "//build/bazel/rules/cc:cc_library_shared.bzl%CcSharedLibraryOutputInfo"
+stubs_tag = "//build/bazel/rules/cc:cc_stub_library.bzl%CcStubInfo"
unstripped_tag = "//build/bazel/rules/cc:stripped_cc_common.bzl%CcUnstrippedInfo"
unstripped = ""
@@ -160,6 +161,8 @@
unstripped = path
if unstripped_tag in p:
unstripped = p[unstripped_tag].unstripped.path
+elif stubs_tag in p:
+ rootSharedLibraries.extend([f.path for f in target.files.to_list()])
else:
for linker_input in linker_inputs:
for library in linker_input.libraries:
diff --git a/bazel/properties.go b/bazel/properties.go
index 40d0ba3..1757bad 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -1424,3 +1424,14 @@
sub := productVariableSubstitutionPattern.ReplaceAllString(s, "$("+productVariable+")")
return sub, s != sub
}
+
+// StringMapAttribute is a map of strings.
+// The use case for this is storing the flag_values in a config_setting object.
+// Bazel rules do not support map attributes, and this should NOT be used in Bazel rules.
+type StringMapAttribute map[string]string
+
+// ConfigSettingAttributes stores the keys of a config_setting object.
+type ConfigSettingAttributes struct {
+ // Each key in Flag_values is a label to a custom string_setting
+ Flag_values StringMapAttribute
+}
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index 598ca32..b6635c4 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -76,6 +76,7 @@
"prebuilt_etc_conversion_test.go",
"python_binary_conversion_test.go",
"python_library_conversion_test.go",
+ "python_test_conversion_test.go",
"sh_conversion_test.go",
"soong_config_module_type_conversion_test.go",
],
diff --git a/bp2build/aar_conversion_test.go b/bp2build/aar_conversion_test.go
index 6020ee5..09d9dc1 100644
--- a/bp2build/aar_conversion_test.go
+++ b/bp2build/aar_conversion_test.go
@@ -66,9 +66,12 @@
"resource_files": `["res/res.png"]`,
"deps": `[":static_lib_dep"]`,
"exports": `[":static_lib_dep"]`,
- "javacopts": `["-source 1.7 -target 1.7"]`,
+ "java_version": `"7"`,
}),
- MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
+ MakeNeverlinkDuplicateTargetWithAttrs(
+ "android_library",
+ "TestLib",
+ AttrNameToString{"java_version": `"7"`}),
}})
}
diff --git a/bp2build/android_app_conversion_test.go b/bp2build/android_app_conversion_test.go
index ef3f124..928a1f2 100644
--- a/bp2build/android_app_conversion_test.go
+++ b/bp2build/android_app_conversion_test.go
@@ -53,6 +53,7 @@
"srcs": `["app.java"]`,
"manifest": `"AndroidManifest.xml"`,
"resource_files": `["res/res.png"]`,
+ "sdk_version": `"current"`,
}),
}})
}
@@ -91,7 +92,8 @@
]`,
"custom_package": `"com.google"`,
"deps": `[":static_lib_dep"]`,
- "javacopts": `["-source 1.7 -target 1.7"]`,
+ "java_version": `"7"`,
+ "sdk_version": `"current"`,
"certificate_name": `"foocert"`,
}),
}})
@@ -131,6 +133,7 @@
})`,
"manifest": `"AndroidManifest.xml"`,
"resource_files": `["res/res.png"]`,
+ "sdk_version": `"current"`,
}),
}})
}
@@ -365,6 +368,7 @@
"manifest_values": `{
"minSdkVersion": "24",
}`,
+ "sdk_version": `"current"`,
}),
}})
}
@@ -388,6 +392,7 @@
"manifest_values": `{
"minSdkVersion": "30",
}`,
+ "sdk_version": `"30"`,
}),
}})
}
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
index d1dfb9d..b22cb28 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -15,6 +15,7 @@
package bp2build
import (
+ "android/soong/starlark_import"
"fmt"
"os"
"path/filepath"
@@ -93,6 +94,12 @@
os.Exit(1)
}
writeFiles(ctx, android.PathForOutput(ctx, bazel.SoongInjectionDirName), injectionFiles)
+ starlarkDeps, err := starlark_import.GetNinjaDeps()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s\n", err)
+ os.Exit(1)
+ }
+ ctx.AddNinjaFileDeps(starlarkDeps...)
return &res.metrics
}
diff --git a/bp2build/bp2build_product_config.go b/bp2build/bp2build_product_config.go
index ab2f821..3abef9d 100644
--- a/bp2build/bp2build_product_config.go
+++ b/bp2build/bp2build_product_config.go
@@ -68,16 +68,6 @@
"@//build/bazel/product_config:__subpackages__",
"@soong_injection//product_config_platforms:__subpackages__",
])
-
-# TODO(b/249685973): Remove this. It was only added for a platform_mappings file,
-# which can possibly be replaced with autogenerating the platform_mappings file,
-# or removing that file entirely.
-alias(
- name = "current_android_platform",
- # TODO: When we start generating the platforms for more than just the
- # currently lunched, product, turn this into a select with an arm for each product.
- actual = "@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}",
-)
`)),
newFile(
"product_config_platforms",
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index fde9b69..a860484 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -321,6 +321,9 @@
// target, each of a different rule class.
metrics.IncrementRuleClassCount(t.ruleClass)
}
+ } else if _, ok := ctx.Config().BazelModulesForceEnabledByFlag()[m.Name()]; ok && m.Name() != "" {
+ err := fmt.Errorf("Force Enabled Module %s not converted", m.Name())
+ errs = append(errs, err)
} else {
metrics.AddUnconvertedModule(moduleType)
return
@@ -597,6 +600,11 @@
// TODO(b/164227191): implement pretty print for interfaces.
// Interfaces are used for for arch, multilib and target properties.
return "", nil
+ case reflect.Map:
+ if v, ok := propertyValue.Interface().(bazel.StringMapAttribute); ok {
+ return starlark_fmt.PrintStringStringDict(v, indent), nil
+ }
+ return "", fmt.Errorf("bp2build expects map of type map[string]string for field: %s", propertyValue)
default:
return "", fmt.Errorf(
"unexpected kind for property struct field: %s", propertyValue.Kind())
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index d312169..1b64055 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -1175,6 +1175,8 @@
bp2buildConfig allowlists.Bp2BuildConfig
checkDir string
fs map[string]string
+ forceEnabledModules []string
+ expectedErrorMessages []string
}{
{
description: "test bp2build config package and subpackages config",
@@ -1237,6 +1239,24 @@
`,
},
},
+ {
+ description: "test force-enabled errors out",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
+ expectedCount: map[string]int{
+ "migrated": 0,
+ "not_migrated": 0,
+ },
+ bp2buildConfig: allowlists.Bp2BuildConfig{
+ "migrated/but_not_really": allowlists.Bp2BuildDefaultFalse,
+ "not_migrated": allowlists.Bp2BuildDefaultFalse,
+ },
+ fs: map[string]string{
+ "migrated/Android.bp": `filegroup { name: "a" }`,
+ },
+ forceEnabledModules: []string{"a"},
+ expectedErrorMessages: []string{"Force Enabled Module a not converted"},
+ },
}
dir := "."
@@ -1252,6 +1272,7 @@
fs[f] = []byte(content)
}
config := android.TestConfig(buildDir, nil, "", fs)
+ config.AddForceEnabledModules(testCase.forceEnabledModules)
ctx := android.NewTestContext(config)
ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
allowlist := android.NewBp2BuildAllowlist().SetDefaultConfig(testCase.bp2buildConfig)
@@ -1268,7 +1289,7 @@
// For each directory, test that the expected number of generated targets is correct.
for dir, expectedCount := range testCase.expectedCount {
bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
- android.FailIfErrored(t, err)
+ android.CheckErrorsAgainstExpectations(t, err, testCase.expectedErrorMessages)
if actualCount := len(bazelTargets); actualCount != expectedCount {
t.Fatalf(
"%s: Expected %d bazel target for %s package, got %d",
@@ -1877,3 +1898,36 @@
Description: "Generating API contribution Bazel targets for custom module",
})
}
+
+func TestGenerateConfigSetting(t *testing.T) {
+ bp := `
+ custom {
+ name: "foo",
+ test_config_setting: true,
+ }
+ `
+ expectedBazelTargets := []string{
+ MakeBazelTargetNoRestrictions(
+ "config_setting",
+ "foo_config_setting",
+ AttrNameToString{
+ "flag_values": `{
+ "//build/bazel/rules/my_string_setting": "foo",
+ }`,
+ },
+ ),
+ MakeBazelTarget(
+ "custom",
+ "foo",
+ AttrNameToString{},
+ ),
+ }
+ registerCustomModule := func(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+ }
+ RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+ Blueprint: bp,
+ ExpectedBazelTargets: expectedBazelTargets,
+ Description: "Generating API contribution Bazel targets for custom module",
+ })
+}
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index a8e557d..fa1bf8a 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -108,6 +108,7 @@
"string_literal_prop": attr.string(),
"string_prop": attr.string(),
"string_ptr_prop": attr.string(),
+ "test_config_setting": attr.bool(),
},
)
@@ -139,6 +140,7 @@
"string_literal_prop": attr.string(),
"string_prop": attr.string(),
"string_ptr_prop": attr.string(),
+ "test_config_setting": attr.bool(),
},
)
@@ -170,6 +172,7 @@
"string_literal_prop": attr.string(),
"string_prop": attr.string(),
"string_ptr_prop": attr.string(),
+ "test_config_setting": attr.bool(),
# test_prop start
# "test_string_prop": attr.string(),
# test_prop end
diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go
index 0315732..89eac8a 100644
--- a/bp2build/cc_binary_conversion_test.go
+++ b/bp2build/cc_binary_conversion_test.go
@@ -996,3 +996,44 @@
},
})
}
+
+func TestCcBinaryHiddenVisibilityConvertedToFeature(t *testing.T) {
+ runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+ description: "cc_binary changes hidden visibility to feature",
+ blueprint: `
+{rule_name} {
+ name: "foo",
+ cflags: ["-fvisibility=hidden"],
+}`,
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `["visibility_hidden"]`,
+ }},
+ },
+ })
+}
+
+func TestCcBinaryHiddenVisibilityConvertedToFeatureOsSpecific(t *testing.T) {
+ runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+ description: "cc_binary changes hidden visibility to feature for specific os",
+ blueprint: `
+{rule_name} {
+ name: "foo",
+ target: {
+ android: {
+ cflags: ["-fvisibility=hidden"],
+ },
+ },
+}`,
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os:android": ["visibility_hidden"],
+ "//conditions:default": [],
+ })`,
+ }},
+ },
+ })
+}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index d2c463d..9f78195 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -4350,3 +4350,136 @@
},
})
}
+
+func TestCcLibraryHiddenVisibilityConvertedToFeature(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library changes hidden visibility flag to feature",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: `
+cc_library {
+ name: "foo",
+ cflags: ["-fvisibility=hidden"],
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "features": `["visibility_hidden"]`,
+ "local_includes": `["."]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `["visibility_hidden"]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryHiddenVisibilityConvertedToFeatureSharedSpecific(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library changes hidden visibility flag to feature when specific to shared variant",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: `
+cc_library {
+ name: "foo",
+ shared: {
+ cflags: ["-fvisibility=hidden"],
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "local_includes": `["."]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `["visibility_hidden"]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryHiddenVisibilityConvertedToFeatureStaticSpecific(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library changes hidden visibility flag to feature when specific to static variant",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: `
+cc_library {
+ name: "foo",
+ static: {
+ cflags: ["-fvisibility=hidden"],
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "features": `["visibility_hidden"]`,
+ "local_includes": `["."]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryHiddenVisibilityConvertedToFeatureOsSpecific(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library changes hidden visibility flag to feature when specific to an os",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: `
+cc_library {
+ name: "foo",
+ target: {
+ android: {
+ cflags: ["-fvisibility=hidden"],
+ },
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "features": `select({
+ "//build/bazel/platforms/os:android": ["visibility_hidden"],
+ "//conditions:default": [],
+ })`,
+ "local_includes": `["."]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `select({
+ "//build/bazel/platforms/os:android": ["visibility_hidden"],
+ "//conditions:default": [],
+ })`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+// Test that a config_setting specific to an apex is created by cc_library.
+func TestCcLibraryCreatesInApexConfigSetting(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library creates a config_setting for each apex in apex_available",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Dir: "build/bazel/rules/apex",
+ Blueprint: `
+cc_library {
+ name: "foo",
+ apex_available: [
+ "//apex_available:platform", // This will be skipped, since it is equivalent to //build/bazel/rules/apex:android-non_apex
+ "myapex"
+ ],
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions(
+ "config_setting",
+ "android-in_myapex",
+ AttrNameToString{
+ "flag_values": `{
+ "//build/bazel/rules/apex:apex_name": "myapex",
+ }`,
+ },
+ ),
+ },
+ })
+}
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index 8e0a728..f5d62c6 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -36,6 +36,7 @@
func runCcLibrarySharedTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
+ t.Parallel()
(&tc).ModuleTypeUnderTest = "cc_library_shared"
(&tc).ModuleTypeUnderTestFactory = cc.LibrarySharedFactory
RunBp2BuildTestCase(t, registerCcLibrarySharedModuleTypes, tc)
@@ -1249,3 +1250,107 @@
},
})
}
+
+func TestCcLibrarySharedHiddenVisibilityConvertedToFeature(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared changes hidden visibility flag to feature",
+ Blueprint: `
+cc_library_shared{
+ name: "foo",
+ cflags: ["-fvisibility=hidden"],
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `["visibility_hidden"]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibrarySharedHiddenVisibilityConvertedToFeatureOsSpecific(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared changes hidden visibility flag to feature for specific os",
+ Blueprint: `
+cc_library_shared{
+ name: "foo",
+ target: {
+ android: {
+ cflags: ["-fvisibility=hidden"],
+ },
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `select({
+ "//build/bazel/platforms/os:android": ["visibility_hidden"],
+ "//conditions:default": [],
+ })`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibrarySharedStubsDessertVersionConversion(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared converts dessert codename versions to numerical versions",
+ Blueprint: `
+cc_library_shared {
+ name: "a",
+ include_build_directory: false,
+ stubs: {
+ symbol_file: "a.map.txt",
+ versions: [
+ "Q",
+ "R",
+ "31",
+ ],
+ },
+}
+cc_library_shared {
+ name: "b",
+ include_build_directory: false,
+ stubs: {
+ symbol_file: "b.map.txt",
+ versions: [
+ "Q",
+ "R",
+ "31",
+ "current",
+ ],
+ },
+}
+`,
+ ExpectedBazelTargets: []string{
+ makeCcStubSuiteTargets("a", AttrNameToString{
+ "soname": `"a.so"`,
+ "source_library_label": `"//:a"`,
+ "stubs_symbol_file": `"a.map.txt"`,
+ "stubs_versions": `[
+ "29",
+ "30",
+ "31",
+ "current",
+ ]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
+ "stubs_symbol_file": `"a.map.txt"`,
+ }),
+ makeCcStubSuiteTargets("b", AttrNameToString{
+ "soname": `"b.so"`,
+ "source_library_label": `"//:b"`,
+ "stubs_symbol_file": `"b.map.txt"`,
+ "stubs_versions": `[
+ "29",
+ "30",
+ "31",
+ "current",
+ ]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "b", AttrNameToString{
+ "stubs_symbol_file": `"b.map.txt"`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index cd4cf51..f89f2dd 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -2032,3 +2032,44 @@
},
})
}
+
+func TestCcLibraryStaticHiddenVisibilityConvertedToFeature(t *testing.T) {
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static changes hidden visibility flag to feature",
+ Blueprint: `
+cc_library_static {
+ name: "foo",
+ cflags: ["-fvisibility=hidden"],
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+ "features": `["visibility_hidden"]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryStaticHiddenVisibilityConvertedToFeatureOsSpecific(t *testing.T) {
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static changes hidden visibility flag to feature for specific os",
+ Blueprint: `
+cc_library_static {
+ name: "foo",
+ target: {
+ android: {
+ cflags: ["-fvisibility=hidden"],
+ },
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+ "features": `select({
+ "//build/bazel/platforms/os:android": ["visibility_hidden"],
+ "//conditions:default": [],
+ })`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/cc_prebuilt_library_conversion_test.go b/bp2build/cc_prebuilt_library_conversion_test.go
index c5a6dfd..b88960e 100644
--- a/bp2build/cc_prebuilt_library_conversion_test.go
+++ b/bp2build/cc_prebuilt_library_conversion_test.go
@@ -20,12 +20,17 @@
"android/soong/cc"
)
+func runCcPrebuiltLibraryTestCase(t *testing.T, tc Bp2buildTestCase) {
+ t.Helper()
+ (&tc).ModuleTypeUnderTest = "cc_prebuilt_library"
+ (&tc).ModuleTypeUnderTestFactory = cc.PrebuiltLibraryFactory
+ RunBp2BuildTestCaseSimple(t, tc)
+}
+
func TestPrebuiltLibraryStaticAndSharedSimple(t *testing.T) {
- RunBp2BuildTestCaseSimple(t,
+ runCcPrebuiltLibraryTestCase(t,
Bp2buildTestCase{
- Description: "prebuilt library static and shared simple",
- ModuleTypeUnderTest: "cc_prebuilt_library",
- ModuleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
+ Description: "prebuilt library static and shared simple",
Filesystem: map[string]string{
"libf.so": "",
},
@@ -51,11 +56,9 @@
}
func TestPrebuiltLibraryWithArchVariance(t *testing.T) {
- RunBp2BuildTestCaseSimple(t,
+ runCcPrebuiltLibraryTestCase(t,
Bp2buildTestCase{
- Description: "prebuilt library with arch variance",
- ModuleTypeUnderTest: "cc_prebuilt_library",
- ModuleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
+ Description: "prebuilt library with arch variance",
Filesystem: map[string]string{
"libf.so": "",
"libg.so": "",
@@ -95,11 +98,9 @@
}
func TestPrebuiltLibraryAdditionalAttrs(t *testing.T) {
- RunBp2BuildTestCaseSimple(t,
+ runCcPrebuiltLibraryTestCase(t,
Bp2buildTestCase{
- Description: "prebuilt library additional attributes",
- ModuleTypeUnderTest: "cc_prebuilt_library",
- ModuleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
+ Description: "prebuilt library additional attributes",
Filesystem: map[string]string{
"libf.so": "",
"testdir/1/include.h": "",
@@ -125,20 +126,19 @@
"export_system_includes": `["testdir/2/"]`,
"alwayslink": "True",
}),
- // TODO(b/229374533): When fixed, update this test
MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
- "shared_library": `"libf.so"`,
+ "shared_library": `"libf.so"`,
+ "export_includes": `["testdir/1/"]`,
+ "export_system_includes": `["testdir/2/"]`,
}),
},
})
}
func TestPrebuiltLibrarySharedStanzaFails(t *testing.T) {
- RunBp2BuildTestCaseSimple(t,
+ runCcPrebuiltLibraryTestCase(t,
Bp2buildTestCase{
- Description: "prebuilt library with shared stanza fails because multiple sources",
- ModuleTypeUnderTest: "cc_prebuilt_library",
- ModuleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
+ Description: "prebuilt library with shared stanza fails because multiple sources",
Filesystem: map[string]string{
"libf.so": "",
"libg.so": "",
@@ -180,11 +180,9 @@
}
func TestPrebuiltLibrarySharedAndStaticStanzas(t *testing.T) {
- RunBp2BuildTestCaseSimple(t,
+ runCcPrebuiltLibraryTestCase(t,
Bp2buildTestCase{
- Description: "prebuilt library with both shared and static stanzas",
- ModuleTypeUnderTest: "cc_prebuilt_library",
- ModuleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
+ Description: "prebuilt library with both shared and static stanzas",
Filesystem: map[string]string{
"libf.so": "",
"libg.so": "",
@@ -217,11 +215,9 @@
// TODO(b/228623543): When this bug is fixed, enable this test
//func TestPrebuiltLibraryOnlyShared(t *testing.T) {
-// RunBp2BuildTestCaseSimple(t,
+// runCcPrebuiltLibraryTestCase(t,
// bp2buildTestCase{
// description: "prebuilt library shared only",
-// moduleTypeUnderTest: "cc_prebuilt_library",
-// moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
// filesystem: map[string]string{
// "libf.so": "",
// },
@@ -244,11 +240,9 @@
// TODO(b/228623543): When this bug is fixed, enable this test
//func TestPrebuiltLibraryOnlyStatic(t *testing.T) {
-// RunBp2BuildTestCaseSimple(t,
+// runCcPrebuiltLibraryTestCase(t,
// bp2buildTestCase{
// description: "prebuilt library static only",
-// moduleTypeUnderTest: "cc_prebuilt_library",
-// moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
// filesystem: map[string]string{
// "libf.so": "",
// },
@@ -272,3 +266,97 @@
// },
// })
//}
+
+func TestPrebuiltLibraryWithExportIncludesArchVariant(t *testing.T) {
+ runCcPrebuiltLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_prebuilt_library correctly translates export_includes with arch variance",
+ Filesystem: map[string]string{
+ "libf.so": "",
+ "libg.so": "",
+ },
+ Blueprint: `
+cc_prebuilt_library {
+ name: "libtest",
+ srcs: ["libf.so"],
+ arch: {
+ arm: { export_include_dirs: ["testdir/1/"], },
+ arm64: { export_include_dirs: ["testdir/2/"], },
+ },
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
+ "shared_library": `"libf.so"`,
+ "export_includes": `select({
+ "//build/bazel/platforms/arch:arm": ["testdir/1/"],
+ "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
+ "//conditions:default": [],
+ })`,
+ }),
+ MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
+ "static_library": `"libf.so"`,
+ "export_includes": `select({
+ "//build/bazel/platforms/arch:arm": ["testdir/1/"],
+ "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
+ "//conditions:default": [],
+ })`,
+ }),
+ MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static_alwayslink", AttrNameToString{
+ "alwayslink": "True",
+ "static_library": `"libf.so"`,
+ "export_includes": `select({
+ "//build/bazel/platforms/arch:arm": ["testdir/1/"],
+ "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
+ "//conditions:default": [],
+ })`,
+ }),
+ },
+ })
+}
+
+func TestPrebuiltLibraryWithExportSystemIncludesArchVariant(t *testing.T) {
+ runCcPrebuiltLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_prebuilt_ibrary correctly translates export_system_includes with arch variance",
+ Filesystem: map[string]string{
+ "libf.so": "",
+ "libg.so": "",
+ },
+ Blueprint: `
+cc_prebuilt_library {
+ name: "libtest",
+ srcs: ["libf.so"],
+ arch: {
+ arm: { export_system_include_dirs: ["testdir/1/"], },
+ arm64: { export_system_include_dirs: ["testdir/2/"], },
+ },
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
+ "shared_library": `"libf.so"`,
+ "export_system_includes": `select({
+ "//build/bazel/platforms/arch:arm": ["testdir/1/"],
+ "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
+ "//conditions:default": [],
+ })`,
+ }),
+ MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
+ "static_library": `"libf.so"`,
+ "export_system_includes": `select({
+ "//build/bazel/platforms/arch:arm": ["testdir/1/"],
+ "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
+ "//conditions:default": [],
+ })`,
+ }),
+ MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static_alwayslink", AttrNameToString{
+ "alwayslink": "True",
+ "static_library": `"libf.so"`,
+ "export_system_includes": `select({
+ "//build/bazel/platforms/arch:arm": ["testdir/1/"],
+ "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
+ "//conditions:default": [],
+ })`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/cc_prebuilt_library_shared_conversion_test.go b/bp2build/cc_prebuilt_library_shared_conversion_test.go
new file mode 100644
index 0000000..9e975ae
--- /dev/null
+++ b/bp2build/cc_prebuilt_library_shared_conversion_test.go
@@ -0,0 +1,165 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package bp2build
+
+import (
+ "testing"
+
+ "android/soong/cc"
+)
+
+func runCcPrebuiltLibrarySharedTestCase(t *testing.T, tc Bp2buildTestCase) {
+ t.Parallel()
+ t.Helper()
+ (&tc).ModuleTypeUnderTest = "cc_prebuilt_library_shared"
+ (&tc).ModuleTypeUnderTestFactory = cc.PrebuiltSharedLibraryFactory
+ RunBp2BuildTestCaseSimple(t, tc)
+}
+
+func TestPrebuiltLibrarySharedSimple(t *testing.T) {
+ runCcPrebuiltLibrarySharedTestCase(t,
+ Bp2buildTestCase{
+ Description: "prebuilt library shared simple",
+ Filesystem: map[string]string{
+ "libf.so": "",
+ },
+ Blueprint: `
+cc_prebuilt_library_shared {
+ name: "libtest",
+ srcs: ["libf.so"],
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
+ "shared_library": `"libf.so"`,
+ }),
+ },
+ })
+}
+
+func TestPrebuiltLibrarySharedWithArchVariance(t *testing.T) {
+ runCcPrebuiltLibrarySharedTestCase(t,
+ Bp2buildTestCase{
+ Description: "prebuilt library shared with arch variance",
+ Filesystem: map[string]string{
+ "libf.so": "",
+ "libg.so": "",
+ },
+ Blueprint: `
+cc_prebuilt_library_shared {
+ name: "libtest",
+ arch: {
+ arm64: { srcs: ["libf.so"], },
+ arm: { srcs: ["libg.so"], },
+ },
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_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,
+ })`,
+ }),
+ },
+ })
+}
+
+func TestPrebuiltLibrarySharedAdditionalAttrs(t *testing.T) {
+ runCcPrebuiltLibrarySharedTestCase(t,
+ Bp2buildTestCase{
+ Description: "prebuilt library shared additional attributes",
+ Filesystem: map[string]string{
+ "libf.so": "",
+ "testdir/1/include.h": "",
+ "testdir/2/other.h": "",
+ },
+ Blueprint: `
+cc_prebuilt_library_shared {
+ name: "libtest",
+ srcs: ["libf.so"],
+ export_include_dirs: ["testdir/1/"],
+ export_system_include_dirs: ["testdir/2/"],
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
+ "shared_library": `"libf.so"`,
+ "export_includes": `["testdir/1/"]`,
+ "export_system_includes": `["testdir/2/"]`,
+ }),
+ },
+ })
+}
+
+func TestPrebuiltLibrarySharedWithExportIncludesArchVariant(t *testing.T) {
+ runCcPrebuiltLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_prebuilt_library_shared correctly translates export_includes with arch variance",
+ Filesystem: map[string]string{
+ "libf.so": "",
+ "libg.so": "",
+ },
+ Blueprint: `
+cc_prebuilt_library_shared {
+ name: "libtest",
+ srcs: ["libf.so"],
+ arch: {
+ arm: { export_include_dirs: ["testdir/1/"], },
+ arm64: { export_include_dirs: ["testdir/2/"], },
+ },
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
+ "shared_library": `"libf.so"`,
+ "export_includes": `select({
+ "//build/bazel/platforms/arch:arm": ["testdir/1/"],
+ "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
+ "//conditions:default": [],
+ })`,
+ }),
+ },
+ })
+}
+
+func TestPrebuiltLibrarySharedWithExportSystemIncludesArchVariant(t *testing.T) {
+ runCcPrebuiltLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_prebuilt_library_shared correctly translates export_system_includes with arch variance",
+ Filesystem: map[string]string{
+ "libf.so": "",
+ "libg.so": "",
+ },
+ Blueprint: `
+cc_prebuilt_library_shared {
+ name: "libtest",
+ srcs: ["libf.so"],
+ arch: {
+ arm: { export_system_include_dirs: ["testdir/1/"], },
+ arm64: { export_system_include_dirs: ["testdir/2/"], },
+ },
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
+ "shared_library": `"libf.so"`,
+ "export_system_includes": `select({
+ "//build/bazel/platforms/arch:arm": ["testdir/1/"],
+ "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
+ "//conditions:default": [],
+ })`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/cc_prebuilt_library_static_conversion_test.go b/bp2build/cc_prebuilt_library_static_conversion_test.go
new file mode 100644
index 0000000..77562e7
--- /dev/null
+++ b/bp2build/cc_prebuilt_library_static_conversion_test.go
@@ -0,0 +1,199 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package bp2build
+
+import (
+ "testing"
+
+ "android/soong/cc"
+)
+
+func runCcPrebuiltLibraryStaticTestCase(t *testing.T, tc Bp2buildTestCase) {
+ t.Parallel()
+ t.Helper()
+ (&tc).ModuleTypeUnderTest = "cc_prebuilt_library_static"
+ (&tc).ModuleTypeUnderTestFactory = cc.PrebuiltStaticLibraryFactory
+ RunBp2BuildTestCaseSimple(t, tc)
+}
+
+func TestPrebuiltLibraryStaticSimple(t *testing.T) {
+ runCcPrebuiltLibraryStaticTestCase(t,
+ Bp2buildTestCase{
+ Description: "prebuilt library static simple",
+ Filesystem: map[string]string{
+ "libf.so": "",
+ },
+ Blueprint: `
+cc_prebuilt_library_static {
+ name: "libtest",
+ srcs: ["libf.so"],
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_prebuilt_library_static", "libtest", AttrNameToString{
+ "static_library": `"libf.so"`,
+ }),
+ MakeBazelTarget("cc_prebuilt_library_static", "libtest_alwayslink", AttrNameToString{
+ "static_library": `"libf.so"`,
+ "alwayslink": "True",
+ }),
+ },
+ })
+}
+
+func TestPrebuiltLibraryStaticWithArchVariance(t *testing.T) {
+ runCcPrebuiltLibraryStaticTestCase(t,
+ Bp2buildTestCase{
+ Description: "prebuilt library with arch variance",
+ Filesystem: map[string]string{
+ "libf.so": "",
+ "libg.so": "",
+ },
+ Blueprint: `
+cc_prebuilt_library_static {
+ name: "libtest",
+ arch: {
+ arm64: { srcs: ["libf.so"], },
+ arm: { srcs: ["libg.so"], },
+ },
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_prebuilt_library_static", "libtest", AttrNameToString{
+ "static_library": `select({
+ "//build/bazel/platforms/arch:arm": "libg.so",
+ "//build/bazel/platforms/arch:arm64": "libf.so",
+ "//conditions:default": None,
+ })`}),
+ MakeBazelTarget("cc_prebuilt_library_static", "libtest_alwayslink", AttrNameToString{
+ "alwayslink": "True",
+ "static_library": `select({
+ "//build/bazel/platforms/arch:arm": "libg.so",
+ "//build/bazel/platforms/arch:arm64": "libf.so",
+ "//conditions:default": None,
+ })`}),
+ },
+ })
+}
+
+func TestPrebuiltLibraryStaticAdditionalAttrs(t *testing.T) {
+ runCcPrebuiltLibraryStaticTestCase(t,
+ Bp2buildTestCase{
+ Description: "prebuilt library additional attributes",
+ Filesystem: map[string]string{
+ "libf.so": "",
+ "testdir/1/include.h": "",
+ "testdir/2/other.h": "",
+ },
+ Blueprint: `
+cc_prebuilt_library_static {
+ name: "libtest",
+ srcs: ["libf.so"],
+ export_include_dirs: ["testdir/1/"],
+ export_system_include_dirs: ["testdir/2/"],
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_prebuilt_library_static", "libtest", AttrNameToString{
+ "static_library": `"libf.so"`,
+ "export_includes": `["testdir/1/"]`,
+ "export_system_includes": `["testdir/2/"]`,
+ }),
+ MakeBazelTarget("cc_prebuilt_library_static", "libtest_alwayslink", AttrNameToString{
+ "static_library": `"libf.so"`,
+ "export_includes": `["testdir/1/"]`,
+ "export_system_includes": `["testdir/2/"]`,
+ "alwayslink": "True",
+ }),
+ },
+ })
+}
+
+func TestPrebuiltLibraryStaticWithExportIncludesArchVariant(t *testing.T) {
+ runCcPrebuiltLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_prebuilt_library_static correctly translates export_includes with arch variance",
+ Filesystem: map[string]string{
+ "libf.so": "",
+ "libg.so": "",
+ },
+ Blueprint: `
+cc_prebuilt_library_static {
+ name: "libtest",
+ srcs: ["libf.so"],
+ arch: {
+ arm: { export_include_dirs: ["testdir/1/"], },
+ arm64: { export_include_dirs: ["testdir/2/"], },
+ },
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_prebuilt_library_static", "libtest", AttrNameToString{
+ "static_library": `"libf.so"`,
+ "export_includes": `select({
+ "//build/bazel/platforms/arch:arm": ["testdir/1/"],
+ "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
+ "//conditions:default": [],
+ })`,
+ }),
+ MakeBazelTarget("cc_prebuilt_library_static", "libtest_alwayslink", AttrNameToString{
+ "alwayslink": "True",
+ "static_library": `"libf.so"`,
+ "export_includes": `select({
+ "//build/bazel/platforms/arch:arm": ["testdir/1/"],
+ "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
+ "//conditions:default": [],
+ })`,
+ }),
+ },
+ })
+}
+
+func TestPrebuiltLibraryStaticWithExportSystemIncludesArchVariant(t *testing.T) {
+ runCcPrebuiltLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_prebuilt_library_static correctly translates export_system_includes with arch variance",
+ Filesystem: map[string]string{
+ "libf.so": "",
+ "libg.so": "",
+ },
+ Blueprint: `
+cc_prebuilt_library_static {
+ name: "libtest",
+ srcs: ["libf.so"],
+ arch: {
+ arm: { export_system_include_dirs: ["testdir/1/"], },
+ arm64: { export_system_include_dirs: ["testdir/2/"], },
+ },
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_prebuilt_library_static", "libtest", AttrNameToString{
+ "static_library": `"libf.so"`,
+ "export_system_includes": `select({
+ "//build/bazel/platforms/arch:arm": ["testdir/1/"],
+ "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
+ "//conditions:default": [],
+ })`,
+ }),
+ MakeBazelTarget("cc_prebuilt_library_static", "libtest_alwayslink", AttrNameToString{
+ "alwayslink": "True",
+ "static_library": `"libf.so"`,
+ "export_system_includes": `select({
+ "//build/bazel/platforms/arch:arm": ["testdir/1/"],
+ "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
+ "//conditions:default": [],
+ })`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/cc_test_conversion_test.go b/bp2build/cc_test_conversion_test.go
index 20adddb..4df4d4d 100644
--- a/bp2build/cc_test_conversion_test.go
+++ b/bp2build/cc_test_conversion_test.go
@@ -76,17 +76,28 @@
static_libs: ["hostlib"],
},
},
+ static_libs: ["cc_test_lib1"],
+ shared_libs: ["cc_test_lib2"],
data: [":data_mod", "file.txt"],
data_bins: [":cc_bin"],
data_libs: [":cc_lib"],
cflags: ["-Wall"],
}
+
+cc_test_library {
+ name: "cc_test_lib1",
+ host_supported: true,
+ include_build_directory: false,
+}
` + simpleModuleDoNotConvertBp2build("cc_library", "foolib") +
simpleModuleDoNotConvertBp2build("cc_library_static", "hostlib") +
simpleModuleDoNotConvertBp2build("genrule", "data_mod") +
simpleModuleDoNotConvertBp2build("cc_binary", "cc_bin") +
- simpleModuleDoNotConvertBp2build("cc_test_library", "cc_lib"),
+ simpleModuleDoNotConvertBp2build("cc_library", "cc_lib") +
+ simpleModuleDoNotConvertBp2build("cc_test_library", "cc_test_lib2"),
targets: []testBazelTarget{
+ {"cc_library_shared", "cc_test_lib1", AttrNameToString{}},
+ {"cc_library_static", "cc_test_lib1_bp2build_cc_library_static", AttrNameToString{}},
{"cc_test", "mytest", AttrNameToString{
"copts": `["-Wall"]`,
"data": `[
@@ -95,7 +106,7 @@
":cc_bin",
":cc_lib",
]`,
- "deps": `select({
+ "deps": `[":cc_test_lib1_bp2build_cc_library_static"] + select({
"//build/bazel/platforms/os:darwin": [":hostlib"],
"//build/bazel/platforms/os:linux_bionic": [":hostlib"],
"//build/bazel/platforms/os:linux_glibc": [":hostlib"],
@@ -106,7 +117,7 @@
"gtest": "True",
"isolated": "True",
"local_includes": `["."]`,
- "dynamic_deps": `select({
+ "dynamic_deps": `[":cc_test_lib2"] + select({
"//build/bazel/platforms/os:android": [":foolib"],
"//conditions:default": [],
})`,
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index 815461a..608fcd8 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -5,6 +5,7 @@
"encoding/json"
"fmt"
"reflect"
+ "strconv"
"strings"
"android/soong/android"
@@ -87,14 +88,19 @@
platformVersionActiveCodenames = append(platformVersionActiveCodenames, fmt.Sprintf("%q", codename))
}
+ platformSdkVersion := "None"
+ if cfg.RawPlatformSdkVersion() != nil {
+ platformSdkVersion = strconv.Itoa(*cfg.RawPlatformSdkVersion())
+ }
+
return fmt.Sprintf(`
platform_versions = struct(
platform_sdk_final = %s,
- platform_sdk_version = %d,
+ platform_sdk_version = %s,
platform_sdk_codename = %q,
platform_version_active_codenames = [%s],
)
-`, starlark_fmt.PrintBool(cfg.PlatformSdkFinal()), cfg.PlatformSdkVersion().FinalInt(), cfg.PlatformSdkCodename(), strings.Join(platformVersionActiveCodenames, ", "))
+`, starlark_fmt.PrintBool(cfg.PlatformSdkFinal()), platformSdkVersion, cfg.PlatformSdkCodename(), strings.Join(platformVersionActiveCodenames, ", "))
}
func CreateBazelFiles(
diff --git a/bp2build/filegroup_conversion_test.go b/bp2build/filegroup_conversion_test.go
index 7ce559d..273d556 100644
--- a/bp2build/filegroup_conversion_test.go
+++ b/bp2build/filegroup_conversion_test.go
@@ -105,6 +105,42 @@
}
}
+func TestFilegroupWithAidlDeps(t *testing.T) {
+ bp := `
+ filegroup {
+ name: "bar",
+ srcs: ["bar.aidl"],
+ }
+ filegroup {
+ name: "foo",
+ srcs: ["aidl/foo.aidl"],
+ path: "aidl",
+ aidl: {
+ deps: [":bar"],
+ }
+ }`
+
+ t.Run("filegroup with aidl deps", func(t *testing.T) {
+ expectedBazelTargets := []string{
+ MakeBazelTargetNoRestrictions("aidl_library", "bar", AttrNameToString{
+ "srcs": `["bar.aidl"]`,
+ "tags": `["apex_available=//apex_available:anyapex"]`,
+ }),
+ MakeBazelTargetNoRestrictions("aidl_library", "foo", AttrNameToString{
+ "srcs": `["aidl/foo.aidl"]`,
+ "strip_import_prefix": `"aidl"`,
+ "deps": `[":bar"]`,
+ "tags": `["apex_available=//apex_available:anyapex"]`,
+ }),
+ }
+ runFilegroupTestCase(t, Bp2buildTestCase{
+ Description: "filegroup with aidl deps",
+ Blueprint: bp,
+ ExpectedBazelTargets: expectedBazelTargets,
+ })
+ })
+}
+
func TestFilegroupWithAidlAndNonAidlSrcs(t *testing.T) {
runFilegroupTestCase(t, Bp2buildTestCase{
Description: "filegroup with aidl and non-aidl srcs",
diff --git a/bp2build/java_binary_host_conversion_test.go b/bp2build/java_binary_host_conversion_test.go
index 1b9777c..c821f59 100644
--- a/bp2build/java_binary_host_conversion_test.go
+++ b/bp2build/java_binary_host_conversion_test.go
@@ -57,24 +57,24 @@
}`,
ExpectedBazelTargets: []string{
MakeBazelTarget("java_library", "java-binary-host-1_lib", AttrNameToString{
- "srcs": `["a.java"]`,
- "deps": `["//other:jni-lib-1"]`,
- "javacopts": `[
- "-Xdoclint:all/protected",
- "-source 1.8 -target 1.8",
- ]`,
+ "srcs": `["a.java"]`,
+ "deps": `["//other:jni-lib-1"]`,
+ "java_version": `"8"`,
+ "javacopts": `["-Xdoclint:all/protected"]`,
"target_compatible_with": `select({
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
"//conditions:default": [],
- })`}),
+ })`,
+ }),
MakeBazelTarget("java_binary", "java-binary-host-1", AttrNameToString{
- "main_class": `"com.android.test.MainClass"`,
- "jvm_flags": `["-Djava.library.path=$${RUNPATH}other"]`,
- "runtime_deps": `[":java-binary-host-1_lib"]`,
+ "main_class": `"com.android.test.MainClass"`,
+ "jvm_flags": `["-Djava.library.path=$${RUNPATH}other"]`,
"target_compatible_with": `select({
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
"//conditions:default": [],
- })`}),
+ })`,
+ "runtime_deps": `[":java-binary-host-1_lib"]`,
+ }),
},
})
}
diff --git a/bp2build/java_host_for_device_conversion_test.go b/bp2build/java_host_for_device_conversion_test.go
index d908d00..448cba4 100644
--- a/bp2build/java_host_for_device_conversion_test.go
+++ b/bp2build/java_host_for_device_conversion_test.go
@@ -51,9 +51,11 @@
}`,
ExpectedBazelTargets: []string{
MakeBazelTarget("java_host_for_device", "java-lib-1", AttrNameToString{
- "deps": `[":java-lib-2"]`,
+ "exports": `[":java-lib-2"]`,
}),
- MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
+ MakeNeverlinkDuplicateTargetWithAttrs("java_library", "java-lib-1", AttrNameToString{
+ "sdk_version": `"none"`,
+ }),
MakeBazelTarget("java_library", "java-lib-2", AttrNameToString{
"srcs": `["b.java"]`,
}),
diff --git a/bp2build/java_import_conversion_test.go b/bp2build/java_import_conversion_test.go
index a5c01cb..5661620 100644
--- a/bp2build/java_import_conversion_test.go
+++ b/bp2build/java_import_conversion_test.go
@@ -49,8 +49,9 @@
"jars": `["import.jar"]`,
}),
MakeBazelTarget("java_library", "example_import-neverlink", AttrNameToString{
- "exports": `[":example_import"]`,
- "neverlink": `True`,
+ "exports": `[":example_import"]`,
+ "neverlink": `True`,
+ "sdk_version": `"none"`,
}),
}})
}
@@ -86,8 +87,9 @@
})`,
}),
MakeBazelTarget("java_library", "example_import-neverlink", AttrNameToString{
- "exports": `[":example_import"]`,
- "neverlink": `True`,
+ "exports": `[":example_import"]`,
+ "neverlink": `True`,
+ "sdk_version": `"none"`,
}),
}})
}
@@ -112,8 +114,9 @@
"jars": `["import.jar"]`,
}),
MakeBazelTarget("java_library", "example_import-neverlink", AttrNameToString{
- "exports": `[":example_import"]`,
- "neverlink": `True`,
+ "exports": `[":example_import"]`,
+ "neverlink": `True`,
+ "sdk_version": `"none"`,
}),
}})
}
diff --git a/bp2build/java_library_conversion_test.go b/bp2build/java_library_conversion_test.go
index 683ee27..24b763b 100644
--- a/bp2build/java_library_conversion_test.go
+++ b/bp2build/java_library_conversion_test.go
@@ -172,10 +172,13 @@
}`,
ExpectedBazelTargets: []string{
MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
- "srcs": `["a.java"]`,
- "javacopts": `["-source 11 -target 11"]`,
+ "srcs": `["a.java"]`,
+ "java_version": `"11"`,
}),
- MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
+ MakeNeverlinkDuplicateTargetWithAttrs(
+ "java_library",
+ "java-lib-1",
+ AttrNameToString{"java_version": `"11"`}),
},
})
}
diff --git a/bp2build/java_library_host_conversion_test.go b/bp2build/java_library_host_conversion_test.go
index 14854c0..9e47b09 100644
--- a/bp2build/java_library_host_conversion_test.go
+++ b/bp2build/java_library_host_conversion_test.go
@@ -63,8 +63,8 @@
})`,
}),
MakeBazelTarget("java_library", "java-lib-host-2", AttrNameToString{
- "javacopts": `["-source 1.9 -target 1.9"]`,
- "srcs": `["c.java"]`,
+ "java_version": `"9"`,
+ "srcs": `["c.java"]`,
"target_compatible_with": `select({
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
"//conditions:default": [],
@@ -77,6 +77,7 @@
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
"//conditions:default": [],
})`,
+ "java_version": `"9"`,
}),
},
})
diff --git a/bp2build/java_plugin_conversion_test.go b/bp2build/java_plugin_conversion_test.go
index 8c6337b..f2b6f20 100644
--- a/bp2build/java_plugin_conversion_test.go
+++ b/bp2build/java_plugin_conversion_test.go
@@ -67,7 +67,7 @@
"a.java",
"b.java",
]`,
- "javacopts": `["-source 1.7 -target 1.7"]`,
+ "java_version": `"7"`,
}),
},
})
diff --git a/bp2build/java_proto_conversion_test.go b/bp2build/java_proto_conversion_test.go
index d25b7c4..f546cf4 100644
--- a/bp2build/java_proto_conversion_test.go
+++ b/bp2build/java_proto_conversion_test.go
@@ -114,13 +114,17 @@
"java_lite_proto_library",
"java-protos_java_proto_lite",
AttrNameToString{
- "deps": `[":java-protos_proto"]`,
+ "deps": `[":java-protos_proto"]`,
+ "java_version": `"7"`,
}),
MakeBazelTarget("java_library", "java-protos", AttrNameToString{
- "exports": `[":java-protos_java_proto_lite"]`,
- "javacopts": `["-source 1.7 -target 1.7"]`,
+ "exports": `[":java-protos_java_proto_lite"]`,
+ "java_version": `"7"`,
}),
- MakeNeverlinkDuplicateTarget("java_library", "java-protos"),
+ MakeNeverlinkDuplicateTargetWithAttrs(
+ "java_library",
+ "java-protos",
+ AttrNameToString{"java_version": `"7"`}),
},
})
}
diff --git a/bp2build/python_test_conversion_test.go b/bp2build/python_test_conversion_test.go
new file mode 100644
index 0000000..4ff1fa1
--- /dev/null
+++ b/bp2build/python_test_conversion_test.go
@@ -0,0 +1,66 @@
+// Copyright 2023 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/python"
+ "testing"
+)
+
+func TestPythonTestHostSimple(t *testing.T) {
+ runBp2BuildTestCaseWithPythonLibraries(t, Bp2buildTestCase{
+ Description: "simple python_test_host converts to a native py_test",
+ ModuleTypeUnderTest: "python_test_host",
+ ModuleTypeUnderTestFactory: python.PythonTestHostFactory,
+ Filesystem: map[string]string{
+ "a.py": "",
+ "b/c.py": "",
+ "b/d.py": "",
+ "b/e.py": "",
+ "files/data.txt": "",
+ },
+ Blueprint: `python_test_host {
+ name: "foo",
+ main: "a.py",
+ srcs: ["**/*.py"],
+ exclude_srcs: ["b/e.py"],
+ data: ["files/data.txt",],
+ libs: ["bar"],
+ bazel_module: { bp2build_available: true },
+}
+ python_library_host {
+ name: "bar",
+ srcs: ["b/e.py"],
+ bazel_module: { bp2build_available: false },
+ }`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("py_test", "foo", AttrNameToString{
+ "data": `["files/data.txt"]`,
+ "deps": `[":bar"]`,
+ "main": `"a.py"`,
+ "imports": `["."]`,
+ "srcs": `[
+ "a.py",
+ "b/c.py",
+ "b/d.py",
+ ]`,
+ "target_compatible_with": `select({
+ "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ })`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 856b6ee..fd99ff0 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -317,6 +317,8 @@
One_to_many_prop *bool
Api *string // File describing the APIs of this module
+
+ Test_config_setting *bool // Used to test generation of config_setting targets
}
type customModule struct {
@@ -490,6 +492,27 @@
}
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
+
+ if proptools.Bool(m.props.Test_config_setting) {
+ m.createConfigSetting(ctx)
+ }
+
+}
+
+func (m *customModule) createConfigSetting(ctx android.TopDownMutatorContext) {
+ csa := bazel.ConfigSettingAttributes{
+ Flag_values: bazel.StringMapAttribute{
+ "//build/bazel/rules/my_string_setting": m.Name(),
+ },
+ }
+ ca := android.CommonAttributes{
+ Name: m.Name() + "_config_setting",
+ }
+ ctx.CreateBazelConfigSetting(
+ csa,
+ ca,
+ ctx.ModuleDir(),
+ )
}
var _ android.ApiProvider = (*customModule)(nil)
@@ -642,10 +665,14 @@
}
func MakeNeverlinkDuplicateTarget(moduleType string, name string) string {
- return MakeBazelTarget(moduleType, name+"-neverlink", AttrNameToString{
- "neverlink": `True`,
- "exports": `[":` + name + `"]`,
- })
+ return MakeNeverlinkDuplicateTargetWithAttrs(moduleType, name, AttrNameToString{})
+}
+
+func MakeNeverlinkDuplicateTargetWithAttrs(moduleType string, name string, extraAttrs AttrNameToString) string {
+ attrs := extraAttrs
+ attrs["neverlink"] = `True`
+ attrs["exports"] = `[":` + name + `"]`
+ return MakeBazelTarget(moduleType, name+"-neverlink", attrs)
}
func getTargetName(targetContent string) string {
diff --git a/cc/afdo.go b/cc/afdo.go
index be4f50a..49f6987 100644
--- a/cc/afdo.go
+++ b/cc/afdo.go
@@ -34,7 +34,7 @@
var afdoProfileProjectsConfigKey = android.NewOnceKey("AfdoProfileProjects")
-const afdoCFlagsFormat = "-funique-internal-linkage-names -fprofile-sample-accurate -fprofile-sample-use=%s"
+const afdoCFlagsFormat = "-fprofile-sample-accurate -fprofile-sample-use=%s"
func recordMissingAfdoProfileFile(ctx android.BaseModuleContext, missing string) {
getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
@@ -66,10 +66,24 @@
// afdoEnabled returns true for binaries and shared libraries
// that set afdo prop to True and there is a profile available
func (afdo *afdo) afdoEnabled() bool {
- return afdo != nil && afdo.Properties.Afdo && afdo.Properties.FdoProfilePath != nil
+ return afdo != nil && afdo.Properties.Afdo
}
func (afdo *afdo) flags(ctx ModuleContext, flags Flags) Flags {
+ if afdo.Properties.Afdo {
+ // We use `-funique-internal-linkage-names` to associate profiles to the right internal
+ // functions. This option should be used before generating a profile. Because a profile
+ // generated for a binary without unique names doesn't work well building a binary with
+ // unique names (they have different internal function names).
+ // To avoid a chicken-and-egg problem, we enable `-funique-internal-linkage-names` when
+ // `afdo=true`, whether a profile exists or not.
+ // The profile can take effect in three steps:
+ // 1. Add `afdo: true` in Android.bp, and build the binary.
+ // 2. Collect an AutoFDO profile for the binary.
+ // 3. Make the profile searchable by the build system. So it's used the next time the binary
+ // is built.
+ flags.Local.CFlags = append([]string{"-funique-internal-linkage-names"}, flags.Local.CFlags...)
+ }
if path := afdo.Properties.FdoProfilePath; path != nil {
// The flags are prepended to allow overriding.
profileUseFlag := fmt.Sprintf(afdoCFlagsFormat, *path)
@@ -129,42 +143,41 @@
// Propagate afdo requirements down from binaries and shared libraries
func afdoDepsMutator(mctx android.TopDownMutatorContext) {
if m, ok := mctx.Module().(*Module); ok && m.afdo.afdoEnabled() {
- if path := m.afdo.Properties.FdoProfilePath; path != nil {
- mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
- tag := mctx.OtherModuleDependencyTag(dep)
- libTag, isLibTag := tag.(libraryDependencyTag)
+ path := m.afdo.Properties.FdoProfilePath
+ mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
+ tag := mctx.OtherModuleDependencyTag(dep)
+ libTag, isLibTag := tag.(libraryDependencyTag)
- // Do not recurse down non-static dependencies
- if isLibTag {
- if !libTag.static() {
- return false
- }
- } else {
- if tag != objDepTag && tag != reuseObjTag {
- return false
- }
+ // Do not recurse down non-static dependencies
+ if isLibTag {
+ if !libTag.static() {
+ return false
}
-
- if dep, ok := dep.(*Module); ok {
- dep.afdo.Properties.AfdoRDeps = append(
- dep.afdo.Properties.AfdoRDeps,
- afdoRdep{
- VariationName: proptools.StringPtr(encodeTarget(m.Name())),
- ProfilePath: path,
- },
- )
+ } else {
+ if tag != objDepTag && tag != reuseObjTag {
+ return false
}
+ }
- return true
- })
- }
+ if dep, ok := dep.(*Module); ok {
+ dep.afdo.Properties.AfdoRDeps = append(
+ dep.afdo.Properties.AfdoRDeps,
+ afdoRdep{
+ VariationName: proptools.StringPtr(encodeTarget(m.Name())),
+ ProfilePath: path,
+ },
+ )
+ }
+
+ return true
+ })
}
}
// Create afdo variants for modules that need them
func afdoMutator(mctx android.BottomUpMutatorContext) {
if m, ok := mctx.Module().(*Module); ok && m.afdo != nil {
- if !m.static() && m.afdo.Properties.Afdo && m.afdo.Properties.FdoProfilePath != nil {
+ if !m.static() && m.afdo.Properties.Afdo {
mctx.SetDependencyVariation(encodeTarget(m.Name()))
return
}
@@ -182,7 +195,7 @@
// \ ^
// ----------------------|
// We only need to create one variant per unique rdep
- if variantNameToProfilePath[variantName] == nil {
+ if _, exists := variantNameToProfilePath[variantName]; !exists {
variationNames = append(variationNames, variantName)
variantNameToProfilePath[variantName] = afdoRDep.ProfilePath
}
@@ -197,6 +210,7 @@
variation := modules[i].(*Module)
variation.Properties.PreventInstall = true
variation.Properties.HideFromMake = true
+ variation.afdo.Properties.Afdo = true
variation.afdo.Properties.FdoProfilePath = variantNameToProfilePath[name]
}
}
diff --git a/cc/afdo_test.go b/cc/afdo_test.go
index 1c20bfc..b250ad1 100644
--- a/cc/afdo_test.go
+++ b/cc/afdo_test.go
@@ -379,3 +379,85 @@
t.Errorf("libFoo missing dependency on non-afdo variant of libBar")
}
}
+
+func TestAfdoDepsWithoutProfile(t *testing.T) {
+ t.Parallel()
+ bp := `
+ cc_library_shared {
+ name: "libTest",
+ srcs: ["test.c"],
+ static_libs: ["libFoo"],
+ afdo: true,
+ }
+
+ cc_library_static {
+ name: "libFoo",
+ srcs: ["foo.c"],
+ static_libs: ["libBar"],
+ }
+
+ cc_library_static {
+ name: "libBar",
+ srcs: ["bar.c"],
+ }
+ `
+
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithFdoProfile,
+ prepareForCcTest,
+ ).RunTestWithBp(t, bp)
+
+ // Even without a profile path, the afdo enabled libraries should be built with
+ // -funique-internal-linkage-names.
+ expectedCFlag := "-funique-internal-linkage-names"
+
+ libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
+ libFooAfdoVariant := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libTest")
+ libBarAfdoVariant := result.ModuleForTests("libBar", "android_arm64_armv8-a_static_afdo-libTest")
+
+ // Check cFlags of afdo-enabled module and the afdo-variant of its static deps
+ cFlags := libTest.Rule("cc").Args["cFlags"]
+ if !strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ cFlags = libFooAfdoVariant.Rule("cc").Args["cFlags"]
+ if !strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libFooAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ cFlags = libBarAfdoVariant.Rule("cc").Args["cFlags"]
+ if !strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libBarAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
+ }
+ // Check dependency edge from afdo-enabled module to static deps
+ if !hasDirectDep(result, libTest.Module(), libFooAfdoVariant.Module()) {
+ t.Errorf("libTest missing dependency on afdo variant of libFoo")
+ }
+
+ if !hasDirectDep(result, libFooAfdoVariant.Module(), libBarAfdoVariant.Module()) {
+ t.Errorf("libTest missing dependency on afdo variant of libBar")
+ }
+
+ // Verify non-afdo variant exists and doesn't contain afdo
+ libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
+ libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
+
+ cFlags = libFoo.Rule("cc").Args["cFlags"]
+ if strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libFoo' to not enable afdo, but found %q in cflags %q", expectedCFlag, cFlags)
+ }
+ cFlags = libBar.Rule("cc").Args["cFlags"]
+ if strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libBar' to not enable afdo, but found %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ // Check dependency edges of static deps
+ if hasDirectDep(result, libTest.Module(), libFoo.Module()) {
+ t.Errorf("libTest should not depend on non-afdo variant of libFoo")
+ }
+
+ if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
+ t.Errorf("libFoo missing dependency on non-afdo variant of libBar")
+ }
+}
diff --git a/cc/binary.go b/cc/binary.go
index 097f822..98b9923 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -661,7 +661,7 @@
// shared with cc_test
binaryAttrs := binaryBp2buildAttrs(ctx, m)
- tags := android.ApexAvailableTags(m)
+ tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{
Rule_class: "cc_binary",
Bzl_load_location: "//build/bazel/rules/cc:cc_binary.bzl",
diff --git a/cc/bp2build.go b/cc/bp2build.go
index c8f516c..1c94741 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -17,6 +17,7 @@
"fmt"
"path/filepath"
"strings"
+ "sync"
"android/soong/android"
"android/soong/bazel"
@@ -67,6 +68,8 @@
Apex_available []string
+ Features bazel.StringListAttribute
+
sdkAttributes
tidyAttributes
@@ -226,7 +229,7 @@
attrs := staticOrSharedAttributes{}
setAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) {
- attrs.Copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag))
+ attrs.Copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag, filterOutHiddenVisibility))
attrs.Srcs.SetSelectValue(axis, config, android.BazelLabelForModuleSrc(ctx, props.Srcs))
attrs.System_dynamic_deps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, props.System_shared_libs))
@@ -268,7 +271,9 @@
attrs.Srcs_c = partitionedSrcs[cSrcPartition]
attrs.Srcs_as = partitionedSrcs[asSrcPartition]
- attrs.Apex_available = android.ConvertApexAvailableToTags(apexAvailable)
+ attrs.Apex_available = android.ConvertApexAvailableToTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), apexAvailable)
+
+ attrs.Features.Append(convertHiddenVisibilityToFeatureStaticOrShared(ctx, module, isStatic))
if !partitionedSrcs[protoSrcPartition].IsEmpty() {
// TODO(b/208815215): determine whether this is used and add support if necessary
@@ -428,6 +433,12 @@
type filterOutFn func(string) bool
+// filterOutHiddenVisibility removes the flag specifying hidden visibility as
+// this flag is converted to a toolchain feature
+func filterOutHiddenVisibility(flag string) bool {
+ return flag == config.VisibilityHiddenFlag
+}
+
func filterOutStdFlag(flag string) bool {
return strings.HasPrefix(flag, "-std=")
}
@@ -490,7 +501,7 @@
// overridden. In Bazel we always allow overriding, via flags; however, this can cause
// incompatibilities, so we remove "-std=" flags from Cflag properties while leaving it in other
// cases.
- ca.copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag, filterOutClangUnknownCflags))
+ ca.copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag, filterOutClangUnknownCflags, filterOutHiddenVisibility))
ca.asFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Asflags, nil))
ca.conlyFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Conlyflags, filterOutClangUnknownCflags))
ca.cppFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Cppflags, filterOutClangUnknownCflags))
@@ -762,8 +773,13 @@
if libraryProps, ok := archVariantLibraryProperties[axis][cfg].(*LibraryProperties); ok {
if axis == bazel.NoConfigAxis {
- compilerAttrs.stubsSymbolFile = libraryProps.Stubs.Symbol_file
- compilerAttrs.stubsVersions.SetSelectValue(axis, cfg, libraryProps.Stubs.Versions)
+ if libraryProps.Stubs.Symbol_file != nil {
+ compilerAttrs.stubsSymbolFile = libraryProps.Stubs.Symbol_file
+ versions := android.CopyOf(libraryProps.Stubs.Versions)
+ normalizeVersions(ctx, versions)
+ versions = addCurrentVersionIfNotPresent(versions)
+ compilerAttrs.stubsVersions.SetSelectValue(axis, cfg, versions)
+ }
}
if suffix := libraryProps.Suffix; suffix != nil {
compilerAttrs.suffix.SetSelectValue(axis, cfg, suffix)
@@ -833,6 +849,7 @@
features := compilerAttrs.features.Clone().Append(linkerAttrs.features).Append(bp2buildSanitizerFeatures(ctx, module))
features = features.Append(bp2buildLtoFeatures(ctx, module))
+ features = features.Append(convertHiddenVisibilityToFeatureBase(ctx, module))
features.DeduplicateAxesFromBase()
addMuslSystemDynamicDeps(ctx, linkerAttrs)
@@ -907,7 +924,7 @@
return false
})
- apexAvailableTags := android.ApexAvailableTags(ctx.Module())
+ apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), ctx.Module())
sdkAttrs := bp2BuildParseSdkAttributes(m)
if !aidlSrcs.IsEmpty() {
@@ -1107,8 +1124,11 @@
// having stubs or not, so Bazel select() statement can be used to choose
// source/stub variants of them.
apexAvailable := module.ApexAvailable()
- setStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.export, &la.dynamicDeps, 0)
- setStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.implementation, &la.implementationDynamicDeps, 1)
+ setStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.export, &la.dynamicDeps, 0, false)
+ setStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.implementation, &la.implementationDynamicDeps, 1, false)
+ if len(systemSharedLibs) > 0 {
+ setStubsForDynamicDeps(ctx, axis, config, apexAvailable, bazelLabelForSharedDeps(ctx, systemSharedLibs), &la.systemDynamicDeps, 2, true)
+ }
}
if !BoolDefault(props.Pack_relocations, packRelocationsDefault) {
@@ -1177,8 +1197,65 @@
return !differ
}
+var (
+ apexConfigSettingKey = android.NewOnceKey("apexConfigSetting")
+ apexConfigSettingLock sync.Mutex
+)
+
+func getApexConfigSettingMap(config android.Config) *map[string]bool {
+ return config.Once(apexConfigSettingKey, func() interface{} {
+ return &map[string]bool{}
+ }).(*map[string]bool)
+}
+
+// Create a config setting for this apex in build/bazel/rules/apex
+// The use case for this is stub/impl selection in cc libraries
+// Long term, these config_setting(s) should be colocated with the respective apex definitions.
+// Note that this is an anti-pattern: The config_setting should be created from the apex definition
+// and not from a cc_library.
+// This anti-pattern is needed today since not all apexes have been allowlisted.
+func createInApexConfigSetting(ctx android.TopDownMutatorContext, apexName string) {
+ if apexName == android.AvailableToPlatform || apexName == android.AvailableToAnyApex {
+ // These correspond to android-non_apex and android-in_apex
+ return
+ }
+ apexConfigSettingLock.Lock()
+ defer apexConfigSettingLock.Unlock()
+
+ // Return if a config_setting has already been created
+ acsm := getApexConfigSettingMap(ctx.Config())
+ if _, exists := (*acsm)[apexName]; exists {
+ return
+ }
+ (*acsm)[apexName] = true
+
+ csa := bazel.ConfigSettingAttributes{
+ Flag_values: bazel.StringMapAttribute{
+ "//build/bazel/rules/apex:apex_name": apexName,
+ },
+ }
+ ca := android.CommonAttributes{
+ Name: "android-in_" + apexName,
+ }
+ ctx.CreateBazelConfigSetting(
+ csa,
+ ca,
+ "build/bazel/rules/apex",
+ )
+}
+
+func inApexConfigSetting(apexAvailable string) string {
+ if apexAvailable == android.AvailableToPlatform {
+ return bazel.AndroidAndNonApex
+ }
+ if apexAvailable == android.AvailableToAnyApex {
+ return bazel.AndroidAndInApex
+ }
+ return "//build/bazel/rules/apex:android-in_" + apexAvailable
+}
+
func setStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis,
- config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int) {
+ config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int, buildNonApexWithStubs bool) {
depsWithStubs := []bazel.Label{}
for _, l := range dynamicLibs.Includes {
@@ -1204,20 +1281,31 @@
inApexSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex)
nonApexSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex)
defaultSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey)
+ nonApexDeps := depsWithStubs
+ if buildNonApexWithStubs {
+ nonApexDeps = stubLibLabels
+ }
if axis == bazel.NoConfigAxis {
(&inApexSelectValue).Append(bazel.MakeLabelList(stubLibLabels))
- (&nonApexSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
+ (&nonApexSelectValue).Append(bazel.MakeLabelList(nonApexDeps))
(&defaultSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.FirstUniqueBazelLabelList(inApexSelectValue))
dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, bazel.FirstUniqueBazelLabelList(nonApexSelectValue))
dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, bazel.FirstUniqueBazelLabelList(defaultSelectValue))
} else if config == bazel.OsAndroid {
(&inApexSelectValue).Append(bazel.MakeLabelList(stubLibLabels))
- (&nonApexSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
+ (&nonApexSelectValue).Append(bazel.MakeLabelList(nonApexDeps))
dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.FirstUniqueBazelLabelList(inApexSelectValue))
dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, bazel.FirstUniqueBazelLabelList(nonApexSelectValue))
}
}
+
+ // Create a config_setting for each apex_available.
+ // This will be used to select impl of a dep if dep is available to the same apex.
+ for _, aa := range apexAvailable {
+ createInApexConfigSetting(ctx.(android.TopDownMutatorContext), aa)
+ }
+
}
func (la *linkerAttributes) convertStripProps(ctx android.BazelConversionPathContext, module *Module) {
@@ -1547,3 +1635,38 @@
}
return ltoStringFeatures
}
+
+func convertHiddenVisibilityToFeatureBase(ctx android.BazelConversionPathContext, m *Module) bazel.StringListAttribute {
+ visibilityHiddenFeature := bazel.StringListAttribute{}
+ bp2BuildPropParseHelper(ctx, m, &BaseCompilerProperties{}, func(axis bazel.ConfigurationAxis, configString string, props interface{}) {
+ if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
+ convertHiddenVisibilityToFeatureHelper(&visibilityHiddenFeature, axis, configString, baseCompilerProps.Cflags)
+ }
+ })
+ return visibilityHiddenFeature
+}
+
+func convertHiddenVisibilityToFeatureStaticOrShared(ctx android.BazelConversionPathContext, m *Module, isStatic bool) bazel.StringListAttribute {
+ visibilityHiddenFeature := bazel.StringListAttribute{}
+ if isStatic {
+ bp2BuildPropParseHelper(ctx, m, &StaticProperties{}, func(axis bazel.ConfigurationAxis, configString string, props interface{}) {
+ if staticProps, ok := props.(*StaticProperties); ok {
+ convertHiddenVisibilityToFeatureHelper(&visibilityHiddenFeature, axis, configString, staticProps.Static.Cflags)
+ }
+ })
+ } else {
+ bp2BuildPropParseHelper(ctx, m, &SharedProperties{}, func(axis bazel.ConfigurationAxis, configString string, props interface{}) {
+ if sharedProps, ok := props.(*SharedProperties); ok {
+ convertHiddenVisibilityToFeatureHelper(&visibilityHiddenFeature, axis, configString, sharedProps.Shared.Cflags)
+ }
+ })
+ }
+
+ return visibilityHiddenFeature
+}
+
+func convertHiddenVisibilityToFeatureHelper(feature *bazel.StringListAttribute, axis bazel.ConfigurationAxis, configString string, cflags []string) {
+ if inList(config.VisibilityHiddenFlag, cflags) {
+ feature.SetSelectValue(axis, configString, []string{"visibility_hidden"})
+ }
+}
diff --git a/cc/cc.go b/cc/cc.go
index 9c555a1..3fbefcd 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1475,7 +1475,7 @@
func InstallToBootstrap(name string, config android.Config) bool {
// NOTE: also update //build/bazel/rules/apex/cc.bzl#_installed_to_bootstrap
// if this list is updated.
- if name == "libclang_rt.hwasan" {
+ if name == "libclang_rt.hwasan" || name == "libc_hwasan" {
return true
}
return isBionic(name)
@@ -1858,6 +1858,10 @@
if c.SplitPerApiLevel() {
subName += "." + c.SdkVersion()
}
+ } else if c.IsStubs() && c.IsSdkVariant() {
+ // Public API surface (NDK)
+ // Add a suffix to this stub variant to distinguish it from the module-lib stub variant.
+ subName = sdkSuffix
}
return subName
@@ -1886,37 +1890,49 @@
c.bazelHandler.QueueBazelCall(ctx, c.getBazelModuleLabel(ctx))
}
-var (
- mixedBuildSupportedCcTest = []string{
- "adbd_test",
- "adb_crypto_test",
- "adb_pairing_auth_test",
- "adb_pairing_connection_test",
- "adb_tls_connection_test",
- }
-)
-
// IsMixedBuildSupported returns true if the module should be analyzed by Bazel
-// in any of the --bazel-mode(s). This filters at the module level and takes
-// precedence over the allowlists in allowlists/allowlists.go.
+// in any of the --bazel-mode(s).
func (c *Module) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
- _, isForTesting := ctx.Config().BazelContext.(android.MockBazelContext)
- if c.testBinary() && !android.InList(c.Name(), mixedBuildSupportedCcTest) && !isForTesting {
- // Per-module rollout of mixed-builds for cc_test modules.
+ if !allEnabledSanitizersSupportedByBazel(c) {
+ //TODO(b/278772861) support sanitizers in Bazel rules
return false
}
-
- // TODO(b/261058727): Remove this (enable mixed builds for modules with UBSan)
- // Currently we can only support ubsan when minimum runtime is used.
- return c.bazelHandler != nil && (!isUbsanEnabled(c) || c.MinimalRuntimeNeeded())
+ return c.bazelHandler != nil
}
-func isUbsanEnabled(c *Module) bool {
+func allEnabledSanitizersSupportedByBazel(c *Module) bool {
if c.sanitize == nil {
- return false
+ return true
}
sanitizeProps := &c.sanitize.Properties.SanitizeMutated
- return Bool(sanitizeProps.Integer_overflow) || len(sanitizeProps.Misc_undefined) > 0
+
+ unsupportedSanitizers := []*bool{
+ sanitizeProps.Safestack,
+ sanitizeProps.Cfi,
+ sanitizeProps.Scudo,
+ BoolPtr(len(c.sanitize.Properties.Sanitize.Recover) > 0),
+ BoolPtr(c.sanitize.Properties.Sanitize.Blocklist != nil),
+ }
+ for _, san := range unsupportedSanitizers {
+ if Bool(san) {
+ return false
+ }
+ }
+
+ for _, san := range Sanitizers {
+ if san == intOverflow {
+ // TODO(b/261058727): enable mixed builds for all modules with UBSan
+ // Currently we can only support ubsan when minimum runtime is used.
+ ubsanEnabled := Bool(sanitizeProps.Integer_overflow) || len(sanitizeProps.Misc_undefined) > 0
+ if ubsanEnabled && !c.MinimalRuntimeNeeded() {
+ return false
+ }
+ } else if c.sanitize.isSanitizerEnabled(san) {
+ return false
+ }
+ }
+
+ return true
}
func GetApexConfigKey(ctx android.BaseModuleContext) *android.ApexConfigKey {
@@ -1960,6 +1976,67 @@
c.maybeInstall(mctx, apexInfo)
}
+func moduleContextFromAndroidModuleContext(actx android.ModuleContext, c *Module) ModuleContext {
+ ctx := &moduleContext{
+ ModuleContext: actx,
+ moduleContextImpl: moduleContextImpl{
+ mod: c,
+ },
+ }
+ ctx.ctx = ctx
+ return ctx
+}
+
+// TODO (b/277651159): Remove this allowlist
+var (
+ skipStubLibraryMultipleApexViolation = map[string]bool{
+ "libclang_rt.asan": true,
+ "libclang_rt.hwasan": true,
+ // runtime apex
+ "libc": true,
+ "libc_hwasan": true,
+ "libdl_android": true,
+ "libm": true,
+ "libdl": true,
+ // art apex
+ "libandroidio": true,
+ "libdexfile": true,
+ "libnativebridge": true,
+ "libnativehelper": true,
+ "libnativeloader": true,
+ "libsigchain": true,
+ }
+)
+
+// Returns true if a stub library could be installed in multiple apexes
+func (c *Module) stubLibraryMultipleApexViolation(ctx android.ModuleContext) bool {
+ // If this is not an apex variant, no check necessary
+ if !c.InAnyApex() {
+ return false
+ }
+ // If this is not a stub library, no check necessary
+ if !c.HasStubsVariants() {
+ return false
+ }
+ // Skip the allowlist
+ // Use BaseModuleName so that this matches prebuilts.
+ if _, exists := skipStubLibraryMultipleApexViolation[c.BaseModuleName()]; exists {
+ return false
+ }
+
+ _, aaWithoutTestApexes, _ := android.ListSetDifference(c.ApexAvailable(), c.TestApexes())
+ // Stub libraries should not have more than one apex_available
+ if len(aaWithoutTestApexes) > 1 {
+ return true
+ }
+ // Stub libraries should not use the wildcard
+ if aaWithoutTestApexes[0] == android.AvailableToAnyApex {
+ return true
+ }
+ // Default: no violation
+ return false
+}
+
func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
// Handle the case of a test module split by `test_per_src` mutator.
//
@@ -1979,19 +2056,17 @@
c.makeLinkType = GetMakeLinkType(actx, c)
- ctx := &moduleContext{
- ModuleContext: actx,
- moduleContextImpl: moduleContextImpl{
- mod: c,
- },
- }
- ctx.ctx = ctx
+ ctx := moduleContextFromAndroidModuleContext(actx, c)
deps := c.depsToPaths(ctx)
if ctx.Failed() {
return
}
+ if c.stubLibraryMultipleApexViolation(actx) {
+ actx.PropertyErrorf("apex_available",
+ "Stub libraries should have a single apex_available (test apexes excluded). Got %v", c.ApexAvailable())
+ }
if c.Properties.Clang != nil && *c.Properties.Clang == false {
ctx.PropertyErrorf("clang", "false (GCC) is no longer supported")
} else if c.Properties.Clang != nil && !ctx.DeviceConfig().BuildBrokenClangProperty() {
@@ -3914,8 +3989,8 @@
// TODO(b/244431896) properly convert cc_test_library to its own macro. This
// will let them add implicit compile deps on gtest, for example.
//
- // For now, treat them as regular shared libraries.
- return sharedLibrary
+ // For now, treat them as regular libraries.
+ return fullLibrary
} else if c.CcLibrary() {
static := false
shared := false
diff --git a/cc/cc_test.go b/cc/cc_test.go
index b986511..f9e661f 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -59,7 +59,7 @@
func mixedBuildsPrepareMutator(ctx android.BottomUpMutatorContext) {
if m := ctx.Module(); m.Enabled() {
if mixedBuildMod, ok := m.(android.MixedBuildBuildable); ok {
- if mixedBuildMod.IsMixedBuildSupported(ctx) && android.MixedBuildsEnabled(ctx) {
+ if mixedBuildMod.IsMixedBuildSupported(ctx) && android.MixedBuildsEnabled(ctx) == android.MixedBuildEnabled {
mixedBuildMod.QueueBazelCall(ctx)
}
}
@@ -3114,6 +3114,11 @@
whole_static_libs: ["whole_static_dep"],
shared_libs: ["shared_dep"],
gtest: false,
+ sanitize: {
+ // cc_test modules default to memtag_heap: true,
+ // but this adds extra dependencies that we don't care about
+ never: true,
+ }
}
cc_binary {
name: "binary",
@@ -3573,9 +3578,6 @@
}
func TestStubsForLibraryInMultipleApexes(t *testing.T) {
- // TODO(b/275313114): Test exposes non-determinism which should be corrected and the test
- // reenabled.
- t.Skip()
t.Parallel()
ctx := testCc(t, `
cc_library_shared {
@@ -3680,6 +3682,130 @@
}
}
+func TestMixedBuildUsesStubs(t *testing.T) {
+ t.Parallel()
+ bp := `
+ cc_library_shared {
+ name: "libFoo",
+ bazel_module: { label: "//:libFoo" },
+ srcs: ["foo.c"],
+ stubs: {
+ symbol_file: "foo.map.txt",
+ versions: ["current"],
+ },
+ apex_available: ["bar", "a1"],
+ }
+
+ cc_library_shared {
+ name: "libBar",
+ srcs: ["bar.c"],
+ shared_libs: ["libFoo"],
+ apex_available: ["a1"],
+ }
+
+ cc_library_shared {
+ name: "libA1",
+ srcs: ["a1.c"],
+ shared_libs: ["libFoo"],
+ apex_available: ["a1"],
+ }
+
+ cc_library_shared {
+ name: "libBarA1",
+ srcs: ["bara1.c"],
+ shared_libs: ["libFoo"],
+ apex_available: ["bar", "a1"],
+ }
+
+ cc_library_shared {
+ name: "libAnyApex",
+ srcs: ["anyApex.c"],
+ shared_libs: ["libFoo"],
+ apex_available: ["//apex_available:anyapex"],
+ }
+
+ cc_library_shared {
+ name: "libBaz",
+ srcs: ["baz.c"],
+ shared_libs: ["libFoo"],
+ apex_available: ["baz"],
+ }
+
+ cc_library_shared {
+ name: "libQux",
+ srcs: ["qux.c"],
+ shared_libs: ["libFoo"],
+ apex_available: ["qux", "bar"],
+ }`
+
+ result := android.GroupFixturePreparers(
+ prepareForCcTest,
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.BazelContext = android.MockBazelContext{
+ OutputBaseDir: "out/bazel",
+ LabelToCcInfo: map[string]cquery.CcInfo{
+ "//:libFoo": {
+ RootDynamicLibraries: []string{"libFoo.so"},
+ },
+ "//:libFoo_stub_libs-current": {
+ RootDynamicLibraries: []string{"libFoo_stub_libs-current.so"},
+ },
+ },
+ }
+ }),
+ ).RunTestWithBp(t, bp)
+ ctx := result.TestContext
+
+ variants := ctx.ModuleVariantsForTests("libFoo")
+ expectedVariants := []string{
+ "android_arm64_armv8-a_shared",
+ "android_arm64_armv8-a_shared_current",
+ "android_arm_armv7-a-neon_shared",
+ "android_arm_armv7-a-neon_shared_current",
+ }
+ variantsMismatch := false
+ if len(variants) != len(expectedVariants) {
+ variantsMismatch = true
+ } else {
+ for _, v := range expectedVariants {
+ if !inList(v, variants) {
+ variantsMismatch = false
+ }
+ }
+ }
+ if variantsMismatch {
+ t.Errorf("variants of libFoo expected:\n")
+ for _, v := range expectedVariants {
+ t.Errorf("%q\n", v)
+ }
+ t.Errorf(", but got:\n")
+ for _, v := range variants {
+ t.Errorf("%q\n", v)
+ }
+ }
+
+ linkAgainstFoo := []string{"libBarA1"}
+ linkAgainstFooStubs := []string{"libBar", "libA1", "libBaz", "libQux", "libAnyApex"}
+
+ libFooPath := "out/bazel/execroot/__main__/libFoo.so"
+ for _, lib := range linkAgainstFoo {
+ libLinkRule := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld")
+ libFlags := libLinkRule.Args["libFlags"]
+ if !strings.Contains(libFlags, libFooPath) {
+ t.Errorf("%q: %q is not found in %q", lib, libFooPath, libFlags)
+ }
+ }
+
+ libFooStubPath := "out/bazel/execroot/__main__/libFoo_stub_libs-current.so"
+ for _, lib := range linkAgainstFooStubs {
+ libLinkRule := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld")
+ libFlags := libLinkRule.Args["libFlags"]
+ if !strings.Contains(libFlags, libFooStubPath) {
+ t.Errorf("%q: %q is not found in %q", lib, libFooStubPath, libFlags)
+ }
+ }
+}
+
func TestVersioningMacro(t *testing.T) {
t.Parallel()
for _, tc := range []struct{ moduleName, expected string }{
@@ -5101,3 +5227,256 @@
expectedOutputFiles := []string{"outputbase/execroot/__main__/foo.so"}
android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
}
+
+func TestDisableSanitizerVariantsInMixedBuilds(t *testing.T) {
+ t.Parallel()
+ bp := `
+ cc_library_static {
+ name: "foo_ubsan_minimal",
+ srcs: ["foo.cc"],
+ bazel_module: { label: "//foo_ubsan_minimal" },
+ sanitize: {
+ all_undefined: true,
+ integer_overflow: true,
+ },
+ }
+ cc_library_static {
+ name: "foo",
+ srcs: ["foo.cc"],
+ bazel_module: { label: "//foo" },
+ sanitize: {
+ address: true,
+ hwaddress: true,
+ fuzzer: true,
+ integer_overflow: true,
+ scs: true,
+ },
+ }
+ cc_library_static {
+ name: "foo_tsan",
+ srcs: ["foo.cc"],
+ bazel_module: { label: "//foo_tsan" },
+ sanitize: {
+ thread: true,
+ },
+ }
+ cc_library_static {
+ name: "foo_cfi",
+ srcs: ["foo.cc"],
+ bazel_module: { label: "//foo_cfi" },
+ sanitize: {
+ cfi: true,
+ },
+ }
+ cc_library_static {
+ name: "foo_memtag_stack",
+ srcs: ["foo.cc"],
+ bazel_module: { label: "//foo_memtag_stack" },
+ sanitize: {
+ memtag_stack: true,
+ },
+ }
+ cc_library_static {
+ name: "foo_memtag_heap",
+ srcs: ["foo.cc"],
+ bazel_module: { label: "//foo_memtag_heap" },
+ sanitize: {
+ memtag_heap: true,
+ },
+ }
+ cc_library_static {
+ name: "foo_safestack",
+ srcs: ["foo.cc"],
+ bazel_module: { label: "//foo_safestack" },
+ sanitize: {
+ safestack: true,
+ },
+ }
+ cc_library_static {
+ name: "foo_scudo",
+ srcs: ["foo.cc"],
+ bazel_module: { label: "//foo_scudo" },
+ sanitize: {
+ scudo: true,
+ },
+ }
+ `
+ testcases := []struct {
+ name string
+ variant string
+ expectedOutputPaths []string
+ }{
+ {
+ name: "foo_ubsan_minimal",
+ variant: "android_arm64_armv8-a_static_apex28",
+ expectedOutputPaths: []string{
+ "outputbase/execroot/__main__/foo_ubsan_minimal.a",
+ },
+ },
+ {
+ name: "foo",
+ variant: "android_arm64_armv8-a_static_apex28",
+ expectedOutputPaths: []string{
+ "outputbase/execroot/__main__/foo.a",
+ },
+ },
+ {
+ name: "foo",
+ variant: "android_arm_armv7-a-neon_static_asan_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo/android_arm_armv7-a-neon_static_asan_apex28/foo.a",
+ },
+ },
+ {
+ name: "foo",
+ variant: "android_arm64_armv8-a_static_hwasan_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo/android_arm64_armv8-a_static_hwasan_apex28/foo.a",
+ },
+ },
+ {
+ name: "foo",
+ variant: "android_arm64_armv8-a_static_fuzzer_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo/android_arm64_armv8-a_static_fuzzer_apex28/foo.a",
+ },
+ },
+ {
+ name: "foo",
+ variant: "android_arm_armv7-a-neon_static_asan_fuzzer_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo/android_arm_armv7-a-neon_static_asan_fuzzer_apex28/foo.a",
+ },
+ },
+ {
+ name: "foo",
+ variant: "android_arm64_armv8-a_static_hwasan_fuzzer_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo/android_arm64_armv8-a_static_hwasan_fuzzer_apex28/foo.a",
+ },
+ },
+ {
+ name: "foo",
+ variant: "android_arm64_armv8-a_static_scs_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo/android_arm64_armv8-a_static_scs_apex28/foo.a",
+ },
+ },
+ {
+ name: "foo",
+ variant: "android_arm64_armv8-a_static_hwasan_scs_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo/android_arm64_armv8-a_static_hwasan_scs_apex28/foo.a",
+ },
+ },
+ {
+ name: "foo",
+ variant: "android_arm64_armv8-a_static_hwasan_scs_fuzzer_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo/android_arm64_armv8-a_static_hwasan_scs_fuzzer_apex28/foo.a",
+ },
+ },
+ {
+ name: "foo_tsan",
+ variant: "android_arm64_armv8-a_static_apex28",
+ expectedOutputPaths: []string{
+ "outputbase/execroot/__main__/foo_tsan.a",
+ },
+ },
+ {
+ name: "foo_tsan",
+ variant: "android_arm64_armv8-a_static_tsan_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo_tsan/android_arm64_armv8-a_static_tsan_apex28/foo_tsan.a",
+ },
+ },
+ {
+ name: "foo_cfi",
+ variant: "android_arm64_armv8-a_static_apex28",
+ expectedOutputPaths: []string{
+ "outputbase/execroot/__main__/foo_cfi.a",
+ },
+ },
+ {
+ name: "foo_cfi",
+ variant: "android_arm64_armv8-a_static_cfi_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo_cfi/android_arm64_armv8-a_static_cfi_apex28/foo_cfi.a",
+ },
+ },
+ {
+ name: "foo_memtag_stack",
+ variant: "android_arm64_armv8-a_static_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo_memtag_stack/android_arm64_armv8-a_static_apex28/foo_memtag_stack.a",
+ },
+ },
+ {
+ name: "foo_memtag_heap",
+ variant: "android_arm64_armv8-a_static_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo_memtag_heap/android_arm64_armv8-a_static_apex28/foo_memtag_heap.a",
+ },
+ },
+ {
+ name: "foo_safestack",
+ variant: "android_arm64_armv8-a_static_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo_safestack/android_arm64_armv8-a_static_apex28/foo_safestack.a",
+ },
+ },
+ {
+ name: "foo_scudo",
+ variant: "android_arm64_armv8-a_static_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo_scudo/android_arm64_armv8-a_static_apex28/foo_scudo.a",
+ },
+ },
+ }
+
+ ctx := android.GroupFixturePreparers(
+ prepareForCcTest,
+ prepareForAsanTest,
+ android.FixtureRegisterWithContext(registerTestMutators),
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.BazelContext = android.MockBazelContext{
+ OutputBaseDir: "outputbase",
+ LabelToCcInfo: map[string]cquery.CcInfo{
+ "//foo_ubsan_minimal": {
+ RootStaticArchives: []string{"foo_ubsan_minimal.a"},
+ },
+ "//foo": {
+ RootStaticArchives: []string{"foo.a"},
+ },
+ "//foo_tsan": {
+ RootStaticArchives: []string{"foo_tsan.a"},
+ },
+ "//foo_cfi": {
+ RootStaticArchives: []string{"foo_cfi.a"},
+ },
+ "//foo_memtag_stack": {
+ RootStaticArchives: []string{"INVALID_ARCHIVE.a"},
+ },
+ "//foo_memtag_heap": {
+ RootStaticArchives: []string{"INVALID_ARCHIVE.a"},
+ },
+ "//foo_safestack": {
+ RootStaticArchives: []string{"INVALID_ARCHIVE.a"},
+ },
+ "//foo_scudo": {
+ RootStaticArchives: []string{"INVALID_ARCHIVE.a"},
+ },
+ },
+ }
+ }),
+ ).RunTestWithBp(t, bp).TestContext
+
+ for _, tc := range testcases {
+ fooMod := ctx.ModuleForTests(tc.name, tc.variant).Module()
+ outputFiles, err := fooMod.(android.OutputFileProducer).OutputFiles("")
+ if err != nil {
+ t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
+ }
+ android.AssertPathsRelativeToTopEquals(t, "output files", tc.expectedOutputPaths, outputFiles)
+ }
+}
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 28f3682..ca2e05f 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -53,8 +53,7 @@
"-Wl,-z,separate-code",
}
- arm64Lldflags = append(arm64Ldflags,
- "-Wl,-z,max-page-size=4096")
+ arm64Lldflags = arm64Ldflags
arm64Cppflags = []string{}
@@ -93,7 +92,13 @@
func init() {
exportedVars.ExportStringListStaticVariable("Arm64Ldflags", arm64Ldflags)
- exportedVars.ExportStringListStaticVariable("Arm64Lldflags", arm64Lldflags)
+
+ exportedVars.ExportStringList("Arm64Lldflags", arm64Lldflags)
+ pctx.VariableFunc("Arm64Lldflags", func(ctx android.PackageVarContext) string {
+ maxPageSizeFlag := "-Wl,-z,max-page-size=" + ctx.Config().MaxPageSizeSupported()
+ flags := append(arm64Lldflags, maxPageSizeFlag)
+ return strings.Join(flags, " ")
+ })
exportedVars.ExportStringListStaticVariable("Arm64Cflags", arm64Cflags)
exportedVars.ExportStringListStaticVariable("Arm64Cppflags", arm64Cppflags)
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index 0704550..dec2b45 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -185,7 +185,12 @@
exportedVars.ExportString("ArmClangTriple", clangTriple)
exportedVars.ExportStringListStaticVariable("ArmLdflags", armLdflags)
- exportedVars.ExportStringListStaticVariable("ArmLldflags", armLldflags)
+ exportedVars.ExportStringList("ArmLldflags", armLldflags)
+ pctx.VariableFunc("ArmLldflags", func(ctx android.PackageVarContext) string {
+ maxPageSizeFlag := "-Wl,-z,max-page-size=" + ctx.Config().MaxPageSizeSupported()
+ flags := append(armLldflags, maxPageSizeFlag)
+ return strings.Join(flags, " ")
+ })
exportedVars.ExportStringListStaticVariable("ArmFixCortexA8LdFlags", armFixCortexA8LdFlags)
exportedVars.ExportStringListStaticVariable("ArmNoFixCortexA8LdFlags", armNoFixCortexA8LdFlags)
diff --git a/cc/config/global.go b/cc/config/global.go
index a2d5cf4..20298dd 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -311,7 +311,7 @@
// prebuilts/clang default settings.
ClangDefaultBase = "prebuilts/clang/host"
- ClangDefaultVersion = "clang-r487747"
+ ClangDefaultVersion = "clang-r487747b"
ClangDefaultShortVersion = "17"
// Directories with warnings from Android.bp files.
@@ -433,12 +433,15 @@
exportedVars.ExportStringList("CommonGlobalIncludes", commonGlobalIncludes)
pctx.PrefixedExistentPathsForSourcesVariable("CommonGlobalIncludes", "-I", commonGlobalIncludes)
+ exportedVars.ExportStringStaticVariable("CLANG_DEFAULT_VERSION", ClangDefaultVersion)
+ exportedVars.ExportStringStaticVariable("CLANG_DEFAULT_SHORT_VERSION", ClangDefaultShortVersion)
+
pctx.StaticVariableWithEnvOverride("ClangBase", "LLVM_PREBUILTS_BASE", ClangDefaultBase)
- exportedVars.ExportStringStaticVariableWithEnvOverride("ClangVersion", "LLVM_PREBUILTS_VERSION", ClangDefaultVersion)
+ pctx.StaticVariableWithEnvOverride("ClangVersion", "LLVM_PREBUILTS_VERSION", ClangDefaultVersion)
pctx.StaticVariable("ClangPath", "${ClangBase}/${HostPrebuiltTag}/${ClangVersion}")
pctx.StaticVariable("ClangBin", "${ClangPath}/bin")
- exportedVars.ExportStringStaticVariableWithEnvOverride("ClangShortVersion", "LLVM_RELEASE_VERSION", ClangDefaultShortVersion)
+ pctx.StaticVariableWithEnvOverride("ClangShortVersion", "LLVM_RELEASE_VERSION", ClangDefaultShortVersion)
pctx.StaticVariable("ClangAsanLibDir", "${ClangBase}/linux-x86/${ClangVersion}/lib/clang/${ClangShortVersion}/lib/linux")
// These are tied to the version of LLVM directly in external/llvm, so they might trail the host prebuilts
diff --git a/cc/config/riscv64_device.go b/cc/config/riscv64_device.go
index 76c8e5d..a63d5c2 100644
--- a/cc/config/riscv64_device.go
+++ b/cc/config/riscv64_device.go
@@ -26,8 +26,6 @@
// Help catch common 32/64-bit errors.
"-Werror=implicit-function-declaration",
"-fno-emulated-tls",
- // For -fsanitize=shadow-call-stack.
- "-ffixed-x18",
// A temporary fix for SExtWRemoval miscompilation bug.
"-mllvm",
"-riscv-disable-sextw-removal=true",
@@ -37,8 +35,6 @@
riscv64Ldflags = []string{
"-Wl,--hash-style=gnu",
- // For -fsanitize=shadow-call-stack.
- "-ffixed-x18",
}
riscv64Lldflags = append(riscv64Ldflags,
diff --git a/cc/library.go b/cc/library.go
index 7504302..13b333a 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -311,6 +311,11 @@
asFlags = bazel.MakeStringListAttribute(nil)
}
+ sharedFeatures := baseAttributes.features.Clone().Append(sharedAttrs.Features)
+ sharedFeatures.DeduplicateAxesFromBase()
+ staticFeatures := baseAttributes.features.Clone().Append(staticAttrs.Features)
+ staticFeatures.DeduplicateAxesFromBase()
+
staticCommonAttrs := staticOrSharedAttributes{
Srcs: *srcs.Clone().Append(staticAttrs.Srcs),
Srcs_c: *compilerAttrs.cSrcs.Clone().Append(staticAttrs.Srcs_c),
@@ -366,7 +371,7 @@
Cpp_std: compilerAttrs.cppStd,
C_std: compilerAttrs.cStd,
- Features: baseAttributes.features,
+ Features: *staticFeatures,
}
sharedTargetAttrs := &bazelCcLibrarySharedAttributes{
@@ -390,7 +395,7 @@
Additional_linker_inputs: linkerAttrs.additionalLinkerInputs,
Strip: stripAttrsFromLinkerAttrs(&linkerAttrs),
- Features: baseAttributes.features,
+ Features: *sharedFeatures,
bazelCcHeaderAbiCheckerAttributes: bp2buildParseAbiCheckerProps(ctx, m),
Fdo_profile: compilerAttrs.fdoProfile,
@@ -428,11 +433,11 @@
var tagsForStaticVariant bazel.StringListAttribute
if compilerAttrs.stubsSymbolFile == nil && len(compilerAttrs.stubsVersions.Value) == 0 {
- tagsForStaticVariant = android.ApexAvailableTags(m)
+ tagsForStaticVariant = android.ApexAvailableTagsWithoutTestApexes(ctx, m)
}
tagsForStaticVariant.Append(bazel.StringListAttribute{Value: staticAttrs.Apex_available})
- tagsForSharedVariant := android.ApexAvailableTags(m)
+ tagsForSharedVariant := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
tagsForSharedVariant.Append(bazel.StringListAttribute{Value: sharedAttrs.Apex_available})
ctx.CreateBazelTargetModuleWithRestrictions(staticProps,
@@ -931,9 +936,17 @@
func (handler *ccLibraryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
bazelCtx := ctx.Config().BazelContext
bazelCtx.QueueBazelRequest(label, cquery.GetCcInfo, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
+ if v := handler.module.library.stubsVersion(); v != "" {
+ stubsLabel := label + "_stub_libs-" + v
+ bazelCtx.QueueBazelRequest(stubsLabel, cquery.GetCcInfo, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
+ }
}
func (handler *ccLibraryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
+ if v := handler.module.library.stubsVersion(); v != "" {
+ // if we are a stubs variant, just use the Bazel stubs target
+ label = label + "_stub_libs-" + v
+ }
bazelCtx := ctx.Config().BazelContext
ccInfo, err := bazelCtx.GetCcInfo(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
if err != nil {
@@ -962,6 +975,9 @@
}
handler.module.setAndroidMkVariablesFromCquery(ccInfo.CcAndroidMkInfo)
+
+ cctx := moduleContextFromAndroidModuleContext(ctx, handler.module)
+ addStubDependencyProviders(cctx)
}
func (library *libraryDecorator) setFlagExporterInfoFromCcInfo(ctx android.ModuleContext, ccInfo cquery.CcInfo) {
@@ -1787,6 +1803,12 @@
Target: ctx.Target(),
})
+ addStubDependencyProviders(ctx)
+
+ return unstrippedOutputFile
+}
+
+func addStubDependencyProviders(ctx ModuleContext) {
stubs := ctx.GetDirectDepsWithTag(stubImplDepTag)
if len(stubs) > 0 {
var stubsInfo []SharedStubLibrary
@@ -1801,12 +1823,9 @@
}
ctx.SetProvider(SharedLibraryStubsProvider, SharedLibraryStubsInfo{
SharedStubLibraries: stubsInfo,
-
- IsLLNDK: ctx.IsLlndk(),
+ IsLLNDK: ctx.IsLlndk(),
})
}
-
- return unstrippedOutputFile
}
func (library *libraryDecorator) unstrippedOutputFilePath() android.Path {
@@ -2193,7 +2212,16 @@
func (library *libraryDecorator) installSymlinkToRuntimeApex(ctx ModuleContext, file android.Path) {
dir := library.baseInstaller.installDir(ctx)
dirOnDevice := android.InstallPathToOnDevicePath(ctx, dir)
- target := "/" + filepath.Join("apex", "com.android.runtime", dir.Base(), "bionic", file.Base())
+ // libc_hwasan has relative_install_dir set, which would mess up the dir.Base() logic.
+ // hardcode here because it's the only target, if we have other targets that use this
+ // we can generalise this.
+ var target string
+ if ctx.baseModuleName() == "libc_hwasan" {
+ target = "/" + filepath.Join("apex", "com.android.runtime", "lib64", "bionic", "hwasan", file.Base())
+ } else {
+ base := dir.Base()
+ target = "/" + filepath.Join("apex", "com.android.runtime", base, "bionic", file.Base())
+ }
ctx.InstallAbsoluteSymlink(dir, file.Base(), target)
library.postInstallCmds = append(library.postInstallCmds, makeSymlinkCmd(dirOnDevice, file.Base(), target))
}
@@ -2383,7 +2411,10 @@
}
// Future API level is implicitly added if there isn't
- vers := library.Properties.Stubs.Versions
+ return addCurrentVersionIfNotPresent(library.Properties.Stubs.Versions)
+}
+
+func addCurrentVersionIfNotPresent(vers []string) []string {
if inList(android.FutureApiLevel.String(), vers) {
return vers
}
@@ -2648,7 +2679,7 @@
// normalizeVersions modifies `versions` in place, so that each raw version
// string becomes its normalized canonical form.
// Validates that the versions in `versions` are specified in least to greatest order.
-func normalizeVersions(ctx android.BaseModuleContext, versions []string) {
+func normalizeVersions(ctx android.BazelConversionPathContext, versions []string) {
var previous android.ApiLevel
for i, v := range versions {
ver, err := android.ApiLevelFromUser(ctx, v)
@@ -2872,6 +2903,9 @@
asFlags = bazel.MakeStringListAttribute(nil)
}
+ features := baseAttributes.features.Clone().Append(libSharedOrStaticAttrs.Features)
+ features.DeduplicateAxesFromBase()
+
commonAttrs := staticOrSharedAttributes{
Srcs: compilerAttrs.srcs,
Srcs_c: compilerAttrs.cSrcs,
@@ -2913,7 +2947,7 @@
Conlyflags: compilerAttrs.conlyFlags,
Asflags: asFlags,
- Features: baseAttributes.features,
+ Features: *features,
}
} else {
commonAttrs.Dynamic_deps.Add(baseAttributes.protoDependency)
@@ -2942,7 +2976,7 @@
Strip: stripAttrsFromLinkerAttrs(&linkerAttrs),
- Features: baseAttributes.features,
+ Features: *features,
Suffix: compilerAttrs.suffix,
@@ -2968,7 +3002,7 @@
Bzl_load_location: fmt.Sprintf("//build/bazel/rules/cc:%s.bzl", modType),
}
- tags := android.ApexAvailableTags(module)
+ tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name(), Tags: tags}, attrs)
}
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 1dee726..ce9c4aa 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -151,7 +151,7 @@
Bzl_load_location: "//build/bazel/rules/cc:cc_library_headers.bzl",
}
- tags := android.ApexAvailableTags(module)
+ tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
ctx.CreateBazelTargetModule(props, android.CommonAttributes{
Name: module.Name(),
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index a824361..f8a3559 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -342,7 +342,14 @@
if android.InList("hwaddress", config.SanitizeDevice()) {
return false
}
- return true
+ // http://b/156513478
+ // http://b/277624006
+ // This step is expensive. We're not able to do anything with the outputs of
+ // this step yet (canDiffAbi is flagged off because libabigail isn't able to
+ // handle all our libraries), disable it. There's no sense in protecting
+ // against checking in code that breaks abidw since by the time any of this
+ // can be turned on we'll need to migrate to STG anyway.
+ return false
}
// Feature flag to disable diffing against prebuilts.
diff --git a/cc/object.go b/cc/object.go
index d65cdea..5d61872 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -226,7 +226,7 @@
Bzl_load_location: "//build/bazel/rules/cc:cc_object.bzl",
}
- tags := android.ApexAvailableTags(m)
+ tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
ctx.CreateBazelTargetModule(props, android.CommonAttributes{
Name: m.Name(),
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 4470f54..44cd0d7 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -376,6 +376,7 @@
Static_library: prebuiltAttrs.Src,
Export_includes: exportedIncludes.Includes,
Export_system_includes: exportedIncludes.SystemIncludes,
+ // TODO: ¿Alwayslink?
}
props := bazel.BazelTargetModuleProperties{
@@ -388,7 +389,7 @@
name += "_bp2build_cc_library_static"
}
- tags := android.ApexAvailableTags(module)
+ tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
ctx.CreateBazelTargetModuleWithRestrictions(props, android.CommonAttributes{Name: name, Tags: tags}, attrs, prebuiltAttrs.Enabled)
_true := true
@@ -398,14 +399,19 @@
}
type bazelPrebuiltLibrarySharedAttributes struct {
- Shared_library bazel.LabelAttribute
+ Shared_library bazel.LabelAttribute
+ Export_includes bazel.StringListAttribute
+ Export_system_includes bazel.StringListAttribute
}
func prebuiltLibrarySharedBp2Build(ctx android.TopDownMutatorContext, module *Module) {
prebuiltAttrs := Bp2BuildParsePrebuiltLibraryProps(ctx, module, false)
+ exportedIncludes := bp2BuildParseExportedIncludes(ctx, module, nil)
attrs := &bazelPrebuiltLibrarySharedAttributes{
- Shared_library: prebuiltAttrs.Src,
+ Shared_library: prebuiltAttrs.Src,
+ Export_includes: exportedIncludes.Includes,
+ Export_system_includes: exportedIncludes.SystemIncludes,
}
props := bazel.BazelTargetModuleProperties{
@@ -414,7 +420,7 @@
}
name := android.RemoveOptionalPrebuiltPrefix(module.Name())
- tags := android.ApexAvailableTags(module)
+ tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
ctx.CreateBazelTargetModuleWithRestrictions(props, android.CommonAttributes{Name: name, Tags: tags}, attrs, prebuiltAttrs.Enabled)
}
@@ -644,7 +650,7 @@
}
name := android.RemoveOptionalPrebuiltPrefix(module.Name())
- tags := android.ApexAvailableTags(module)
+ tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name, Tags: tags}, attrs)
}
@@ -807,7 +813,7 @@
}
name := android.RemoveOptionalPrebuiltPrefix(module.Name())
- tags := android.ApexAvailableTags(module)
+ tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name, Tags: tags}, attrs)
}
diff --git a/cc/proto.go b/cc/proto.go
index 97470e5..5d9aef6 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -207,7 +207,7 @@
protoAttrs.Min_sdk_version = m.Properties.Min_sdk_version
name := m.Name() + suffix
- tags := android.ApexAvailableTags(m)
+ tags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), m)
ctx.CreateBazelTargetModule(
bazel.BazelTargetModuleProperties{
Rule_class: rule_class,
diff --git a/cc/sanitize.go b/cc/sanitize.go
index f19659c..7fddc1b 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -64,12 +64,13 @@
cfiBlocklistPath = "external/compiler-rt/lib/cfi"
cfiBlocklistFilename = "cfi_blocklist.txt"
- cfiCflags = []string{"-flto", "-fsanitize-cfi-cross-dso",
+ cfiCrossDsoFlag = "-fsanitize-cfi-cross-dso"
+ cfiCflags = []string{"-flto", cfiCrossDsoFlag,
"-fsanitize-ignorelist=" + cfiBlocklistPath + "/" + cfiBlocklistFilename}
// -flto and -fvisibility are required by clang when -fsanitize=cfi is
// used, but have no effect on assembly files
cfiAsflags = []string{"-flto", "-fvisibility=default"}
- cfiLdflags = []string{"-flto", "-fsanitize-cfi-cross-dso", "-fsanitize=cfi",
+ cfiLdflags = []string{"-flto", cfiCrossDsoFlag, "-fsanitize=cfi",
"-Wl,-plugin-opt,O1"}
cfiExportsMapPath = "build/soong/cc/config"
cfiExportsMapFilename = "cfi_exports.map"
@@ -393,11 +394,13 @@
exportedVars.ExportStringList("DeviceOnlySanitizeFlags", deviceOnlySanitizeFlags)
// Leave out "-flto" from the slices exported to bazel, as we will use the
- // dedicated LTO feature for this
- exportedVars.ExportStringList("CfiCFlags", cfiCflags[1:])
+ // dedicated LTO feature for this. For C Flags and Linker Flags, also leave
+ // out the cross DSO flag which will be added separately by transitions.
+ exportedVars.ExportStringList("CfiCFlags", cfiCflags[2:])
+ exportedVars.ExportStringList("CfiLdFlags", cfiLdflags[2:])
exportedVars.ExportStringList("CfiAsFlags", cfiAsflags[1:])
- exportedVars.ExportStringList("CfiLdFlags", cfiLdflags[1:])
+ exportedVars.ExportString("CfiCrossDsoFlag", cfiCrossDsoFlag)
exportedVars.ExportString("CfiBlocklistPath", cfiBlocklistPath)
exportedVars.ExportString("CfiBlocklistFilename", cfiBlocklistFilename)
exportedVars.ExportString("CfiExportsMapPath", cfiExportsMapPath)
@@ -590,6 +593,12 @@
}
}
+ // Enable HWASan for all components in the include paths (for Aarch64 only)
+ if s.Hwaddress == nil && ctx.Config().HWASanEnabledForPath(ctx.ModuleDir()) &&
+ ctx.Arch().ArchType == android.Arm64 && ctx.toolchain().Bionic() {
+ s.Hwaddress = proptools.BoolPtr(true)
+ }
+
// Enable CFI for non-host components in the include paths
if s.Cfi == nil && ctx.Config().CFIEnabledForPath(ctx.ModuleDir()) && !ctx.Host() {
s.Cfi = proptools.BoolPtr(true)
@@ -613,6 +622,10 @@
if (ctx.Arch().ArchType != android.Arm64 && ctx.Arch().ArchType != android.Riscv64) || !ctx.toolchain().Bionic() {
s.Scs = nil
}
+ // ...but temporarily globally disabled on riscv64 (http://b/277909695).
+ if ctx.Arch().ArchType == android.Riscv64 {
+ s.Scs = nil
+ }
// Memtag_heap is only implemented on AArch64.
// Memtag ABI is Android specific for now, so disable for host.
@@ -785,6 +798,13 @@
if Bool(sanProps.Writeonly) {
flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-hwasan-instrument-reads=0")
}
+ if !ctx.staticBinary() && !ctx.Host() {
+ if ctx.bootstrap() {
+ flags.DynamicLinker = "/system/bin/bootstrap/linker_hwasan64"
+ } else {
+ flags.DynamicLinker = "/system/bin/linker_hwasan64"
+ }
+ }
}
if Bool(sanProps.Fuzzer) {
diff --git a/cc/sanitize_test.go b/cc/sanitize_test.go
index 718186d..29b17d4 100644
--- a/cc/sanitize_test.go
+++ b/cc/sanitize_test.go
@@ -1166,3 +1166,83 @@
checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync)
checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync)
}
+
+func TestCfi(t *testing.T) {
+ t.Parallel()
+
+ bp := `
+ cc_library_shared {
+ name: "shared_with_cfi",
+ static_libs: [
+ "static_dep_with_cfi",
+ "static_dep_no_cfi",
+ ],
+ sanitize: {
+ cfi: true,
+ },
+ }
+
+ cc_library_shared {
+ name: "shared_no_cfi",
+ static_libs: [
+ "static_dep_with_cfi",
+ "static_dep_no_cfi",
+ ],
+ }
+
+ cc_library_static {
+ name: "static_dep_with_cfi",
+ sanitize: {
+ cfi: true,
+ },
+ }
+
+ cc_library_static {
+ name: "static_dep_no_cfi",
+ }
+
+ cc_library_shared {
+ name: "shared_rdep_no_cfi",
+ static_libs: ["static_dep_with_cfi_2"],
+ }
+
+ cc_library_static {
+ name: "static_dep_with_cfi_2",
+ sanitize: {
+ cfi: true,
+ },
+ }
+`
+ preparer := android.GroupFixturePreparers(
+ prepareForCcTest,
+ )
+ result := preparer.RunTestWithBp(t, bp)
+ ctx := result.TestContext
+
+ buildOs := "android_arm64_armv8-a"
+ shared_suffix := "_shared"
+ cfi_suffix := "_cfi"
+ static_suffix := "_static"
+
+ sharedWithCfiLib := result.ModuleForTests("shared_with_cfi", buildOs+shared_suffix+cfi_suffix)
+ sharedNoCfiLib := result.ModuleForTests("shared_no_cfi", buildOs+shared_suffix)
+ staticWithCfiLib := result.ModuleForTests("static_dep_with_cfi", buildOs+static_suffix)
+ staticWithCfiLibCfiVariant := result.ModuleForTests("static_dep_with_cfi", buildOs+static_suffix+cfi_suffix)
+ staticNoCfiLib := result.ModuleForTests("static_dep_no_cfi", buildOs+static_suffix)
+ staticNoCfiLibCfiVariant := result.ModuleForTests("static_dep_no_cfi", buildOs+static_suffix+cfi_suffix)
+ sharedRdepNoCfi := result.ModuleForTests("shared_rdep_no_cfi", buildOs+shared_suffix)
+ staticDepWithCfi2Lib := result.ModuleForTests("static_dep_with_cfi_2", buildOs+static_suffix)
+
+ // Confirm assumptions about propagation of CFI enablement
+ expectStaticLinkDep(t, ctx, sharedWithCfiLib, staticWithCfiLibCfiVariant)
+ expectStaticLinkDep(t, ctx, sharedNoCfiLib, staticWithCfiLib)
+ expectStaticLinkDep(t, ctx, sharedWithCfiLib, staticNoCfiLibCfiVariant)
+ expectStaticLinkDep(t, ctx, sharedNoCfiLib, staticNoCfiLib)
+ expectStaticLinkDep(t, ctx, sharedRdepNoCfi, staticDepWithCfi2Lib)
+
+ // Confirm that non-CFI variants do not add CFI flags
+ bazLibCflags := staticWithCfiLib.Rule("cc").Args["cFlags"]
+ if strings.Contains(bazLibCflags, "-fsanitize-cfi-cross-dso") {
+ t.Errorf("non-CFI variant of baz not expected to contain CFI flags ")
+ }
+}
diff --git a/cc/sysprop.go b/cc/sysprop.go
index 0df290a..7ddd476 100644
--- a/cc/sysprop.go
+++ b/cc/sysprop.go
@@ -38,7 +38,7 @@
}
func Bp2buildSysprop(ctx android.Bp2buildMutatorContext, labels SyspropLibraryLabels, srcs bazel.LabelListAttribute, minSdkVersion *string) {
- apexAvailableTags := android.ApexAvailableTags(ctx.Module())
+ apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), ctx.Module())
ctx.CreateBazelTargetModule(
bazel.BazelTargetModuleProperties{
Rule_class: "sysprop_library",
diff --git a/cc/util.go b/cc/util.go
index aa0f6b5..6d8ac43 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -100,17 +100,6 @@
"ln -sf " + target + " " + filepath.Join(dir, linkName)
}
-func combineNoticesRule(ctx android.SingletonContext, paths android.Paths, out string) android.OutputPath {
- outPath := android.PathForOutput(ctx, out)
- ctx.Build(pctx, android.BuildParams{
- Rule: android.Cat,
- Inputs: paths,
- Output: outPath,
- Description: "combine notices for " + out,
- })
- return outPath
-}
-
// Dump a map to a list file as:
//
// {key1} {value1}
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 9b12bfa..e6e5660 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -157,9 +157,10 @@
// extra config files
InitRc []string `json:",omitempty"`
VintfFragments []string `json:",omitempty"`
+ MinSdkVersion string `json:",omitempty"`
}
-var ccSnapshotAction snapshot.GenerateSnapshotAction = func(s snapshot.SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) android.Paths {
+var ccSnapshotAction snapshot.GenerateSnapshotAction = func(s snapshot.SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) snapshot.SnapshotPaths {
/*
Vendor snapshot zipped artifacts directory structure for cc modules:
{SNAPSHOT_ARCH}/
@@ -194,10 +195,10 @@
*/
var snapshotOutputs android.Paths
+ var snapshotNotices android.Paths
includeDir := filepath.Join(snapshotArchDir, "include")
configsDir := filepath.Join(snapshotArchDir, "configs")
- noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES")
installedNotices := make(map[string]bool)
installedConfigs := make(map[string]bool)
@@ -227,7 +228,7 @@
prop := snapshotJsonFlags{}
// Common properties among snapshots.
- prop.ModuleName = ctx.ModuleName(m)
+ prop.InitBaseSnapshotPropsWithName(m, ctx.ModuleName(m))
if supportsVndkExt(s.Image) && m.IsVndkExt() {
// vndk exts are installed to /vendor/lib(64)?/vndk(-sp)?
if m.IsVndkSp() {
@@ -249,6 +250,7 @@
for _, path := range m.VintfFragments() {
prop.VintfFragments = append(prop.VintfFragments, filepath.Join("configs", path.Base()))
}
+ prop.MinSdkVersion = m.MinSdkVersion()
// install config files. ignores any duplicates.
for _, path := range append(m.InitRc(), m.VintfFragments()...) {
@@ -404,13 +406,10 @@
headers = append(headers, m.SnapshotHeaders()...)
}
- if len(m.EffectiveLicenseFiles()) > 0 {
- noticeName := ctx.ModuleName(m) + ".txt"
- noticeOut := filepath.Join(noticeDir, noticeName)
- // skip already copied notice file
- if !installedNotices[noticeOut] {
- installedNotices[noticeOut] = true
- snapshotOutputs = append(snapshotOutputs, combineNoticesRule(ctx, m.EffectiveLicenseFiles(), noticeOut))
+ for _, notice := range m.EffectiveLicenseFiles() {
+ if _, ok := installedNotices[notice.String()]; !ok {
+ installedNotices[notice.String()] = true
+ snapshotNotices = append(snapshotNotices, notice)
}
}
})
@@ -420,7 +419,7 @@
snapshotOutputs = append(snapshotOutputs, copyFile(ctx, header, filepath.Join(includeDir, header.String()), s.Fake))
}
- return snapshotOutputs
+ return snapshot.SnapshotPaths{OutputFiles: snapshotOutputs, NoticeFiles: snapshotNotices}
}
func init() {
diff --git a/cc/vndk.go b/cc/vndk.go
index be66cd7..30bfdd8 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -706,6 +706,7 @@
// json struct to export snapshot information
prop := struct {
+ MinSdkVersion string `json:",omitempty"`
LicenseKinds []string `json:",omitempty"`
LicenseTexts []string `json:",omitempty"`
ExportedDirs []string `json:",omitempty"`
@@ -716,6 +717,7 @@
prop.LicenseKinds = m.EffectiveLicenseKinds()
prop.LicenseTexts = m.EffectiveLicenseFiles().Strings()
+ prop.MinSdkVersion = m.MinSdkVersion()
if ctx.Config().VndkSnapshotBuildArtifacts() {
exportedInfo := ctx.ModuleProvider(m, FlagExporterInfoProvider).(FlagExporterInfo)
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 79a5ce4..53e0e55 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -85,7 +85,7 @@
flag.BoolVar(&cmdlineArgs.BazelModeDev, "bazel-mode-dev", false, "use bazel for analysis of a large number of modules (less stable)")
flag.BoolVar(&cmdlineArgs.UseBazelProxy, "use-bazel-proxy", false, "communicate with bazel using unix socket proxy instead of spawning subprocesses")
flag.BoolVar(&cmdlineArgs.BuildFromTextStub, "build-from-text-stub", false, "build Java stubs from API text files instead of source files")
-
+ flag.BoolVar(&cmdlineArgs.EnsureAllowlistIntegrity, "ensure-allowlist-integrity", false, "verify that allowlisted modules are mixed-built")
// Flags that probably shouldn't be flags of soong_build, but we haven't found
// the time to remove them yet
flag.BoolVar(&cmdlineArgs.RunGoTests, "t", false, "build and run go tests during bootstrap")
@@ -288,6 +288,46 @@
maybeQuit(err, "error writing soong_build metrics %s", metricsFile)
}
+// Errors out if any modules expected to be mixed_built were not, unless
+// there is a platform incompatibility.
+func checkForAllowlistIntegrityError(configuration android.Config, isStagingMode bool) error {
+ modules := findModulesNotMixedBuiltForAnyVariant(configuration, isStagingMode)
+ if len(modules) == 0 {
+ return nil
+ }
+
+ return fmt.Errorf("Error: expected the following modules to be mixed_built: %s", modules)
+}
+
+// Returns the list of modules that should have been mixed_built (per the
+// allowlists and cmdline flags) but were not.
+func findModulesNotMixedBuiltForAnyVariant(configuration android.Config, isStagingMode bool) []string {
+ retval := []string{}
+ forceEnabledModules := configuration.BazelModulesForceEnabledByFlag()
+
+ mixedBuildsEnabled := configuration.GetMixedBuildsEnabledModules()
+ for _, module := range allowlists.ProdMixedBuildsEnabledList {
+ if _, ok := mixedBuildsEnabled[module]; !ok && module != "" {
+ retval = append(retval, module)
+ }
+ }
+
+ if isStagingMode {
+ for _, module := range allowlists.StagingMixedBuildsEnabledList {
+ if _, ok := mixedBuildsEnabled[module]; !ok && module != "" {
+ retval = append(retval, module)
+ }
+ }
+ }
+
+ for module, _ := range forceEnabledModules {
+ if _, ok := mixedBuildsEnabled[module]; !ok && module != "" {
+ retval = append(retval, module)
+ }
+ }
+ return retval
+}
+
func writeJsonModuleGraphAndActions(ctx *android.Context, cmdArgs android.CmdArgs) {
graphFile, graphErr := os.Create(shared.JoinPath(topDir, cmdArgs.ModuleGraphFile))
maybeQuit(graphErr, "graph err")
@@ -433,8 +473,14 @@
writeMetrics(configuration, ctx.EventHandler, metricsDir)
default:
ctx.Register()
- if configuration.IsMixedBuildsEnabled() {
+ isMixedBuildsEnabled := configuration.IsMixedBuildsEnabled()
+ if isMixedBuildsEnabled {
finalOutputFile = runMixedModeBuild(ctx, extraNinjaDeps)
+ if cmdlineArgs.EnsureAllowlistIntegrity {
+ if err := checkForAllowlistIntegrityError(configuration, cmdlineArgs.BazelModeStaging); err != nil {
+ maybeQuit(err, "")
+ }
+ }
} else {
finalOutputFile = runSoongOnlyBuild(ctx, extraNinjaDeps)
}
diff --git a/cmd/soong_build/queryview.go b/cmd/soong_build/queryview.go
index ce32184..67cb6cf 100644
--- a/cmd/soong_build/queryview.go
+++ b/cmd/soong_build/queryview.go
@@ -15,6 +15,7 @@
package main
import (
+ "android/soong/starlark_import"
"io/fs"
"io/ioutil"
"os"
@@ -47,6 +48,14 @@
}
}
+ // Add starlark deps here, so that they apply to both queryview and apibp2build which
+ // both run this function.
+ starlarkDeps, err2 := starlark_import.GetNinjaDeps()
+ if err2 != nil {
+ return err2
+ }
+ ctx.AddNinjaFileDeps(starlarkDeps...)
+
return nil
}
diff --git a/cmd/zip2zip/zip2zip.go b/cmd/zip2zip/zip2zip.go
index 491267b..5ab9656 100644
--- a/cmd/zip2zip/zip2zip.go
+++ b/cmd/zip2zip/zip2zip.go
@@ -128,12 +128,6 @@
}
for _, arg := range args {
- // Reserve escaping for future implementation, so make sure no
- // one is using \ and expecting a certain behavior.
- if strings.Contains(arg, "\\") {
- return fmt.Errorf("\\ characters are not currently supported")
- }
-
input, output := includeSplit(arg)
var includeMatches []pair
diff --git a/cmd/zip2zip/zip2zip_test.go b/cmd/zip2zip/zip2zip_test.go
index 2c4e005..c238098 100644
--- a/cmd/zip2zip/zip2zip_test.go
+++ b/cmd/zip2zip/zip2zip_test.go
@@ -38,13 +38,6 @@
storedFiles []string
err error
}{
- {
- name: "unsupported \\",
-
- args: []string{"a\\b:b"},
-
- err: fmt.Errorf("\\ characters are not currently supported"),
- },
{ // This is modelled after the update package build rules in build/make/core/Makefile
name: "filter globs",
@@ -406,6 +399,13 @@
"b/a/b",
},
},
+ {
+ name: "escaping",
+
+ inputFiles: []string{"a"},
+ args: []string{"\\a"},
+ outputFiles: []string{"a"},
+ },
}
func errorString(e error) string {
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index dcd7fdc..6817dce 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -617,7 +617,7 @@
return true
}
-func generatePrebuiltSnapshot(s snapshot.SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) android.Paths {
+func generatePrebuiltSnapshot(s snapshot.SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) snapshot.SnapshotPaths {
/*
Snapshot zipped artifacts directory structure for etc modules:
{SNAPSHOT_ARCH}/
@@ -631,7 +631,7 @@
(notice files)
*/
var snapshotOutputs android.Paths
- noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES")
+ var snapshotNotices android.Paths
installedNotices := make(map[string]bool)
ctx.VisitAllModules(func(module android.Module) {
@@ -651,7 +651,7 @@
prop := snapshot.SnapshotJsonFlags{}
propOut := snapshotLibOut + ".json"
- prop.ModuleName = m.BaseModuleName()
+ prop.InitBaseSnapshotProps(m)
if m.subdirProperties.Relative_install_path != nil {
prop.RelativeInstallPath = *m.subdirProperties.Relative_install_path
}
@@ -667,27 +667,16 @@
}
snapshotOutputs = append(snapshotOutputs, snapshot.WriteStringToFileRule(ctx, string(j), propOut))
- if len(m.EffectiveLicenseFiles()) > 0 {
- noticeName := ctx.ModuleName(m) + ".txt"
- noticeOut := filepath.Join(noticeDir, noticeName)
- // skip already copied notice file
- if !installedNotices[noticeOut] {
- installedNotices[noticeOut] = true
-
- noticeOutPath := android.PathForOutput(ctx, noticeOut)
- ctx.Build(pctx, android.BuildParams{
- Rule: android.Cat,
- Inputs: m.EffectiveLicenseFiles(),
- Output: noticeOutPath,
- Description: "combine notices for " + noticeOut,
- })
- snapshotOutputs = append(snapshotOutputs, noticeOutPath)
+ for _, notice := range m.EffectiveLicenseFiles() {
+ if _, ok := installedNotices[notice.String()]; !ok {
+ installedNotices[notice.String()] = true
+ snapshotNotices = append(snapshotNotices, notice)
}
}
})
- return snapshotOutputs
+ return snapshot.SnapshotPaths{OutputFiles: snapshotOutputs, NoticeFiles: snapshotNotices}
}
// For Bazel / bp2build
diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go
index 8175a37..f76529d 100644
--- a/fuzz/fuzz_common.go
+++ b/fuzz/fuzz_common.go
@@ -338,6 +338,8 @@
IsJni *bool `json:"is_jni,omitempty"`
// List of modules for monitoring coverage drops in directories (e.g. "libicu")
Target_modules []string `json:"target_modules,omitempty"`
+ // Specifies a bug assignee to replace default ISE assignment
+ Triage_assignee string `json:"triage_assignee,omitempty"`
}
type FuzzFrameworks struct {
diff --git a/genrule/genrule.go b/genrule/genrule.go
index f5da50e..00adb70 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -940,7 +940,7 @@
}
}
- tags := android.ApexAvailableTags(m)
+ tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
if ctx.ModuleType() == "gensrcs" {
// The Output_extension prop is not in an immediately accessible field
diff --git a/go.mod b/go.mod
index a5d9dd5..4a511c5 100644
--- a/go.mod
+++ b/go.mod
@@ -6,4 +6,5 @@
github.com/google/blueprint v0.0.0
google.golang.org/protobuf v0.0.0
prebuilts/bazel/common/proto/analysis_v2 v0.0.0
+ go.starlark.net v0.0.0
)
diff --git a/go.work b/go.work
index 737a9df..67f6549 100644
--- a/go.work
+++ b/go.work
@@ -4,6 +4,7 @@
.
../../external/go-cmp
../../external/golang-protobuf
+ ../../external/starlark-go
../../prebuilts/bazel/common/proto/analysis_v2
../../prebuilts/bazel/common/proto/build
../blueprint
@@ -16,4 +17,5 @@
google.golang.org/protobuf v0.0.0 => ../../external/golang-protobuf
prebuilts/bazel/common/proto/analysis_v2 v0.0.0 => ../../prebuilts/bazel/common/proto/analysis_v2
prebuilts/bazel/common/proto/build v0.0.0 => ../../prebuilts/bazel/common/proto/build
+ go.starlark.net v0.0.0 => ../../external/starlark-go
)
diff --git a/java/aar.go b/java/aar.go
index 47e6efa..f1b137d 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -1015,9 +1015,10 @@
}
type bazelAndroidLibraryImport struct {
- Aar bazel.Label
- Deps bazel.LabelListAttribute
- Exports bazel.LabelListAttribute
+ Aar bazel.Label
+ Deps bazel.LabelListAttribute
+ Exports bazel.LabelListAttribute
+ Sdk_version bazel.StringAttribute
}
func (a *aapt) convertAaptAttrsWithBp2Build(ctx android.TopDownMutatorContext) *bazelAapt {
@@ -1059,9 +1060,10 @@
},
android.CommonAttributes{Name: name},
&bazelAndroidLibraryImport{
- Aar: aars.Includes[0],
- Deps: bazel.MakeLabelListAttribute(deps),
- Exports: bazel.MakeLabelListAttribute(exports),
+ Aar: aars.Includes[0],
+ Deps: bazel.MakeLabelListAttribute(deps),
+ Exports: bazel.MakeLabelListAttribute(exports),
+ Sdk_version: bazel.StringAttribute{Value: a.properties.Sdk_version},
},
)
@@ -1073,6 +1075,9 @@
javaLibraryAttributes: &javaLibraryAttributes{
Neverlink: bazel.BoolAttribute{Value: &neverlink},
Exports: bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + name}),
+ javaCommonAttributes: &javaCommonAttributes{
+ Sdk_version: bazel.StringAttribute{Value: a.properties.Sdk_version},
+ },
},
},
)
@@ -1119,6 +1124,10 @@
javaLibraryAttributes: &javaLibraryAttributes{
Neverlink: bazel.BoolAttribute{Value: &neverlink},
Exports: bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + name}),
+ javaCommonAttributes: &javaCommonAttributes{
+ Sdk_version: bazel.StringAttribute{Value: a.deviceProperties.Sdk_version},
+ Java_version: bazel.StringAttribute{Value: a.properties.Java_version},
+ },
},
},
)
diff --git a/java/android_manifest.go b/java/android_manifest.go
index dbcf098..f2ebfa6 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -63,9 +63,11 @@
// 2. The module is run as part of MTS, and should be testable on stable branches
// Do not return 10000 if we are enforcing default targetSdkVersion and sdk has been finalised
func shouldReturnFinalOrFutureInt(ctx android.ModuleContext, targetSdkVersionLevel android.ApiLevel, enforceDefaultTargetSdkVersion bool) bool {
- if enforceDefaultTargetSdkVersion && ctx.Config().PlatformSdkFinal() {
+ // If this is a REL branch, do not return 10000
+ if ctx.Config().PlatformSdkFinal() {
return false
}
+ // If this a module targeting an unreleased SDK (MTS or unbundled builds), return 10000
return targetSdkVersionLevel.IsPreview() && (ctx.Config().UnbundledBuildApps() || includedInMts(ctx.Module()))
}
diff --git a/java/app.go b/java/app.go
index 52caf6d..7bb8cdb 100755
--- a/java/app.go
+++ b/java/app.go
@@ -1461,10 +1461,8 @@
// verifyUsesLibrariesAPK checks the <uses-library> tags in the manifest of an APK against the build
// system and returns the path to a copy of the APK.
-func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk android.Path) android.Path {
+func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk android.Path) {
u.verifyUsesLibraries(ctx, apk, nil) // for APKs manifest_check does not write output file
- outputFile := android.PathForModuleOut(ctx, "verify_uses_libraries", apk.Base())
- return outputFile
}
// For Bazel / bp2build
@@ -1565,6 +1563,9 @@
appAttrs.bazelAapt = &bazelAapt{Manifest: aapt.Manifest}
appAttrs.Deps = bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + ktName})
+ appAttrs.javaCommonAttributes = &javaCommonAttributes{
+ Sdk_version: commonAttrs.Sdk_version,
+ }
}
ctx.CreateBazelTargetModule(
diff --git a/java/app_import.go b/java/app_import.go
index c1de667..bfd6767 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -17,9 +17,10 @@
// This file contains the module implementations for android_app_import and android_test_import.
import (
- "github.com/google/blueprint"
"reflect"
+ "github.com/google/blueprint"
+
"github.com/google/blueprint/proptools"
"android/soong/android"
@@ -48,6 +49,17 @@
CommandDeps: []string{"${config.Zip2ZipCmd}"},
Description: "Uncompress dex files",
})
+
+ checkJniAndDexLibsAreUncompressedRule = pctx.AndroidStaticRule("check-jni-and-dex-libs-are-uncompressed", blueprint.RuleParams{
+ // grep -v ' stor ' will search for lines that don't have ' stor '. stor means the file is stored uncompressed
+ Command: "if (zipinfo $in 'lib/*.so' '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then " +
+ "echo $in: Contains compressed JNI libraries and/or dex files >&2;" +
+ "exit 1; " +
+ "else " +
+ "touch $out; " +
+ "fi",
+ Description: "Check for compressed JNI libs or dex files",
+ })
)
func RegisterAppImportBuildComponents(ctx android.RegistrationContext) {
@@ -72,8 +84,6 @@
usesLibrary usesLibrary
- preprocessed bool
-
installPath android.InstallPath
hideApexVariantFromMake bool
@@ -127,6 +137,13 @@
// Optional. Install to a subdirectory of the default install path for the module
Relative_install_path *string
+
+ // Whether the prebuilt apk can be installed without additional processing. Default is false.
+ Preprocessed *bool
+
+ // Whether or not to skip checking the preprocessed apk for proper alignment and uncompressed
+ // JNI libs and dex files. Default is false
+ Skip_preprocessed_apk_checks *bool
}
func (a *AndroidAppImport) IsInstallable() bool {
@@ -177,10 +194,6 @@
}
}
-func (a *AndroidAppImport) isPrebuiltFrameworkRes() bool {
- return a.Name() == "prebuilt_framework-res"
-}
-
func (a *AndroidAppImport) DepsMutator(ctx android.BottomUpMutatorContext) {
cert := android.SrcIsModule(String(a.properties.Certificate))
if cert != "" {
@@ -197,14 +210,14 @@
}
}
- a.usesLibrary.deps(ctx, !a.isPrebuiltFrameworkRes())
+ a.usesLibrary.deps(ctx, true)
}
func (a *AndroidAppImport) uncompressEmbeddedJniLibs(
ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) {
// Test apps don't need their JNI libraries stored uncompressed. As a matter of fact, messing
// with them may invalidate pre-existing signature data.
- if ctx.InstallInTestcases() && (Bool(a.properties.Presigned) || a.preprocessed) {
+ if ctx.InstallInTestcases() && (Bool(a.properties.Presigned) || Bool(a.properties.Preprocessed)) {
ctx.Build(pctx, android.BuildParams{
Rule: android.Cp,
Output: outputPath,
@@ -222,7 +235,7 @@
// Returns whether this module should have the dex file stored uncompressed in the APK.
func (a *AndroidAppImport) shouldUncompressDex(ctx android.ModuleContext) bool {
- if ctx.Config().UnbundledBuild() || a.preprocessed {
+ if ctx.Config().UnbundledBuild() || proptools.Bool(a.properties.Preprocessed) {
return false
}
@@ -243,6 +256,10 @@
}
func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext) {
+ if a.Name() == "prebuilt_framework-res" {
+ ctx.ModuleErrorf("prebuilt_framework-res found. This used to have special handling in soong, but was removed due to prebuilt_framework-res no longer existing. This check is to ensure it doesn't come back without readding the special handling.")
+ }
+
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
if !apexInfo.IsForPlatform() {
a.hideApexVariantFromMake = true
@@ -278,14 +295,7 @@
var pathFragments []string
relInstallPath := String(a.properties.Relative_install_path)
- if a.isPrebuiltFrameworkRes() {
- // framework-res.apk is installed as system/framework/framework-res.apk
- if relInstallPath != "" {
- ctx.PropertyErrorf("relative_install_path", "Relative_install_path cannot be set for framework-res")
- }
- pathFragments = []string{"framework"}
- a.preprocessed = true
- } else if Bool(a.properties.Privileged) {
+ if Bool(a.properties.Privileged) {
pathFragments = []string{"priv-app", relInstallPath, a.BaseModuleName()}
} else if ctx.InstallInTestcases() {
pathFragments = []string{relInstallPath, a.BaseModuleName(), ctx.DeviceConfig().DeviceArch()}
@@ -303,7 +313,7 @@
a.dexpreopter.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
if a.usesLibrary.enforceUsesLibraries() {
- srcApk = a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk)
+ a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk)
}
a.dexpreopter.dexpreopt(ctx, jnisUncompressed)
@@ -323,14 +333,15 @@
// Sign or align the package if package has not been preprocessed
- if a.isPrebuiltFrameworkRes() {
- a.outputFile = srcApk
- a.certificate, certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx)
- if len(certificates) != 1 {
- ctx.ModuleErrorf("Unexpected number of certificates were extracted: %q", certificates)
- }
- } else if a.preprocessed {
- a.outputFile = srcApk
+ if proptools.Bool(a.properties.Preprocessed) {
+ output := srcApk
+ // TODO(b/185811447) Uncomment this after all existing failing apks set skip_preprocessed_apk_checks: true
+ //if !proptools.Bool(a.properties.Skip_preprocessed_apk_checks) {
+ // writableOutput := android.PathForModuleOut(ctx, "validated-prebuilt", apkFilename)
+ // a.validatePreprocessedApk(ctx, srcApk, writableOutput)
+ // output = writableOutput
+ //}
+ a.outputFile = output
a.certificate = PresignedCertificate
} else if !Bool(a.properties.Presigned) {
// If the certificate property is empty at this point, default_dev_cert must be set to true.
@@ -364,6 +375,30 @@
// TODO: androidmk converter jni libs
}
+func (a *AndroidAppImport) validatePreprocessedApk(ctx android.ModuleContext, srcApk android.Path, dstApk android.WritablePath) {
+ alignmentStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "alignment.stamp")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: checkZipAlignment,
+ Input: srcApk,
+ Output: alignmentStamp,
+ })
+ compressionStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "compression.stamp")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: checkJniAndDexLibsAreUncompressedRule,
+ Input: srcApk,
+ Output: compressionStamp,
+ })
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: srcApk,
+ Output: dstApk,
+ Validations: []android.Path{
+ alignmentStamp,
+ compressionStamp,
+ },
+ })
+}
+
func (a *AndroidAppImport) Prebuilt() *android.Prebuilt {
return &a.prebuilt
}
@@ -499,11 +534,6 @@
return module
}
-type androidTestImportProperties struct {
- // Whether the prebuilt apk can be installed without additional processing. Default is false.
- Preprocessed *bool
-}
-
type AndroidTestImport struct {
AndroidAppImport
@@ -520,14 +550,10 @@
Per_testcase_directory *bool
}
- testImportProperties androidTestImportProperties
-
data android.Paths
}
func (a *AndroidTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- a.preprocessed = Bool(a.testImportProperties.Preprocessed)
-
a.generateAndroidBuildActions(ctx)
a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
@@ -544,7 +570,6 @@
module.AddProperties(&module.properties)
module.AddProperties(&module.dexpreoptProperties)
module.AddProperties(&module.testProperties)
- module.AddProperties(&module.testImportProperties)
module.populateAllVariantStructs()
android.AddLoadHook(module, func(ctx android.LoadHookContext) {
module.processVariants(ctx)
diff --git a/java/app_import_test.go b/java/app_import_test.go
index 528fffe..845a962 100644
--- a/java/app_import_test.go
+++ b/java/app_import_test.go
@@ -505,67 +505,6 @@
}
}
-func TestAndroidAppImport_frameworkRes(t *testing.T) {
- ctx, _ := testJava(t, `
- android_app_import {
- name: "framework-res",
- certificate: "platform",
- apk: "package-res.apk",
- prefer: true,
- export_package_resources: true,
- // Disable dexpreopt and verify_uses_libraries check as the app
- // contains no Java code to be dexpreopted.
- enforce_uses_libs: false,
- dex_preopt: {
- enabled: false,
- },
- }
- `)
-
- mod := ctx.ModuleForTests("prebuilt_framework-res", "android_common").Module()
- a := mod.(*AndroidAppImport)
-
- if !a.preprocessed {
- t.Errorf("prebuilt framework-res is not preprocessed")
- }
-
- expectedInstallPath := "out/soong/target/product/test_device/system/framework/framework-res.apk"
-
- android.AssertPathRelativeToTopEquals(t, "prebuilt framework-res install location", expectedInstallPath, a.dexpreopter.installPath)
-
- entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
-
- expectedPath := "."
- // From apk property above, in the root of the source tree.
- expectedPrebuiltModuleFile := "package-res.apk"
- // Verify that the apk is preprocessed: The export package is the same
- // as the prebuilt.
- expectedSoongResourceExportPackage := expectedPrebuiltModuleFile
-
- actualPath := entries.EntryMap["LOCAL_PATH"]
- actualPrebuiltModuleFile := entries.EntryMap["LOCAL_PREBUILT_MODULE_FILE"]
- actualSoongResourceExportPackage := entries.EntryMap["LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE"]
-
- if len(actualPath) != 1 {
- t.Errorf("LOCAL_PATH incorrect len %d", len(actualPath))
- } else if actualPath[0] != expectedPath {
- t.Errorf("LOCAL_PATH mismatch, actual: %s, expected: %s", actualPath[0], expectedPath)
- }
-
- if len(actualPrebuiltModuleFile) != 1 {
- t.Errorf("LOCAL_PREBUILT_MODULE_FILE incorrect len %d", len(actualPrebuiltModuleFile))
- } else if actualPrebuiltModuleFile[0] != expectedPrebuiltModuleFile {
- t.Errorf("LOCAL_PREBUILT_MODULE_FILE mismatch, actual: %s, expected: %s", actualPrebuiltModuleFile[0], expectedPrebuiltModuleFile)
- }
-
- if len(actualSoongResourceExportPackage) != 1 {
- t.Errorf("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE incorrect len %d", len(actualSoongResourceExportPackage))
- } else if actualSoongResourceExportPackage[0] != expectedSoongResourceExportPackage {
- t.Errorf("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE mismatch, actual: %s, expected: %s", actualSoongResourceExportPackage[0], expectedSoongResourceExportPackage)
- }
- android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "android_app_import", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
-}
-
func TestAndroidAppImport_relativeInstallPath(t *testing.T) {
bp := `
android_app_import {
@@ -582,13 +521,6 @@
}
android_app_import {
- name: "framework-res",
- apk: "prebuilts/apk/app.apk",
- presigned: true,
- prefer: true,
- }
-
- android_app_import {
name: "privileged_relative_install_path",
apk: "prebuilts/apk/app.apk",
presigned: true,
@@ -612,11 +544,6 @@
errorMessage: "Install path is not correct for app when relative_install_path is present",
},
{
- name: "prebuilt_framework-res",
- expectedInstallPath: "out/soong/target/product/test_device/system/framework/framework-res.apk",
- errorMessage: "Install path is not correct for framework-res",
- },
- {
name: "privileged_relative_install_path",
expectedInstallPath: "out/soong/target/product/test_device/system/priv-app/my/path/privileged_relative_install_path/privileged_relative_install_path.apk",
errorMessage: "Install path is not correct for privileged app when relative_install_path is present",
@@ -730,6 +657,30 @@
}
}
+// TODO(b/185811447) Uncomment this after all existing failing apks set skip_preprocessed_apk_checks: true
+//func TestAndroidAppImport_Preprocessed(t *testing.T) {
+// ctx, _ := testJava(t, `
+// android_app_import {
+// name: "foo",
+// apk: "prebuilts/apk/app.apk",
+// presigned: true,
+// preprocessed: true,
+// }
+// `)
+//
+// apkName := "foo.apk"
+// variant := ctx.ModuleForTests("foo", "android_common")
+// outputBuildParams := variant.Output("validated-prebuilt/" + apkName).BuildParams
+// if outputBuildParams.Rule.String() != android.Cp.String() {
+// t.Errorf("Unexpected prebuilt android_app_import rule: " + outputBuildParams.Rule.String())
+// }
+//
+// // Make sure compression and aligning were validated.
+// if len(outputBuildParams.Validations) != 2 {
+// t.Errorf("Expected compression/alignment validation rules, found %d validations", len(outputBuildParams.Validations))
+// }
+//}
+
func TestAndroidTestImport_UncompressDex(t *testing.T) {
testCases := []struct {
name string
diff --git a/java/app_test.go b/java/app_test.go
index 561be68..7e97b0f 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -3034,11 +3034,13 @@
func TestTargetSdkVersionManifestFixer(t *testing.T) {
platform_sdk_codename := "Tiramisu"
+ platform_sdk_version := 33
testCases := []struct {
name string
targetSdkVersionInBp string
targetSdkVersionExpected string
unbundledBuild bool
+ platformSdkFinal bool
}{
{
name: "Non-Unbundled build: Android.bp has targetSdkVersion",
@@ -3075,6 +3077,12 @@
targetSdkVersionExpected: "10000",
unbundledBuild: true,
},
+ {
+ name: "Bundled build in REL branches",
+ targetSdkVersionExpected: "33",
+ unbundledBuild: false,
+ platformSdkFinal: true,
+ },
}
for _, testCase := range testCases {
targetSdkVersionTemplate := ""
@@ -3091,8 +3099,12 @@
fixture := android.GroupFixturePreparers(
prepareForJavaTest,
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ if testCase.platformSdkFinal {
+ variables.Platform_sdk_final = proptools.BoolPtr(true)
+ }
// explicitly set platform_sdk_codename to make the test deterministic
variables.Platform_sdk_codename = &platform_sdk_codename
+ variables.Platform_sdk_version = &platform_sdk_version
variables.Platform_version_active_codenames = []string{platform_sdk_codename}
// create a non-empty list if unbundledBuild==true
if testCase.unbundledBuild {
diff --git a/java/base.go b/java/base.go
index 9911323..374138c 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1923,9 +1923,12 @@
func (m *Module) getSdkLinkType(ctx android.BaseModuleContext, name string) (ret sdkLinkType, stubs bool) {
switch name {
- case android.SdkCore.JavaLibraryName(ctx.Config()), "legacy.core.platform.api.stubs", "stable.core.platform.api.stubs",
+ case android.SdkCore.JavaLibraryName(ctx.Config()),
+ android.JavaApiLibraryName(ctx.Config(), "legacy.core.platform.api.stubs"),
+ android.JavaApiLibraryName(ctx.Config(), "stable.core.platform.api.stubs"),
"stub-annotations", "private-stub-annotations-jar",
- "core-lambda-stubs", "core-generated-annotation-stubs":
+ android.JavaApiLibraryName(ctx.Config(), "core-lambda-stubs"),
+ "core-generated-annotation-stubs":
return javaCore, true
case android.SdkPublic.JavaLibraryName(ctx.Config()):
return javaSdk, true
diff --git a/java/builder.go b/java/builder.go
index 4626267..0c57738 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -246,6 +246,19 @@
CommandDeps: []string{"${config.ZipAlign}"},
},
)
+
+ checkZipAlignment = pctx.AndroidStaticRule("checkzipalign",
+ blueprint.RuleParams{
+ Command: "if ! ${config.ZipAlign} -c -p 4 $in > /dev/null; then " +
+ "echo $in: Improper package alignment >&2; " +
+ "exit 1; " +
+ "else " +
+ "touch $out; " +
+ "fi",
+ CommandDeps: []string{"${config.ZipAlign}"},
+ Description: "Check zip alignment",
+ },
+ )
)
func init() {
diff --git a/java/config/makevars.go b/java/config/makevars.go
index 273aca0..d383d98 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -28,8 +28,11 @@
ctx.Strict("FRAMEWORK_LIBRARIES", strings.Join(FrameworkLibraries, " "))
// These are used by make when LOCAL_PRIVATE_PLATFORM_APIS is set (equivalent to platform_apis in blueprint):
- ctx.Strict("LEGACY_CORE_PLATFORM_BOOTCLASSPATH_LIBRARIES", strings.Join(LegacyCorePlatformBootclasspathLibraries, " "))
- ctx.Strict("LEGACY_CORE_PLATFORM_SYSTEM_MODULES", LegacyCorePlatformSystemModules)
+ ctx.Strict("LEGACY_CORE_PLATFORM_BOOTCLASSPATH_LIBRARIES",
+ strings.Join(android.JavaApiLibraryNames(ctx.Config(), LegacyCorePlatformBootclasspathLibraries), " "))
+ ctx.Strict("LEGACY_CORE_PLATFORM_SYSTEM_MODULES",
+ android.JavaApiLibraryName(ctx.Config(), LegacyCorePlatformSystemModules),
+ )
ctx.Strict("ANDROID_JAVA_HOME", "${JavaHome}")
ctx.Strict("ANDROID_JAVA8_HOME", "prebuilts/jdk/jdk8/${hostPrebuiltTag}")
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index 656c866..3581040 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -21,6 +21,8 @@
"android/soong/android"
"android/soong/bazel"
"android/soong/dexpreopt"
+
+ "github.com/google/blueprint/proptools"
)
type DeviceHostConverter struct {
@@ -191,7 +193,7 @@
}
type bazelDeviceHostConverterAttributes struct {
- Deps bazel.LabelListAttribute
+ Exports bazel.LabelListAttribute
}
func (d *DeviceHostConverter) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
@@ -202,13 +204,15 @@
},
android.CommonAttributes{Name: d.Name()},
&bazelDeviceHostConverterAttributes{
- Deps: bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, d.properties.Libs)),
+ Exports: bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, d.properties.Libs)),
},
)
- neverlinkProp := true
neverLinkAttrs := &javaLibraryAttributes{
Exports: bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + d.Name()}),
- Neverlink: bazel.BoolAttribute{Value: &neverlinkProp},
+ Neverlink: bazel.BoolAttribute{Value: proptools.BoolPtr(true)},
+ javaCommonAttributes: &javaCommonAttributes{
+ Sdk_version: bazel.StringAttribute{Value: proptools.StringPtr("none")},
+ },
}
ctx.CreateBazelTargetModule(
javaLibraryBazelTargetModuleProperties(),
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index c6176e6..96e084a 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -241,7 +241,7 @@
testStubModules = append(testStubModules, android.SdkTest.JavaLibraryName(config))
}
// We do not have prebuilts of the core platform api yet
- corePlatformStubModules = append(corePlatformStubModules, "legacy.core.platform.api.stubs")
+ corePlatformStubModules = append(corePlatformStubModules, android.JavaApiLibraryName(config, "legacy.core.platform.api.stubs"))
// Allow products to define their own stubs for custom product jars that apps can use.
publicStubModules = append(publicStubModules, config.ProductHiddenAPIStubs()...)
diff --git a/java/java.go b/java/java.go
index d400b0c..0da7328 100644
--- a/java/java.go
+++ b/java/java.go
@@ -456,7 +456,9 @@
ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
ctx.AddVariationDependencies(nil, sdkLibTag, sdkDep.classpath...)
if d.effectiveOptimizeEnabled() && sdkDep.hasStandardLibs() {
- ctx.AddVariationDependencies(nil, proguardRaiseTag, config.LegacyCorePlatformBootclasspathLibraries...)
+ ctx.AddVariationDependencies(nil, proguardRaiseTag,
+ android.JavaApiLibraryNames(ctx.Config(), config.LegacyCorePlatformBootclasspathLibraries)...,
+ )
}
if d.effectiveOptimizeEnabled() && sdkDep.hasFrameworkLibs() {
ctx.AddVariationDependencies(nil, proguardRaiseTag, config.FrameworkLibraries...)
@@ -2740,9 +2742,11 @@
type javaCommonAttributes struct {
*javaResourcesAttributes
*kotlinAttributes
- Srcs bazel.LabelListAttribute
- Plugins bazel.LabelListAttribute
- Javacopts bazel.StringListAttribute
+ Srcs bazel.LabelListAttribute
+ Plugins bazel.LabelListAttribute
+ Javacopts bazel.StringListAttribute
+ Sdk_version bazel.StringAttribute
+ Java_version bazel.StringAttribute
}
type javaDependencyLabels struct {
@@ -2835,7 +2839,7 @@
return android.IsConvertedToAidlLibrary(ctx, src.OriginalModuleName)
})
- apexAvailableTags := android.ApexAvailableTags(ctx.Module())
+ apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx, ctx.Module())
if !aidlSrcs.IsEmpty() {
aidlLibName := m.Name() + "_aidl_library"
@@ -2873,10 +2877,6 @@
if m.properties.Javacflags != nil {
javacopts = append(javacopts, m.properties.Javacflags...)
}
- if m.properties.Java_version != nil {
- javaVersion := normalizeJavaVersion(ctx, *m.properties.Java_version).String()
- javacopts = append(javacopts, fmt.Sprintf("-source %s -target %s", javaVersion, javaVersion))
- }
epEnabled := m.properties.Errorprone.Enabled
//TODO(b/227504307) add configuration that depends on RUN_ERROR_PRONE environment variable
@@ -2890,7 +2890,9 @@
Plugins: bazel.MakeLabelListAttribute(
android.BazelLabelForModuleDeps(ctx, m.properties.Plugins),
),
- Javacopts: bazel.MakeStringListAttribute(javacopts),
+ Javacopts: bazel.MakeStringListAttribute(javacopts),
+ Java_version: bazel.StringAttribute{Value: m.properties.Java_version},
+ Sdk_version: bazel.StringAttribute{Value: m.deviceProperties.Sdk_version},
}
for axis, configToProps := range archVariantProps {
@@ -2981,19 +2983,9 @@
deps := depLabels.Deps
if !commonAttrs.Srcs.IsEmpty() {
deps.Append(depLabels.StaticDeps) // we should only append these if there are sources to use them
-
- sdkVersion := m.SdkVersion(ctx)
- if sdkVersion.Kind == android.SdkPublic && sdkVersion.ApiLevel == android.FutureApiLevel {
- // TODO(b/220869005) remove forced dependency on current public android.jar
- deps.Add(bazel.MakeLabelAttribute("//prebuilts/sdk:public_current_android_sdk_java_import"))
- } else if sdkVersion.Kind == android.SdkSystem && sdkVersion.ApiLevel == android.FutureApiLevel {
- // TODO(b/215230098) remove forced dependency on current public android.jar
- deps.Add(bazel.MakeLabelAttribute("//prebuilts/sdk:system_current_android_sdk_java_import"))
- }
} else if !deps.IsEmpty() {
ctx.ModuleErrorf("Module has direct dependencies but no sources. Bazel will not allow this.")
}
-
var props bazel.BazelTargetModuleProperties
attrs := &javaLibraryAttributes{
javaCommonAttributes: commonAttrs,
@@ -3013,6 +3005,10 @@
neverLinkAttrs := &javaLibraryAttributes{
Exports: bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + name}),
Neverlink: bazel.BoolAttribute{Value: &neverlinkProp},
+ javaCommonAttributes: &javaCommonAttributes{
+ Sdk_version: bazel.StringAttribute{Value: m.deviceProperties.Sdk_version},
+ Java_version: bazel.StringAttribute{Value: m.properties.Java_version},
+ },
}
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name + "-neverlink"}, neverLinkAttrs)
@@ -3152,6 +3148,9 @@
neverlinkAttrs := &javaLibraryAttributes{
Neverlink: bazel.BoolAttribute{Value: &neverlink},
Exports: bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + name}),
+ javaCommonAttributes: &javaCommonAttributes{
+ Sdk_version: bazel.StringAttribute{Value: proptools.StringPtr("none")},
+ },
}
ctx.CreateBazelTargetModule(
javaLibraryBazelTargetModuleProperties(),
diff --git a/java/legacy_core_platform_api_usage.go b/java/legacy_core_platform_api_usage.go
index 6cb549e..04c6d05 100644
--- a/java/legacy_core_platform_api_usage.go
+++ b/java/legacy_core_platform_api_usage.go
@@ -93,16 +93,16 @@
func corePlatformSystemModules(ctx android.EarlyModuleContext) string {
if useLegacyCorePlatformApi(ctx, ctx.ModuleName()) {
- return config.LegacyCorePlatformSystemModules
+ return android.JavaApiLibraryName(ctx.Config(), config.LegacyCorePlatformSystemModules)
} else {
- return config.StableCorePlatformSystemModules
+ return android.JavaApiLibraryName(ctx.Config(), config.StableCorePlatformSystemModules)
}
}
func corePlatformBootclasspathLibraries(ctx android.EarlyModuleContext) []string {
if useLegacyCorePlatformApi(ctx, ctx.ModuleName()) {
- return config.LegacyCorePlatformBootclasspathLibraries
+ return android.JavaApiLibraryNames(ctx.Config(), config.LegacyCorePlatformBootclasspathLibraries)
} else {
- return config.StableCorePlatformBootclasspathLibraries
+ return android.JavaApiLibraryNames(ctx.Config(), config.StableCorePlatformBootclasspathLibraries)
}
}
diff --git a/java/proto.go b/java/proto.go
index 5280077..c732d98 100644
--- a/java/proto.go
+++ b/java/proto.go
@@ -143,7 +143,9 @@
}
type protoAttributes struct {
- Deps bazel.LabelListAttribute
+ Deps bazel.LabelListAttribute
+ Sdk_version bazel.StringAttribute
+ Java_version bazel.StringAttribute
}
func bp2buildProto(ctx android.Bp2buildMutatorContext, m *Module, protoSrcs bazel.LabelListAttribute) *bazel.Label {
@@ -175,8 +177,11 @@
}
protoLabel := bazel.Label{Label: ":" + m.Name() + "_proto"}
- var protoAttrs protoAttributes
- protoAttrs.Deps.SetValue(bazel.LabelList{Includes: []bazel.Label{protoLabel}})
+ protoAttrs := &protoAttributes{
+ Deps: bazel.MakeSingleLabelListAttribute(protoLabel),
+ Java_version: bazel.StringAttribute{Value: m.properties.Java_version},
+ Sdk_version: bazel.StringAttribute{Value: m.deviceProperties.Sdk_version},
+ }
name := m.Name() + suffix
@@ -186,7 +191,7 @@
Bzl_load_location: "//build/bazel/rules/java:proto.bzl",
},
android.CommonAttributes{Name: name},
- &protoAttrs)
+ protoAttrs)
return &bazel.Label{Label: ":" + name}
}
diff --git a/java/testing.go b/java/testing.go
index 0764d26..f68e12f 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -389,15 +389,16 @@
}
extraApiLibraryModules := map[string]string{
- "android_stubs_current.from-text": "api/current.txt",
- "android_system_stubs_current.from-text": "api/system-current.txt",
- "android_test_stubs_current.from-text": "api/test-current.txt",
- "android_module_lib_stubs_current.from-text": "api/module-lib-current.txt",
- "android_system_server_stubs_current.from-text": "api/system-server-current.txt",
- "core.current.stubs.from-text": "api/current.txt",
- "legacy.core.platform.api.stubs.from-text": "api/current.txt",
- "stable.core.platform.api.stubs.from-text": "api/current.txt",
- "core-lambda-stubs.from-text": "api/current.txt",
+ "android_stubs_current.from-text": "api/current.txt",
+ "android_system_stubs_current.from-text": "api/system-current.txt",
+ "android_test_stubs_current.from-text": "api/test-current.txt",
+ "android_module_lib_stubs_current.from-text": "api/module-lib-current.txt",
+ "android_module_lib_stubs_current_full.from-text": "api/module-lib-current.txt",
+ "android_system_server_stubs_current.from-text": "api/system-server-current.txt",
+ "core.current.stubs.from-text": "api/current.txt",
+ "legacy.core.platform.api.stubs.from-text": "api/current.txt",
+ "stable.core.platform.api.stubs.from-text": "api/current.txt",
+ "core-lambda-stubs.from-text": "api/current.txt",
}
for libName, apiFile := range extraApiLibraryModules {
diff --git a/licenses/Android.bp b/licenses/Android.bp
index 7267cf3..dee72ed 100644
--- a/licenses/Android.bp
+++ b/licenses/Android.bp
@@ -923,7 +923,10 @@
license_kind {
name: "SPDX-license-identifier-Linux-syscall-note",
// expanding visibility requires approval from an OSPO lawyer or pcounsel
- visibility: ["//external/libbpf:__subpackages__"],
+ visibility: [
+ "//external/libbpf:__subpackages__",
+ "//prebuilts/vsdk:__subpackages__",
+ ],
conditions: ["permissive"],
url: "https://spdx.org/licenses/Linux-syscall-note.html",
}
diff --git a/mk2rbc/soong_variables.go b/mk2rbc/soong_variables.go
index a52ec4f..7a6aa5f 100644
--- a/mk2rbc/soong_variables.go
+++ b/mk2rbc/soong_variables.go
@@ -67,7 +67,11 @@
var valueType starlarkType
switch typeString {
case "bool":
- valueType = starlarkTypeBool
+ // TODO: We run into several issues later on if we type this as a bool:
+ // - We still assign bool-typed variables to strings
+ // - When emitting the final results as make code, some bool's false values have to
+ // be an empty string, and some have to be false in order to match the make variables.
+ valueType = starlarkTypeString
case "csv":
// Only PLATFORM_VERSION_ALL_CODENAMES, and it's a list
valueType = starlarkTypeList
diff --git a/python/binary.go b/python/binary.go
index 75135f3..a5db2f6 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -37,7 +37,7 @@
// this file must also be listed in srcs.
// If left unspecified, module name is used instead.
// If name doesn’t match any filename in srcs, main must be specified.
- Main *string `android:"arch_variant"`
+ Main *string
// set the name of the output binary.
Stem *string `android:"arch_variant"`
diff --git a/python/bp2build.go b/python/bp2build.go
index bdac2dc..cd3f2a1 100644
--- a/python/bp2build.go
+++ b/python/bp2build.go
@@ -15,7 +15,6 @@
package python
import (
- "fmt"
"path/filepath"
"strings"
@@ -118,42 +117,19 @@
return attrs
}
-func pythonLibBp2Build(ctx android.TopDownMutatorContext, m *PythonLibraryModule) {
- // TODO(b/182306917): this doesn't fully handle all nested props versioned
- // by the python version, which would have been handled by the version split
- // mutator. This is sufficient for very simple python_library modules under
- // Bionic.
+func (m *PythonLibraryModule) bp2buildPythonVersion(ctx android.TopDownMutatorContext) *string {
py3Enabled := proptools.BoolDefault(m.properties.Version.Py3.Enabled, true)
py2Enabled := proptools.BoolDefault(m.properties.Version.Py2.Enabled, false)
- var python_version *string
if py2Enabled && !py3Enabled {
- python_version = &pyVersion2
+ return &pyVersion2
} else if !py2Enabled && py3Enabled {
- python_version = &pyVersion3
+ return &pyVersion3
} else if !py2Enabled && !py3Enabled {
ctx.ModuleErrorf("bp2build converter doesn't understand having neither py2 nor py3 enabled")
+ return &pyVersion3
} else {
- // do nothing, since python_version defaults to PY2ANDPY3
+ return &pyVersion2And3
}
-
- baseAttrs := m.makeArchVariantBaseAttributes(ctx)
-
- attrs := &bazelPythonLibraryAttributes{
- Srcs: baseAttrs.Srcs,
- Deps: baseAttrs.Deps,
- Srcs_version: python_version,
- Imports: baseAttrs.Imports,
- }
-
- props := bazel.BazelTargetModuleProperties{
- // Use the native py_library rule.
- Rule_class: "py_library",
- }
-
- ctx.CreateBazelTargetModule(props, android.CommonAttributes{
- Name: m.Name(),
- Data: baseAttrs.Data,
- }, attrs)
}
type bazelPythonBinaryAttributes struct {
@@ -164,43 +140,71 @@
Imports bazel.StringListAttribute
}
-func pythonBinaryBp2Build(ctx android.TopDownMutatorContext, m *PythonBinaryModule) {
+func (p *PythonLibraryModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ // TODO(b/182306917): this doesn't fully handle all nested props versioned
+ // by the python version, which would have been handled by the version split
+ // mutator. This is sufficient for very simple python_library modules under
+ // Bionic.
+ baseAttrs := p.makeArchVariantBaseAttributes(ctx)
+ pyVersion := p.bp2buildPythonVersion(ctx)
+ if *pyVersion == pyVersion2And3 {
+ // Libraries default to python 2 and 3
+ pyVersion = nil
+ }
+
+ attrs := &bazelPythonLibraryAttributes{
+ Srcs: baseAttrs.Srcs,
+ Deps: baseAttrs.Deps,
+ Srcs_version: pyVersion,
+ Imports: baseAttrs.Imports,
+ }
+
+ props := bazel.BazelTargetModuleProperties{
+ // Use the native py_library rule.
+ Rule_class: "py_library",
+ }
+
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{
+ Name: p.Name(),
+ Data: baseAttrs.Data,
+ }, attrs)
+}
+
+func (p *PythonBinaryModule) bp2buildBinaryProperties(ctx android.TopDownMutatorContext) (*bazelPythonBinaryAttributes, bazel.LabelListAttribute) {
// TODO(b/182306917): this doesn't fully handle all nested props versioned
// by the python version, which would have been handled by the version split
// mutator. This is sufficient for very simple python_binary_host modules
// under Bionic.
- py3Enabled := proptools.BoolDefault(m.properties.Version.Py3.Enabled, false)
- py2Enabled := proptools.BoolDefault(m.properties.Version.Py2.Enabled, false)
- var python_version *string
- if py3Enabled && py2Enabled {
- panic(fmt.Errorf(
- "error for '%s' module: bp2build's python_binary_host converter does not support "+
- "converting a module that is enabled for both Python 2 and 3 at the same time.", m.Name()))
- } else if py2Enabled {
- python_version = &pyVersion2
- } else {
- // do nothing, since python_version defaults to PY3.
+
+ baseAttrs := p.makeArchVariantBaseAttributes(ctx)
+ pyVersion := p.bp2buildPythonVersion(ctx)
+ if *pyVersion == pyVersion3 {
+ // Binaries default to python 3
+ pyVersion = nil
+ } else if *pyVersion == pyVersion2And3 {
+ ctx.ModuleErrorf("error for '%s' module: bp2build's python_binary_host converter "+
+ "does not support converting a module that is enabled for both Python 2 and 3 at the "+
+ "same time.", p.Name())
}
- baseAttrs := m.makeArchVariantBaseAttributes(ctx)
attrs := &bazelPythonBinaryAttributes{
Main: nil,
Srcs: baseAttrs.Srcs,
Deps: baseAttrs.Deps,
- Python_version: python_version,
+ Python_version: pyVersion,
Imports: baseAttrs.Imports,
}
- for _, propIntf := range m.GetProperties() {
- if props, ok := propIntf.(*BinaryProperties); ok {
- // main is optional.
- if props.Main != nil {
- main := android.BazelLabelForModuleSrcSingle(ctx, *props.Main)
- attrs.Main = &main
- break
- }
- }
+ // main is optional.
+ if p.binaryProperties.Main != nil {
+ main := android.BazelLabelForModuleSrcSingle(ctx, *p.binaryProperties.Main)
+ attrs.Main = &main
}
+ return attrs, baseAttrs.Data
+}
+
+func (p *PythonBinaryModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ attrs, data := p.bp2buildBinaryProperties(ctx)
props := bazel.BazelTargetModuleProperties{
// Use the native py_binary rule.
@@ -208,19 +212,22 @@
}
ctx.CreateBazelTargetModule(props, android.CommonAttributes{
- Name: m.Name(),
- Data: baseAttrs.Data,
+ Name: p.Name(),
+ Data: data,
}, attrs)
}
-func (p *PythonLibraryModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
- pythonLibBp2Build(ctx, p)
-}
+func (p *PythonTestModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ // Python tests are currently exactly the same as binaries, but with a different module type
+ attrs, data := p.bp2buildBinaryProperties(ctx)
-func (p *PythonBinaryModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
- pythonBinaryBp2Build(ctx, p)
-}
+ props := bazel.BazelTargetModuleProperties{
+ // Use the native py_binary rule.
+ Rule_class: "py_test",
+ }
-func (p *PythonTestModule) ConvertWithBp2build(_ android.TopDownMutatorContext) {
- // Tests are currently unsupported
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{
+ Name: p.Name(),
+ Data: data,
+ }, attrs)
}
diff --git a/python/python.go b/python/python.go
index c7c523d..1a12973 100644
--- a/python/python.go
+++ b/python/python.go
@@ -239,6 +239,7 @@
protoExt = ".proto"
pyVersion2 = "PY2"
pyVersion3 = "PY3"
+ pyVersion2And3 = "PY2ANDPY3"
internalPath = "internal"
)
diff --git a/rust/binary.go b/rust/binary.go
index 056888e..2de92c1 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -72,11 +72,14 @@
func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
flags = binary.baseCompiler.compilerFlags(ctx, flags)
+ if ctx.Os().Linux() {
+ flags.LinkFlags = append(flags.LinkFlags, "-Wl,--gc-sections")
+ }
+
if ctx.toolchain().Bionic() {
// no-undefined-version breaks dylib compilation since __rust_*alloc* functions aren't defined,
// but we can apply this to binaries.
flags.LinkFlags = append(flags.LinkFlags,
- "-Wl,--gc-sections",
"-Wl,-z,nocopyreloc",
"-Wl,--no-undefined-version")
@@ -136,7 +139,7 @@
flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
- flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
+ flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects.Strings()...)
if binary.stripper.NeedsStrip(ctx) {
strippedOutputFile := outputFile
diff --git a/rust/binary_test.go b/rust/binary_test.go
index 7dac249..dd4f993 100644
--- a/rust/binary_test.go
+++ b/rust/binary_test.go
@@ -123,7 +123,7 @@
bootstrap: true,
}`)
- foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc")
+ foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustLink")
flag := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker64"
if !strings.Contains(foo.Args["linkFlags"], flag) {
@@ -140,10 +140,11 @@
}`)
fizzOut := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc")
+ fizzOutLink := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustLink")
fizzMod := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module)
flags := fizzOut.Args["rustcFlags"]
- linkFlags := fizzOut.Args["linkFlags"]
+ linkFlags := fizzOutLink.Args["linkFlags"]
if !strings.Contains(flags, "-C relocation-model=static") {
t.Errorf("static binary missing '-C relocation-model=static' in rustcFlags, found: %#v", flags)
}
@@ -173,7 +174,7 @@
name: "libfoo",
}`)
- fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Rule("rustc")
+ fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Rule("rustLink")
linkFlags := fizzBuzz.Args["linkFlags"]
if !strings.Contains(linkFlags, "/libfoo.so") {
t.Errorf("missing shared dependency 'libfoo.so' in linkFlags: %#v", linkFlags)
diff --git a/rust/builder.go b/rust/builder.go
index 0aef13d..0aa2225 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -26,14 +26,14 @@
var (
_ = pctx.SourcePathVariable("rustcCmd", "${config.RustBin}/rustc")
+ _ = pctx.SourcePathVariable("mkcraterspCmd", "build/soong/scripts/mkcratersp.py")
rustc = pctx.AndroidStaticRule("rustc",
blueprint.RuleParams{
Command: "$envVars $rustcCmd " +
- "-C linker=${config.RustLinker} " +
- "-C link-args=\"${crtBegin} ${config.RustLinkerArgs} ${linkFlags} ${crtEnd}\" " +
+ "-C linker=$mkcraterspCmd " +
"--emit link -o $out --emit dep-info=$out.d.raw $in ${libFlags} $rustcFlags" +
" && grep \"^$out:\" $out.d.raw > $out.d",
- CommandDeps: []string{"$rustcCmd"},
+ CommandDeps: []string{"$rustcCmd", "$mkcraterspCmd"},
// Rustc deps-info writes out make compatible dep files: https://github.com/rust-lang/rust/issues/7633
// Rustc emits unneeded dependency lines for the .d and input .rs files.
// Those extra lines cause ninja warning:
@@ -42,7 +42,12 @@
Deps: blueprint.DepsGCC,
Depfile: "$out.d",
},
- "rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd", "envVars")
+ "rustcFlags", "libFlags", "envVars")
+ rustLink = pctx.AndroidStaticRule("rustLink",
+ blueprint.RuleParams{
+ Command: "${config.RustLinker} -o $out ${crtBegin} ${config.RustLinkerArgs} @$in ${linkFlags} ${crtEnd}",
+ },
+ "linkFlags", "crtBegin", "crtEnd")
_ = pctx.SourcePathVariable("rustdocCmd", "${config.RustBin}/rustdoc")
rustdoc = pctx.AndroidStaticRule("rustdoc",
@@ -101,14 +106,13 @@
`KYTHE_CANONICALIZE_VNAME_PATHS=prefer-relative ` +
`$rustExtractor $envVars ` +
`$rustcCmd ` +
- `-C linker=${config.RustLinker} ` +
- `-C link-args="${crtBegin} ${config.RustLinkerArgs} ${linkFlags} ${crtEnd}" ` +
+ `-C linker=true ` +
`$in ${libFlags} $rustcFlags`,
CommandDeps: []string{"$rustExtractor", "$kytheVnames"},
Rspfile: "${out}.rsp",
RspfileContent: "$in",
},
- "rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd", "envVars")
+ "rustcFlags", "libFlags", "envVars")
)
type buildOutput struct {
@@ -220,11 +224,9 @@
outputFile android.WritablePath, crateType string) buildOutput {
var inputs android.Paths
- var implicits android.Paths
- var orderOnly android.Paths
+ var implicits, linkImplicits, linkOrderOnly android.Paths
var output buildOutput
var rustcFlags, linkFlags []string
- var implicitOutputs android.WritablePaths
output.outputFile = outputFile
crateName := ctx.RustModule().CrateName()
@@ -281,15 +283,15 @@
implicits = append(implicits, rustLibsToPaths(deps.RLibs)...)
implicits = append(implicits, rustLibsToPaths(deps.DyLibs)...)
implicits = append(implicits, rustLibsToPaths(deps.ProcMacros)...)
- implicits = append(implicits, deps.StaticLibs...)
- implicits = append(implicits, deps.SharedLibDeps...)
- implicits = append(implicits, deps.srcProviderFiles...)
implicits = append(implicits, deps.AfdoProfiles...)
+ implicits = append(implicits, deps.srcProviderFiles...)
+ implicits = append(implicits, deps.WholeStaticLibs...)
- implicits = append(implicits, deps.CrtBegin...)
- implicits = append(implicits, deps.CrtEnd...)
+ linkImplicits = append(linkImplicits, deps.LibDeps...)
+ linkImplicits = append(linkImplicits, deps.CrtBegin...)
+ linkImplicits = append(linkImplicits, deps.CrtEnd...)
- orderOnly = append(orderOnly, deps.SharedLibs...)
+ linkOrderOnly = append(linkOrderOnly, deps.linkObjects...)
if len(deps.SrcDeps) > 0 {
moduleGenDir := ctx.RustModule().compiler.CargoOutDir()
@@ -328,16 +330,16 @@
}
}
+ envVars = append(envVars, "AR=${cc_config.ClangBin}/llvm-ar")
+
if flags.Clippy {
clippyFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy")
ctx.Build(pctx, android.BuildParams{
- Rule: clippyDriver,
- Description: "clippy " + main.Rel(),
- Output: clippyFile,
- ImplicitOutputs: nil,
- Inputs: inputs,
- Implicits: implicits,
- OrderOnly: orderOnly,
+ Rule: clippyDriver,
+ Description: "clippy " + main.Rel(),
+ Output: clippyFile,
+ Inputs: inputs,
+ Implicits: implicits,
Args: map[string]string{
"rustcFlags": strings.Join(rustcFlags, " "),
"libFlags": strings.Join(libFlags, " "),
@@ -349,24 +351,41 @@
implicits = append(implicits, clippyFile)
}
+ rustcOutputFile := outputFile
+ usesLinker := crateType == "bin" || crateType == "dylib" || crateType == "cdylib" || crateType == "proc-macro"
+ if usesLinker {
+ rustcOutputFile = android.PathForModuleOut(ctx, outputFile.Base()+".rsp")
+ }
+
ctx.Build(pctx, android.BuildParams{
- Rule: rustc,
- Description: "rustc " + main.Rel(),
- Output: outputFile,
- ImplicitOutputs: implicitOutputs,
- Inputs: inputs,
- Implicits: implicits,
- OrderOnly: orderOnly,
+ Rule: rustc,
+ Description: "rustc " + main.Rel(),
+ Output: rustcOutputFile,
+ Inputs: inputs,
+ Implicits: implicits,
Args: map[string]string{
"rustcFlags": strings.Join(rustcFlags, " "),
- "linkFlags": strings.Join(linkFlags, " "),
"libFlags": strings.Join(libFlags, " "),
- "crtBegin": strings.Join(deps.CrtBegin.Strings(), " "),
- "crtEnd": strings.Join(deps.CrtEnd.Strings(), " "),
"envVars": strings.Join(envVars, " "),
},
})
+ if usesLinker {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: rustLink,
+ Description: "rustLink " + main.Rel(),
+ Output: outputFile,
+ Inputs: android.Paths{rustcOutputFile},
+ Implicits: linkImplicits,
+ OrderOnly: linkOrderOnly,
+ Args: map[string]string{
+ "linkFlags": strings.Join(linkFlags, " "),
+ "crtBegin": strings.Join(deps.CrtBegin.Strings(), " "),
+ "crtEnd": strings.Join(deps.CrtEnd.Strings(), " "),
+ },
+ })
+ }
+
if flags.EmitXrefs {
kytheFile := android.PathForModuleOut(ctx, outputFile.Base()+".kzip")
ctx.Build(pctx, android.BuildParams{
@@ -375,13 +394,9 @@
Output: kytheFile,
Inputs: inputs,
Implicits: implicits,
- OrderOnly: orderOnly,
Args: map[string]string{
"rustcFlags": strings.Join(rustcFlags, " "),
- "linkFlags": strings.Join(linkFlags, " "),
"libFlags": strings.Join(libFlags, " "),
- "crtBegin": strings.Join(deps.CrtBegin.Strings(), " "),
- "crtEnd": strings.Join(deps.CrtEnd.Strings(), " "),
"envVars": strings.Join(envVars, " "),
},
})
diff --git a/rust/config/global.go b/rust/config/global.go
index 8894938..2d1f0c1 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -104,7 +104,7 @@
pctx.ImportAs("cc_config", "android/soong/cc/config")
pctx.StaticVariable("RustLinker", "${cc_config.ClangBin}/clang++")
- pctx.StaticVariable("RustLinkerArgs", "")
+ pctx.StaticVariable("RustLinkerArgs", "-Wl,--as-needed")
pctx.StaticVariable("DeviceGlobalLinkFlags", strings.Join(deviceGlobalLinkFlags, " "))
diff --git a/rust/coverage.go b/rust/coverage.go
index bc6504d..5216d60 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -65,7 +65,7 @@
"-C instrument-coverage", "-g")
flags.LinkFlags = append(flags.LinkFlags,
profileInstrFlag, "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,open")
- deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile().Path())
+ deps.LibDeps = append(deps.LibDeps, coverage.OutputFile().Path())
// no_std modules are missing libprofiler_builtins which provides coverage, so we need to add it as a dependency.
if rustModule, ok := ctx.Module().(*Module); ok && rustModule.compiler.noStdlibs() {
diff --git a/rust/coverage_test.go b/rust/coverage_test.go
index 0f599d7..64077cf 100644
--- a/rust/coverage_test.go
+++ b/rust/coverage_test.go
@@ -55,6 +55,10 @@
libbarNoCov := ctx.ModuleForTests("libbar_nocov", "android_arm64_armv8-a_dylib").Rule("rustc")
fizzCov := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc")
buzzNoCov := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc")
+ libfooCovLink := ctx.ModuleForTests("libfoo_cov", "android_arm64_armv8-a_dylib_cov").Rule("rustLink")
+ libbarNoCovLink := ctx.ModuleForTests("libbar_nocov", "android_arm64_armv8-a_dylib").Rule("rustLink")
+ fizzCovLink := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustLink")
+ buzzNoCovLink := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustLink")
rustcCoverageFlags := []string{"-C instrument-coverage", " -g "}
for _, flag := range rustcCoverageFlags {
@@ -80,17 +84,17 @@
missingErrorStr := "missing rust linker flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v"
containsErrorStr := "contains rust linker flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v"
- if !strings.Contains(fizzCov.Args["linkFlags"], flag) {
- t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCov.Args["linkFlags"])
+ if !strings.Contains(fizzCovLink.Args["linkFlags"], flag) {
+ t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCovLink.Args["linkFlags"])
}
- if !strings.Contains(libfooCov.Args["linkFlags"], flag) {
- t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCov.Args["linkFlags"])
+ if !strings.Contains(libfooCovLink.Args["linkFlags"], flag) {
+ t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCovLink.Args["linkFlags"])
}
- if strings.Contains(buzzNoCov.Args["linkFlags"], flag) {
- t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCov.Args["linkFlags"])
+ if strings.Contains(buzzNoCovLink.Args["linkFlags"], flag) {
+ t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCovLink.Args["linkFlags"])
}
- if strings.Contains(libbarNoCov.Args["linkFlags"], flag) {
- t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCov.Args["linkFlags"])
+ if strings.Contains(libbarNoCovLink.Args["linkFlags"], flag) {
+ t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCovLink.Args["linkFlags"])
}
}
@@ -103,7 +107,7 @@
srcs: ["foo.rs"],
}`)
- fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("rustc")
+ fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("rustLink")
if !strings.Contains(fizz.Args["linkFlags"], "libprofile-clang-extras.a") {
t.Fatalf("missing expected coverage 'libprofile-clang-extras' dependency in linkFlags: %#v", fizz.Args["linkFlags"])
}
diff --git a/rust/library.go b/rust/library.go
index bc9c9aa..a3a5672 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -520,7 +520,7 @@
flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
- flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
+ flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects.Strings()...)
if library.dylib() {
// We need prefer-dynamic for now to avoid linking in the static stdlib. See:
@@ -543,6 +543,7 @@
if library.rlib() || library.dylib() {
library.flagExporter.exportLinkDirs(deps.linkDirs...)
library.flagExporter.exportLinkObjects(deps.linkObjects...)
+ library.flagExporter.exportLibDeps(deps.LibDeps...)
}
if library.static() || library.shared() {
diff --git a/rust/library_test.go b/rust/library_test.go
index e3e4d0f..d4b525f 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -148,7 +148,7 @@
libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared")
- libfooOutput := libfoo.Rule("rustc")
+ libfooOutput := libfoo.Rule("rustLink")
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"])
diff --git a/rust/protobuf.go b/rust/protobuf.go
index e30f25d..0cf6e8c 100644
--- a/rust/protobuf.go
+++ b/rust/protobuf.go
@@ -52,6 +52,10 @@
// List of libraries which export include paths required for this module
Header_libs []string `android:"arch_variant,variant_prepend"`
+
+ // Use protobuf version 3.x. This will be deleted once we migrate all current users
+ // of protobuf off of 2.x.
+ Use_protobuf3 *bool
}
type protobufDecorator struct {
@@ -65,6 +69,10 @@
protoFlags android.ProtoFlags
}
+func (proto *protobufDecorator) useProtobuf3() bool {
+ return Bool(proto.Properties.Use_protobuf3)
+}
+
func (proto *protobufDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path {
var protoFlags android.ProtoFlags
var grpcProtoFlags android.ProtoFlags
@@ -73,7 +81,13 @@
outDir := android.PathForModuleOut(ctx)
protoFiles := android.PathsForModuleSrc(ctx, proto.Properties.Protos)
grpcFiles := android.PathsForModuleSrc(ctx, proto.Properties.Grpc_protos)
+
+ // For now protobuf2 (the deprecated version) remains the default. This will change in the
+ // future as we update the various users.
protoPluginPath := ctx.Config().HostToolPath(ctx, "protoc-gen-rust-deprecated")
+ if proto.useProtobuf3() == true {
+ protoPluginPath = ctx.Config().HostToolPath(ctx, "protoc-gen-rust")
+ }
commonProtoFlags = append(commonProtoFlags, defaultProtobufFlags...)
commonProtoFlags = append(commonProtoFlags, proto.Properties.Proto_flags...)
@@ -206,10 +220,20 @@
func (proto *protobufDecorator) SourceProviderDeps(ctx DepsContext, deps Deps) Deps {
deps = proto.BaseSourceProvider.SourceProviderDeps(ctx, deps)
- deps.Rustlibs = append(deps.Rustlibs, "libprotobuf_deprecated")
+ useProtobuf3 := proto.useProtobuf3()
+ if useProtobuf3 == true {
+ deps.Rustlibs = append(deps.Rustlibs, "libprotobuf")
+ } else {
+ deps.Rustlibs = append(deps.Rustlibs, "libprotobuf_deprecated")
+ }
deps.HeaderLibs = append(deps.SharedLibs, proto.Properties.Header_libs...)
if len(proto.Properties.Grpc_protos) > 0 {
+ if useProtobuf3 == true {
+ ctx.PropertyErrorf("protos", "rust_protobuf with grpc_protos defined must currently use "+
+ "`use_protobuf3: false,` in the Android.bp file. This is temporary until the "+
+ "grpcio crate is updated to use the current version of the protobuf crate.")
+ }
deps.Rustlibs = append(deps.Rustlibs, "libgrpcio", "libfutures")
deps.HeaderLibs = append(deps.HeaderLibs, "libprotobuf-cpp-full")
}
diff --git a/rust/protobuf_test.go b/rust/protobuf_test.go
index 0aa4549..b723f3f 100644
--- a/rust/protobuf_test.go
+++ b/rust/protobuf_test.go
@@ -69,6 +69,55 @@
}
}
+func TestRustProtobuf3(t *testing.T) {
+ ctx := testRust(t, `
+ rust_protobuf {
+ name: "librust_proto",
+ protos: ["buf.proto", "proto.proto"],
+ crate_name: "rust_proto",
+ source_stem: "buf",
+ use_protobuf3: true,
+ shared_libs: ["libfoo_shared"],
+ static_libs: ["libfoo_static"],
+ }
+ cc_library_shared {
+ name: "libfoo_shared",
+ export_include_dirs: ["shared_include"],
+ }
+ cc_library_static {
+ name: "libfoo_static",
+ export_include_dirs: ["static_include"],
+ }
+ `)
+ // Check that libprotobuf is added as a dependency.
+ librust_proto := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_dylib").Module().(*Module)
+ if !android.InList("libprotobuf", librust_proto.Properties.AndroidMkDylibs) {
+ t.Errorf("libprotobuf dependency missing for rust_protobuf (dependency missing from AndroidMkDylibs)")
+ }
+
+ // Make sure the correct plugin is being used.
+ librust_proto_out := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").Output("buf.rs")
+ cmd := librust_proto_out.RuleParams.Command
+ if w := "protoc-gen-rust"; !strings.Contains(cmd, w) {
+ t.Errorf("expected %q in %q", w, cmd)
+ }
+
+ // Check exported include directories
+ if w := "-Ishared_include"; !strings.Contains(cmd, w) {
+ t.Errorf("expected %q in %q", w, cmd)
+ }
+ if w := "-Istatic_include"; !strings.Contains(cmd, w) {
+ t.Errorf("expected %q in %q", w, cmd)
+ }
+
+ // Check proto.rs, the second protobuf, is listed as an output
+ librust_proto_outputs := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").AllOutputs()
+ if android.InList("proto.rs", librust_proto_outputs) {
+ t.Errorf("rust_protobuf is not producing multiple outputs; expected 'proto.rs' in list, got: %#v ",
+ librust_proto_outputs)
+ }
+}
+
func TestRustGrpc(t *testing.T) {
ctx := testRust(t, `
rust_protobuf {
diff --git a/rust/rust.go b/rust/rust.go
index 56b4631..7b520cd 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -420,13 +420,12 @@
}
type PathDeps struct {
- DyLibs RustLibraries
- RLibs RustLibraries
- SharedLibs android.Paths
- SharedLibDeps android.Paths
- StaticLibs android.Paths
- ProcMacros RustLibraries
- AfdoProfiles android.Paths
+ DyLibs RustLibraries
+ RLibs RustLibraries
+ LibDeps android.Paths
+ WholeStaticLibs android.Paths
+ ProcMacros RustLibraries
+ AfdoProfiles android.Paths
// depFlags and depLinkFlags are rustc and linker (clang) flags.
depFlags []string
@@ -435,7 +434,7 @@
// linkDirs are link paths passed via -L to rustc. linkObjects are objects passed directly to the linker.
// Both of these are exported and propagate to dependencies.
linkDirs []string
- linkObjects []string
+ linkObjects android.Paths
// Used by bindgen modules which call clang
depClangFlags []string
@@ -498,7 +497,7 @@
type exportedFlagsProducer interface {
exportLinkDirs(...string)
- exportLinkObjects(...string)
+ exportLinkObjects(...android.Path)
}
type xref interface {
@@ -507,21 +506,27 @@
type flagExporter struct {
linkDirs []string
- linkObjects []string
+ linkObjects android.Paths
+ libDeps android.Paths
}
func (flagExporter *flagExporter) exportLinkDirs(dirs ...string) {
flagExporter.linkDirs = android.FirstUniqueStrings(append(flagExporter.linkDirs, dirs...))
}
-func (flagExporter *flagExporter) exportLinkObjects(flags ...string) {
- flagExporter.linkObjects = android.FirstUniqueStrings(append(flagExporter.linkObjects, flags...))
+func (flagExporter *flagExporter) exportLinkObjects(flags ...android.Path) {
+ flagExporter.linkObjects = android.FirstUniquePaths(append(flagExporter.linkObjects, flags...))
+}
+
+func (flagExporter *flagExporter) exportLibDeps(paths ...android.Path) {
+ flagExporter.libDeps = android.FirstUniquePaths(append(flagExporter.libDeps, paths...))
}
func (flagExporter *flagExporter) setProvider(ctx ModuleContext) {
ctx.SetProvider(FlagExporterInfoProvider, FlagExporterInfo{
LinkDirs: flagExporter.linkDirs,
LinkObjects: flagExporter.linkObjects,
+ LibDeps: flagExporter.libDeps,
})
}
@@ -534,7 +539,8 @@
type FlagExporterInfo struct {
Flags []string
LinkDirs []string // TODO: this should be android.Paths
- LinkObjects []string // TODO: this should be android.Paths
+ LinkObjects android.Paths
+ LibDeps android.Paths
}
var FlagExporterInfoProvider = blueprint.NewProvider(FlagExporterInfo{})
@@ -1250,6 +1256,7 @@
depPaths.linkDirs = append(depPaths.linkDirs, exportedInfo.LinkDirs...)
depPaths.depFlags = append(depPaths.depFlags, exportedInfo.Flags...)
depPaths.linkObjects = append(depPaths.linkObjects, exportedInfo.LinkObjects...)
+ depPaths.LibDeps = append(depPaths.LibDeps, exportedInfo.LibDeps...)
}
if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
@@ -1293,6 +1300,7 @@
depPaths.depLinkFlags = append(depPaths.depLinkFlags, []string{"-Wl,--whole-archive", linkObject.Path().String(), "-Wl,--no-whole-archive"}...)
} else if libName, ok := libNameFromFilePath(linkObject.Path()); ok {
depPaths.depFlags = append(depPaths.depFlags, "-lstatic="+libName)
+ depPaths.WholeStaticLibs = append(depPaths.WholeStaticLibs, linkObject.Path())
} else {
ctx.ModuleErrorf("'%q' cannot be listed as a whole_static_library in Rust modules unless the output is prefixed by 'lib'", depName, ctx.ModuleName())
}
@@ -1300,7 +1308,7 @@
// Add this to linkObjects to pass the library directly to the linker as well. This propagates
// to dependencies to avoid having to redeclare static libraries for dependents of the dylib variant.
- depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String())
+ depPaths.linkObjects = append(depPaths.linkObjects, linkObject.AsPaths()...)
depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
exportedInfo := ctx.OtherModuleProvider(dep, cc.FlagExporterInfoProvider).(cc.FlagExporterInfo)
@@ -1326,7 +1334,7 @@
linkPath = linkPathFromFilePath(linkObject.Path())
depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
- depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String())
+ depPaths.linkObjects = append(depPaths.linkObjects, linkObject.AsPaths()...)
depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...)
depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, exportedInfo.SystemIncludeDirs...)
depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...)
@@ -1352,7 +1360,9 @@
// Make sure these dependencies are propagated
if lib, ok := mod.compiler.(exportedFlagsProducer); ok && exportDep {
lib.exportLinkDirs(linkPath)
- lib.exportLinkObjects(linkObject.String())
+ if linkObject.Valid() {
+ lib.exportLinkObjects(linkObject.Path())
+ }
}
} else {
switch {
@@ -1384,19 +1394,16 @@
procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
}
- var staticLibDepFiles android.Paths
+ var libDepFiles android.Paths
for _, dep := range directStaticLibDeps {
- staticLibDepFiles = append(staticLibDepFiles, dep.OutputFile().Path())
+ libDepFiles = append(libDepFiles, dep.OutputFile().Path())
}
- var sharedLibFiles android.Paths
- var sharedLibDepFiles android.Paths
for _, dep := range directSharedLibDeps {
- sharedLibFiles = append(sharedLibFiles, dep.SharedLibrary)
if dep.TableOfContents.Valid() {
- sharedLibDepFiles = append(sharedLibDepFiles, dep.TableOfContents.Path())
+ libDepFiles = append(libDepFiles, dep.TableOfContents.Path())
} else {
- sharedLibDepFiles = append(sharedLibDepFiles, dep.SharedLibrary)
+ libDepFiles = append(libDepFiles, dep.SharedLibrary)
}
}
@@ -1412,15 +1419,13 @@
depPaths.RLibs = append(depPaths.RLibs, rlibDepFiles...)
depPaths.DyLibs = append(depPaths.DyLibs, dylibDepFiles...)
- depPaths.SharedLibs = append(depPaths.SharedLibs, sharedLibFiles...)
- depPaths.SharedLibDeps = append(depPaths.SharedLibDeps, sharedLibDepFiles...)
- depPaths.StaticLibs = append(depPaths.StaticLibs, staticLibDepFiles...)
+ depPaths.LibDeps = append(depPaths.LibDeps, libDepFiles...)
depPaths.ProcMacros = append(depPaths.ProcMacros, procMacroDepFiles...)
depPaths.SrcDeps = append(depPaths.SrcDeps, srcProviderDepFiles...)
// Dedup exported flags from dependencies
depPaths.linkDirs = android.FirstUniqueStrings(depPaths.linkDirs)
- depPaths.linkObjects = android.FirstUniqueStrings(depPaths.linkObjects)
+ depPaths.linkObjects = android.FirstUniquePaths(depPaths.linkObjects)
depPaths.depFlags = android.FirstUniqueStrings(depPaths.depFlags)
depPaths.depClangFlags = android.FirstUniqueStrings(depPaths.depClangFlags)
depPaths.depIncludePaths = android.FirstUniquePaths(depPaths.depIncludePaths)
diff --git a/rust/rust_test.go b/rust/rust_test.go
index e8e5800..2a38b89 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -258,6 +258,7 @@
`)
module := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
rustc := ctx.ModuleForTests("librlib", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc")
+ rustLink := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustLink")
// Since dependencies are added to AndroidMk* properties, we can check these to see if they've been picked up.
if !android.InList("libdylib", module.Properties.AndroidMkDylibs) {
@@ -284,16 +285,16 @@
t.Errorf("-lstatic flag not being passed to rustc for static library %#v", rustc.Args["rustcFlags"])
}
- if !strings.Contains(rustc.Args["linkFlags"], "cc_stubs_dep.so") {
- t.Errorf("shared cc_library not being passed to rustc linkFlags %#v", rustc.Args["linkFlags"])
+ if !strings.Contains(rustLink.Args["linkFlags"], "cc_stubs_dep.so") {
+ t.Errorf("shared cc_library not being passed to rustc linkFlags %#v", rustLink.Args["linkFlags"])
}
- if !android.SuffixInList(rustc.OrderOnly.Strings(), "cc_stubs_dep.so") {
- t.Errorf("shared cc dep not being passed as order-only to rustc %#v", rustc.OrderOnly.Strings())
+ if !android.SuffixInList(rustLink.OrderOnly.Strings(), "cc_stubs_dep.so") {
+ t.Errorf("shared cc dep not being passed as order-only to rustc %#v", rustLink.OrderOnly.Strings())
}
- if !android.SuffixInList(rustc.Implicits.Strings(), "cc_stubs_dep.so.toc") {
- t.Errorf("shared cc dep TOC not being passed as implicit to rustc %#v", rustc.Implicits.Strings())
+ if !android.SuffixInList(rustLink.Implicits.Strings(), "cc_stubs_dep.so.toc") {
+ t.Errorf("shared cc dep TOC not being passed as implicit to rustc %#v", rustLink.Implicits.Strings())
}
}
diff --git a/rust/sanitize_test.go b/rust/sanitize_test.go
index d6a14b2..43e95f4 100644
--- a/rust/sanitize_test.go
+++ b/rust/sanitize_test.go
@@ -35,7 +35,7 @@
note_sync := "note_memtag_heap_sync"
found := None
- implicits := m.Rule("rustc").Implicits
+ implicits := m.Rule("rustLink").Implicits
for _, lib := range implicits {
if strings.Contains(lib.Rel(), note_async) {
found = Async
diff --git a/rust/testing.go b/rust/testing.go
index a33d948..0a6a870 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -127,6 +127,12 @@
min_sdk_version: "29",
}
rust_library {
+ name: "libprotobuf",
+ crate_name: "protobuf",
+ srcs: ["foo.rs"],
+ host_supported: true,
+ }
+ rust_library {
name: "libprotobuf_deprecated",
crate_name: "protobuf",
srcs: ["foo.rs"],
diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go
index e1b3c86..2e7a330 100644
--- a/rust/vendor_snapshot_test.go
+++ b/rust/vendor_snapshot_test.go
@@ -941,7 +941,7 @@
ctx := testRustVndkFsVersions(t, "", mockFS, "30", "current", "31")
// libclient uses libvndk.vndk.30.arm64, libvendor.vendor_static.30.arm64, libvendor_without_snapshot
- libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("rustc").Args["linkFlags"]
+ libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("rustLink").Args["linkFlags"]
for _, input := range [][]string{
[]string{sharedVariant, "libvndk.vndk.30.arm64"},
[]string{staticVariant, "libvendor.vendor_static.30.arm64"},
@@ -997,7 +997,7 @@
t.Errorf("Unexpected rust rlib name in AndroidMk: %q, expected: %q\n", rustVendorBinMkRlibName, expectedRustVendorSnapshotName)
}
- binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("rustc").Args["linkFlags"]
+ binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("rustLink").Args["linkFlags"]
libVndkStaticOutputPaths := cc.GetOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.30.arm64"})
if !strings.Contains(binWithoutSnapshotLdFlags, libVndkStaticOutputPaths[0].String()) {
t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v",
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 26fe432..9367ff0 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -189,6 +189,7 @@
libs: [
"linker_config_proto",
],
+ visibility: ["//system/linkerconfig"],
}
python_test_host {
diff --git a/scripts/mkcratersp.py b/scripts/mkcratersp.py
new file mode 100755
index 0000000..86b4aa3
--- /dev/null
+++ b/scripts/mkcratersp.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 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.
+#
+
+"""
+This script is used as a replacement for the Rust linker. It converts a linker
+command line into a rspfile that can be used during the link phase.
+"""
+
+import os
+import shutil
+import subprocess
+import sys
+
+def create_archive(out, objects, archives):
+ mricmd = f'create {out}\n'
+ for o in objects:
+ mricmd += f'addmod {o}\n'
+ for a in archives:
+ mricmd += f'addlib {a}\n'
+ mricmd += 'save\nend\n'
+ subprocess.run([os.getenv('AR'), '-M'], encoding='utf-8', input=mricmd, check=True)
+
+objects = []
+archives = []
+linkdirs = []
+libs = []
+temp_archives = []
+version_script = None
+
+for i, arg in enumerate(sys.argv):
+ if arg == '-o':
+ out = sys.argv[i+1]
+ if arg == '-L':
+ linkdirs.append(sys.argv[i+1])
+ if arg.startswith('-l') or arg == '-shared':
+ libs.append(arg)
+ if arg.startswith('-Wl,--version-script='):
+ version_script = arg[21:]
+ if arg[0] == '-':
+ continue
+ if arg.endswith('.o') or arg.endswith('.rmeta'):
+ objects.append(arg)
+ if arg.endswith('.rlib'):
+ if arg.startswith(os.getenv('TMPDIR')):
+ temp_archives.append(arg)
+ else:
+ archives.append(arg)
+
+create_archive(f'{out}.whole.a', objects, [])
+create_archive(f'{out}.a', [], temp_archives)
+
+with open(out, 'w') as f:
+ print(f'-Wl,--whole-archive', file=f)
+ print(f'{out}.whole.a', file=f)
+ print(f'-Wl,--no-whole-archive', file=f)
+ print(f'{out}.a', file=f)
+ for a in archives:
+ print(a, file=f)
+ for linkdir in linkdirs:
+ print(f'-L{linkdir}', file=f)
+ for l in libs:
+ print(l, file=f)
+ if version_script:
+ shutil.copyfile(version_script, f'{out}.version_script')
+ print(f'-Wl,--version-script={out}.version_script', file=f)
diff --git a/snapshot/host_snapshot.go b/snapshot/host_snapshot.go
index 9793218..edcc163 100644
--- a/snapshot/host_snapshot.go
+++ b/snapshot/host_snapshot.go
@@ -96,6 +96,7 @@
var jsonData []SnapshotJsonFlags
var metaPaths android.Paths
+ installedNotices := make(map[string]bool)
metaZipFile := android.PathForModuleOut(ctx, fileName).OutputPath
// Create JSON file based on the direct dependencies
@@ -104,12 +105,14 @@
if desc != nil {
jsonData = append(jsonData, *desc)
}
- if len(dep.EffectiveLicenseFiles()) > 0 {
- noticeFile := android.PathForModuleOut(ctx, "NOTICE_FILES", dep.Name()+".txt").OutputPath
- android.CatFileRule(ctx, dep.EffectiveLicenseFiles(), noticeFile)
- metaPaths = append(metaPaths, noticeFile)
+ for _, notice := range dep.EffectiveLicenseFiles() {
+ if _, ok := installedNotices[notice.String()]; !ok {
+ installedNotices[notice.String()] = true
+ noticeOut := android.PathForModuleOut(ctx, "NOTICE_FILES", notice.String()).OutputPath
+ CopyFileToOutputPathRule(pctx, ctx, notice, noticeOut)
+ metaPaths = append(metaPaths, noticeOut)
+ }
}
-
})
// Sort notice paths and json data for repeatble build
sort.Slice(jsonData, func(i, j int) bool {
@@ -220,8 +223,7 @@
}
if path.Valid() && path.String() != "" {
- return &SnapshotJsonFlags{
- ModuleName: m.Name(),
+ props := &SnapshotJsonFlags{
ModuleStemName: moduleStem,
Filename: path.String(),
Required: append(m.HostRequiredModuleNames(), m.RequiredModuleNames()...),
@@ -229,6 +231,8 @@
RustProcMacro: procMacro,
CrateName: crateName,
}
+ props.InitBaseSnapshotProps(m)
+ return props
}
return nil
}
diff --git a/snapshot/snapshot.go b/snapshot/snapshot.go
index 206ecc9..c95a537 100644
--- a/snapshot/snapshot.go
+++ b/snapshot/snapshot.go
@@ -26,6 +26,10 @@
var pctx = android.NewPackageContext("android/soong/snapshot")
+func init() {
+ pctx.Import("android/soong/android")
+}
+
type SnapshotSingleton struct {
// Name, e.g., "vendor", "recovery", "ramdisk".
name string
@@ -48,8 +52,18 @@
Fake bool
}
+// The output files to be included in the snapshot.
+type SnapshotPaths struct {
+ // All files to be included in the snapshot
+ OutputFiles android.Paths
+
+ // Notice files of the snapshot output files
+ NoticeFiles android.Paths
+}
+
// Interface of function to capture snapshot from each module
-type GenerateSnapshotAction func(snapshot SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) android.Paths
+// Returns snapshot ouputs and notice files.
+type GenerateSnapshotAction func(snapshot SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) SnapshotPaths
var snapshotActionList []GenerateSnapshotAction
@@ -74,9 +88,19 @@
snapshotDir = filepath.Join("fake", snapshotDir)
}
snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
+ noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES")
+ installedNotices := make(map[string]bool)
for _, f := range snapshotActionList {
- snapshotOutputs = append(snapshotOutputs, f(*c, ctx, snapshotArchDir)...)
+ snapshotPaths := f(*c, ctx, snapshotArchDir)
+ snapshotOutputs = append(snapshotOutputs, snapshotPaths.OutputFiles...)
+ for _, notice := range snapshotPaths.NoticeFiles {
+ if _, ok := installedNotices[notice.String()]; !ok {
+ installedNotices[notice.String()] = true
+ snapshotOutputs = append(snapshotOutputs, CopyFileRule(
+ pctx, ctx, notice, filepath.Join(noticeDir, notice.String())))
+ }
+ }
}
// All artifacts are ready. Sort them to normalize ninja and then zip.
diff --git a/snapshot/snapshot_base.go b/snapshot/snapshot_base.go
index 809ca3d..fb4ee0c 100644
--- a/snapshot/snapshot_base.go
+++ b/snapshot/snapshot_base.go
@@ -120,4 +120,19 @@
// dependencies
Required []string `json:",omitempty"`
Overrides []string `json:",omitempty"`
+
+ // license information
+ LicenseKinds []string `json:",omitempty"`
+ LicenseTexts []string `json:",omitempty"`
+}
+
+func (prop *SnapshotJsonFlags) InitBaseSnapshotPropsWithName(m android.Module, name string) {
+ prop.ModuleName = name
+
+ prop.LicenseKinds = m.EffectiveLicenseKinds()
+ prop.LicenseTexts = m.EffectiveLicenseFiles().Strings()
+}
+
+func (prop *SnapshotJsonFlags) InitBaseSnapshotProps(m android.Module) {
+ prop.InitBaseSnapshotPropsWithName(m, m.Name())
}
diff --git a/snapshot/util.go b/snapshot/util.go
index 806ac90..c87c508 100644
--- a/snapshot/util.go
+++ b/snapshot/util.go
@@ -21,17 +21,25 @@
return outPath
}
-func CopyFileRule(pctx android.PackageContext, ctx android.SingletonContext, path android.Path, out string) android.OutputPath {
- outPath := android.PathForOutput(ctx, out)
+type buildContext interface {
+ Build(pctx android.PackageContext, params android.BuildParams)
+}
+
+func CopyFileToOutputPathRule(pctx android.PackageContext, ctx buildContext, path android.Path, outPath android.OutputPath) {
ctx.Build(pctx, android.BuildParams{
Rule: android.Cp,
Input: path,
Output: outPath,
- Description: "copy " + path.String() + " -> " + out,
+ Description: "copy " + path.String() + " -> " + outPath.String(),
Args: map[string]string{
- "cpFlags": "-f -L",
+ "cpFlags": "-L",
},
})
+}
+
+func CopyFileRule(pctx android.PackageContext, ctx android.SingletonContext, path android.Path, out string) android.OutputPath {
+ outPath := android.PathForOutput(ctx, out)
+ CopyFileToOutputPathRule(pctx, ctx, path, outPath)
return outPath
}
diff --git a/starlark_fmt/format.go b/starlark_fmt/format.go
index a97f71b..4209507 100644
--- a/starlark_fmt/format.go
+++ b/starlark_fmt/format.go
@@ -99,6 +99,16 @@
return PrintDict(valDict, indentLevel)
}
+// PrintStringStringDict returns a Starlark-compatible string formatted as dictionary with
+// string keys and string values.
+func PrintStringStringDict(dict map[string]string, indentLevel int) string {
+ valDict := make(map[string]string, len(dict))
+ for k, v := range dict {
+ valDict[k] = fmt.Sprintf(`"%s"`, v)
+ }
+ return PrintDict(valDict, indentLevel)
+}
+
// PrintDict returns a starlark-compatible string containing a dictionary with string keys and
// values printed with no additional formatting.
func PrintDict(dict map[string]string, indentLevel int) string {
diff --git a/starlark_import/Android.bp b/starlark_import/Android.bp
new file mode 100644
index 0000000..b43217b
--- /dev/null
+++ b/starlark_import/Android.bp
@@ -0,0 +1,36 @@
+// Copyright 2023 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+ name: "soong-starlark",
+ pkgPath: "android/soong/starlark_import",
+ srcs: [
+ "starlark_import.go",
+ "unmarshal.go",
+ ],
+ testSrcs: [
+ "starlark_import_test.go",
+ "unmarshal_test.go",
+ ],
+ deps: [
+ "go-starlark-starlark",
+ "go-starlark-starlarkstruct",
+ "go-starlark-starlarkjson",
+ "go-starlark-starlarktest",
+ ],
+}
diff --git a/starlark_import/README.md b/starlark_import/README.md
new file mode 100644
index 0000000..e444759
--- /dev/null
+++ b/starlark_import/README.md
@@ -0,0 +1,14 @@
+# starlark_import package
+
+This allows soong to read constant information from starlark files. At package initialization
+time, soong will read `build/bazel/constants_exported_to_soong.bzl`, and then make the
+variables from that file available via `starlark_import.GetStarlarkValue()`. So to import
+a new variable, it must be added to `constants_exported_to_soong.bzl` and then it can
+be accessed by name.
+
+Only constant information can be read, since this is not a full bazel execution but a
+standalone starlark interpreter. This means you can't use bazel contructs like `rule`,
+`provider`, `select`, `glob`, etc.
+
+All starlark files that were loaded must be added as ninja deps that cause soong to rerun.
+The loaded files can be retrieved via `starlark_import.GetNinjaDeps()`.
diff --git a/starlark_import/starlark_import.go b/starlark_import/starlark_import.go
new file mode 100644
index 0000000..ebe4247
--- /dev/null
+++ b/starlark_import/starlark_import.go
@@ -0,0 +1,306 @@
+// Copyright 2023 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 starlark_import
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+ "sync"
+ "time"
+
+ "go.starlark.net/starlark"
+ "go.starlark.net/starlarkjson"
+ "go.starlark.net/starlarkstruct"
+)
+
+func init() {
+ go func() {
+ startTime := time.Now()
+ v, d, err := runStarlarkFile("//build/bazel/constants_exported_to_soong.bzl")
+ endTime := time.Now()
+ //fmt.Fprintf(os.Stderr, "starlark run time: %s\n", endTime.Sub(startTime).String())
+ globalResult.Set(starlarkResult{
+ values: v,
+ ninjaDeps: d,
+ err: err,
+ startTime: startTime,
+ endTime: endTime,
+ })
+ }()
+}
+
+type starlarkResult struct {
+ values starlark.StringDict
+ ninjaDeps []string
+ err error
+ startTime time.Time
+ endTime time.Time
+}
+
+// setOnce wraps a value and exposes Set() and Get() accessors for it.
+// The Get() calls will block until a Set() has been called.
+// A second call to Set() will panic.
+// setOnce must be created using newSetOnce()
+type setOnce[T any] struct {
+ value T
+ lock sync.Mutex
+ wg sync.WaitGroup
+ isSet bool
+}
+
+func (o *setOnce[T]) Set(value T) {
+ o.lock.Lock()
+ defer o.lock.Unlock()
+ if o.isSet {
+ panic("Value already set")
+ }
+
+ o.value = value
+ o.isSet = true
+ o.wg.Done()
+}
+
+func (o *setOnce[T]) Get() T {
+ if !o.isSet {
+ o.wg.Wait()
+ }
+ return o.value
+}
+
+func newSetOnce[T any]() *setOnce[T] {
+ result := &setOnce[T]{}
+ result.wg.Add(1)
+ return result
+}
+
+var globalResult = newSetOnce[starlarkResult]()
+
+func GetStarlarkValue[T any](key string) (T, error) {
+ result := globalResult.Get()
+ if result.err != nil {
+ var zero T
+ return zero, result.err
+ }
+ if !result.values.Has(key) {
+ var zero T
+ return zero, fmt.Errorf("a starlark variable by that name wasn't found, did you update //build/bazel/constants_exported_to_soong.bzl?")
+ }
+ return Unmarshal[T](result.values[key])
+}
+
+func GetNinjaDeps() ([]string, error) {
+ result := globalResult.Get()
+ if result.err != nil {
+ return nil, result.err
+ }
+ return result.ninjaDeps, nil
+}
+
+func getTopDir() (string, error) {
+ // It's hard to communicate the top dir to this package in any other way than reading the
+ // arguments directly, because we need to know this at package initialization time. Many
+ // soong constants that we'd like to read from starlark are initialized during package
+ // initialization.
+ for i, arg := range os.Args {
+ if arg == "--top" {
+ if i < len(os.Args)-1 && os.Args[i+1] != "" {
+ return os.Args[i+1], nil
+ }
+ }
+ }
+
+ // When running tests, --top is not passed. Instead, search for the top dir manually
+ cwd, err := os.Getwd()
+ if err != nil {
+ return "", err
+ }
+ for cwd != "/" {
+ if _, err := os.Stat(filepath.Join(cwd, "build/soong/soong_ui.bash")); err == nil {
+ return cwd, nil
+ }
+ cwd = filepath.Dir(cwd)
+ }
+ return "", fmt.Errorf("could not find top dir")
+}
+
+const callerDirKey = "callerDir"
+
+type modentry struct {
+ globals starlark.StringDict
+ err error
+}
+
+func unsupportedMethod(t *starlark.Thread, fn *starlark.Builtin, _ starlark.Tuple, _ []starlark.Tuple) (starlark.Value, error) {
+ return nil, fmt.Errorf("%sthis file is read by soong, and must therefore be pure starlark and include only constant information. %q is not allowed", t.CallStack().String(), fn.Name())
+}
+
+var builtins = starlark.StringDict{
+ "aspect": starlark.NewBuiltin("aspect", unsupportedMethod),
+ "glob": starlark.NewBuiltin("glob", unsupportedMethod),
+ "json": starlarkjson.Module,
+ "provider": starlark.NewBuiltin("provider", unsupportedMethod),
+ "rule": starlark.NewBuiltin("rule", unsupportedMethod),
+ "struct": starlark.NewBuiltin("struct", starlarkstruct.Make),
+ "select": starlark.NewBuiltin("select", unsupportedMethod),
+ "transition": starlark.NewBuiltin("transition", unsupportedMethod),
+}
+
+// Takes a module name (the first argument to the load() function) and returns the path
+// it's trying to load, stripping out leading //, and handling leading :s.
+func cleanModuleName(moduleName string, callerDir string) (string, error) {
+ if strings.Count(moduleName, ":") > 1 {
+ return "", fmt.Errorf("at most 1 colon must be present in starlark path: %s", moduleName)
+ }
+
+ // We don't have full support for external repositories, but at least support skylib's dicts.
+ if moduleName == "@bazel_skylib//lib:dicts.bzl" {
+ return "external/bazel-skylib/lib/dicts.bzl", nil
+ }
+
+ localLoad := false
+ if strings.HasPrefix(moduleName, "@//") {
+ moduleName = moduleName[3:]
+ } else if strings.HasPrefix(moduleName, "//") {
+ moduleName = moduleName[2:]
+ } else if strings.HasPrefix(moduleName, ":") {
+ moduleName = moduleName[1:]
+ localLoad = true
+ } else {
+ return "", fmt.Errorf("load path must start with // or :")
+ }
+
+ if ix := strings.LastIndex(moduleName, ":"); ix >= 0 {
+ moduleName = moduleName[:ix] + string(os.PathSeparator) + moduleName[ix+1:]
+ }
+
+ if filepath.Clean(moduleName) != moduleName {
+ return "", fmt.Errorf("load path must be clean, found: %s, expected: %s", moduleName, filepath.Clean(moduleName))
+ }
+ if strings.HasPrefix(moduleName, "../") {
+ return "", fmt.Errorf("load path must not start with ../: %s", moduleName)
+ }
+ if strings.HasPrefix(moduleName, "/") {
+ return "", fmt.Errorf("load path starts with /, use // for a absolute path: %s", moduleName)
+ }
+
+ if localLoad {
+ return filepath.Join(callerDir, moduleName), nil
+ }
+
+ return moduleName, nil
+}
+
+// loader implements load statement. The format of the loaded module URI is
+//
+// [//path]:base
+//
+// The file path is $ROOT/path/base if path is present, <caller_dir>/base otherwise.
+func loader(thread *starlark.Thread, module string, topDir string, moduleCache map[string]*modentry, moduleCacheLock *sync.Mutex, filesystem map[string]string) (starlark.StringDict, error) {
+ modulePath, err := cleanModuleName(module, thread.Local(callerDirKey).(string))
+ if err != nil {
+ return nil, err
+ }
+ moduleCacheLock.Lock()
+ e, ok := moduleCache[modulePath]
+ if e == nil {
+ if ok {
+ moduleCacheLock.Unlock()
+ return nil, fmt.Errorf("cycle in load graph")
+ }
+
+ // Add a placeholder to indicate "load in progress".
+ moduleCache[modulePath] = nil
+ moduleCacheLock.Unlock()
+
+ childThread := &starlark.Thread{Name: "exec " + module, Load: thread.Load}
+
+ // Cheating for the sake of testing:
+ // propagate starlarktest's Reporter key, otherwise testing
+ // the load function may cause panic in starlarktest code.
+ const testReporterKey = "Reporter"
+ if v := thread.Local(testReporterKey); v != nil {
+ childThread.SetLocal(testReporterKey, v)
+ }
+
+ childThread.SetLocal(callerDirKey, filepath.Dir(modulePath))
+
+ if filesystem != nil {
+ globals, err := starlark.ExecFile(childThread, filepath.Join(topDir, modulePath), filesystem[modulePath], builtins)
+ e = &modentry{globals, err}
+ } else {
+ globals, err := starlark.ExecFile(childThread, filepath.Join(topDir, modulePath), nil, builtins)
+ e = &modentry{globals, err}
+ }
+
+ // Update the cache.
+ moduleCacheLock.Lock()
+ moduleCache[modulePath] = e
+ }
+ moduleCacheLock.Unlock()
+ return e.globals, e.err
+}
+
+// Run runs the given starlark file and returns its global variables and a list of all starlark
+// files that were loaded. The top dir for starlark's // is found via getTopDir().
+func runStarlarkFile(filename string) (starlark.StringDict, []string, error) {
+ topDir, err := getTopDir()
+ if err != nil {
+ return nil, nil, err
+ }
+ return runStarlarkFileWithFilesystem(filename, topDir, nil)
+}
+
+func runStarlarkFileWithFilesystem(filename string, topDir string, filesystem map[string]string) (starlark.StringDict, []string, error) {
+ if !strings.HasPrefix(filename, "//") && !strings.HasPrefix(filename, ":") {
+ filename = "//" + filename
+ }
+ filename, err := cleanModuleName(filename, "")
+ if err != nil {
+ return nil, nil, err
+ }
+ moduleCache := make(map[string]*modentry)
+ moduleCache[filename] = nil
+ moduleCacheLock := &sync.Mutex{}
+ mainThread := &starlark.Thread{
+ Name: "main",
+ Print: func(_ *starlark.Thread, msg string) {
+ // Ignore prints
+ },
+ Load: func(thread *starlark.Thread, module string) (starlark.StringDict, error) {
+ return loader(thread, module, topDir, moduleCache, moduleCacheLock, filesystem)
+ },
+ }
+ mainThread.SetLocal(callerDirKey, filepath.Dir(filename))
+
+ var result starlark.StringDict
+ if filesystem != nil {
+ result, err = starlark.ExecFile(mainThread, filepath.Join(topDir, filename), filesystem[filename], builtins)
+ } else {
+ result, err = starlark.ExecFile(mainThread, filepath.Join(topDir, filename), nil, builtins)
+ }
+ return result, sortedStringKeys(moduleCache), err
+}
+
+func sortedStringKeys(m map[string]*modentry) []string {
+ s := make([]string, 0, len(m))
+ for k := range m {
+ s = append(s, k)
+ }
+ sort.Strings(s)
+ return s
+}
diff --git a/starlark_import/starlark_import_test.go b/starlark_import/starlark_import_test.go
new file mode 100644
index 0000000..8a58e3b
--- /dev/null
+++ b/starlark_import/starlark_import_test.go
@@ -0,0 +1,122 @@
+// Copyright 2023 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 starlark_import
+
+import (
+ "strings"
+ "testing"
+
+ "go.starlark.net/starlark"
+)
+
+func TestBasic(t *testing.T) {
+ globals, _, err := runStarlarkFileWithFilesystem("a.bzl", "", map[string]string{
+ "a.bzl": `
+my_string = "hello, world!"
+`})
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ if globals["my_string"].(starlark.String) != "hello, world!" {
+ t.Errorf("Expected %q, got %q", "hello, world!", globals["my_string"].String())
+ }
+}
+
+func TestLoad(t *testing.T) {
+ globals, _, err := runStarlarkFileWithFilesystem("a.bzl", "", map[string]string{
+ "a.bzl": `
+load("//b.bzl", _b_string = "my_string")
+my_string = "hello, " + _b_string
+`,
+ "b.bzl": `
+my_string = "world!"
+`})
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ if globals["my_string"].(starlark.String) != "hello, world!" {
+ t.Errorf("Expected %q, got %q", "hello, world!", globals["my_string"].String())
+ }
+}
+
+func TestLoadRelative(t *testing.T) {
+ globals, ninjaDeps, err := runStarlarkFileWithFilesystem("a.bzl", "", map[string]string{
+ "a.bzl": `
+load(":b.bzl", _b_string = "my_string")
+load("//foo/c.bzl", _c_string = "my_string")
+my_string = "hello, " + _b_string
+c_string = _c_string
+`,
+ "b.bzl": `
+my_string = "world!"
+`,
+ "foo/c.bzl": `
+load(":d.bzl", _d_string = "my_string")
+my_string = "hello, " + _d_string
+`,
+ "foo/d.bzl": `
+my_string = "world!"
+`})
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ if globals["my_string"].(starlark.String) != "hello, world!" {
+ t.Errorf("Expected %q, got %q", "hello, world!", globals["my_string"].String())
+ }
+
+ expectedNinjaDeps := []string{
+ "a.bzl",
+ "b.bzl",
+ "foo/c.bzl",
+ "foo/d.bzl",
+ }
+ if !slicesEqual(ninjaDeps, expectedNinjaDeps) {
+ t.Errorf("Expected %v ninja deps, got %v", expectedNinjaDeps, ninjaDeps)
+ }
+}
+
+func TestLoadCycle(t *testing.T) {
+ _, _, err := runStarlarkFileWithFilesystem("a.bzl", "", map[string]string{
+ "a.bzl": `
+load(":b.bzl", _b_string = "my_string")
+my_string = "hello, " + _b_string
+`,
+ "b.bzl": `
+load(":a.bzl", _a_string = "my_string")
+my_string = "hello, " + _a_string
+`})
+ if err == nil || !strings.Contains(err.Error(), "cycle in load graph") {
+ t.Errorf("Expected cycle in load graph, got: %v", err)
+ return
+ }
+}
+
+func slicesEqual[T comparable](a []T, b []T) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i := range a {
+ if a[i] != b[i] {
+ return false
+ }
+ }
+ return true
+}
diff --git a/starlark_import/unmarshal.go b/starlark_import/unmarshal.go
new file mode 100644
index 0000000..1b54437
--- /dev/null
+++ b/starlark_import/unmarshal.go
@@ -0,0 +1,288 @@
+// Copyright 2023 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 starlark_import
+
+import (
+ "fmt"
+ "math"
+ "reflect"
+ "unsafe"
+
+ "go.starlark.net/starlark"
+ "go.starlark.net/starlarkstruct"
+)
+
+func Unmarshal[T any](value starlark.Value) (T, error) {
+ var zero T
+ x, err := UnmarshalReflect(value, reflect.TypeOf(zero))
+ return x.Interface().(T), err
+}
+
+func UnmarshalReflect(value starlark.Value, ty reflect.Type) (reflect.Value, error) {
+ zero := reflect.Zero(ty)
+ var result reflect.Value
+ if ty.Kind() == reflect.Interface {
+ var err error
+ ty, err = typeOfStarlarkValue(value)
+ if err != nil {
+ return zero, err
+ }
+ }
+ if ty.Kind() == reflect.Map {
+ result = reflect.MakeMap(ty)
+ } else {
+ result = reflect.Indirect(reflect.New(ty))
+ }
+
+ switch v := value.(type) {
+ case starlark.String:
+ if result.Type().Kind() != reflect.String {
+ return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+ }
+ result.SetString(v.GoString())
+ case starlark.Int:
+ signedValue, signedOk := v.Int64()
+ unsignedValue, unsignedOk := v.Uint64()
+ switch result.Type().Kind() {
+ case reflect.Int64:
+ if !signedOk {
+ return zero, fmt.Errorf("starlark int didn't fit in go int64")
+ }
+ result.SetInt(signedValue)
+ case reflect.Int32:
+ if !signedOk || signedValue > math.MaxInt32 || signedValue < math.MinInt32 {
+ return zero, fmt.Errorf("starlark int didn't fit in go int32")
+ }
+ result.SetInt(signedValue)
+ case reflect.Int16:
+ if !signedOk || signedValue > math.MaxInt16 || signedValue < math.MinInt16 {
+ return zero, fmt.Errorf("starlark int didn't fit in go int16")
+ }
+ result.SetInt(signedValue)
+ case reflect.Int8:
+ if !signedOk || signedValue > math.MaxInt8 || signedValue < math.MinInt8 {
+ return zero, fmt.Errorf("starlark int didn't fit in go int8")
+ }
+ result.SetInt(signedValue)
+ case reflect.Int:
+ if !signedOk || signedValue > math.MaxInt || signedValue < math.MinInt {
+ return zero, fmt.Errorf("starlark int didn't fit in go int")
+ }
+ result.SetInt(signedValue)
+ case reflect.Uint64:
+ if !unsignedOk {
+ return zero, fmt.Errorf("starlark int didn't fit in go uint64")
+ }
+ result.SetUint(unsignedValue)
+ case reflect.Uint32:
+ if !unsignedOk || unsignedValue > math.MaxUint32 {
+ return zero, fmt.Errorf("starlark int didn't fit in go uint32")
+ }
+ result.SetUint(unsignedValue)
+ case reflect.Uint16:
+ if !unsignedOk || unsignedValue > math.MaxUint16 {
+ return zero, fmt.Errorf("starlark int didn't fit in go uint16")
+ }
+ result.SetUint(unsignedValue)
+ case reflect.Uint8:
+ if !unsignedOk || unsignedValue > math.MaxUint8 {
+ return zero, fmt.Errorf("starlark int didn't fit in go uint8")
+ }
+ result.SetUint(unsignedValue)
+ case reflect.Uint:
+ if !unsignedOk || unsignedValue > math.MaxUint {
+ return zero, fmt.Errorf("starlark int didn't fit in go uint")
+ }
+ result.SetUint(unsignedValue)
+ default:
+ return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+ }
+ case starlark.Float:
+ f := float64(v)
+ switch result.Type().Kind() {
+ case reflect.Float64:
+ result.SetFloat(f)
+ case reflect.Float32:
+ if f > math.MaxFloat32 || f < -math.MaxFloat32 {
+ return zero, fmt.Errorf("starlark float didn't fit in go float32")
+ }
+ result.SetFloat(f)
+ default:
+ return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+ }
+ case starlark.Bool:
+ if result.Type().Kind() != reflect.Bool {
+ return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+ }
+ result.SetBool(bool(v))
+ case starlark.Tuple:
+ if result.Type().Kind() != reflect.Slice {
+ return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+ }
+ elemType := result.Type().Elem()
+ // TODO: Add this grow call when we're on go 1.20
+ //result.Grow(v.Len())
+ for i := 0; i < v.Len(); i++ {
+ elem, err := UnmarshalReflect(v.Index(i), elemType)
+ if err != nil {
+ return zero, err
+ }
+ result = reflect.Append(result, elem)
+ }
+ case *starlark.List:
+ if result.Type().Kind() != reflect.Slice {
+ return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+ }
+ elemType := result.Type().Elem()
+ // TODO: Add this grow call when we're on go 1.20
+ //result.Grow(v.Len())
+ for i := 0; i < v.Len(); i++ {
+ elem, err := UnmarshalReflect(v.Index(i), elemType)
+ if err != nil {
+ return zero, err
+ }
+ result = reflect.Append(result, elem)
+ }
+ case *starlark.Dict:
+ if result.Type().Kind() != reflect.Map {
+ return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+ }
+ keyType := result.Type().Key()
+ valueType := result.Type().Elem()
+ for _, pair := range v.Items() {
+ key := pair.Index(0)
+ value := pair.Index(1)
+
+ unmarshalledKey, err := UnmarshalReflect(key, keyType)
+ if err != nil {
+ return zero, err
+ }
+ unmarshalledValue, err := UnmarshalReflect(value, valueType)
+ if err != nil {
+ return zero, err
+ }
+
+ result.SetMapIndex(unmarshalledKey, unmarshalledValue)
+ }
+ case *starlarkstruct.Struct:
+ if result.Type().Kind() != reflect.Struct {
+ return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+ }
+ if result.NumField() != len(v.AttrNames()) {
+ return zero, fmt.Errorf("starlark struct and go struct have different number of fields (%d and %d)", len(v.AttrNames()), result.NumField())
+ }
+ for _, attrName := range v.AttrNames() {
+ attr, err := v.Attr(attrName)
+ if err != nil {
+ return zero, err
+ }
+
+ // TODO(b/279787235): this should probably support tags to rename the field
+ resultField := result.FieldByName(attrName)
+ if resultField == (reflect.Value{}) {
+ return zero, fmt.Errorf("starlark struct had field %s, but requested struct type did not", attrName)
+ }
+ // This hack allows us to change unexported fields
+ resultField = reflect.NewAt(resultField.Type(), unsafe.Pointer(resultField.UnsafeAddr())).Elem()
+ x, err := UnmarshalReflect(attr, resultField.Type())
+ if err != nil {
+ return zero, err
+ }
+ resultField.Set(x)
+ }
+ default:
+ return zero, fmt.Errorf("unimplemented starlark type: %s", value.Type())
+ }
+
+ return result, nil
+}
+
+func typeOfStarlarkValue(value starlark.Value) (reflect.Type, error) {
+ var err error
+ switch v := value.(type) {
+ case starlark.String:
+ return reflect.TypeOf(""), nil
+ case *starlark.List:
+ innerType := reflect.TypeOf("")
+ if v.Len() > 0 {
+ innerType, err = typeOfStarlarkValue(v.Index(0))
+ if err != nil {
+ return nil, err
+ }
+ }
+ for i := 1; i < v.Len(); i++ {
+ innerTypeI, err := typeOfStarlarkValue(v.Index(i))
+ if err != nil {
+ return nil, err
+ }
+ if innerType != innerTypeI {
+ return nil, fmt.Errorf("List must contain elements of entirely the same type, found %v and %v", innerType, innerTypeI)
+ }
+ }
+ return reflect.SliceOf(innerType), nil
+ case *starlark.Dict:
+ keyType := reflect.TypeOf("")
+ valueType := reflect.TypeOf("")
+ keys := v.Keys()
+ if v.Len() > 0 {
+ firstKey := keys[0]
+ keyType, err = typeOfStarlarkValue(firstKey)
+ if err != nil {
+ return nil, err
+ }
+ firstValue, found, err := v.Get(firstKey)
+ if !found {
+ err = fmt.Errorf("value not found")
+ }
+ if err != nil {
+ return nil, err
+ }
+ valueType, err = typeOfStarlarkValue(firstValue)
+ if err != nil {
+ return nil, err
+ }
+ }
+ for _, key := range keys {
+ keyTypeI, err := typeOfStarlarkValue(key)
+ if err != nil {
+ return nil, err
+ }
+ if keyType != keyTypeI {
+ return nil, fmt.Errorf("dict must contain elements of entirely the same type, found %v and %v", keyType, keyTypeI)
+ }
+ value, found, err := v.Get(key)
+ if !found {
+ err = fmt.Errorf("value not found")
+ }
+ if err != nil {
+ return nil, err
+ }
+ valueTypeI, err := typeOfStarlarkValue(value)
+ if valueType.Kind() != reflect.Interface && valueTypeI != valueType {
+ // If we see conflicting value types, change the result value type to an empty interface
+ valueType = reflect.TypeOf([]interface{}{}).Elem()
+ }
+ }
+ return reflect.MapOf(keyType, valueType), nil
+ case starlark.Int:
+ return reflect.TypeOf(0), nil
+ case starlark.Float:
+ return reflect.TypeOf(0.0), nil
+ case starlark.Bool:
+ return reflect.TypeOf(true), nil
+ default:
+ return nil, fmt.Errorf("unimplemented starlark type: %s", value.Type())
+ }
+}
diff --git a/starlark_import/unmarshal_test.go b/starlark_import/unmarshal_test.go
new file mode 100644
index 0000000..ee7a9e3
--- /dev/null
+++ b/starlark_import/unmarshal_test.go
@@ -0,0 +1,133 @@
+// Copyright 2023 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 starlark_import
+
+import (
+ "reflect"
+ "testing"
+
+ "go.starlark.net/starlark"
+)
+
+func createStarlarkValue(t *testing.T, code string) starlark.Value {
+ t.Helper()
+ result, err := starlark.ExecFile(&starlark.Thread{}, "main.bzl", "x = "+code, builtins)
+ if err != nil {
+ panic(err)
+ }
+ return result["x"]
+}
+
+func TestUnmarshallConcreteType(t *testing.T) {
+ x, err := Unmarshal[string](createStarlarkValue(t, `"foo"`))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if x != "foo" {
+ t.Errorf(`Expected "foo", got %q`, x)
+ }
+}
+
+func TestUnmarshallConcreteTypeWithInterfaces(t *testing.T) {
+ x, err := Unmarshal[map[string]map[string]interface{}](createStarlarkValue(t,
+ `{"foo": {"foo2": "foo3"}, "bar": {"bar2": ["bar3"]}}`))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ expected := map[string]map[string]interface{}{
+ "foo": {"foo2": "foo3"},
+ "bar": {"bar2": []string{"bar3"}},
+ }
+ if !reflect.DeepEqual(x, expected) {
+ t.Errorf(`Expected %v, got %v`, expected, x)
+ }
+}
+
+func TestUnmarshall(t *testing.T) {
+ testCases := []struct {
+ input string
+ expected interface{}
+ }{
+ {
+ input: `"foo"`,
+ expected: "foo",
+ },
+ {
+ input: `5`,
+ expected: 5,
+ },
+ {
+ input: `["foo", "bar"]`,
+ expected: []string{"foo", "bar"},
+ },
+ {
+ input: `("foo", "bar")`,
+ expected: []string{"foo", "bar"},
+ },
+ {
+ input: `("foo",5)`,
+ expected: []interface{}{"foo", 5},
+ },
+ {
+ input: `{"foo": 5, "bar": 10}`,
+ expected: map[string]int{"foo": 5, "bar": 10},
+ },
+ {
+ input: `{"foo": ["qux"], "bar": []}`,
+ expected: map[string][]string{"foo": {"qux"}, "bar": nil},
+ },
+ {
+ input: `struct(Foo="foo", Bar=5)`,
+ expected: struct {
+ Foo string
+ Bar int
+ }{Foo: "foo", Bar: 5},
+ },
+ {
+ // Unexported fields version of the above
+ input: `struct(foo="foo", bar=5)`,
+ expected: struct {
+ foo string
+ bar int
+ }{foo: "foo", bar: 5},
+ },
+ {
+ input: `{"foo": "foo2", "bar": ["bar2"], "baz": 5, "qux": {"qux2": "qux3"}, "quux": {"quux2": "quux3", "quux4": 5}}`,
+ expected: map[string]interface{}{
+ "foo": "foo2",
+ "bar": []string{"bar2"},
+ "baz": 5,
+ "qux": map[string]string{"qux2": "qux3"},
+ "quux": map[string]interface{}{
+ "quux2": "quux3",
+ "quux4": 5,
+ },
+ },
+ },
+ }
+
+ for _, tc := range testCases {
+ x, err := UnmarshalReflect(createStarlarkValue(t, tc.input), reflect.TypeOf(tc.expected))
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if !reflect.DeepEqual(x.Interface(), tc.expected) {
+ t.Errorf(`Expected %#v, got %#v`, tc.expected, x.Interface())
+ }
+ }
+}
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index 68d7f8d..71e6af0 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -53,6 +53,20 @@
if [[ "$buildfile_mtime1" != "$buildfile_mtime2" ]]; then
fail "BUILD.bazel was updated even though contents are same"
fi
+
+ # Force bp2build to rerun by updating the timestamp of the constants_exported_to_soong.bzl file.
+ touch build/bazel/constants_exported_to_soong.bzl
+
+ run_soong bp2build
+ local -r buildfile_mtime3=$(stat -c "%y" out/soong/bp2build/pkg/BUILD.bazel)
+ local -r marker_mtime3=$(stat -c "%y" out/soong/bp2build_workspace_marker)
+
+ if [[ "$marker_mtime2" == "$marker_mtime3" ]]; then
+ fail "Expected bp2build marker file to change"
+ fi
+ if [[ "$buildfile_mtime2" != "$buildfile_mtime3" ]]; then
+ fail "BUILD.bazel was updated even though contents are same"
+ fi
}
# Tests that blueprint files that are deleted are not present when the
diff --git a/tests/mixed_mode_test.sh b/tests/mixed_mode_test.sh
index 7b3151b..ca63fdf 100755
--- a/tests/mixed_mode_test.sh
+++ b/tests/mixed_mode_test.sh
@@ -1,4 +1,4 @@
-#!/bin/bash -eu
+#!/bin/bash
set -o pipefail
@@ -63,4 +63,37 @@
fi
}
-scan_and_run_tests
\ No newline at end of file
+function test_force_enabled_modules {
+ setup
+ # b/273910287 - test force enable modules
+ mkdir -p soong_tests/a/b
+ cat > soong_tests/a/b/Android.bp <<'EOF'
+genrule {
+ name: "touch-file",
+ out: ["fake-out.txt"],
+ cmd: "touch $(out)",
+ bazel_module: { bp2build_available: true },
+}
+
+genrule {
+ name: "unenabled-touch-file",
+ out: ["fake-out2.txt"],
+ cmd: "touch $(out)",
+ bazel_module: { bp2build_available: false },
+}
+EOF
+ run_soong --bazel-mode-staging --bazel-force-enabled-modules=touch-file nothing
+ local bazel_contained=`grep out/soong/.intermediates/soong_tests/a/b/touch-file/gen/fake-out.txt out/soong/build.ninja`
+ if [[ $bazel_contained == '' ]]; then
+ fail "Bazel actions not found for force-enabled module"
+ fi
+
+ unused=`run_soong --bazel-force-enabled-modules=unenabled-touch-file --ensure-allowlist-integrity nothing >/dev/null`
+
+ if [[ $? -ne 1 ]]; then
+ fail "Expected failure due to force-enabling an unenabled module "
+ fi
+}
+
+
+scan_and_run_tests
diff --git a/tests/persistent_bazel_test.sh b/tests/persistent_bazel_test.sh
index 4e2982a..9b7b58f 100755
--- a/tests/persistent_bazel_test.sh
+++ b/tests/persistent_bazel_test.sh
@@ -73,8 +73,8 @@
USE_PERSISTENT_BAZEL=1 run_soong nothing 1>out/failurelog.txt 2>&1 && fail "Expected build failure" || true
- if ! grep -sq "'build/bazel/rules' is not a package" out/failurelog.txt ; then
- fail "Expected error to contain 'build/bazel/rules' is not a package, instead got:\n$(cat out/failurelog.txt)"
+ if ! grep -sq "cannot load //build/bazel/rules/common/api_constants.bzl" out/failurelog.txt ; then
+ fail "Expected error to contain 'cannot load //build/bazel/rules/common/api_constants.bzl', instead got:\n$(cat out/failurelog.txt)"
fi
kill $(cat out/bazel/output/server/server.pid.txt) 2>/dev/null || true
diff --git a/tradefed/suite_harness/tradefed_binary.go b/tradefed/suite_harness/tradefed_binary.go
index a421d8b..1ce94bc 100644
--- a/tradefed/suite_harness/tradefed_binary.go
+++ b/tradefed/suite_harness/tradefed_binary.go
@@ -78,7 +78,6 @@
// Add dependencies required by all tradefed_binary modules.
props.Libs = []string{
"tradefed",
- "tradefed-test-framework",
"loganalysis",
"compatibility-host-util",
}
diff --git a/ui/build/build.go b/ui/build/build.go
index edc595d..6874ef7 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -259,10 +259,16 @@
startGoma(ctx, config)
}
+ rbeCh := make(chan bool)
if config.StartRBE() {
cleanupRBELogsDir(ctx, config)
- startRBE(ctx, config)
+ go func() {
+ startRBE(ctx, config)
+ close(rbeCh)
+ }()
defer DumpRBEMetrics(ctx, config, filepath.Join(config.LogsDir(), "rbe_metrics.pb"))
+ } else {
+ close(rbeCh)
}
if what&RunProductConfig != 0 {
@@ -315,11 +321,11 @@
testForDanglingRules(ctx, config)
}
+ <-rbeCh
if what&RunNinja != 0 {
if what&RunKati != 0 {
installCleanIfNecessary(ctx, config)
}
-
runNinjaForBuild(ctx, config)
}
diff --git a/ui/build/config.go b/ui/build/config.go
index a755d14..2dda52a 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -67,28 +67,29 @@
logsPrefix string
// From the arguments
- parallel int
- keepGoing int
- verbose bool
- checkbuild bool
- dist bool
- jsonModuleGraph bool
- apiBp2build bool // Generate BUILD files for Soong modules that contribute APIs
- bp2build bool
- queryview bool
- reportMkMetrics bool // Collect and report mk2bp migration progress metrics.
- soongDocs bool
- multitreeBuild bool // This is a multitree build.
- skipConfig bool
- skipKati bool
- skipKatiNinja bool
- skipSoong bool
- skipNinja bool
- skipSoongTests bool
- searchApiDir bool // Scan the Android.bp files generated in out/api_surfaces
- skipMetricsUpload bool
- buildStartedTime int64 // For metrics-upload-only - manually specify a build-started time
- buildFromTextStub bool
+ parallel int
+ keepGoing int
+ verbose bool
+ checkbuild bool
+ dist bool
+ jsonModuleGraph bool
+ apiBp2build bool // Generate BUILD files for Soong modules that contribute APIs
+ bp2build bool
+ queryview bool
+ reportMkMetrics bool // Collect and report mk2bp migration progress metrics.
+ soongDocs bool
+ multitreeBuild bool // This is a multitree build.
+ skipConfig bool
+ skipKati bool
+ skipKatiNinja bool
+ skipSoong bool
+ skipNinja bool
+ skipSoongTests bool
+ searchApiDir bool // Scan the Android.bp files generated in out/api_surfaces
+ skipMetricsUpload bool
+ buildStartedTime int64 // For metrics-upload-only - manually specify a build-started time
+ buildFromTextStub bool
+ ensureAllowlistIntegrity bool // For CI builds - make sure modules are mixed-built
// From the product config
katiArgs []string
@@ -813,9 +814,6 @@
// by a previous build.
c.skipConfig = true
c.skipKati = true
- } else if arg == "--skip-kati" {
- // TODO: remove --skip-kati once module builds have been migrated to --song-only
- c.skipKati = true
} else if arg == "--soong-only" {
c.skipKati = true
c.skipKatiNinja = true
@@ -883,6 +881,8 @@
} else {
ctx.Fatalf("Error parsing build-time-started-unix-millis", err)
}
+ } else if arg == "--ensure-allowlist-integrity" {
+ c.ensureAllowlistIntegrity = true
} else if len(arg) > 0 && arg[0] == '-' {
parseArgNum := func(def int) int {
if len(arg) > 2 {
@@ -1374,6 +1374,15 @@
return filepath.Join(buildTmpDir, "rbe")
}
+func (c *configImpl) rbeCacheDir() string {
+ for _, f := range []string{"RBE_cache_dir", "FLAG_cache_dir"} {
+ if v, ok := c.environ.Get(f); ok {
+ return v
+ }
+ }
+ return shared.JoinPath(c.SoongOutDir(), "rbe")
+}
+
func (c *configImpl) shouldCleanupRBELogsDir() bool {
// Perform a log directory cleanup only when the log directory
// is auto created by the build rather than user-specified.
@@ -1701,6 +1710,10 @@
return c.skipMetricsUpload
}
+func (c *configImpl) EnsureAllowlistIntegrity() bool {
+ return c.ensureAllowlistIntegrity
+}
+
// Returns a Time object if one was passed via a command-line flag.
// Otherwise returns the passed default.
func (c *configImpl) BuildStartedTimeOrDefault(defaultTime time.Time) time.Time {
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
index 1d17216..6479925 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -60,6 +60,7 @@
"RBE_exec_root": config.rbeExecRoot(),
"RBE_output_dir": config.rbeProxyLogsDir(),
"RBE_proxy_log_dir": config.rbeProxyLogsDir(),
+ "RBE_cache_dir": config.rbeCacheDir(),
"RBE_platform": "container-image=" + remoteexec.DefaultImage,
}
if config.StartRBE() {
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 9287731..563199b 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -288,6 +288,9 @@
if config.buildFromTextStub {
mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--build-from-text-stub")
}
+ if config.ensureAllowlistIntegrity {
+ mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--ensure-allowlist-integrity")
+ }
queryviewDir := filepath.Join(config.SoongOutDir(), "queryview")
// The BUILD files will be generated in out/soong/.api_bp2build (no symlinks to src files)
diff --git a/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go b/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go
index f8b8fd6..bf5e80b 100644
--- a/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go
+++ b/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go
@@ -14,8 +14,8 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.28.0
-// protoc v3.21.7
+// protoc-gen-go v1.30.0
+// protoc v3.21.12
// source: bazel_metrics.proto
package bazel_metrics_proto
@@ -41,6 +41,7 @@
PhaseTimings []*PhaseTiming `protobuf:"bytes,1,rep,name=phase_timings,json=phaseTimings,proto3" json:"phase_timings,omitempty"`
Total *int64 `protobuf:"varint,2,opt,name=total,proto3,oneof" json:"total,omitempty"`
+ ExitCode *int32 `protobuf:"varint,3,opt,name=exit_code,json=exitCode,proto3,oneof" json:"exit_code,omitempty"`
}
func (x *BazelMetrics) Reset() {
@@ -89,6 +90,13 @@
return 0
}
+func (x *BazelMetrics) GetExitCode() int32 {
+ if x != nil && x.ExitCode != nil {
+ return *x.ExitCode
+ }
+ return 0
+}
+
type PhaseTiming struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -161,15 +169,18 @@
0x0a, 0x13, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69,
0x6c, 0x64, 0x5f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
- 0x22, 0x80, 0x01, 0x0a, 0x0c, 0x42, 0x61, 0x7a, 0x65, 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
+ 0x22, 0xb0, 0x01, 0x0a, 0x0c, 0x42, 0x61, 0x7a, 0x65, 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
0x73, 0x12, 0x4b, 0x0a, 0x0d, 0x70, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x69, 0x6e,
0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67,
0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x65, 0x74,
0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x68, 0x61, 0x73, 0x65, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67,
0x52, 0x0c, 0x70, 0x68, 0x61, 0x73, 0x65, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x19,
0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52,
- 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x74, 0x6f,
- 0x74, 0x61, 0x6c, 0x22, 0xd1, 0x01, 0x0a, 0x0b, 0x50, 0x68, 0x61, 0x73, 0x65, 0x54, 0x69, 0x6d,
+ 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, 0x65, 0x78, 0x69,
+ 0x74, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x48, 0x01, 0x52, 0x08,
+ 0x65, 0x78, 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f,
+ 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x63,
+ 0x6f, 0x64, 0x65, 0x22, 0xd1, 0x01, 0x0a, 0x0b, 0x50, 0x68, 0x61, 0x73, 0x65, 0x54, 0x69, 0x6d,
0x69, 0x6e, 0x67, 0x12, 0x22, 0x0a, 0x0a, 0x70, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x6e, 0x61, 0x6d,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x70, 0x68, 0x61, 0x73, 0x65,
0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x2a, 0x0a, 0x0e, 0x64, 0x75, 0x72, 0x61, 0x74,
diff --git a/ui/metrics/bazel_metrics_proto/bazel_metrics.proto b/ui/metrics/bazel_metrics_proto/bazel_metrics.proto
index 57eed4c..9073080 100644
--- a/ui/metrics/bazel_metrics_proto/bazel_metrics.proto
+++ b/ui/metrics/bazel_metrics_proto/bazel_metrics.proto
@@ -20,6 +20,7 @@
message BazelMetrics {
repeated PhaseTiming phase_timings = 1;
optional int64 total = 2;
+ optional int32 exit_code = 3;
}
message PhaseTiming {